| undefined) ?? {};
g[f.name] = v;
out[f.group] = g;
} else {
out[f.name] = v;
}
}
this.dispatchEvent(
new CustomEvent('roxy-submit', {
detail: { endpoint: this.endpoint, values: out },
bubbles: true,
composed: true,
}),
);
};
render() {
if (!this.loaded) {
return html``;
}
if (this.specError) {
return html`
Schema load failed: ${this.specError}
Retry
`;
}
const renderField = (f: FieldDef) => {
if (
this.groupHasLocation(f.group) &&
(f.name === 'latitude' ||
f.name === 'longitude' ||
f.name === 'timezone')
) {
return nothing;
}
const inputId = `roxy-form-${f.key}`;
return html`
${humanize(f.name)}${f.required ? html`* ` : nothing}
${
f.enum
? html` this.setValue(f.key, (e.target as HTMLSelectElement).value)}
>
Choose
${f.enum.map(
(
opt,
) => html`
${opt}
`,
)}
`
: html`
this.setValue(
f.key,
this.coerce(f.type, (e.target as HTMLInputElement).value),
)}
/>`
}
${f.description ? html`${f.description} ` : nothing}
`;
};
// Ordered list of field groups: the flat top level (undefined) plus each
// nested object (person1/person2). Order follows first appearance.
const groups: (string | undefined)[] = [];
for (const f of this.fields) {
if (!groups.includes(f.group)) groups.push(f.group);
}
const locationBlock = (group?: string) =>
this.groupHasLocation(group)
? html`
${group ? `${humanize(group)} location` : 'Birth location'}
Required: latitude, longitude, timezone. Pick a city to autofill.
`
: nothing;
const groupBody = (group?: string) => html`${locationBlock(group)}
${this.fields.filter((f) => f.group === group).map((f) => renderField(f))}
`;
return html``;
}
private htmlType(t: string): string {
switch (t) {
case 'date':
return 'date';
case 'time':
return 'time';
case 'datetime':
return 'datetime-local';
case 'number':
return 'number';
default:
return 'text';
}
}
private coerce(t: string, v: string): unknown {
if (v === '') return undefined;
if (t === 'number') {
const n = Number(v);
return Number.isFinite(n) ? n : undefined;
}
return v;
}
}
declare global {
interface HTMLElementTagNameMap {
'roxy-endpoint-form': RoxyEndpointForm;
}
}