fast-tooling/packages/design-to-code
FAST DevOps 3dfde1536c applying package updates 2022-10-04 07:14:24 +00:00
..
app Update packages to new name (#229) 2022-10-03 10:13:10 -07:00
build Update packages to new name (#229) 2022-10-03 10:13:10 -07:00
src Update packages to new name (#229) 2022-10-03 10:13:10 -07:00
.eslintignore Update packages to new name (#229) 2022-10-03 10:13:10 -07:00
.eslintrc.cjs Update packages to new name (#229) 2022-10-03 10:13:10 -07:00
.mocharc.json Update packages to new name (#229) 2022-10-03 10:13:10 -07:00
.npmignore Update packages to new name (#229) 2022-10-03 10:13:10 -07:00
.prettierignore Update packages to new name (#229) 2022-10-03 10:13:10 -07:00
CHANGELOG.json applying package updates 2022-10-04 07:14:24 +00:00
CHANGELOG.md Update packages to new name (#229) 2022-10-03 10:13:10 -07:00
README.md Update packages to new name (#229) 2022-10-03 10:13:10 -07:00
karma.conf.cjs Update packages to new name (#229) 2022-10-03 10:13:10 -07:00
package.json Update packages to new name (#229) 2022-10-03 10:13:10 -07:00
playwright-webpack.config.ts Update packages to new name (#229) 2022-10-03 10:13:10 -07:00
playwright.config.ts Update packages to new name (#229) 2022-10-03 10:13:10 -07:00
playwright.global-setup.ts Update packages to new name (#229) 2022-10-03 10:13:10 -07:00
tsconfig.cjs.json Update packages to new name (#229) 2022-10-03 10:13:10 -07:00
tsconfig.esm.json Update packages to new name (#229) 2022-10-03 10:13:10 -07:00
tsconfig.json Update packages to new name (#229) 2022-10-03 10:13:10 -07:00
webpack.config.cjs Update packages to new name (#229) 2022-10-03 10:13:10 -07:00
webpack.message-system.config.cjs Update packages to new name (#229) 2022-10-03 10:13:10 -07:00

README.md

Design to Code

Design to Code is a library agnostic specific set of utilities to assist in creating web UI.

JavaScript   TypeScript

Installation

npm i --save @microsoft/design-to-code

Concepts

JSON Schema

JSON schema are used by Design to Code libraries for generating data and creating UI. They have been extended to provide additional hooks for plugin systems in the Design to Code libraries. When providing a dictionary of JSON schema, use the id as a key, this is required for utilities to quickly access the correct JSON schema.

Nesting data

To identify nesting structures in the JSON schemas, such as with composable components, use the linkedDataSchema export from the @microsoft/design-to-code package which defines the interface expected for the link and adds a property key to identify this section of data as linked data.

Example JSON Schema with linked data properties:

import { linkedDataSchema } from "@microsoft/design-to-code";

export default {
    $schema: "http://json-schema.org/schema#",
    title: "Component with nested properties",
    type: "object",
    id: "nestable-component",
    properties: {
        children: {
            ...linkedDataSchema,
            title: "Children",
            type: "string"
        },
    }
}

Although JSON schema can be written in JSON, it is recommended creating the schema as a data blob in a JavaScript or TypeScript file so that it can use the provided helper exports.

Message system

Design to Code components rely on including a secondary script which contains a web worker called the message system.

This worker performs all of the data manipulation and provides a navigational data structure based on data passed.

Sending and receiving messages

There is a secondary export, MessageSystem, which must be instantiated with the location on the server of the web worker. The file is located at @microsoft/design-to-code/message-system.min.js. This is then passed to various components that are part of the tooling package to sync data and navigation.

Example implementation:

import { MessageSystem } from "@microsoft/design-to-code";

let messageSystem;

// Your JSON schema
const mySchema = {
    id: "my-schema",
    type: "object",
    properties: {
        foo: {
            type: "string"
        }
    }
}

if (window.Worker) {

    messageSystem = new MessageSystem({
        // The string location of the file on the server or the Worker instance.
        // If using webpack, include it in the entry section of the config.
        // Alternatively if instantiating the web worker with the webpack worker-loader,
        // simply use the Worker instance that has been imported
        webWorker: "message-system.min.js",

        // your data dictionary to initialize with (you may only need a single item)
        dataDictionary: [
            {
                dataDictionaryKey1: {
                    schemaId: mySchema.id,
                    data: {
                        foo: "Hello world"
                    },
                },
            },
            "dataDictionaryKey1",
        ],

        // your dictionary of schemas to validate data in the dictionary
        schemaDictionary: {
            [mySchema.id]: mySchema,
        },
    });
}

The dataDictionary and the schemaDictionary are not required when creating the instance of the message system but can be provided for a single point of intialization.

If initialization occurs later, the following method can be used:

messageSystem = new MessageSystem({
    webWorker: "message-system.min.js",
});

...

messageSystem.initialize({
    dataDictionary: myDataDictionary,
    schemaDictionary: mySchemaDictionary,
});

Initialization message

To re-initialize the message system an initialization message can be sent which requires a dataDictionary and schemaDictionary to be provided.

Example:

import { MessageSystemType } from "@microsoft/design-to-code";

...

messageSystem.postMessage({
    type: MessageSystemType.initialize,
    dataDictionary: myDataDictionary,
    schemaDictionary: mySchemaDictionary
});

Custom messages

It is possible to send custom messages, all that is required is the data being sent includes the type MessageSystemType.custom.

Example:

import { MessageSystemType } from "@microsoft/design-to-code";

...

messageSystem.postMessage({
    type: MessageSystemType.custom,
    myMessage: "Hello world"
});

Data utilities

Data utilities are used for the various data manipulations in the message system, they are also provided as exports.

Generating data from JSON schema

Data may be generated from a JSON schema using the getDataFromSchema export. This will only generate the required items as dictated by the JSON schema, and will always choose the first potential match in any situation, for example if a property is an enum and is required, it will add the first value in the enum list.

An example of generating data from the @microsoft/design-to-code package:

import { getDataFromSchema } from "@microsoft/design-to-code";

const data = getDataFromSchema(schema);

Mapping data

Data from the dictionary of data can be mapped with a helper mapDataDictionary. This will allow you transform the data dictionary into another type of data structure by writing a helper. For example, if the data dictionary represented React component props, you could write a mapper using the React createElement function and return a functional React component.

The mapDataDictionary export takes an object with the following properties:

  • dataDictionary - A dictionary of data, this is similar to other data dictionary formats in this library but instead of specifying a root data item, it is the dictionary only.
  • dataDictionaryKey - This should be the root data items key.
  • schemaDictionary - This should be the dictionary of JSON schemas where each schema is identified in the object by its id which is used as a key.
  • mapper - The function provided that maps the data.

The mapping function that should be provided as the mapper in the mapDataDictionary argument accepts as its argument an object with the following properties:

  • data - The raw unchanged data.
  • resolvedData - Data that has been run through the mapper before.
  • schema - The JSON schema that maps to this piece of data, it should validate against the data property.

Example:

import { mapDataDictionary } from "@microsoft/design-to-code";

const mappingFunction = function(config) {
    return config.resolvedData;
}

const mappedData = mapDataDictionary({
    dataDictionary: {
        "root": {
            schemaId: "foo",
            data: {
                greeting: "Hello world"
            }
        }
    },
    dataDictionaryKey: "root",
    schemaDictionary: {
        foo: {
            id: "foo",
            type: "object"
        }
    },
    mapper: mappingFunction
});

The expected result:

{
    greeting: "Hello world"
}

Mapping Web Component definitions

Web components can be described with the TypeScript interface WebComponentDefinition or the JSON schema webComponentSchema, available as named exports from @microsoft/design-to-code.

Data that maps to these definitions can be passed as an argument to the mapWebComponentDefinitionToJSONSchema utility. This will generate an array of JSON schemas (one for each available tag) that the tooling can use.

Example:

import { mapWebComponentDefinitionToJSONSchema } from "@microsoft/design-to-code";

const myWebComponentJSONSchema = mapWebComponentDefinitionToJSONSchema(myWebComponentDefinition);

Validation

Validation is treated as optional by the message system but is available as a utility. This is done in case other validation methods are used as validators are decently sized packages and there may be validation scenarios that are not covered by standard JSON schema validation.

To facilitate ease of use however, the export AjvMapper is provided which utilizes the ajv library.

Example:

import { AjvMapper, MessageSystem } from "@microsoft/design-to-code";

let messageSystem: MessageSystem;
let ajvMapper: AjvMapper;

if ((window as any).Worker) {
    messageSystem = new MessageSystem({
        ...
    });
    ajvMapper = new AjvMapper({
        messageSystem: messageSystem,
    });
}

If necessary it is possible to make a custom validator. The AjvMapper can be used as a guide for mapping the pathing values and error messages to a format the message system can accept.