UNPKG

@formdown/ui

Version:

Pure HTML renderer for Formdown syntax

1,306 lines (1,231 loc) 42.1 kB
import { css as F, LitElement as P, html as b } from "lit"; import { extensionManager as v, registerHook as _, registerPlugin as T, FormManager as z } from "@formdown/core"; /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ const A = (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 g = globalThis, E = g.ShadowRoot && (g.ShadyCSS === void 0 || g.ShadyCSS.nativeShadow) && "adoptedStyleSheets" in Document.prototype && "replace" in CSSStyleSheet.prototype, C = Symbol(), M = /* @__PURE__ */ new WeakMap(); let I = class { constructor(t, r, o) { if (this._$cssResult$ = !0, o !== C) 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 (E && t === void 0) { const o = r !== void 0 && r.length === 1; o && (t = M.get(r)), t === void 0 && ((this.o = t = new CSSStyleSheet()).replaceSync(this.cssText), o && M.set(r, t)); } return t; } toString() { return this.cssText; } }; const O = (e) => new I(typeof e == "string" ? e : e + "", void 0, C), R = (e, t) => { if (E) e.adoptedStyleSheets = t.map((r) => r instanceof CSSStyleSheet ? r : r.styleSheet); else for (const r of t) { const o = document.createElement("style"), i = g.litNonce; i !== void 0 && o.setAttribute("nonce", i), o.textContent = r.cssText, e.appendChild(o); } }, k = E ? (e) => e : (e) => e instanceof CSSStyleSheet ? ((t) => { let r = ""; for (const o of t.cssRules) r += o.cssText; return O(r); })(e) : e; /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ const { is: D, defineProperty: L, getOwnPropertyDescriptor: H, getOwnPropertyNames: B, getOwnPropertySymbols: j, getPrototypeOf: q } = Object, h = globalThis, $ = h.trustedTypes, V = $ ? $.emptyScript : "", w = h.reactiveElementPolyfillSupport, f = (e, t) => e, y = { toAttribute(e, t) { switch (t) { case Boolean: e = e ? V : 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; } }, S = (e, t) => !D(e, t), U = { attribute: !0, type: String, converter: y, reflect: !1, useDefault: !1, hasChanged: S }; Symbol.metadata ?? (Symbol.metadata = Symbol("metadata")), h.litPropertyMetadata ?? (h.litPropertyMetadata = /* @__PURE__ */ new WeakMap()); class m 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 = U) { 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 o = Symbol(), i = this.getPropertyDescriptor(t, o, r); i !== void 0 && L(this.prototype, t, i); } } static getPropertyDescriptor(t, r, o) { const { get: i, set: a } = H(this.prototype, t) ?? { get() { return this[r]; }, set(n) { this[r] = n; } }; return { get: i, set(n) { const s = i == null ? void 0 : i.call(this); a == null || a.call(this, n), this.requestUpdate(t, s, o); }, configurable: !0, enumerable: !0 }; } static getPropertyOptions(t) { return this.elementProperties.get(t) ?? U; } static _$Ei() { if (this.hasOwnProperty(f("elementProperties"))) return; const t = q(this); t.finalize(), t.l !== void 0 && (this.l = [...t.l]), this.elementProperties = new Map(t.elementProperties); } static finalize() { if (this.hasOwnProperty(f("finalized"))) return; if (this.finalized = !0, this._$Ei(), this.hasOwnProperty(f("properties"))) { const r = this.properties, o = [...B(r), ...j(r)]; for (const i of o) this.createProperty(i, r[i]); } const t = this[Symbol.metadata]; if (t !== null) { const r = litPropertyMetadata.get(t); if (r !== void 0) for (const [o, i] of r) this.elementProperties.set(o, i); } this._$Eh = /* @__PURE__ */ new Map(); for (const [r, o] of this.elementProperties) { const i = this._$Eu(r, o); i !== void 0 && this._$Eh.set(i, r); } this.elementStyles = this.finalizeStyles(this.styles); } static finalizeStyles(t) { const r = []; if (Array.isArray(t)) { const o = new Set(t.flat(1 / 0).reverse()); for (const i of o) r.unshift(k(i)); } else t !== void 0 && r.push(k(t)); return r; } static _$Eu(t, r) { const o = r.attribute; return o === !1 ? void 0 : typeof o == "string" ? o : 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 o of r.keys()) this.hasOwnProperty(o) && (t.set(o, this[o]), delete this[o]); t.size > 0 && (this._$Ep = t); } createRenderRoot() { const t = this.shadowRoot ?? this.attachShadow(this.constructor.shadowRootOptions); return R(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 o; return (o = r.hostConnected) == null ? void 0 : o.call(r); }); } enableUpdating(t) { } disconnectedCallback() { var t; (t = this._$EO) == null || t.forEach((r) => { var o; return (o = r.hostDisconnected) == null ? void 0 : o.call(r); }); } attributeChangedCallback(t, r, o) { this._$AK(t, o); } _$ET(t, r) { var a; const o = this.constructor.elementProperties.get(t), i = this.constructor._$Eu(t, o); if (i !== void 0 && o.reflect === !0) { const n = (((a = o.converter) == null ? void 0 : a.toAttribute) !== void 0 ? o.converter : y).toAttribute(r, o.type); this._$Em = t, n == null ? this.removeAttribute(i) : this.setAttribute(i, n), this._$Em = null; } } _$AK(t, r) { var a, n; const o = this.constructor, i = o._$Eh.get(t); if (i !== void 0 && this._$Em !== i) { const s = o.getPropertyOptions(i), l = typeof s.converter == "function" ? { fromAttribute: s.converter } : ((a = s.converter) == null ? void 0 : a.fromAttribute) !== void 0 ? s.converter : y; this._$Em = i, this[i] = l.fromAttribute(r, s.type) ?? ((n = this._$Ej) == null ? void 0 : n.get(i)) ?? null, this._$Em = null; } } requestUpdate(t, r, o) { var i; if (t !== void 0) { const a = this.constructor, n = this[t]; if (o ?? (o = a.getPropertyOptions(t)), !((o.hasChanged ?? S)(n, r) || o.useDefault && o.reflect && n === ((i = this._$Ej) == null ? void 0 : i.get(t)) && !this.hasAttribute(a._$Eu(t, o)))) return; this.C(t, r, o); } this.isUpdatePending === !1 && (this._$ES = this._$EP()); } C(t, r, { useDefault: o, reflect: i, wrapped: a }, n) { o && !(this._$Ej ?? (this._$Ej = /* @__PURE__ */ new Map())).has(t) && (this._$Ej.set(t, n ?? r ?? this[t]), a !== !0 || n !== void 0) || (this._$AL.has(t) || (this.hasUpdated || o || (r = void 0), this._$AL.set(t, r)), i === !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 o; if (!this.isUpdatePending) return; if (!this.hasUpdated) { if (this.renderRoot ?? (this.renderRoot = this.createRenderRoot()), this._$Ep) { for (const [a, n] of this._$Ep) this[a] = n; this._$Ep = void 0; } const i = this.constructor.elementProperties; if (i.size > 0) for (const [a, n] of i) { const { wrapped: s } = n, l = this[a]; s !== !0 || this._$AL.has(a) || l === void 0 || this.C(a, void 0, n, l); } } let t = !1; const r = this._$AL; try { t = this.shouldUpdate(r), t ? (this.willUpdate(r), (o = this._$EO) == null || o.forEach((i) => { var a; return (a = i.hostUpdate) == null ? void 0 : a.call(i); }), this.update(r)) : this._$EM(); } catch (i) { throw t = !1, this._$EM(), i; } t && this._$AE(r); } willUpdate(t) { } _$AE(t) { var r; (r = this._$EO) == null || r.forEach((o) => { var i; return (i = o.hostUpdated) == null ? void 0 : i.call(o); }), 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) { } } m.elementStyles = [], m.shadowRootOptions = { mode: "open" }, m[f("elementProperties")] = /* @__PURE__ */ new Map(), m[f("finalized")] = /* @__PURE__ */ new Map(), w == null || w({ ReactiveElement: m }), (h.reactiveElementVersions ?? (h.reactiveElementVersions = [])).push("2.1.0"); /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ const N = { attribute: !0, type: String, converter: y, reflect: !1, hasChanged: S }, K = (e = N, t, r) => { const { kind: o, metadata: i } = r; let a = globalThis.litPropertyMetadata.get(i); if (a === void 0 && globalThis.litPropertyMetadata.set(i, a = /* @__PURE__ */ new Map()), o === "setter" && ((e = Object.create(e)).wrapped = !0), a.set(r.name, e), o === "accessor") { const { name: n } = r; return { set(s) { const l = t.get.call(this); t.set.call(this, s), this.requestUpdate(n, l, e); }, init(s) { return s !== void 0 && this.C(n, void 0, e, s), s; } }; } if (o === "setter") { const { name: n } = r; return function(s) { const l = this[n]; t.call(this, s), this.requestUpdate(n, l, e); }; } throw Error("Unsupported decorator location: " + o); }; function p(e) { return (t, r) => typeof r == "object" ? K(e, t, r) : ((o, i, a) => { const n = i.hasOwnProperty(a); return i.constructor.createProperty(a, o), n ? Object.getOwnPropertyDescriptor(i, a) : void 0; })(e, t, r); } const c = class c { constructor() { this.initialized = !1; } static getInstance() { return c.instance || (c.instance = new c()), c.instance; } async initialize() { if (!this.initialized) try { await v.initialize(), this.setupUIHooks(), this.initialized = !0; } catch { } } setupUIHooks() { _({ name: "field-render", priority: 1, handler: this.handleFieldRender.bind(this) }), _({ 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 T(t); } /** * Get extension statistics */ getExtensionStats() { return v.getStats(); } /** * Execute hooks for UI operations */ async executeUIHooks(t, r, ...o) { return v.executeHooks(t, r, ...o); } }; c.instance = null; let x = c; const W = x.getInstance(), Y = F` :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); } /* Placeholder styling for all input types */ input::placeholder, textarea::placeholder { color: var(--theme-text-secondary, #94a3b8); font-style: italic; opacity: 0.8; } 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-block; min-width: 60px; max-width: 200px; font-style: normal; color: inherit; font-size: inherit; line-height: 1.5; font-family: inherit; font-weight: inherit; cursor: text; outline: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; vertical-align: middle; box-decoration-break: clone; } /* Placeholder for inline contenteditable fields */ [contenteditable="true"]:not(textarea):empty::before { content: attr(data-placeholder); color: var(--theme-text-secondary, #94a3b8); font-style: italic; font-weight: normal; opacity: 0.7; pointer-events: none; user-select: none; } /* Enhanced visual styling for inline fields */ [contenteditable="true"]:not(textarea) { border: 1px solid var(--theme-border, rgba(209, 213, 219, 0.6)); background-color: var(--theme-bg-secondary, rgba(248, 250, 252, 0.8)); border-radius: 0.25rem; padding: 0.125rem 0.5rem; transition: all 0.2s ease-in-out; box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.05); position: relative; min-height: 1.5em; } [contenteditable="true"]:not(textarea):hover { background-color: var(--theme-bg-secondary, rgba(241, 245, 249, 0.9)); border-color: var(--theme-border, rgba(156, 163, 175, 0.8)); box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), inset 0 1px 2px rgba(0, 0, 0, 0.05); transform: translateY(-1px); } [contenteditable="true"]:not(textarea):focus { background-color: var(--theme-bg-primary, #ffffff); border-color: var(--theme-accent, #3b82f6); box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2), 0 2px 8px rgba(0, 0, 0, 0.15); color: var(--theme-text-primary, #1f2937); transform: translateY(-1px); } /* Better visual distinction when field has content */ [contenteditable="true"]:not(textarea):not(:empty) { background-color: var(--theme-bg-primary, #ffffff); border-color: var(--theme-border, rgba(156, 163, 175, 0.9)); font-weight: normal; } /* 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); } /* Code blocks */ pre { background-color: var(--theme-bg-secondary, #f6f8fa); border: 1px solid var(--theme-border, #d0d7de); border-radius: 0.375rem; padding: 1rem; margin: 1rem 0; overflow-x: auto; font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace; font-size: 0.875rem; line-height: 1.6; } code { font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace; font-size: 0.875em; background-color: var(--theme-bg-secondary, rgba(175, 184, 193, 0.2)); padding: 0.125rem 0.375rem; border-radius: 0.25rem; color: var(--theme-text-primary, #1f2937); } pre code { background-color: transparent; padding: 0; border-radius: 0; font-size: 0.875rem; color: var(--theme-text-primary, #24292f); } /* Syntax highlighting support (basic) */ .language-javascript, .language-js, .language-typescript, .language-ts, .language-python, .language-py, .language-html, .language-css, .language-json, .language-bash { display: block; } /* 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; } /* Base button styles - all buttons */ .submit-button, button, input[type="submit"], input[type="button"], input[type="reset"] { color: white; padding: 0.75rem 1.75rem; border: none; border-radius: 0.5rem; font-size: 1rem; font-weight: 600; cursor: pointer; transition: all 0.2s ease-in-out; margin-top: 1.5rem; width: auto; max-width: 100%; letter-spacing: 0.025em; position: relative; overflow: hidden; font-family: inherit; } /* Shine effect for all buttons */ .submit-button::before, button::before, input[type="submit"]::before, input[type="button"]::before, input[type="reset"]::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%; background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); transition: left 0.5s ease-in-out; } /* Hover shine effect */ .submit-button:hover::before, button:hover::before, input[type="submit"]:hover::before, input[type="button"]:hover::before, input[type="reset"]:hover::before { left: 100%; } /* Common hover state */ .submit-button:hover, button:hover, input[type="submit"]:hover, input[type="button"]:hover, input[type="reset"]:hover { transform: translateY(-2px); } /* Common active state */ .submit-button:active, button:active, input[type="submit"]:active, input[type="button"]:active, input[type="reset"]:active { transform: translateY(0); } /* Common disabled state */ .submit-button:disabled, button:disabled, input[type="submit"]:disabled, input[type="button"]:disabled, input[type="reset"]:disabled { background: linear-gradient(135deg, #9ca3af 0%, #6b7280 100%); cursor: not-allowed; transform: none; box-shadow: none; opacity: 0.6; } .submit-button:disabled::before, button:disabled::before, input[type="submit"]:disabled::before, input[type="button"]:disabled::before, input[type="reset"]:disabled::before { display: none; } /* Primary button (submit) - Blue */ .submit-button, button[type="submit"], input[type="submit"], button:not([type]) { background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%); box-shadow: 0 2px 4px rgba(59, 130, 246, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); } .submit-button:hover, button[type="submit"]:hover, input[type="submit"]:hover, button:not([type]):hover { background: linear-gradient(135deg, #2563eb 0%, #1d4ed8 100%); box-shadow: 0 6px 12px rgba(59, 130, 246, 0.3), 0 2px 4px rgba(0, 0, 0, 0.1); } .submit-button:active, button[type="submit"]:active, input[type="submit"]:active, button:not([type]):active { box-shadow: 0 2px 4px rgba(59, 130, 246, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); } /* Secondary button - Slate */ button[type="button"], input[type="button"] { background: linear-gradient(135deg, #64748b 0%, #475569 100%); box-shadow: 0 2px 4px rgba(100, 116, 139, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); } button[type="button"]:hover, input[type="button"]:hover { background: linear-gradient(135deg, #475569 0%, #334155 100%); box-shadow: 0 6px 12px rgba(100, 116, 139, 0.3), 0 2px 4px rgba(0, 0, 0, 0.1); } button[type="button"]:active, input[type="button"]:active { box-shadow: 0 2px 4px rgba(100, 116, 139, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); } /* Danger button (reset) - Red */ button[type="reset"], input[type="reset"] { background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%); box-shadow: 0 2px 4px rgba(239, 68, 68, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); } button[type="reset"]:hover, input[type="reset"]:hover { background: linear-gradient(135deg, #dc2626 0%, #b91c1c 100%); box-shadow: 0 6px 12px rgba(239, 68, 68, 0.3), 0 2px 4px rgba(0, 0, 0, 0.1); } button[type="reset"]:active, input[type="reset"]:active { box-shadow: 0 2px 4px rgba(239, 68, 68, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); } /* 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; } /* Table styles - GitHub Flavored Markdown standard */ .formdown-table { width: 100%; border-collapse: collapse; margin: var(--formdown-table-margin, 1rem 0); background-color: var(--formdown-table-bg, var(--theme-bg-primary, #ffffff)); border: var(--formdown-table-border-width, 1px) solid var(--formdown-table-border-color, var(--theme-border, #d0d7de)); border-radius: var(--formdown-table-border-radius, 6px); overflow: hidden; font-size: var(--formdown-table-font-size, 0.875rem); } .formdown-table thead { background-color: var(--formdown-table-header-bg, var(--theme-bg-secondary, #f6f8fa)); border-bottom: var(--formdown-table-header-border-width, 1px) solid var(--formdown-table-border-color, var(--theme-border, #d0d7de)); } .formdown-table th { padding: var(--formdown-table-cell-padding, 0.5rem 1rem); text-align: var(--formdown-table-header-align, left); font-weight: var(--formdown-table-header-weight, 600); font-size: var(--formdown-table-header-font-size, inherit); color: var(--formdown-table-header-color, var(--theme-text-primary, #1f2328)); border-right: var(--formdown-table-cell-border-width, 1px) solid var(--formdown-table-border-color, var(--theme-border, #d0d7de)); } .formdown-table th:last-child { border-right: none; } .formdown-table td { padding: var(--formdown-table-cell-padding, 0.5rem 1rem); border-top: var(--formdown-table-cell-border-width, 1px) solid var(--formdown-table-border-color, var(--theme-border, #d0d7de)); border-right: var(--formdown-table-cell-border-width, 1px) solid var(--formdown-table-border-color, var(--theme-border, #d0d7de)); color: var(--formdown-table-cell-color, var(--theme-text-secondary, #656d76)); line-height: 1.5; } .formdown-table td:last-child { border-right: none; } .formdown-table tbody tr { transition: background-color var(--formdown-table-transition, 0.1s ease); } .formdown-table tbody tr:hover { background-color: var(--formdown-table-row-hover-bg, var(--theme-bg-secondary, #f6f8fa)); } .formdown-table tbody tr:last-child td { border-bottom: none; } /* Inline fields within table cells */ .formdown-table td [contenteditable="true"] { min-width: var(--formdown-table-inline-field-min-width, 80px); max-width: 100%; display: inline-block; } /* Responsive table on mobile */ @media (max-width: 768px) { .formdown-table { font-size: var(--formdown-table-font-size-mobile, 0.8125rem); border-radius: var(--formdown-table-border-radius-mobile, 4px); } .formdown-table th, .formdown-table td { padding: var(--formdown-table-cell-padding-mobile, 0.375rem 0.75rem); } } `; var G = Object.defineProperty, J = Object.getOwnPropertyDescriptor, u = (e, t, r, o) => { for (var i = o > 1 ? void 0 : o ? J(t, r) : t, a = e.length - 1, n; a >= 0; a--) (n = e[a]) && (i = (o ? n(t, r, i) : n(i)) || i); return o && i && G(t, r, i), i; }; let d = class extends P { 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.formManager = new z(), this.domBinder = this.formManager.createDOMBinder(), this.setupCoreUIBridge(), this.setupFormManagerEvents(); } 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); } /** * Simplified Core-UI bridge using EventOrchestrator */ setupCoreUIBridge() { this.formManager.setupComponentBridge({ id: "formdown-ui", type: "ui", emit: (e, t) => this.dispatchEvent(new CustomEvent(e, { detail: t, bubbles: !0 })), on: (e, t) => () => { } }); } /** * Streamlined 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 W.initialize(); } catch { } !this.content && ((e = this.textContent) != null && e.trim()) && (this.content = this.textContent.trim(), this.textContent = ""); } render() { if (!this.content || !this.content.trim()) return b`<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() ? b`<div class="error">Generated HTML is empty</div>` : b`<div id="content-container"></div>`; } catch (e) { const t = e instanceof Error ? e.message : String(e); return b`<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 o = this.formManager.renderToTemplate({ container: this }); if (!o.html || o.html.trim() === "") { r.innerHTML = '<div class="error">FormManager returned empty HTML</div>'; return; } r.innerHTML = o.html, this.injectExtensionAssets(r), this.setupFieldHandlers(r); } catch (r) { const o = (t = this.shadowRoot) == null ? void 0 : t.querySelector("#content-container"); if (o) { const i = r instanceof Error ? r.message : String(r); o.innerHTML = `<div class="error">Error: ${i}</div>`; } } } /** * Simplified extension asset injection */ injectExtensionAssets(e) { try { const t = /* @__PURE__ */ new Set(); e.querySelectorAll("[data-field-type]").forEach((o) => { const i = o.getAttribute("data-field-type"); i && t.add(i); }); } catch { } } setupFieldHandlers(e) { this.fieldRegistry.clear(), e.querySelectorAll('input, textarea, select, [contenteditable="true"]').forEach((o) => { const i = o, a = this.getFieldName(i); a && (this.registerField(a, i), this.setupFieldEventHandlers(i, a)); }); const r = e.querySelectorAll('input:not([type="radio"]):not([type="checkbox"]), [contenteditable="true"]'); this.setupBasicKeyboardNavigation(r); } setupBasicKeyboardNavigation(e) { e.forEach((t, r) => { t.addEventListener("keydown", (o) => { const i = o; if (i.key === "Enter" && t.tagName.toLowerCase() !== "textarea") { i.preventDefault(); const a = r + 1; a < e.length && e[a].focus(); } }); }); } setupFieldEventHandlers(e, t) { this.domBinder.bindFieldToElement(t, e); const r = (i) => { this.formManager.handleUIEvent(i, this.domBinder); const a = this.getFieldValueFromElement(e); this.updateDataReactively(t, a); }, o = (i) => { const a = i.target; a.hasAttribute("contenteditable") && setTimeout(() => { const n = document.createRange(), s = window.getSelection(); s && a.textContent && (n.selectNodeContents(a), s.removeAllRanges(), s.addRange(n)); }, 0), a instanceof HTMLInputElement && a.type !== "file" && a.type !== "checkbox" && a.type !== "radio" && setTimeout(() => { a.select(); }, 0); }; e.addEventListener("input", r), e.addEventListener("change", r), e.addEventListener("focus", o), e.hasAttribute("contenteditable") && e.addEventListener("blur", r); } // Field-specific behaviors delegated to DOMBinder in setupFieldHandlers // Simplified reactive data management with test compatibility updateDataReactively(e, t, r) { this._isUpdatingUI || (this.formManager.setFieldValue(e, t), this.data = { ...this.data, [e]: t }, this.emitFieldEvents(e, t)); } syncUIFromData() { var e; if (!this._isUpdatingUI) { this._isUpdatingUI = !0; try { const t = (e = this.shadowRoot) == null ? void 0 : e.activeElement; this.domBinder.getValueAssignments(this.data).forEach(({ element: o, value: i, fieldType: a }) => { const n = o; n !== t && this.applyValueToElement(n, i, a); }); } finally { this._isUpdatingUI = !1, this.domBinder.releaseSyncLock(); } } } /** * Apply a value to a DOM element based on field type */ applyValueToElement(e, t, r) { e instanceof HTMLInputElement ? r === "checkbox" ? typeof t == "boolean" ? e.checked = t : Array.isArray(t) && (e.checked = t.includes(e.value)) : r === "radio" ? e.checked = e.value === String(t) : e.value = String(t ?? "") : e instanceof HTMLTextAreaElement || e instanceof HTMLSelectElement ? e.value = String(t ?? "") : e.hasAttribute("contenteditable") && (e.textContent = String(t ?? "")); } // 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; } // Simplified field value extraction getFieldValueFromElement(e) { var t; if (e instanceof HTMLInputElement) { if (e.type === "checkbox") { const r = e.name, o = { querySelector: (n) => { var s; return (s = this.shadowRoot) == null ? void 0 : s.querySelector(n); }, querySelectorAll: (n) => { var s; return Array.from(((s = this.shadowRoot) == null ? void 0 : s.querySelectorAll(n)) || []); } }, a = this.formManager.createFieldProcessor().processCheckboxGroup(r, o); return a.success ? a.value : e.checked; } else if (e.type === "radio") return e.value; return e.value; } else { if (e instanceof HTMLTextAreaElement || e instanceof HTMLSelectElement) return e.value; if (e.hasAttribute("contenteditable")) return ((t = e.textContent) == null ? void 0 : t.trim()) || ""; } return ""; } // 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 })); } // Field synchronization - delegated to FormManager syncFieldValue(e, t) { this.formManager.setFieldValue(e, t), this.data = this.formManager.getData(), this.emitFieldEvents(e, t); } // Form data methods - delegated to FormManager updateFormData(e, t) { this.formManager.setFieldValue(e, t), this.data = this.formManager.getData(), this.emitFieldEvents(e, t); } getFormData() { return this.formManager.getData(); } getDefaultValues() { return this.formManager.getDefaultValues(); } // Schema default value getter removed - functionality delegated to FormManager 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 - delegated to FormManager resetForm() { this.formManager.reset(), this.data = this.formManager.getData(), this.clearValidationStates(); } /** * Update entire form data from external source (for two-way binding) */ setFormData(e) { var r; if (!this.formManager) return; const t = (r = this.shadowRoot) == null ? void 0 : r.querySelector("#content-container"); t && (Object.entries(e).forEach(([o, i]) => { let a = t.querySelector(`[name="${o}"]`); a || (a = t.querySelector(`[data-field-name="${o}"]`)), a || (a = t.querySelector(`#${o}`)), a && (a.hasAttribute("contenteditable") ? a.textContent = String(i || "") : a instanceof HTMLInputElement ? a.type === "checkbox" || a.type === "radio" ? a.checked = !!i : a.value = String(i || "") : (a instanceof HTMLTextAreaElement || a instanceof HTMLSelectElement) && (a.value = String(i || "")), a.dispatchEvent(new Event("input", { bubbles: !0 }))); }), this.data = { ...e }); } }; d.styles = Y; 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([ A("formdown-ui") ], d); const tt = (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; }, et = () => { }; export { d as FormdownUI, x as UIExtensionSupport, tt as createFormdownUI, et as registerFormdownUI, W as uiExtensionSupport };