Skip to content

Latest commit

 

History

History
553 lines (453 loc) · 14.3 KB

README.md

File metadata and controls

553 lines (453 loc) · 14.3 KB

Solid FE Form CLI

The Solid Front End Form CLI is meant to help creating forms on Vue/Angular frameworks from SHACL (Shapes Constraint Language) files.

Index


Main Features

  • sfef list-shapes : List of available shapes (SHACL .ttl files)

  • sfef set-custom-css : Set up custom CSS classes to be used in the form component

  • sfef create : Creates form component following SHACL shape


Install

  • Solid-sfef-cli is a development CLI tool, it is recommened to install it using --global option.

    npm install @solidlab/solid-fef-cli --global

    or

    npm i @solidlab/solid-fef-cli -g
  • It could also be install locally as a dev dependency using --save-dev option.

    npm install @solidlab/solid-fef-cli --save-dev

    or

    npm i @solidlab/solid-fef-cli -D

Usage and examples

Print out the commands and options in the CLI tool

sfef help

List shapes available

List the actual available shapes inside the solid-fef-cli package.

sfef list-shapes

Example of path shape location: '/Users/myname/node_modules/@solidlab/solid-fef-cli/.assets/shacl/'


Set custom CSS styles

Define some custom CSS classes to be used when creating the form.

sfef set-custom-css

The command asks for CSS classes on:

  • <form> element
  • <div> wrapper around input and label
  • <label> element
  • <em> element which contains additional information binded to the label (sh:description)
  • <input> element

The custom classes are stored in project root under filename form-custom-classes.json.

Example of custom CSS classes json structure:

[
    {
        "element":"form",
        "classes":["css-custom__form"]
    }, {
        "element":"input-wrapper",
        "classes":["css-custom__wrapper"]
    }, {
        "element":"input-label",
        "classes":["css-custom__label", "css-custom__label--bold"]
    }, {
        "element":"input-additional-info",
        "classes":["css-custom__info"]
    }, {
        "element":"input-element",
        "classes":["css-custom__input", "css-custom__input--required"]
    }
]

Create form file and dependencies

Creates the form component according to frame selected (vue/angular) and the shape (.ttl file).

sfef create --framework [vue/angular] --shape [fileName]

or

sfef create -f [vue/angular] -s [fileName]

With the optional parameter --css, the component file will include the css classes available in form-custom-classes.json

sfef create --framework [vue/angular] --shape [fileName] --css

or

sfef create -f [vue/angular] -s [fileName] --c

The fileName could be an absolute path or a relative path (in the solid-fef-cli package).

examples of valid fileName values:

  • adresregister-SHACL

    relative path expected to be in cli package. Check available .ttl file names using sfef list-shapes command.

  • /Users/myname/Documents/GIT/myProject/.shapes/my-project-shape.ttl

    absolute path


Vue example

sfef create -f vue -s example

Executing above command will create the FormExample.vue file in src/vue folder along with all depency components (BasicInput.vue and BasicOption.vue).

The example.ttl includes various input types: text, date, email, checkbox and number.

Being 'Given name', 'Family name', 'Street address', 'house number' and 'Postal code' required fields.

The 'Genre' field uses a <datalist> to restrict the options allowed.

Finally 'Postal code' uses a regex pattern.

