@formdown/ui
Version:
Pure HTML renderer for Formdown syntax
1,306 lines (1,231 loc) • 42.1 kB
JavaScript
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 */
(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 */
(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
};