Initial RDF forms component#798
Conversation
Prompt: reading the RDFinput file, pls make suggestions of how to impprve the code to make it easier to follow and read. I beliebe it is difficult to follow the fact that one has a rdf forms subject and a data subject as well and how it is all itertwinded. Co-Authored-By: GitHub Copilot (raptor-mini) <copilot@github.com>
NoelDeMartin
left a comment
There was a problem hiding this comment.
Added a few initial comments, mostly regarding a11y and component architecture.
| return html` <solid-ui-rdf-input | ||
| .store=${store} | ||
| .formSubject=${sym(part.value)} | ||
| .dataSubject=${me} |
There was a problem hiding this comment.
I think all inputs should also have a name attribute. Otherwise, they'll be ignored by the form (again, important for a11y, etc.).
| export type FieldParamsObject = { | ||
| size?: number, // input element size attribute | ||
| type?: InputType, // input element type attribute. Default: 'text' (not for Comment and Heading) | ||
| element?: string, // element type to use (Comment and Heading only) | ||
| style?: string, // style to use | ||
| dt?: string, // xsd data type for the RDF Literal corresponding to the field value. Default: xsd:string | ||
| defaultInputValue?: string, // e.g. 'mailto:'. Default value in input field, will be removed when displaying actual value to user. | ||
| namedNode?: boolean, // if true, field value corresponds to the URI of an RDF NamedNode. Overrides dt and defaultInputValue. | ||
| pattern?: RegExp // for client-side input validation; field will go red if violated, green if ok | ||
| } |
There was a problem hiding this comment.
Many of these are currently unused, right? I see that this is a WIP, so it's fine. But before merging, I would remove everything that isn't used (you know, YAGNI, removing dead code, etc.).
Also, I'm not sure I like the style config... that goes a bit against the idea of RDF forms, given that different UI libraries may render forms differently, and inline styles are probably not going to work correctly in all of them. But if that was a design decision when creating the RDF forms, ok.
Prompt: can this #sym:HTMLElementTagNameMap be generated automatically from vite-config/ components.ts for all RDF suffixed components? Co-Authored-By: GitHub Copilot (raptor-mini) <copilot@github.com>
|
RDFInput will make use of the new Input components when it is merged: #815 |
|
We need to improve the name property of the generated form and make sure they are unique. All HTML elements created automatically from the ontology ui file need names but there could be more input fields called input-name. I am not sure I can just use a random id generator. |
Co-authored-by: Noel De Martin <noel@noeldemartin.com>
Prompt: I have this accessors rdfURI and subjectURi which should be URIs. I would like to use a lit converter for them instead of my code: https://lit.dev/docs/components/properties/#conversion-converter Help me with it. Prompt: I want the converter to only return URL or null Co-Authored-By: GitHub Copilot (raptor-mini) <copilot@github.com>
|
I just saw this now, here's my thoughts:
It depends on how the form is going to be used by the consumer. If everything is handled in javascript, there's nothing wrong with using names generated by the id generator. However, if the consumer wants to actually submit this form to a server they would need to know the actual names. I haven't looked at the Basically, the behaviour I would like to see is that by default it generates random input names using the id generator, but if the RDF definitions specify the name of the form control, we'll use that. If those are not unique, I don't think we should do anything about it, that's the responsibility of whoever is defining the RDF (if they want two fields to have the same name, let them do it, although we could throw a helpful warning in the console or something). That would be useful for different reasons, not just to handle the form submission. For example, the name of an input can influence some browser extensions or autocompletes. |
|
What we also need to decide is if we take the input size property into consideration. |
|
I guess this is something to discuss, but personally I don't think the RDF should be able to affect the UI (things like size). That's the whole point of the approach, that the form gets rendered using the RDF definition in a way that works for the current UI/project. I guess it's fine to have some properties like "primary color" for theming or something like that. But even then, shouldn't the "primary color" be set by the application where the form is rendered in? Maybe it can be useful to change an accent or something, to distinguish a button or input from others... But I'm not sure I like the idea. As per how the size is determined now, I haven't looked too much into it, but usually inputs have a min-width or take 100% of their container. That's something that should be configured in the form. For now I think it's fine to simply have a max-width in the form and otherwise take up the entire container. We can tweak these things later, possibly with some properties in the component. |
There was a problem hiding this comment.
Pull request overview
Introduces an initial RDF Forms implementation for the component library, wiring it into Storybook and adding an RDF-backed input Web Component, alongside supporting infrastructure (store context, helpers, and generated custom-elements typing).
Changes:
- Add
<solid-ui-rdf-form>and<solid-ui-rdf-input>components plus Storybook story/provider/store plumbing for rdflib-backed document loading. - Add rdflib form helper utilities and field parameter mappings for selecting appropriate HTML input types.
- Add a Vite plugin to auto-generate
src/types/custom-elements.d.ts, and extend existing form controls with areadonlyAPI surface.
Reviewed changes
Copilot reviewed 18 out of 20 changed files in this pull request and generated 13 comments.
Show a summary per file
| File | Description |
|---|---|
| vite.config.mts | Registers a new Vite plugin to generate custom element typings. |
| vite-config/components.ts | Implements custom element type generation and a Vite plugin hook for it. |
| src/types/custom-elements.d.ts | Updates the (now-generated) HTMLElementTagNameMap entries for custom elements. |
| src/storybook/store/StorybookStore.ts | Adds a Storybook rdflib store wrapper for RDF forms. |
| src/storybook/components/StorybookProvider.ts | Provides the RDF store context in Storybook. |
| src/lib/forms/store/StoreContext.ts | Introduces a Lit context interface for injecting an rdflib LiveStore. |
| src/lib/forms/store/NoopStore.ts | Adds a default “no store” implementation that throws when accessed. |
| src/lib/forms/rdfFormsHelper.ts | Adds document loading, fetching, and RDF form utility helpers. |
| src/lib/forms/fieldParams.ts | Adds field-type → HTML input parameter mappings for RDF form fields. |
| src/lib/components/traits/InputTrait.ts | Extends the input trait target contract to include readonly. |
| src/components/select/Select.ts | Adds a readonly property to <solid-ui-select> and attempts to bind it to the native <select>. |
| src/components/rdf-input/RDFInput.ts | Implements <solid-ui-rdf-input> for reading/writing RDF-backed field values. |
| src/components/rdf-input/index.ts | Exports the RDF input component entrypoint. |
| src/components/rdf-form/RDForm.stories.ts | Adds a Storybook story for <solid-ui-rdf-form>. |
| src/components/rdf-form/RDFForm.ts | Implements <solid-ui-rdf-form> for rendering form parts from RDF. |
| src/components/rdf-form/index.ts | Exports the RDF form component entrypoint. |
| src/components/input/Input.ts | Adds readonly support to <solid-ui-input> and binds it to the native <input>. |
| src/components/input/Input.styles.css | Adds read-only styling rules for the native <input>. |
| src/components/combobox/Combobox.ts | Adds readonly support to <solid-ui-combobox> and binds it to the native <input>. |
| .gitignore | Ignores the generated src/types/custom-elements.d.ts file. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // for building the HTML input element | ||
| const uiPropertyTerm = this.getFormProperty(this.formSubject, ns.ui('property'), document) | ||
| const inputLabel = this.getInputLabel(this.formSubject, uiPropertyTerm, document) | ||
| const readonly = this.getReadOnly(this.readonly, this.formSubject, document) |
| private async updateData (e: CustomEvent) { | ||
| const newValue = (e.target as HTMLInputElement).value | ||
| this._pendingUpdateValue = newValue |
| if (this.storeContext.store.updater?.editable(this.dataSubject) === false) { | ||
| this._updateInFlight = false | ||
| return | ||
| } |
| toInsertSt = toDeleteSt.map(statement => st(statement.subject, statement.predicate, objectFromNewValue, statement.why)) | ||
| if (toInsertSt.length === 0) { | ||
| toInsertSt = [st(this.formSubject, property as any, objectFromNewValue, this.getDocument(this.dataSubject))] | ||
| } |
I have decided to do a generateId (random id) since we did not have the name attribute at all in the past. A random one is enough for now. |
This is for now: