UNPKG

@formdown/ui

Version:

Pure HTML renderer for Formdown syntax

1,180 lines (1,139 loc) 39.5 kB
import { css as P, LitElement as I, html as v } from "lit"; import { extensionManager as y, registerHook as C, registerPlugin as R, FormManager as O } from "@formdown/core"; /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ const z = (e) => (t, r) => { r !== void 0 ? r.addInitializer(() => { customElements.define(e, t); }) : customElements.define(e, t); }; /** * @license * Copyright 2019 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ const w = globalThis, _ = w.ShadowRoot && (w.ShadyCSS === void 0 || w.ShadyCSS.nativeShadow) && "adoptedStyleSheets" in Document.prototype && "replace" in CSSStyleSheet.prototype, T = Symbol(), U = /* @__PURE__ */ new WeakMap(); let q = class { constructor(t, r, i) { if (this._$cssResult$ = !0, i !== T) throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead."); this.cssText = t, this.t = r; } get styleSheet() { let t = this.o; const r = this.t; if (_ && t === void 0) { const i = r !== void 0 && r.length === 1; i && (t = U.get(r)), t === void 0 && ((this.o = t = new CSSStyleSheet()).replaceSync(this.cssText), i && U.set(r, t)); } return t; } toString() { return this.cssText; } }; const D = (e) => new q(typeof e == "string" ? e : e + "", void 0, T), L = (e, t) => { if (_) e.adoptedStyleSheets = t.map((r) => r instanceof CSSStyleSheet ? r : r.styleSheet); else for (const r of t) { const i = document.createElement("style"), o = w.litNonce; o !== void 0 && i.setAttribute("nonce", o), i.textContent = r.cssText, e.appendChild(i); } }, k = _ ? (e) => e : (e) => e instanceof CSSStyleSheet ? ((t) => { let r = ""; for (const i of t.cssRules) r += i.cssText; return D(r); })(e) : e; /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ const { is: j, defineProperty: H, getOwnPropertyDescriptor: V, getOwnPropertyNames: B, getOwnPropertySymbols: N, getPrototypeOf: K } = Object, h = globalThis, A = h.trustedTypes, W = A ? A.emptyScript : "", x = h.reactiveElementPolyfillSupport, b = (e, t) => e, E = { toAttribute(e, t) { switch (t) { case Boolean: e = e ? W : null; break; case Object: case Array: e = e == null ? e : JSON.stringify(e); } return e; }, fromAttribute(e, t) { let r = e; switch (t) { case Boolean: r = e !== null; break; case Number: r = e === null ? null : Number(e); break; case Object: case Array: try { r = JSON.parse(e); } catch { r = null; } } return r; } }, $ = (e, t) => !j(e, t), F = { attribute: !0, type: String, converter: E, reflect: !1, useDefault: !1, hasChanged: $ }; Symbol.metadata ?? (Symbol.metadata = Symbol("metadata")), h.litPropertyMetadata ?? (h.litPropertyMetadata = /* @__PURE__ */ new WeakMap()); class g extends HTMLElement { static addInitializer(t) { this._$Ei(), (this.l ?? (this.l = [])).push(t); } static get observedAttributes() { return this.finalize(), this._$Eh && [...this._$Eh.keys()]; } static createProperty(t, r = F) { if (r.state && (r.attribute = !1), this._$Ei(), this.prototype.hasOwnProperty(t) && ((r = Object.create(r)).wrapped = !0), this.elementProperties.set(t, r), !r.noAccessor) { const i = Symbol(), o = this.getPropertyDescriptor(t, i, r); o !== void 0 && H(this.prototype, t, o); } } static getPropertyDescriptor(t, r, i) { const { get: o, set: s } = V(this.prototype, t) ?? { get() { return this[r]; }, set(n) { this[r] = n; } }; return { get: o, set(n) { const a = o == null ? void 0 : o.call(this); s == null || s.call(this, n), this.requestUpdate(t, a, i); }, configurable: !0, enumerable: !0 }; } static getPropertyOptions(t) { return this.elementProperties.get(t) ?? F; } static _$Ei() { if (this.hasOwnProperty(b("elementProperties"))) return; const t = K(this); t.finalize(), t.l !== void 0 && (this.l = [...t.l]), this.elementProperties = new Map(t.elementProperties); } static finalize() { if (this.hasOwnProperty(b("finalized"))) return; if (this.finalized = !0, this._$Ei(), this.hasOwnProperty(b("properties"))) { const r = this.properties, i = [...B(r), ...N(r)]; for (const o of i) this.createProperty(o, r[o]); } const t = this[Symbol.metadata]; if (t !== null) { const r = litPropertyMetadata.get(t); if (r !== void 0) for (const [i, o] of r) this.elementProperties.set(i, o); } this._$Eh = /* @__PURE__ */ new Map(); for (const [r, i] of this.elementProperties) { const o = this._$Eu(r, i); o !== void 0 && this._$Eh.set(o, r); } this.elementStyles = this.finalizeStyles(this.styles); } static finalizeStyles(t) { const r = []; if (Array.isArray(t)) { const i = new Set(t.flat(1 / 0).reverse()); for (const o of i) r.unshift(k(o)); } else t !== void 0 && r.push(k(t)); return r; } static _$Eu(t, r) { const i = r.attribute; return i === !1 ? void 0 : typeof i == "string" ? i : typeof t == "string" ? t.toLowerCase() : void 0; } constructor() { super(), this._$Ep = void 0, this.isUpdatePending = !1, this.hasUpdated = !1, this._$Em = null, this._$Ev(); } _$Ev() { var t; this._$ES = new Promise((r) => this.enableUpdating = r), this._$AL = /* @__PURE__ */ new Map(), this._$E_(), this.requestUpdate(), (t = this.constructor.l) == null || t.forEach((r) => r(this)); } addController(t) { var r; (this._$EO ?? (this._$EO = /* @__PURE__ */ new Set())).add(t), this.renderRoot !== void 0 && this.isConnected && ((r = t.hostConnected) == null || r.call(t)); } removeController(t) { var r; (r = this._$EO) == null || r.delete(t); } _$E_() { const t = /* @__PURE__ */ new Map(), r = this.constructor.elementProperties; for (const i of r.keys()) this.hasOwnProperty(i) && (t.set(i, this[i]), delete this[i]); t.size > 0 && (this._$Ep = t); } createRenderRoot() { const t = this.shadowRoot ?? this.attachShadow(this.constructor.shadowRootOptions); return L(t, this.constructor.elementStyles), t; } connectedCallback() { var t; this.renderRoot ?? (this.renderRoot = this.createRenderRoot()), this.enableUpdating(!0), (t = this._$EO) == null || t.forEach((r) => { var i; return (i = r.hostConnected) == null ? void 0 : i.call(r); }); } enableUpdating(t) { } disconnectedCallback() { var t; (t = this._$EO) == null || t.forEach((r) => { var i; return (i = r.hostDisconnected) == null ? void 0 : i.call(r); }); } attributeChangedCallback(t, r, i) { this._$AK(t, i); } _$ET(t, r) { var s; const i = this.constructor.elementProperties.get(t), o = this.constructor._$Eu(t, i); if (o !== void 0 && i.reflect === !0) { const n = (((s = i.converter) == null ? void 0 : s.toAttribute) !== void 0 ? i.converter : E).toAttribute(r, i.type); this._$Em = t, n == null ? this.removeAttribute(o) : this.setAttribute(o, n), this._$Em = null; } } _$AK(t, r) { var s, n; const i = this.constructor, o = i._$Eh.get(t); if (o !== void 0 && this._$Em !== o) { const a = i.getPropertyOptions(o), c = typeof a.converter == "function" ? { fromAttribute: a.converter } : ((s = a.converter) == null ? void 0 : s.fromAttribute) !== void 0 ? a.converter : E; this._$Em = o; const f = c.fromAttribute(r, a.type); this[o] = f ?? ((n = this._$Ej) == null ? void 0 : n.get(o)) ?? f, this._$Em = null; } } requestUpdate(t, r, i) { var o; if (t !== void 0) { const s = this.constructor, n = this[t]; if (i ?? (i = s.getPropertyOptions(t)), !((i.hasChanged ?? $)(n, r) || i.useDefault && i.reflect && n === ((o = this._$Ej) == null ? void 0 : o.get(t)) && !this.hasAttribute(s._$Eu(t, i)))) return; this.C(t, r, i); } this.isUpdatePending === !1 && (this._$ES = this._$EP()); } C(t, r, { useDefault: i, reflect: o, wrapped: s }, n) { i && !(this._$Ej ?? (this._$Ej = /* @__PURE__ */ new Map())).has(t) && (this._$Ej.set(t, n ?? r ?? this[t]), s !== !0 || n !== void 0) || (this._$AL.has(t) || (this.hasUpdated || i || (r = void 0), this._$AL.set(t, r)), o === !0 && this._$Em !== t && (this._$Eq ?? (this._$Eq = /* @__PURE__ */ new Set())).add(t)); } async _$EP() { this.isUpdatePending = !0; try { await this._$ES; } catch (r) { Promise.reject(r); } const t = this.scheduleUpdate(); return t != null && await t, !this.isUpdatePending; } scheduleUpdate() { return this.performUpdate(); } performUpdate() { var i; if (!this.isUpdatePending) return; if (!this.hasUpdated) { if (this.renderRoot ?? (this.renderRoot = this.createRenderRoot()), this._$Ep) { for (const [s, n] of this._$Ep) this[s] = n; this._$Ep = void 0; } const o = this.constructor.elementProperties; if (o.size > 0) for (const [s, n] of o) { const { wrapped: a } = n, c = this[s]; a !== !0 || this._$AL.has(s) || c === void 0 || this.C(s, void 0, n, c); } } let t = !1; const r = this._$AL; try { t = this.shouldUpdate(r), t ? (this.willUpdate(r), (i = this._$EO) == null || i.forEach((o) => { var s; return (s = o.hostUpdate) == null ? void 0 : s.call(o); }), this.update(r)) : this._$EM(); } catch (o) { throw t = !1, this._$EM(), o; } t && this._$AE(r); } willUpdate(t) { } _$AE(t) { var r; (r = this._$EO) == null || r.forEach((i) => { var o; return (o = i.hostUpdated) == null ? void 0 : o.call(i); }), this.hasUpdated || (this.hasUpdated = !0, this.firstUpdated(t)), this.updated(t); } _$EM() { this._$AL = /* @__PURE__ */ new Map(), this.isUpdatePending = !1; } get updateComplete() { return this.getUpdateComplete(); } getUpdateComplete() { return this._$ES; } shouldUpdate(t) { return !0; } update(t) { this._$Eq && (this._$Eq = this._$Eq.forEach((r) => this._$ET(r, this[r]))), this._$EM(); } updated(t) { } firstUpdated(t) { } } g.elementStyles = [], g.shadowRootOptions = { mode: "open" }, g[b("elementProperties")] = /* @__PURE__ */ new Map(), g[b("finalized")] = /* @__PURE__ */ new Map(), x == null || x({ ReactiveElement: g }), (h.reactiveElementVersions ?? (h.reactiveElementVersions = [])).push("2.1.1"); /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ const J = { attribute: !0, type: String, converter: E, reflect: !1, hasChanged: $ }, Y = (e = J, t, r) => { const { kind: i, metadata: o } = r; let s = globalThis.litPropertyMetadata.get(o); if (s === void 0 && globalThis.litPropertyMetadata.set(o, s = /* @__PURE__ */ new Map()), i === "setter" && ((e = Object.create(e)).wrapped = !0), s.set(r.name, e), i === "accessor") { const { name: n } = r; return { set(a) { const c = t.get.call(this); t.set.call(this, a), this.requestUpdate(n, c, e); }, init(a) { return a !== void 0 && this.C(n, void 0, e, a), a; } }; } if (i === "setter") { const { name: n } = r; return function(a) { const c = this[n]; t.call(this, a), this.requestUpdate(n, c, e); }; } throw Error("Unsupported decorator location: " + i); }; function p(e) { return (t, r) => typeof r == "object" ? Y(e, t, r) : ((i, o, s) => { const n = o.hasOwnProperty(s); return o.constructor.createProperty(s, i), n ? Object.getOwnPropertyDescriptor(o, s) : void 0; })(e, t, r); } const l = class l { constructor() { this.initialized = !1; } static getInstance() { return l.instance || (l.instance = new l()), l.instance; } async initialize() { if (!this.initialized) try { await y.initialize(), this.setupUIHooks(), this.initialized = !0; } catch (t) { console.debug("Extension system already initialized or error:", t); } } setupUIHooks() { C({ name: "field-render", priority: 1, handler: this.handleFieldRender.bind(this) }), C({ name: "field-validate", priority: 1, handler: this.handleFieldValidate.bind(this) }); } handleFieldRender(t, r) { return r; } handleFieldValidate(t, r) { return { valid: !0, message: "" }; } /** * Register a UI-specific plugin */ async registerUIPlugin(t) { await R(t); } /** * Get extension statistics */ getExtensionStats() { return y.getStats(); } /** * Execute hooks for UI operations */ async executeUIHooks(t, r, ...i) { return y.executeHooks(t, r, ...i); } }; l.instance = null; let S = l; const G = S.getInstance(); var Q = Object.defineProperty, X = Object.getOwnPropertyDescriptor, u = (e, t, r, i) => { for (var o = i > 1 ? void 0 : i ? X(t, r) : t, s = e.length - 1, n; s >= 0; s--) (n = e[s]) && (o = (i ? n(t, r, o) : n(o)) || o); return i && o && Q(t, r, o), o; }; let d = class extends I { constructor() { super(), this.content = "", this.selectOnFocus = !0, this.formId = "", this.showSubmitButton = !0, this.submitText = "Submit", this._data = {}, this.fieldRegistry = /* @__PURE__ */ new Map(), this._isUpdatingUI = !1, this._schema = null, this._uniqueFormId = this.formId || `formdown-${Math.random().toString(36).substring(2, 15)}`, this.formManager = new O(), this.fieldProcessor = this.formManager.createFieldProcessor(), this.domBinder = this.formManager.createDOMBinder(), this.setupCoreUIBridge(), this.setupFormManagerEvents(); } // Get the form ID (user-provided or auto-generated) getFormId() { return this.formId || this._uniqueFormId; } get data() { return this._data; } set data(e) { if (this._isUpdatingUI) return; const t = this._data; this._data = e != null && typeof e == "object" ? { ...e } : {}, this.requestUpdate("data", t), this.formManager && this._schema && !this._isUpdatingUI && this.formManager.updateData(this._data); } // Public method to update data programmatically updateData(e) { this.data = e, this.formManager && this._schema && this.formManager.updateData(e); } // Public method to update single field updateField(e, t) { this.data = { ...this.data, [e]: t }, this.formManager && this._schema && this.formManager.setFieldValue(e, t); } /** * Set up Core-UI component bridge using EventOrchestrator */ setupCoreUIBridge() { const e = { id: "formdown-ui", type: "ui", emit: (t, r) => { this.dispatchEvent(new CustomEvent(t, { detail: r, bubbles: !0 })); }, on: (t, r) => () => { } }; this.formManager.setupComponentBridge(e); } /** * Set up event forwarding from FormManager to UI */ setupFormManagerEvents() { this.formManager.on("data-change", ({ formData: e }) => { this._isUpdatingUI || (this._isUpdatingUI = !0, this.data = e, this._isUpdatingUI = !1); }), this.formManager.on("validation-error", ({ field: e, errors: t }) => { this.dispatchEvent(new CustomEvent("validation-error", { detail: { field: e, errors: t }, bubbles: !0 })); }), this.formManager.on("form-submit", ({ formData: e }) => { this.dispatchEvent(new CustomEvent("form-submit", { detail: { formData: e }, bubbles: !0 })); }); } /** * Public API methods to expose FormManager functionality */ /** * Validate the current form data */ validate() { return !this.formManager || !this._schema ? { isValid: !0, errors: [] } : this.formManager.validate(); } /** * Get form schema */ getSchema() { return this._schema; } /** * Reset form to default values */ reset() { this.formManager && this._schema && (this.formManager.reset(), this.data = this.formManager.getData()); } /** * Check if form has unsaved changes */ isDirty() { return !this.formManager || !this._schema ? !1 : this.formManager.isDirty(); } async connectedCallback() { var e; super.connectedCallback(); try { await G.initialize(); } catch (t) { console.debug("Extension system initialization:", t); } !this.content && ((e = this.textContent) != null && e.trim()) && (this.content = this.textContent.trim(), this.textContent = ""); } render() { if (!this.content || !this.content.trim()) return v`<div class="error">No Formdown content provided</div>`; try { this.formManager.parse(this.content), this._schema = this.formManager.getSchema(), this.data && Object.keys(this.data).length > 0 && this.formManager.updateData(this.data); const e = this.formManager.renderToTemplate({ container: this }); return !e.html || !e.html.trim() ? v`<div class="error">Generated HTML is empty</div>` : v`<div id="content-container"></div>`; } catch (e) { const t = e instanceof Error ? e.message : String(e); return v`<div class="error">Error rendering content: ${t}</div>`; } } // Override firstUpdated to set innerHTML after the initial render firstUpdated() { this.updateContent(), setTimeout(() => { this.syncUIFromData(); }, 0); } // Override updated to update content when properties change updated(e) { super.updated(e), e.has("content") && (this.updateContent(), setTimeout(() => { this.syncUIFromData(); }, 0)), e.has("data") && this.syncUIFromData(); } updateContent() { var e, t; if (!(!this.content || !this.content.trim())) try { const r = (e = this.shadowRoot) == null ? void 0 : e.querySelector("#content-container"); if (!r) return; this.formManager.parse(this.content), this._schema = this.formManager.getSchema(), this.data && Object.keys(this.data).length > 0 && this.formManager.updateData(this.data); const i = this.formManager.renderToTemplate({ container: this }); if (!i.html || i.html.trim() === "") { r.innerHTML = '<div class="error">FormManager returned empty HTML</div>'; return; } r.innerHTML = i.html, this.injectExtensionAssets(r), this.setupFieldHandlers(r); } catch (r) { const i = (t = this.shadowRoot) == null ? void 0 : t.querySelector("#content-container"); if (i) { const o = r instanceof Error ? r.message : String(r); i.innerHTML = `<div class="error">Error: ${o}</div>`; } } } /** * Inject extension styles and scripts into the component */ injectExtensionAssets(e) { try { const t = this.getUsedFieldTypes(e), r = y.getFieldTypeRegistry().getStylesForTypes(t); r && this.injectStyles(r); const i = y.getFieldTypeRegistry().getScriptsForTypes(t); i && this.injectScripts(i); } catch (t) { console.debug("Extension asset injection failed:", t); } } /** * Get list of field types used in the rendered form */ getUsedFieldTypes(e) { const t = /* @__PURE__ */ new Set(); return e.querySelectorAll("[data-field-type]").forEach((o) => { const s = o.getAttribute("data-field-type"); s && t.add(s); }), e.querySelectorAll('[class*="formdown-"][class*="-field"]').forEach((o) => { const n = o.className.match(/formdown-(\w+)-field/); n && t.add(n[1]); }), Array.from(t); } /** * Inject CSS styles into the shadow DOM */ injectStyles(e) { var r, i; if (!e.trim()) return; const t = (r = this.shadowRoot) == null ? void 0 : r.querySelector("#extension-styles"); if (t) t.textContent = e; else { const o = document.createElement("style"); o.id = "extension-styles", o.textContent = e, (i = this.shadowRoot) == null || i.appendChild(o); } } /** * Inject JavaScript into the document (global scope for form interactions) */ injectScripts(e) { if (!e.trim()) return; const t = "formdown-extension-scripts"; if (document.getElementById(t)) return; const r = document.createElement("script"); r.id = t, r.textContent = e, document.head.appendChild(r); } setupFieldHandlers(e) { this.fieldRegistry.clear(); const t = e.querySelectorAll('input:not([type="radio"]):not([type="checkbox"]), [contenteditable="true"]'); this.setupKeyboardNavigation(t), e.querySelectorAll('input, textarea, select, [contenteditable="true"]').forEach((i) => { const o = i, s = this.getFieldName(o); if (s) { this.registerField(s, o); const n = this.data[s]; if (n !== void 0) this.setElementValue(o, n); else { const a = this.getSchemaDefaultValue(s); a !== void 0 && this.updateDataReactively(s, a, o); } this.setupFieldEventHandlers(o, s), this.setupFieldSpecificBehaviors(o); } else o.id && o.id.includes("_other_input") && this.setupOtherInputHandlers(o); }); } setupKeyboardNavigation(e) { e.forEach((t, r) => { t.addEventListener("keydown", (i) => { const o = i; if (o.key === "Enter") { if (o.preventDefault(), t.tagName.toLowerCase() === "textarea") return; const s = r + 1; s < e.length && e[s].focus(); } }); }); } setupFieldEventHandlers(e, t) { const r = (o) => { this.formManager.handleUIEvent(o, this.domBinder); }, i = { querySelector: (o) => { var s; return (s = this.shadowRoot) == null ? void 0 : s.querySelector(o); }, querySelectorAll: (o) => { var s; return Array.from(((s = this.shadowRoot) == null ? void 0 : s.querySelectorAll(o)) || []); } }; this.domBinder.bindFieldToElement(t, e, i), e.hasAttribute("contenteditable") ? e.addEventListener("input", r) : (e.addEventListener("input", r), e.addEventListener("change", r)); } setupFieldSpecificBehaviors(e) { e.hasAttribute("contenteditable") && this.setupContentEditableBehaviors(e); } setupOtherInputHandlers(e) { const t = e.id.replace("_other_input", ""), r = () => { var s, n, a; const i = (s = this.shadowRoot) == null ? void 0 : s.querySelector(`#${t}_other_radio`), o = (n = this.shadowRoot) == null ? void 0 : n.querySelector(`#${t}_other_checkbox`); if (i) i.checked = !0, this.updateDataReactively(t, e.value.trim(), e); else if (o) { o.checked = !0; const c = (a = this.shadowRoot) == null ? void 0 : a.querySelectorAll(`input[type="checkbox"][name="${t}"]`), f = []; c.forEach((m) => { if (m.checked) if (m.value === "" && m.id.includes("_other_checkbox")) { const M = e.value.trim(); M && f.push(M); } else m.value !== "" && f.push(m.value); }), this.updateDataReactively(t, f, e); } }; e.addEventListener("input", r), e.addEventListener("change", r); } setupContentEditableBehaviors(e) { var i; const t = e.dataset.placeholder; ((i = e.textContent) == null ? void 0 : i.trim()) === t && (e.textContent = ""), e.addEventListener("focus", () => { var o; if (((o = e.textContent) == null ? void 0 : o.trim()) === t && (e.textContent = ""), this.selectOnFocus) { const s = window.getSelection(), n = document.createRange(); n.selectNodeContents(e), s == null || s.removeAllRanges(), s == null || s.addRange(n); } }), e.addEventListener("blur", () => { var o; (o = e.textContent) != null && o.trim() || (e.textContent = t || ""); }), e.dataset.fieldType === "email" && e.addEventListener("input", () => { var s; const o = ((s = e.textContent) == null ? void 0 : s.trim()) || ""; o && !o.includes("@") ? e.style.color = "#dc2626" : e.style.color = "#1e40af"; }); } // Reactive data management - delegated to FormManager updateDataReactively(e, t, r) { this._isUpdatingUI || (this.formManager.setFieldValue(e, t), this.data = { ...this.data, [e]: t }, this.syncUIFromData(e, r), this.emitFieldEvents(e, t)); } syncUIFromData(e, t) { if (!this._isUpdatingUI) { this._isUpdatingUI = !0; try { const r = { querySelector: (i) => { var o; return (o = this.shadowRoot) == null ? void 0 : o.querySelector(i); }, querySelectorAll: (i) => { var o; return Array.from(((o = this.shadowRoot) == null ? void 0 : o.querySelectorAll(i)) || []); } }; if (this.domBinder.syncFormData(this.data, r), e) { const i = this.data[e] ?? "", o = this.fieldRegistry.get(e); o == null || o.forEach((s) => { s !== t && this.setElementValue(s, i); }); } } finally { this._isUpdatingUI = !1; } } } // Universal element value setter - delegated to Core FieldProcessor setElementValue(e, t) { const r = { querySelector: (s) => { var n; return (n = this.shadowRoot) == null ? void 0 : n.querySelector(s); }, querySelectorAll: (s) => { var n; return Array.from(((n = this.shadowRoot) == null ? void 0 : n.querySelectorAll(s)) || []); } }, i = this.fieldProcessor.getFieldType(e); if (!this.fieldProcessor.setFieldValue(e, t, i, r) && e instanceof HTMLElement) { if (e.hasAttribute("contenteditable")) { const s = Array.isArray(t) ? t.join(", ") : String(t); e.textContent !== s && (e.textContent = s); } else if (e instanceof HTMLInputElement) { if (e.type === "checkbox" && typeof t == "boolean") e.checked = t; else if (e.type !== "checkbox" && e.type !== "radio") { const s = Array.isArray(t) ? t.join(", ") : String(t); e.value !== s && (e.value = s); } } else if (e instanceof HTMLTextAreaElement || e instanceof HTMLSelectElement) { const s = Array.isArray(t) ? t.join(", ") : String(t); e.value !== s && (e.value = s); } } } // Universal field name extractor getFieldName(e) { return e instanceof HTMLInputElement || e instanceof HTMLTextAreaElement || e instanceof HTMLSelectElement ? e.name || e.id || null : e.dataset.fieldName || e.id || null; } // Universal field value extractor - delegated to FieldProcessor // These methods were removed - functionality delegated to Core modules // Extract initial value from HTML attributes (for HTML-standard value initialization) // Note: This method is preserved for compatibility but not actively used // since we now rely on schema values instead of HTML attributes // @ts-ignore - preserved for test compatibility getElementInitialValue(e) { var t, r; if (e instanceof HTMLInputElement) return e.type === "checkbox" ? e.hasAttribute("checked") ? e.value === "true" ? !0 : e.value : null : e.type === "radio" ? e.hasAttribute("checked") ? e.value : null : e.hasAttribute("value") && e.getAttribute("value") ? e.getAttribute("value") || "" : null; if (e instanceof HTMLTextAreaElement) { const i = (t = e.textContent) == null ? void 0 : t.trim(); return i || null; } else if (e instanceof HTMLSelectElement) { const i = e.querySelector("option[selected]"); return i ? i.value : null; } else if (e.hasAttribute("contenteditable")) { const i = e.getAttribute("data-value"); if (i) return i; const o = (r = e.textContent) == null ? void 0 : r.trim(); return o && o !== e.dataset.placeholder ? o : null; } return null; } // Register field in the universal registry registerField(e, t) { this.fieldRegistry.has(e) || this.fieldRegistry.set(e, /* @__PURE__ */ new Set()), this.fieldRegistry.get(e).add(t); } // Emit standardized events emitFieldEvents(e, t) { const r = this.getFormData(); this.dispatchEvent(new CustomEvent("formdown-change", { detail: { fieldName: e, value: t, formData: r }, bubbles: !0 })), this.dispatchEvent(new CustomEvent("formdown-data-update", { detail: { formData: r }, bubbles: !0 })); } // Universal field synchronization method - expected by tests syncFieldValue(e, t) { this.data = { ...this.data, [e]: t }, this.emitFieldEvents(e, t); } // Update form data method - expected by tests updateFormData(e, t) { this.data = { ...this.data, [e]: t }, this.emitFieldEvents(e, t); } // Get form data programmatically - use reactive data as source of truth getFormData() { return { ...this.data }; } // Get default values from schema (keeping for backward compatibility) getDefaultValues() { if (!this._schema) return {}; const e = {}; return Object.entries(this._schema).forEach(([t, r]) => { r.value !== void 0 && (e[t] = r.value); }), e; } // Get schema default value for a specific field getSchemaDefaultValue(e) { if (!(!this._schema || !this._schema[e])) return this._schema[e].value; } clearValidationStates() { var t; const e = (t = this.shadowRoot) == null ? void 0 : t.querySelector("#content-container"); e && (e.querySelectorAll(".field-error, .field-valid").forEach((r) => { r.classList.remove("field-error", "field-valid"); }), e.querySelectorAll(".validation-error-message").forEach((r) => { r.remove(); })); } // Reset form method resetForm() { var r; const e = this.getFormId(), t = (r = this.shadowRoot) == null ? void 0 : r.querySelector(`#${e}`); t && t.reset(), this.data = {}, this.clearValidationStates(); } }; d.styles = P` :host { display: block; font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.5; color: var(--theme-text-primary, #1f2937); background: var(--theme-bg-primary, #ffffff); max-width: 100%; box-sizing: border-box; overflow-y: auto; } * { box-sizing: border-box; } .formdown-form { max-width: 100%; width: 100%; margin: 0; padding: 0; display: none; /* Hidden form for form attribute reference */ } .formdown-field { margin-bottom: 1.5rem; max-width: 100%; } /* Add spacing between consecutive field containers */ .formdown-field-container { margin-bottom: 0.75rem; } .formdown-field-container:last-child { margin-bottom: 0; } label { display: block; margin-bottom: 0.5rem; font-weight: 500; color: var(--theme-text-primary, #374151); font-size: 0.875rem; line-height: 1.25; } input, textarea, select { width: 100%; max-width: 100%; padding: 0.75rem; border: 1px solid var(--theme-border, #d1d5db); border-radius: 0.5rem; font-size: 1rem; font-family: inherit; line-height: 1.5; transition: all 0.15s ease-in-out; background-color: var(--theme-bg-primary, #ffffff); color: var(--theme-text-primary, #1f2937); } input:focus, textarea:focus, select:focus { outline: none; border-color: var(--theme-accent, #3b82f6); box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); background-color: var(--theme-bg-primary, #ffffff); } input:hover, textarea:hover, select:hover { border-color: var(--theme-text-secondary, #9ca3af); } input[type="radio"], input[type="checkbox"] { width: auto; max-width: none; margin-right: 0.5rem; margin-bottom: 0; } textarea { min-height: 6rem; resize: vertical; } select { cursor: pointer; appearance: none; -webkit-appearance: none; -moz-appearance: none; background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3e%3c/svg%3e"); background-position: right 0.5rem center; background-repeat: no-repeat; background-size: 1.5em 1.5em; padding-right: 2.5rem; } fieldset { border: 1px solid var(--theme-border, #d1d5db); border-radius: 0.5rem; padding: 1.25rem; margin: 0 0 1.5rem 0; max-width: 100%; background-color: var(--theme-bg-primary, #ffffff); } legend { font-weight: 600; color: var(--theme-text-primary, #374151); padding: 0 0.75rem; font-size: 0.875rem; } fieldset label { display: flex; align-items: center; margin-bottom: 0.75rem; font-weight: normal; font-size: 0.875rem; } /* Enhanced inline formdown-field elements with contentEditable */ formdown-field, [contenteditable="true"]:not(textarea) { display: inline; min-width: 60px; max-width: 200px; padding: 0.125rem 0.25rem; border: 1px solid transparent; background-color: var(--theme-bg-secondary, rgba(239, 246, 255, 0.6)); border-radius: 0.125rem; font-style: normal; color: inherit; font-size: inherit; line-height: inherit; font-family: inherit; font-weight: inherit; cursor: text; outline: none; transition: all 0.15s ease-in-out; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; vertical-align: baseline; box-decoration-break: clone; } [contenteditable="true"]:not(textarea):hover { background-color: var(--theme-bg-secondary, rgba(219, 234, 254, 0.8)); border-color: var(--theme-border, rgba(147, 197, 253, 0.5)); } [contenteditable="true"]:not(textarea):focus { background-color: var(--theme-bg-primary, rgba(255, 255, 255, 0.9)); border-color: var(--theme-accent, #3b82f6); box-shadow: 0 0 0 1px rgba(59, 130, 246, 0.2); color: var(--theme-accent, #1e40af); } [contenteditable="true"]:not(textarea):empty::before { content: attr(data-placeholder); color: var(--theme-text-secondary, #94a3b8); font-style: italic; opacity: 0.7; } /* Enhanced typography for markdown content */ h1, h2, h3, h4, h5, h6 { margin-top: 0; margin-bottom: 1rem; color: var(--theme-text-primary, #1f2937); font-weight: 600; line-height: 1.25; } h1 { font-size: 2.25rem; font-weight: 700; } h2 { font-size: 1.875rem; font-weight: 600; } h3 { font-size: 1.5rem; font-weight: 600; } h4 { font-size: 1.25rem; font-weight: 600; } h5 { font-size: 1.125rem; font-weight: 600; } h6 { font-size: 1rem; font-weight: 600; } p { margin-bottom: 1rem; line-height: 1.7; color: var(--theme-text-secondary, #4b5563); } /* Responsive design */ @media (max-width: 768px) { :host { font-size: 0.875rem; } input, textarea, select { padding: 0.625rem; font-size: 0.875rem; } h1 { font-size: 1.875rem; } h2 { font-size: 1.5rem; } h3 { font-size: 1.25rem; } } .error { color: var(--theme-error, #dc2626); font-size: 0.875rem; margin-top: 0.5rem; display: block; } /* Field validation styles */ .field-error { border-color: var(--theme-error, #dc2626) !important; box-shadow: 0 0 0 1px rgba(220, 38, 38, 0.1) !important; } .field-error:focus { border-color: var(--theme-error, #dc2626) !important; box-shadow: 0 0 0 3px rgba(220, 38, 38, 0.1) !important; } .validation-error-message { color: var(--theme-error, #dc2626); font-size: 0.75rem; margin-top: 0.25rem; display: block; font-weight: 500; } /* Success state */ .field-valid { border-color: #10b981 !important; box-shadow: 0 0 0 1px rgba(16, 185, 129, 0.1) !important; } .submit-button { background-color: #3b82f6; color: white; padding: 0.75rem 1.5rem; border: none; border-radius: 0.5rem; font-size: 1rem; font-weight: 500; cursor: pointer; transition: all 0.15s ease-in-out; margin-top: 1.5rem; width: auto; max-width: 100%; } .submit-button:hover { background-color: #2563eb; transform: translateY(-1px); box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); } .submit-button:disabled { background-color: #9ca3af; cursor: not-allowed; transform: none; box-shadow: none; } .submit-button:active { transform: translateY(0); } /* Ensure content doesn't overflow */ #content-container { max-width: 100%; overflow-wrap: break-word; word-wrap: break-word; } /* Radio and checkbox groups */ .radio-group, .checkbox-group { display: flex; gap: 0.75rem; flex-wrap: wrap; } /* Inline layout (default) */ .radio-group.inline, .checkbox-group.inline { flex-direction: row; align-items: center; } /* Vertical layout */ .radio-group.vertical, .checkbox-group.vertical { flex-direction: column; align-items: flex-start; } .formdown-option-label { display: flex; align-items: center; margin-bottom: 0; font-weight: normal; cursor: pointer; font-size: 0.875rem; white-space: nowrap; } .formdown-option-label input { margin-right: 0.5rem; margin-bottom: 0; } .formdown-option-label span { user-select: none; } /* Legacy support for old structure */ .radio-group label, .checkbox-group label { display: flex; align-items: center; margin-bottom: 0; font-weight: normal; cursor: pointer; }/* Better spacing for form elements */ .formdown-form > * + * { margin-top: 1rem; } `; u([ p() ], d.prototype, "content", 2); u([ p({ type: Boolean, attribute: "select-on-focus" }) ], d.prototype, "selectOnFocus", 2); u([ p({ attribute: "form-id" }) ], d.prototype, "formId", 2); u([ p({ type: Boolean, attribute: "show-submit-button" }) ], d.prototype, "showSubmitButton", 2); u([ p({ attribute: "submit-text" }) ], d.prototype, "submitText", 2); u([ p({ type: Object }) ], d.prototype, "data", 1); d = u([ z("formdown-ui") ], d); const Z = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({ __proto__: null, get FormdownUI() { return d; } }, Symbol.toStringTag, { value: "Module" })), it = (e, t = {}) => { const r = document.createElement("formdown-ui"); return t.content && (r.content = t.content), t.formId && (r.formId = t.formId), t.showSubmitButton !== void 0 && (r.showSubmitButton = t.showSubmitButton), t.submitText && (r.submitText = t.submitText), e.appendChild(r), r; }, ot = () => { customElements.get("formdown-ui") || Promise.resolve().then(() => Z); }; export { d as FormdownUI, S as UIExtensionSupport, it as createFormdownUI, ot as registerFormdownUI, G as uiExtensionSupport };