import { LitElement, html, css } from 'lit'; import { customElement, property, state, queryAssignedNodes } from 'lit/decorators.js'; interface FormField { name: string; type: string; label?: string; placeholder?: string; } @customElement('iu-form') export class Form extends LitElement { static override styles = css` input { padding: 8px; font-size: 1rem; width: 100%; box-sizing: border-box; } div{ margin-bottom: 20px; } label{ font-weight: bold; margin-bottom: 4px; display: block; } button { position: relative; display: inline-flex; align-items: center; background: var(--iu-color-grey-100); padding: 0.375rem 0.75rem; color: var(--iu-color-black); text-decoration: none; border: 0; font: var(--iu-f-sm); cursor: pointer; margin-top: 20px; &:hover{ background: var(--iu-color-black); color: var(--iu-color-white); } margin-top: var(--iu-spacing-4); } ::slotted(iu-heading){ --iu-heading-margin-top: var(--iu-spacing-7); } `; // Define the structure of form fields @property({ type: Array }) fields: FormField[] = []; // Reactive state to hold form values @state() private formData: Record<string, string> = {}; // Query slot content to check if sections are provided @queryAssignedNodes() private slottedElements?: NodeList; private handleInput(event: Event) { const target = event.target as HTMLInputElement; this.formData = { ...this.formData, [target.name]: target.value }; } private handleSubmit(event: Event) { event.preventDefault(); console.log('Form Data:', this.formData); // Dispatch custom event with form data this.dispatchEvent(new CustomEvent('form-submit', { detail: this.formData, bubbles: true, composed: true, })); } // make sure that every component inside this has <iu-container> set // to nested to disable padding left on the container itself private updateSlottedElements() { if (!this.slottedElements) return; this.slottedElements.forEach((slot) => { if (slot instanceof HTMLElement) { // Set the `nested` attribute or property slot.setAttribute('nested', 'true'); } }); } override firstUpdated() { super.firstUpdated(); this.updateSlottedElements(); } constructor() { super(); // Initialize form data with empty values this.fields.forEach(field => { this.formData[field.name] = ''; }); } override render() { const hasSections = this.slottedElements && this.slottedElements.length > 0; return html` <iu-container columns-md="2"> <form @submit="${this.handleSubmit}"> <slot></slot> ${!hasSections && this.fields.length > 0 ? this.fields.map( field => html` <div> <label for="${field.name}">${field.label}</label> <input type="${field.type}" name="${field.name}" placeholder="${field.placeholder || ''}" @input="${this.handleInput}" .value="${this.formData[field.name] || ''}" required /> </div> `) : '' } <button type="submit">Invia</button> </form> </iu-container> `; } } declare global { interface HTMLElementTagNameMap { 'iu-form': Form; } }