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;
}
}