The Webcomponent Manifest
Any webcomponent is or aims to be:
- an HTML tag
- a CSS encapsulated environment
- a JS business logic unit
As HTML tag, a custom webcomponent has attributes
and properties
. Moreover a pair attribute
and property
can be coupled by reflecting changes: a change on the former is mirrored on the latter, and viceversa.
Basics
The Configurator layout section queries the webcomponents to discover their properties/attributes using a static getter promise called a Manifest.
You can use the JSON schema to check your components manifests.
The __manifest
static getter must return a JavaScript object that has a key type
which must be object
(to be JSON schema compatible) and a map of properties
.
const manifest = {
type: 'object',
properties: {
// list of properties
}
}
A custom button might look like:
// my-button.ts
import { LitElement } from 'lit'
class MyButton extends LitElement {
static get __manifest() {
return import('./manifest').then(({default: manifest}) => manifest)
}
@property() hidden?: boolean
}
and thus will instruct the Configurator preview section with the following manifest
// manifest.ts
import type { Manifest } from '@micro-lc/compose-toolkit'
const manifest = {
type: 'object',
properties: {
hidden: {
type: 'boolean'
}
}
}
export default manifest
In the outlined example, the Configurator layout section will provide its configuration form with a boolean toggle for the hidden
property.
Types can be almost anything that JSON schema provides:
boolean
string
number
object
array
- a
oneOf
array of primitives
For each of these, the Configurator layout will provide a consistent form input to edit the property.
Trivially, primitive types boolean
, string
, and number
are simple to edit from a form input.
Complex properties such as objects and arrays are also handled in a no-code
fashion so far the manifest is precise in describing their nested properties.
The most basic visualization for an object
without a schema is an IDE-like editor, with basic JSON validation capabilities. Likewise an array has a no-code
item selector, which again, without schema will spawn an IDE-like editor for each one of its items.
The owner/developer of custom webcomponents can enforce no-code
configurability by nesting the component manifest.
For instance:
// my-button.ts
import { LitElement } from 'lit'
interface Action {
type: 'http-request' | 'file-upload'
url: string
}
class MyButton extends LitElement {
static get __manifest() {
return import('./manifest').then(({default: manifest}) => manifest)
}
@property() action?: Action
}
can be described by the following manifest
// manifest.ts
import type { Manifest } from '@micro-lc/compose-toolkit'
const manifest: Manifest = {
type: 'object',
properties: {
action: {
type: 'object',
properties: {
type: {type: 'string', enum: ['http-request', 'file-upload']},
url: {type: 'string'}
}
}
}
}
export default manifest
Despite the action
being an object, the Configurator layout section will spawn a modal (which can have potentially infinite levels of nesting) to configure type
as a string with at most 2 fixed values and url
as a string.
Mia's Configuration Advanced
The Webcomponent manifest is a superset of a compliant draft-07 JSON schema. The Configurator guarantees to display a no-code
comfortable version of each property.
Beside this specification, Configurator can enforce some extra logic using a special property, available to any webcomponent property or nested property: __mia_configuration
.
Let's consider a custom button
// my-button.ts
import { LitElement } from 'lit'
class MyButton extends LitElement {
static get __manifest() {
return import('./manifest').then(({default: manifest}) => manifest)
}
@property() hidden?: boolean
}
with manifest
// manifest.ts
import type { Manifest } from '@micro-lc/compose-toolkit'
const manifest = {
type: 'object',
properties: {
hidden: {
type: 'boolean'
__mia_configuration: {
// mia specific configurations
}
}
}
}
export default manifest
The __mia_configuration
object targets the following use cases:
deprecated
▶️ mark a property for deprecationlabel
▶️ The label to show on the form input/editor used to configure the given property. This label supports i18n by supporting both astring
and a dictionary where the key is the language 2 letters code and the translation.description
▶️ helpful when the property configuration is complicated or nested: provides a description tooltip to help the user.docLink
▶️ replaces thedescription
tooltip with a link to external documentationoneOfGuard
▶️ see refoneOfDefault
▶️ allows to select adefault
branch of a JSON schemaoneOf
section.priority
▶️ groups properties in 3 levels inside the Configurator layout section form. Helpful when multiple personas are interacting with the configuration by highlighting those properties which are most likely to be tuned.attribute
▶️ instructs the Configurator layout section that the property is mirrored by an HTML attribute (NOT USED ATM).schema-hint
▶️ Configurator layout section knows some often used property schemas and provides labels to select them instead of writing the whole property JSON schema.shared-key
▶️ Configurator allows to share JSON schema definitions by resolving in-place their references.enumLabels
▶️ provides the capability to i18n-ify string enums
Summarizing the __mia_configuration
property must comply with the following type:
/**
* This interface was referenced by `MiaSchema`'s JSON-Schema
* via the `definition` "__mia_configuration".
*/
export interface MiaConfiguration {
deprecated?:
| boolean
| {
since?: string
description?: LocalizedText
[k: string]: unknown
}
label?: LocalizedText
description?: LocalizedText
docLink?: string
oneOfGuard?: string
oneOfDefault?: number
priority?: "high" | "medium" | "low"
attribute?: boolean | string
"schema-hint"?:
| "localized-text"
| "dynamic-icon"
| "on-off-toggle"
| "color"
| "event"
| "mia/endpoints"
| "mia/endpoints/crud"
| "mia/endpoints/crud-and-generate-data-schema"
| "micro-lc/applications"
"shared-key"?: "back-kit/data-schema" | string
enumLabels?: {
[k: string]: LocalizedText
}
}
The oneOfGuard
key
Suppose your property is a JSON oneOf
an there's a guard key which allows to distinguish non-overlapping types. For instance:
// manifest.ts
import type { Manifest } from '@micro-lc/compose-toolkit'
const manifest = {
type: 'object',
properties: {
action: {
type: 'object',
oneOf: [
{
properties: {
type: {const: 'http-post'},
url: {type: 'string'},
payload: {type: 'string'}
}
},
{
properties: {
type: {const: 'event'},
payload: {type: 'object'}
}
}
]
__mia_configuration: {
oneOfGuard: 'type'
}
}
}
}
export default manifest
By using oneOfGuard
set to type
Configurator layout section is able to provide a no-code
configuration to the property action
by requesting the user to select a type
between http-post
and event
and then the rest of the object.
If the user selects http-post
then 2 string input will appear in order to configure url
and payload
, otherwise an IDE-like editor will allow to type directly the payload
property since no schema was provided.
The schema-hint
key
Configurator provides some types that are well known and often used in order to avoid writing down a repeating JSON schema multiple times.
- A
localized-text
hints for a string or a dictionary of translations - A
dynamic-icon
is a property that complies with the@micro-lc/iconic
icon interface - An
on-off-toggle
is a number, either0
and1
which will be rendered as a boolean toggle - A
color
spawns a color picker - An
event
expects an object with at least 2 properties:- a
label
which must be astring
- and a
payload
which must be anobject
- a
- A
mia/endpoints
spawns a selection with a fixed list of options which are Mia Platform's Console currently available http endpoints. - A
mia/endpoints/crud
is the list ofmia/endpoints
coming from aCRUD Service
microservice. - A
mia/endpoints/data-source
is the list ofmia/endpoints
coming from aCRUD Service
microservice, a Mongo View, a Fast Data projection, or a Fast Data Single View. - A
micro-lc/applications
is the list of currently configured applications in the Configurator initial section.
The shared-key
key
JSON schema supports referencing of property definitions. Despite not being a fixed pattern there's a recommendation for draft-07 which suggests to use the key definitions
at the first level of your JSON configuration. In the most recent drafts it will be substituted by the $defs
keyword.
The following example shows how it works:
{
"definitions": {
"propertyUsedMultipleTimes": {
// property schema
}
},
"type": "object",
"properties": {
"first": {
"$ref": "#/definitions/propertyUsedMultipleTimes"
},
"second": {
"$ref": "#/definitions/propertyUsedMultipleTimes"
}
}
}
The shared-key
property suggests to the Configurator how to group properties using JSON definitions
(refer to the dedicated documentation for more information).