feat(web_components): implement basic web components and catalog adapters - #2074
feat(web_components): implement basic web components and catalog adapters#2074josemontespg wants to merge 2 commits into
Conversation
…ters Implement basic web components (a2ui-card, a2ui-button, a2ui-text-field, a2ui-select, a2ui-switch, a2ui-dialog, a2ui-toast) and catalog adapters according to the approved A2UI Task Analysis design.
There was a problem hiding this comment.
Code Review
This pull request introduces portable Web Components for Select, Switch, Dialog, and Toast in the Lit renderer, along with their corresponding schemas and tests in web_core. It also adds catalog adapter helpers to map component APIs to custom element tag names. The review feedback highlights several issues: the Select component prevents change events when the initial value is undefined; the Dialog component defaults to open when the property is omitted, and its ::backdrop styling will not render correctly under declarative usage; the adapter helpers generate incorrect tag names for multi-word components by not using kebab-case; and finally, the new Lit components lack unit tests, violating the repository style guide.
| if (this.controller.props?.value) { | ||
| // Dispatch custom event for binding update | ||
| this.dispatchEvent( | ||
| new CustomEvent('a2uichange', { | ||
| detail: {value: target.value}, | ||
| bubbles: true, | ||
| composed: true, | ||
| }), | ||
| ); | ||
| } |
There was a problem hiding this comment.
The if (this.controller.props?.value) check prevents the a2uichange event from firing if the initial value is empty ("") or undefined. Since we want to allow users to select an option even if no value was previously set, this check should be removed so the event is always dispatched on change.
// Dispatch custom event for binding update
this.dispatchEvent(
new CustomEvent('a2uichange', {
detail: {value: target.value},
bubbles: true,
composed: true,
}),
);There was a problem hiding this comment.
Done. Removed the check.
| const props = this.controller.props; | ||
| if (!props) return nothing; | ||
|
|
||
| const isOpen = props.open !== false; |
There was a problem hiding this comment.
Using props.open !== false means that if props.open is undefined, isOpen will evaluate to true. However, the DialogApi schema defines open with a default of false. To respect this default and prevent the dialog from being open by default when the property is omitted, use Boolean(props.open) instead.
| const isOpen = props.open !== false; | |
| const isOpen = Boolean(props.open); |
There was a problem hiding this comment.
Done. Used Boolean(props.open).
| dialog::backdrop { | ||
| background: rgba(0, 0, 0, 0.5); | ||
| backdrop-filter: blur(2px); | ||
| } |
There was a problem hiding this comment.
The dialog::backdrop pseudo-element is only rendered by browsers when the dialog is opened using the native .showModal() method. Since this component renders <dialog open> declaratively, the native backdrop will not be displayed. Consider rendering a custom backdrop element in the template or managing the dialog opening/closing imperatively using .showModal() and .close() in the Lit lifecycle.
There was a problem hiding this comment.
Done. Managed open/close imperatively using showModal() and close() in updated lifecycle to ensure native backdrop rendering.
| for (const [name, comp] of catalog.components.entries()) { | ||
| const tagName = tagMap[name] || `a2ui-${name.toLowerCase()}`; | ||
| adaptedComponents.push(createComponentAdapter(comp, tagName)); | ||
| } |
There was a problem hiding this comment.
Using name.toLowerCase() directly will produce incorrect tag names for multi-word components (e.g., a2ui-textfield instead of a2ui-text-field, or a2ui-datetimeinput instead of a2ui-date-time-input). Convert the PascalCase/camelCase component names to kebab-case to ensure consistent and correct tag names.
for (const [name, comp] of catalog.components.entries()) {
const kebabName = name.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
const tagName = tagMap[name] || ('a2ui-' + kebabName);
adaptedComponents.push(createComponentAdapter(comp, tagName));
}There was a problem hiding this comment.
Done. Added toKebabCase helper and used it.
| for (const [name, comp] of catalog.components.entries()) { | ||
| const tagName = tagMap[name] || `a2ui-${name.toLowerCase()}`; | ||
| adaptedComponents.push(createComponentAdapter(comp, tagName)); | ||
| } |
There was a problem hiding this comment.
Using name.toLowerCase() directly will produce incorrect tag names for multi-word components (e.g., a2ui-textfield instead of a2ui-text-field, or a2ui-datetimeinput instead of a2ui-date-time-input). Convert the PascalCase/camelCase component names to kebab-case to ensure consistent and correct tag names.
for (const [name, comp] of catalog.components.entries()) {
const kebabName = name.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
const tagName = tagMap[name] || ('a2ui-' + kebabName);
adaptedComponents.push(createComponentAdapter(comp, tagName));
}There was a problem hiding this comment.
Done. Added toKebabCase helper and used it.
| BASIC_FUNCTIONS, | ||
| ); | ||
|
|
||
| export {A2uiSelect, A2uiSwitch, A2uiDialog, A2uiToast}; |
There was a problem hiding this comment.
According to the repository style guide, code changes should have tests. The newly added Lit components (Select, Switch, Dialog, Toast) currently lack unit/component tests in renderers/lit. Please add corresponding tests to verify their rendering and behavior.
References
- If there are code changes, code should have tests. (link)
There was a problem hiding this comment.
Done. Added unit tests for Select, Switch, Dialog, and Toast in renderers/lit.
…ropagation, fix Dialog backdrop and default open values, fix kebab-case tag name construction for multi-word components, and add component tests for Select, Switch, Dialog, and Toast.
What
Implement basic web components (
a2ui-card,a2ui-button,a2ui-text-field,a2ui-select,a2ui-switch,a2ui-dialog,a2ui-toast) and catalog adapters for Angular and React.Why
Consolidates duplicated framework-specific templates into portable Lit Custom Elements, reducing maintenance overhead and ensuring cross-framework interoperability.
Effect
Implements the approved A2UI Task Analysis design for Web Components.