// FormExample.vue
<template>
<form id="example" class="">
    <h2>PersonShape</h2>
    <BasicInput
        inputType="text"
        inputId="given-name-0-0"
        inputName="given-name-0-0"
        inputForm="example"
        inputWrapperClass=""
        inputClass=""
        inputLabel="Given name or first name"
        inputLabelClass="input-label "
        :inputRequired="true"
    />
    <BasicInput
        inputType="text"
        inputId="family-name-0-1"
        inputName="family-name-0-1"
        inputForm="example"
        inputWrapperClass=""
        inputClass=""
        inputLabel="Family name or surname"
        inputLabelClass="input-label "
        :inputRequired="true"
    />
    <BasicInput
        inputType="date"
        inputId="birth-date-0-2"
        inputName="birth-date-0-2"
        inputForm="example"
        inputWrapperClass=""
        inputClass=""
        inputLabel="Birth Date"
        inputLabelClass="input-label "
    />
    <BasicInput
        inputType="text"
        inputId="gender-0-3"
        inputName="gender-0-3"
        inputForm="example"
        inputWrapperClass=""
        inputClass=""
        inputLabel="Gender"
        inputLabelClass="input-label "
        inputListId="list-gender-0-3"
        :inputListOptions='[{"label":"Female","value":"female"},{"label":"Male","value":"male"}]'
    />
    <BasicInput
        inputType="email"
        inputId="email-0-4"
        inputName="email-0-4"
        inputForm="example"
        inputWrapperClass=""
        inputClass=""
        inputLabel="E-mail address"
        inputLabelClass="input-label "
    />
    <BasicInput
        inputType="checkbox"
        inputId="receive-newsletter-0-5"
        inputName="receive-newsletter-0-5"
        inputForm="example"
        inputWrapperClass=""
        inputClass=""
        inputLabel="Receive newsletter"
        inputLabelClass="input-label "
    />
    <BasicInput
        inputType="text"
        inputId="address-0-6"
        inputName="address-0-6"
        inputForm="example"
        inputWrapperClass=""
        inputClass=""
        inputLabel="Address"
        inputLabelClass="input-label "
    />
    <h2>AddressShape</h2>
    <BasicInput
        inputType="text"
        inputId="street-address-1-0"
        inputName="street-address-1-0"
        inputForm="example"
        inputWrapperClass=""
        inputClass=""
        inputLabel="Street Address"
        inputLabelClass="input-label "
        :inputRequired="true"
    />
    <BasicInput
        inputType="number"
        inputId="street-number-1-1"
        inputName="street-number-1-1"
        inputForm="example"
        inputWrapperClass=""
        inputClass=""
        inputLabel="Street Number"
        inputLabelClass="input-label "
        :inputRequired="true"
    />
    <BasicInput
        inputType="text"
        inputId="postal-code-1-2"
        inputName="postal-code-1-2"
        inputForm="example"
        inputWrapperClass=""
        inputClass=""
        inputLabel="Postal Code"
        inputLabelClass="input-label "
        inputAdditionalInfo="Type postal code: 2 letters + 4 digits"
        inputLabelInfoClass=""
        :inputRequired="true"
        inputPattern="[a-z A-Z]{2}[0-9]{4}"
    />
</form>
</template>
<script lang="ts">
import { defineComponent } from "vue"

import BasicInput from "./components/BasicInput.vue"
export default defineComponent({
    name: "FormExample",
    components: {
        BasicInput,
    },
})
</script>

Which will look like:

form without styling

and with a some minimal styling:

form with styling

when all fields are filled properly:

form with styling and filled correctly


Angular example

sfef create -f angular -s another-example -c

Executing above command will create the FormAnotherExample.component.html and FormAnotherExample.component.ts file in src/app/FormAnotherExample folder along with BasicInput depency component.

The another-example.ttl includes various input types text and email.

Being 'Given name', 'Family name', 'Country', 'City', 'Street Line', 'Postal code' and 'Organization name' required fields.

As the optional -c (--css) is also present, the css classes from form-custom-classes.json are also applied.

[
    {"element":"form","classes":["css__form"]},
    {"element":"input-wrapper","classes":["css__wrapper"]},
    {"element":"input-label","classes":["css__label"]},
    {"element":"input-additional-info","classes":["css__xtra-info"]},
    {"element":"input-element","classes":["css__input"]}
]

Resulting in following html and ts files:

