npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@rokkit/form

v1.0.0-next.36

Published

Dynamic form components for svelte apps.

Downloads

28

Readme

Dynamic Forms

Dynamic forms created using JSON Schema will speed up the UI development process.

Three ways to build dynamic forms:

  • Write the form structure using JSON Schema
  • Visually create the form using the <FormBuilder> component
  • Convert a database table definition to JSON Schema

Validation v/s Layout

I think that validation and layout should be different.

Examples

{
  "type": "array",
  "component": "master-detail",
  "items": {
    "type": "object",
    "required": ["answers"],
    "layout": "vertical",
    "order": ["contenturl", "questionId", "question", "prompt", "answers"],
    "properties": {
      "contenturl": {
        "type": "string",
        "component": "custom"
      },
      "question": {
        "type": "string",
        "readOnly": true
      },
      "prompt": {
        "type": "string",
        "readOnly": true
      },
      "answers": {
        "type": "string"
      },
      "questionId": {
        "type": "string",
        "readOnly": true
      }
    }
  }
}

Lists

Lists can be represented using a master-detail component.

DynamicField

A schema defines the field properties.

Any field can be defined using the properties below.

  • [ ] Value: this is a bound property so that changes are propagated both ways
  • [ ] Properties: this can be passed using a spread operator and can consist of multiple varied properties
  • [ ] Events: in a generic input we can handle the blur event along with the change event to identify when a field should be validated
  • [ ] hasChanged (can be a bound property to identify that this attribute has undergone a change and should be validated again)
  • [ ] message : A message along with type to displayed the validation message. The type can be used to show an icon also

This covers all inputs provided Input handles all the types listed. Even select and range because the additional props are provided.

There are a few special types of inputs, which cannot be included in the generic <InputField/>. Object and array are two that come to mind. There are many ways an array can be visually represented. One of them is a tabbed view. This allows us to add and remove items as well. If the tabs are scrollable and an arbitrary index can be provided then this can support large arrays. Another approach is paginated tabs. This can have limited values visible with page increment/decrement options.

Another is a master detail, with a scrollable list to display items and detail for the item edit. To support add/delete action buttons need to be provided. A swipeable page with dots to navigate is yet another option to edit arrays. The content of an array can be an object, multiple typed items or a set of same type items. Like an array of mixed type elements, array of string or numbers, array of objects.

An object has multiple attributes and each attribute can be represented using the InputField or ArrayField or ObjectField.

The top level of any dynamic data input is either an array or an object. When the top level is an array it is preferable to use the master-detail approach. When the array is nested deeper, then one of the other approaches can be used. A paginated set seems to be the simplest user experience for an array.

At the top level using a master-detail approach allows us to perform independent updates on each item change instead of a bulk change at the array level. We also have the flexibility to use different types of list views for the master. This can be a simple list, accordion, tree or a nested list.

Properties to configure master detail. Another alternative is an inline list editor where each item is an editable form.

  • [ ] type: type of list
  • [ ] items: the array
  • [ ] fields: field mapping for item
  • [ ] using: the component for the item (this can be a predefined dynamic form)
  • [ ] schema: schema to be used for the content. This can be used to generate the detail form for the object. In the case of mixed data types this can be a nested object with types as keys and for each key a schema for the data.
  • [ ] mixed: false. Identifies whether the array is mixed.
  • [ ] inline: false. identifies whether the detail should be inline or not.
  • [ ] inline editing should be avoided for cases where we need accordion and addition of rows. It can be nice for a fixed set of rows.

Object field needs the following attributes.

  • [ ] schema: schema definition to be used for validation
  • [ ] value: the value object to be updated
  • [ ] layout: optional layout that allows building multi column layout for the attributes in the object. In case it is not provided this can be derived from the schema.
  • [ ] A group attribute can be used to identify the layout. If it is not provided then all attributes are in single group. If a group number is provided then we can split the schema into different arrays where group number is the index of the array. We may need to handle bad data (missing groups) in an optimal way. In case of grouped layout the layout attribute should be an array or the value should be used across all groups.

// ObjectField.svelte

<script >
export let data={}
export let schema={}
export let layout

</script >

{#if typeof data == object }
{#if schema.groups}
<input-group class={layout}>
{#each schema.groups as {layout, label, keys}}
     <InputObject bind:value=data {label}bind:properties=schema.properties
keys/>
</input-group>
{/each}
{:else}

  <InputObject bind:value=data bind:properties=schema.properties
/>

{/if}
{:else}
  <error>
    expected data attribute to be an object.
  </error>
{/if}

// InputObject

<script >
export let label
export let value
export let using
export let name
export let properties
export let keys = Object.keys(properties)
</script >

<Fieldset {label}>
{#each keys as k}
         {@const component=using[properties[k].component]}
         {@const props = omit([‘component’,’hasChanged’], schema.properties[k]}
         <svelte:component this=component bind:value=data[k]
            bind:hasChanged={properties[k].hasChanged]
{…props} />
// if type is object do svelte:self
      {/each}

 </Fieldset>