// FormAnotherExample.component.html
<form id="another-example" class="css__form">
    <h2>Contact</h2>
    <app-basic-input
        inputType="text"
        inputId="given-name-0-0"
        inputName="given-name-0-0"
        inputForm="another-example"
        inputWrapperClass="css__wrapper"
        inputClass="css__input"
        inputLabel="Given Name"
        inputLabelClass="input-label css__label"
        inputRequired="true"
    ></app-basic-input>
    <app-basic-input
        inputType="text"
        inputId="family-name-0-1"
        inputName="family-name-0-1"
        inputForm="another-example"
        inputWrapperClass="css__wrapper"
        inputClass="css__input"
        inputLabel="Family Name"
        inputLabelClass="input-label css__label"
        inputRequired="true"
    ></app-basic-input>
    <app-basic-input
        inputType="email"
        inputId="email-0-2"
        inputName="email-0-2"
        inputForm="another-example"
        inputWrapperClass="css__wrapper"
        inputClass="css__input"
        inputLabel="Email"
        inputLabelClass="input-label css__label"
    ></app-basic-input>
    <app-basic-input
        inputType="text"
        inputId="address-0-3"
        inputName="address-0-3"
        inputForm="another-example"
        inputWrapperClass="css__wrapper"
        inputClass="css__input"
        inputLabel="Address"
        inputLabelClass="input-label css__label"
    ></app-basic-input>
    <app-basic-input
        inputType="text"
        inputId="works-for-0-4"
        inputName="works-for-0-4"
        inputForm="another-example"
        inputWrapperClass="css__wrapper"
        inputClass="css__input"
        inputLabel="Works For"
        inputLabelClass="input-label css__label"
    ></app-basic-input>
    <h2>Address</h2>
    <app-basic-input
        inputType="text"
        inputId="address-country-1-0"
        inputName="address-country-1-0"
        inputForm="another-example"
        inputWrapperClass="css__wrapper"
        inputClass="css__input"
        inputLabel="Country"
        inputLabelClass="input-label css__label"
        inputRequired="true"
    ></app-basic-input>
    <app-basic-input
        inputType="text"
        inputId="address-locality-1-1"
        inputName="address-locality-1-1"
        inputForm="another-example"
        inputWrapperClass="css__wrapper"
        inputClass="css__input"
        inputLabel="City"
        inputLabelClass="input-label css__label"
        inputRequired="true"
    ></app-basic-input>
    <app-basic-input
        inputType="text"
        inputId="street-address-1-2"
        inputName="street-address-1-2"
        inputForm="another-example"
        inputWrapperClass="css__wrapper"
        inputClass="css__input"
        inputLabel="Street Line"
        inputLabelClass="input-label css__label"
        inputRequired="true"
    ></app-basic-input>
    <app-basic-input
        inputType="text"
        inputId="postal-code-1-3"
        inputName="postal-code-1-3"
        inputForm="another-example"
        inputWrapperClass="css__wrapper"
        inputClass="css__input"
        inputLabel="Postal Code"
        inputLabelClass="input-label css__label"
        inputRequired="true"
    ></app-basic-input>
    <h2>Organization</h2>
    <app-basic-input
        inputType="text"
        inputId="name-2-0"
        inputName="name-2-0"
        inputForm="another-example"
        inputWrapperClass="css__wrapper"
        inputClass="css__input"
        inputLabel="Organization Name"
        inputLabelClass="input-label css__label"
        inputRequired="true"
    ></app-basic-input>
    <app-basic-input
        inputType="text"
        inputId="address-2-1"
        inputName="address-2-1"
        inputForm="another-example"
        inputWrapperClass="css__wrapper"
        inputClass="css__input"
        inputLabel="Organization Address"
        inputLabelClass="input-label css__label"
    ></app-basic-input>
</form>

and

// FormAnotherExample.component.ts
import { Component, ViewEncapsulation } from '@angular/core';

import { BasicInputComponent } from "../components/BasicInput/BasicInput.component"

@Component({
    selector: "app-form-another-example",
    standalone: true,
    imports: [
        BasicInputComponent,
    ],
    templateUrl: './FormAnotherExample.component.html',
    encapsulation: ViewEncapsulation.None
})
export class FormAnotherExample {
}

Which will look like:

form without styling

and with a some minimal styling:

form with styling

when all fields are filled properly:

form with styling and filled correctly


Uninstall

To uninstall, simply run:

  • for global installation:

    npm uninstall @solidlab/solid-fef-cli --global

    or

    npm rm @solidlab/solid-fef-cli -g
  • for development installation:

    npm uninstall @solidlab/solid-fef-cli --save-dev

    or

    npm rm @solidlab/solid-fef-cli -D