@optionfactory/fml 9.0.0-rc4 → 9.0.0-rc5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"ful.iife.min.js","sources":["../src/ful/storage.mjs","../src/ful/events/async.mjs","../src/ful/claims.mjs","../src/ful/descriptions.mjs","../src/ful/timing.mjs","../src/ful/forms/bindings.mjs","../src/ful/forms/field.mjs","../src/ful/forms/form.mjs","../src/ful/forms/input.mjs","../src/ful/forms/temporals.mjs","../src/ful/forms/files.mjs","../src/ful/disclosures/anchors.mjs","../src/ful/forms/select.mjs","../src/ful/forms/radio.mjs","../src/ful/forms/checkbox.mjs","../src/ful/navigation/table.mjs","../src/ful/forms/choice-button.mjs","../src/ful/forms/filters.mjs","../src/ful/events/sections.mjs","../src/ful/disclosures/targets.mjs","../src/ful/disclosures/info.mjs","../src/ful/disclosures/drawer.mjs","../src/ful/disclosures/toast.mjs","../src/ful/navigation/tabs.mjs","../src/ful/disclosures/accordion.mjs","../src/ful/navigation/wizard.mjs","../src/ful/plugin.mjs","../src/ful/l10n/en.mjs","../src/ful/l10n/it.mjs","../src/ful/l10n/es.mjs","../src/ful/l10n/fr.mjs"],"sourcesContent":["/**\n * Builds a json-encoding wrapper over one of the page's storages. The backing\n * is deferred (an accessor, not the storage itself): where storage is denied\n * (blocked cookies, some embedded or private contexts) the accessor itself\n * throws, and must do so per call, never at module load. The methods are bound\n * to nothing: destructuring keeps them working.\n * @param {() => globalThis.Storage} backing\n */\nconst storage = (backing) => {\n const remove = (k) => {\n try {\n backing().removeItem(k);\n } catch {\n //nothing to remove where storage is unreachable\n }\n };\n const load = (k) => {\n let got;\n try {\n got = backing().getItem(k);\n } catch {\n //storage can be unreachable altogether (blocked cookies, embedded or\n //private contexts): a read that cannot reach it is a miss, not a failure\n return undefined;\n }\n if (got === null) {\n return undefined;\n }\n try {\n return JSON.parse(got);\n } catch {\n //not what save wrote: drop it, otherwise every later read fails the same way\n remove(k);\n return undefined;\n }\n };\n const save = (k, v) => {\n backing().setItem(k, JSON.stringify(v));\n };\n const pop = (k) => {\n const decoded = load(k);\n remove(k);\n return decoded;\n };\n return { save, load, remove, pop };\n};\n\n/**\n * Builds a revision-guarded view over a storage wrapper: a load under a\n * revision other than the stored one is a miss that also evicts the entry.\n * @param {ReturnType<typeof storage>} store\n */\nconst versioned = (store) => ({\n save(key, revision, data) {\n store.save(key, { revision, data });\n },\n load(key, revision) {\n const stored = store.load(key);\n if (stored == null || typeof stored !== 'object' || stored.revision !== revision) {\n store.remove(key);\n return undefined;\n }\n return stored.data;\n },\n});\n\nconst LocalStorage = storage(() => localStorage);\nconst SessionStorage = storage(() => sessionStorage);\nconst VersionedLocalStorage = versioned(LocalStorage);\nconst VersionedSessionStorage = versioned(SessionStorage);\n\nexport { LocalStorage, VersionedLocalStorage, SessionStorage, VersionedSessionStorage };\n","/**\n * @typedef {Object} AsyncExtension\n * @property {Promise<any>[]} promises\n * @typedef {Event & { async?: AsyncExtension }} AsyncEvent\n */\n/**\n * Dispatching an event and waiting for what its listeners answer. A listener\n * registered through `asyncOn` attaches its promise to the event, and\n * `fireAsync` resolves once they have all settled: `broadcast` collects every\n * answer, `pipeline` allows at most one, `delegate` requires exactly one.\n */\nclass AsyncEvents {\n /**\n * Dispatches an event and handles asynchronous resolution based on the execution mode.\n * @param {HTMLElement} el - The target element dispatching the event.\n * @param {AsyncEvent} evt - The event instance.\n * @param {{mode?: 'broadcast' | 'pipeline' | 'delegate'}} [options] - Configuration options (defaults to 'broadcast').\n * @returns {Promise<any>} Resolves with an array of values for broadcasts, a single value for pipelines/delegates, or undefined.\n */\n static async fireAsync(el, evt, options) {\n el.dispatchEvent(evt);\n const promises = evt.async?.promises ?? [];\n const mode = options?.mode ?? 'broadcast';\n if ((mode === 'pipeline' && promises.length > 1) || (mode === 'delegate' && promises.length !== 1)) {\n //the listeners ran under a broken configuration: nothing legitimately\n //awaits their outcome, and their failures are not page errors\n Promise.all(promises).catch(() => {});\n throw new Error(\n mode === 'pipeline'\n ? `[AsyncEvents] Event \"${evt.type}\" is configured in 'pipeline' mode and expects at most one async listener, but ${promises.length} listeners were triggered on this element.`\n : `[AsyncEvents] Event \"${evt.type}\" is configured in 'delegate' mode and requires exactly one async listener, but ${promises.length} were registered.`,\n );\n }\n return mode === 'broadcast' ? Promise.all(promises) : Promise.resolve(promises[0]);\n }\n\n /**\n * Registers an asynchronous event listener wrapper.\n * @param {HTMLElement} el - The target element.\n * @param {string} type - The event name/type.\n * @param {Function} fn - The async listener middleware function returning the execution result.\n * @param {AddEventListenerOptions} [options] - Native addEventListener options.\n * @returns {EventListener} The underlying proxy listener function needed for cleanup via asyncOff.\n */\n static asyncOn(el, type, fn, options) {\n /** @type {(evt: Event) => Promise<void>} */\n const listener = async (event) => {\n const ae = /** @type {AsyncEvent} */ (event);\n if (!ae.async) {\n ae.async = { promises: [] };\n }\n const { promise, resolve, reject } = Promise.withResolvers();\n ae.async.promises.push(promise);\n try {\n resolve(await fn(ae));\n } catch (e) {\n reject(e);\n }\n };\n\n el.addEventListener(type, listener, options);\n return listener;\n }\n\n /**\n * Unregisters an asynchronous event listener proxy.\n * @param {HTMLElement} el - The target element.\n * @param {string} type - The event name/type.\n * @param {EventListener} listener - The proxy listener instance previously returned by asyncOn.\n * @param {EventListenerOptions} [options] - Native removeEventListener options.\n */\n static asyncOff(el, type, listener, options) {\n el.removeEventListener(type, listener, options);\n }\n /**\n * Mixes the asynchronous execution engine extensions into target class prototypes.\n * @param {...Function} classes - The target class constructors to decorate.\n */\n static mixInto(...classes) {\n for (const k of classes) {\n Object.assign(k.prototype, {\n /**\n * @this {HTMLElement}\n * @param {AsyncEvent} evt\n * @param {{mode?: 'broadcast' | 'pipeline' | 'delegate'}} [options]\n * @returns {Promise<any>}\n */\n async fireAsync(evt, options) {\n return await AsyncEvents.fireAsync(this, evt, options);\n },\n\n /**\n * @this {HTMLElement}\n * @param {string} type\n * @param {Function} fn\n * @param {AddEventListenerOptions} [options]\n * @returns {EventListener}\n */\n asyncOn(type, fn, options) {\n return AsyncEvents.asyncOn(this, type, fn, options);\n },\n\n /**\n * @this {HTMLElement}\n * @param {string} type\n * @param {EventListener} listener\n * @param {EventListenerOptions} [options]\n * @returns {void}\n */\n asyncOff(type, listener, options) {\n AsyncEvents.asyncOff(this, type, listener, options);\n },\n });\n }\n }\n}\n\nexport { AsyncEvents };\n","/**\n * @typedef {{ readonly stale: boolean }} Claim\n */\n/**\n * The generations of claims over one contended resource. Every take() starts a\n * new generation, superseding every claim before it, and a holder asks its\n * claim `stale` before painting chrome, storing state or throwing towards a\n * caller: a superseded outcome owns nothing. hold() joins the current\n * generation without superseding it (a fetch that any later reconfiguration\n * must detach), and invalidate() supersedes without claiming (a hide ending\n * every pending show). One Claims per contended resource: a component whose\n * dropdown, value labels and loader configuration contend separately holds one\n * each.\n */\nclass Claims {\n #generation = 0;\n /**\n * Starts a new generation, superseding every earlier claim, and holds it.\n * @returns {Claim}\n */\n take() {\n ++this.#generation;\n return this.hold();\n }\n /**\n * Holds the current generation without superseding anything.\n * @returns {Claim}\n */\n hold() {\n const held = this.#generation;\n const claims = this;\n return {\n /** true once a later take() or invalidate() superseded this claim */\n get stale() {\n return held !== claims.#generation;\n },\n };\n }\n /** Supersedes every claim without holding a new one. */\n invalidate() {\n ++this.#generation;\n }\n}\n\nexport { Claims };\n","/**\n * The protocol by which content standing inside a field becomes part of the\n * accessible description of that field's control.\n *\n * A field owns its control's `aria-describedby`: it is the only thing that\n * knows which element the description belongs on, and it already writes the\n * entry for its own error region. Content the author slotted into the field\n * cannot write that attribute itself without becoming a second owner of it, and\n * it cannot be wired by the field either, because a slotted custom element\n * renders after the field has mounted and has nothing to point at when the\n * field looks.\n *\n * So the content asks, once it has something to offer. `describable(el)`\n * answers the nearest ancestor that accepts a description, and the caller hands\n * its element to that ancestor's `describedBy`, which answers whether it was\n * taken. Nothing here names a field or a tooltip: the relation is expressed as\n * a capability, so the two ends need not import each other, which matters\n * because the library's own arrow runs from the forms to the disclosures.\n *\n * The lookup lives here rather than at its one call site so the protocol has a\n * name, a place to be documented and a single definition to change.\n */\n\n/**\n * @typedef {{ describedBy(el: HTMLElement): boolean }} Describable\n */\n\n/**\n * The nearest ancestor of `el` that accepts elements into the description of\n * whatever it considers its control, or null when nothing in the ancestry does.\n * @param {Element} el\n * @returns {(Element & Describable) | null}\n */\nconst describable = (el) => {\n for (let at = el.parentElement; at; at = at.parentElement) {\n if (typeof (/** @type {any} */ (at).describedBy) === 'function') {\n return /** @type {any} */ (at);\n }\n }\n return null;\n};\n\nexport { describable };\n","/**\n * Sleeping, debouncing and throttling. Debounce and throttle both return the\n * wrapped function together with a cancel function.\n */\nclass Timing {\n /** Resolves after the given milliseconds. @param {number} ms */\n static sleep(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n /**\n * Executes only after a period of inactivity (pause in events).\n * Respond to the \"end\" of a series of events.\n * @param {number} timeoutMs\n * @param {function} func\n * @param {{ immediate?: boolean }} [options] - immediate fires on the leading edge instead of the trailing one\n * @returns {[function, function]}\n */\n static debounce(timeoutMs, func, options) {\n const immediate = options?.immediate ?? false;\n let tid = /** @type {number | null} */ (null);\n let args = [];\n let previousTimestamp = 0;\n\n const later = () => {\n const elapsed = performance.now() - previousTimestamp;\n if (timeoutMs > elapsed) {\n tid = setTimeout(later, timeoutMs - elapsed);\n return;\n }\n tid = null;\n if (!immediate) {\n func(...args);\n }\n //func may have called debounced again, arming a new timer with new args:\n //clearing them then would drop the call that is now pending\n if (tid === null) {\n args = [];\n }\n };\n\n const debounced = (...called) => {\n args = called;\n previousTimestamp = performance.now();\n if (tid === null) {\n tid = setTimeout(later, timeoutMs);\n if (immediate) {\n func(...args);\n }\n }\n };\n const abort = () => {\n clearTimeout(tid ?? undefined);\n tid = null;\n args = [];\n };\n return [debounced, abort];\n }\n /**\n * Executes at most once per specified time interval, regardless of ongoing events.\n * @param {number} timeoutMs\n * @param {function} func\n * @param {{ leading?: boolean, trailing?: boolean }} [options] - which edges of the interval call, both by default\n * @returns {[function, function]}\n */\n static throttle(timeoutMs, func, options) {\n const leading = options?.leading ?? true;\n const trailing = options?.trailing ?? true;\n let tid = /** @type {number | null} */ (null);\n let args = [];\n let previousTimestamp = 0;\n\n const later = () => {\n previousTimestamp = leading ? performance.now() : 0;\n tid = null;\n func(...args);\n if (tid === null) {\n args = [];\n }\n };\n const throttled = (...called) => {\n const now = performance.now();\n if (!previousTimestamp && !leading) {\n previousTimestamp = now;\n }\n const remaining = previousTimestamp === 0 ? 0 : timeoutMs - (now - previousTimestamp);\n args = called;\n if (remaining <= 0 || remaining > timeoutMs) {\n if (tid !== null) {\n clearTimeout(tid);\n tid = null;\n }\n previousTimestamp = now;\n func(...args);\n if (tid === null) {\n args = [];\n }\n } else if (tid === null && trailing) {\n tid = setTimeout(later, remaining);\n }\n };\n const abort = () => {\n clearTimeout(tid ?? undefined);\n tid = null;\n args = [];\n };\n return [throttled, abort];\n }\n}\n\nexport { Timing };\n","/** Field wiring: extracting and filling values, pinning problems to the fields they name. */\nclass Bindings {\n /**\n * Flattens a nested object into dotted keys, stopping wherever `stops` names\n * a key: a field named `address` takes the whole object, while one named\n * `address.city` takes the leaf.\n * @param {{ [x: string]: any; }} obj\n * @param {string} prefix\n * @param {Set<String>} stops - the names the form actually has fields for\n * @return {{ [x: string]: any; }}\n */\n static flatten(obj, prefix, stops) {\n return Object.keys(obj).reduce((acc, k) => {\n const pre = prefix.length ? `${prefix}.${k}` : k;\n if (!stops.has(pre) && typeof obj[k] === 'object' && obj[k] !== null) {\n Object.assign(acc, Bindings.flatten(obj[k], pre, stops));\n } else {\n acc[pre] = obj[k];\n }\n return acc;\n }, {});\n }\n\n /**\n * Walking a dotted name would otherwise descend into `Object.prototype`:\n * `__proto__` passes the `typeof === 'object'` test below and becomes the\n * walk's target, so `providePath({}, '__proto__.x', v)` would write on every\n * object in the page. A field name reaching here is author markup, but it can\n * be bound from data through `data-tpl-name` and `providePath` is public, so\n * the segments that can reach the prototype chain are refused outright rather\n * than left to the caller to prove unreachable.\n */\n static #FORBIDDEN = new Set(['__proto__', 'prototype', 'constructor']);\n /**\n * Writes a value into an object at a dotted path, creating the intermediate\n * objects and arrays the path implies. A numeric segment makes an array.\n * @param {any} result\n * @param {string} path - a field name, `a.b` or `a[0].b`\n * @param {any} value\n */\n static providePath(result, path, value) {\n const keys = path.split('.').map((k) => (/^[0-9]+$/.test(k) ? +k : k));\n for (const key of keys) {\n if (Bindings.#FORBIDDEN.has(/** @type any */ (key))) {\n throw new Error(`unsupported name segment '${key}' in '${path}'`);\n }\n }\n let current = result ?? {};\n let previous = /** @type {any} */ (null);\n for (let i = 0; ; ++i) {\n const ckey = keys[i];\n const pkey = keys[i - 1];\n if (Number.isInteger(ckey) && !Array.isArray(current)) {\n if (previous !== null) {\n previous[pkey] = current = [];\n } else {\n result = current = [];\n }\n }\n if (i === keys.length - 1) {\n //an undefined value declares the path without filling it: an entry\n //already there is left alone, a missing one is created null\n current[ckey] = value !== undefined ? value : ckey in current ? current[ckey] : null;\n return result;\n }\n //an overlapping name (a before a.b) leaves a scalar or a null here:\n //the later, more specific name rebuilds the container, exactly as the\n //reverse order always replaced the container with the scalar\n if (typeof current[ckey] !== 'object' || current[ckey] === null) {\n current[ckey] = {};\n }\n previous = current;\n current = current[ckey];\n }\n }\n /**\n * Reads one control's value the way its kind demands: an unchecked radio\n * answers undefined so it contributes nothing, a checkbox answers its\n * checked state, a multiple select answers its selected values, and a blank\n * native control answers null rather than an empty string.\n * @param {Element & {dataset?: any} & {checked?: boolean} & {value?: any}} el\n * @returns {any} the value, or undefined where the control contributes none\n */\n static extract(el) {\n if (el.getAttribute('type') === 'radio') {\n if (!el.checked) {\n return undefined;\n }\n return el.dataset.fulBindType === 'boolean' ? el.value === 'true' : el.value;\n }\n if (el.getAttribute('type') === 'checkbox') {\n return el.checked;\n }\n if (el.dataset.fulBindType === 'boolean') {\n return !el.value ? null : el.value === 'true';\n }\n if (el.tagName === 'SELECT' && /** @type {HTMLSelectElement} */ (el).multiple) {\n return Array.from(/** @type {HTMLSelectElement} */ (el).selectedOptions).map((o) => o.value);\n }\n if (el.tagName === 'INPUT' || el.tagName === 'SELECT' || el.tagName === 'TEXTAREA') {\n return el.value === '' || el.value === undefined ? null : el.value;\n }\n return el.value;\n }\n\n /**\n * Reads every named, enabled control of a form into a nested object, the\n * dotted field names deciding its shape.\n * @param {HTMLFormElement} form\n * @param {HTMLElement} [submitter]\n * @returns\n */\n /**\n * Whether a control is one of a form's buttons, whose name travels only when it\n * is the one that submitted.\n * @param {Element & {type?: string}} el\n */\n static #submits(el) {\n return el.type === 'submit' || el.type === 'reset' || el.type === 'button';\n }\n static extractFrom(form, submitter) {\n let result = {};\n for (const el of form.elements) {\n if (!el.hasAttribute('name')) {\n continue;\n }\n //a form submits the name of the button that submitted it and of no other,\n //which is the platform's own rule. It used to fall out of the spinner\n //having disabled every button by the time the values were read, so the\n //affordance was quietly load-bearing for the payload\n if (Bindings.#submits(el) && el !== submitter) {\n continue;\n }\n //the submitter is exempt from the disabled check: a form holds its buttons\n //off while submitting, and its own submitter still names a value\n if (el.matches(':disabled') && el !== submitter) {\n continue;\n }\n result = Bindings.providePath(\n result,\n /** @type {string} */ (el.getAttribute('name')),\n Bindings.extract(el),\n );\n }\n return result;\n }\n\n /**\n * Writes a value into one control, the inverse of `extract`: a radio is\n * checked when its own value matches, a checkbox takes the value as its\n * checked state, and a multiple select selects the options the list names.\n * @param {Element & {dataset?: any} & {checked?: boolean} & {value?: any}} el\n * @param {any} raw the value as it arrived, coerced per control kind\n */\n static mutate(el, raw) {\n if (el.getAttribute('type') === 'radio') {\n //values are matched as strings, as ful-radio-group does: extract decodes\n //boolean radios, and payloads carry numbers where the attribute is text\n el.checked = raw != null && el.getAttribute('value') === String(raw);\n return;\n }\n if (el.getAttribute('type') === 'checkbox') {\n el.checked = raw;\n return;\n }\n if (el.tagName === 'SELECT' && /** @type {HTMLSelectElement} */ (el).multiple) {\n const values = Array.isArray(raw) ? raw.map(String) : raw == null ? [] : [String(raw)];\n Array.from(/** @type {HTMLSelectElement} */ (el).options).forEach((o) => {\n o.selected = values.includes(o.value);\n });\n return;\n }\n el.value = raw;\n }\n\n static mutateIn(form, values) {\n const names = Array.from(form.elements)\n .map((el) => el.getAttribute('name'))\n .filter((n) => n);\n for (const [flattenedKey, value] of Object.entries(Bindings.flatten(values, '', new Set(names)))) {\n for (const el of form.querySelectorAll(`[name='${CSS.escape(flattenedKey)}']`)) {\n Bindings.mutate(el, value);\n }\n }\n }\n\n static errors(form, es, scrollOnError) {\n //focus management announces the error of the field it lands on through\n //aria-describedby: a live region on top of that would read everything twice,\n //so the polite announcement exists only when nothing takes the focus\n form.querySelectorAll('ful-field-error').forEach((el) => {\n el.setAttribute('aria-live', scrollOnError ? 'off' : 'polite');\n });\n const pinned = (e) => (e.type === 'FIELD_ERROR' || e.type === 'INVALID_FORMAT') && e.context;\n const fieldErrors = es.filter(pinned);\n const globalErrors = es.filter((e) => !pinned(e));\n form.querySelectorAll(`[name]`).forEach((el) => {\n el.setCustomValidity?.('');\n });\n form.querySelectorAll('ful-errors').forEach((el) => {\n el.setAttribute('role', 'alert');\n el.replaceChildren();\n el.setAttribute('hidden', '');\n });\n const unmatched = [];\n fieldErrors.forEach((e) => {\n const name = e.context.replace(/\\[/g, '.').replace(/\\]\\./g, '.').replace(/\\]/g, '');\n const parts = name.split('.');\n for (let i = parts.length; i !== 0; --i) {\n const prefix = parts.slice(0, i).join('.');\n const targets = form.querySelectorAll(`[name='${CSS.escape(prefix)}']`);\n if (targets.length === 0) {\n continue;\n }\n //the most specific name wins: the walk exists so a composite field\n //owning a whole subtree catches its inner contexts, not so an outer\n //field doubles a problem an exact one already shows. The remaining\n //path rides along ('' on an exact match), so a composite can route\n //the problem to the inner control it names\n const context = parts.slice(i).join('.');\n targets.forEach((input) => {\n input.setCustomValidity?.(e.reason, context);\n });\n return;\n }\n //a context naming no field must not vanish: it reads in the banner\n unmatched.push(e);\n });\n const bannered = [...globalErrors, ...unmatched];\n form.querySelectorAll('ful-errors').forEach((el) => {\n const hel = /** @type HTMLElement} */ (el);\n if (bannered.length === 0) {\n hel.innerText = '';\n return;\n }\n //revealed before it is filled: a live region mutated while hidden and\n //shown afterwards is announced unreliably, the change having happened\n //where nothing was watching\n el.removeAttribute('hidden');\n hel.innerText = bannered.map((e) => e.reason).join('\\n');\n });\n if (es.length === 0 || !scrollOnError) {\n return;\n }\n Array.from(form.querySelectorAll(`:invalid`))\n .sort((a, b) => a.getBoundingClientRect().y - b.getBoundingClientRect().y)[0]\n ?.focus();\n }\n}\n\nexport { Bindings };\n","import { Attributes, ParsedElement } from '../../ftl/index.mjs';\n\n/**\n * The base of every form-associated ful field: a form-associated custom element\n * carrying the validity protocol, the field error live region, focus\n * delegation, the label chrome and the disabled, readonly and required claims.\n *\n * A subclass owns its template, its value semantics and its change events. It\n * implements `_build(conf)`, which builds its dom and returns the pieces the\n * base drives: the control, the error region, the label, and the optional\n * `claims`, `announces`, `freeze` and `also`. The base does the wiring,\n * the mounting and the application of the declared state. Nothing in the base\n * is there to be called from a subclass's build.\n *\n * The pieces are the contract: the claim setters, the validity protocol and\n * the aria wiring all act on them, so a field with no native control returns a\n * focusable piece of its own chrome as the control. The getters and `focus()`\n * are the only members that tolerate a not-yet-rendered element, where page\n * code may read a claim or ask for the focus before the upgrade; the\n * properties go live only after the render, as ParsedElement documents. The\n * base references no ful vocabulary, only what its subclasses return to it.\n */\nclass Field extends ParsedElement {\n static formAssociated = true;\n /**\n * The claim attributes and the value are observed here so every field,\n * including the custom ones, keeps them live after the upgrade: the\n * attribute is a third way to author a claim, beside the markup and the\n * property,\n * exactly as a native input's. The value defaults to the string mapper and\n * every field with its own vocabulary overrides it (`value:bool`,\n * `value:csv`, `value:json`).\n */\n static observed = ['disabled:presence', 'readonly:presence', 'required:presence', 'value'];\n /** the role the element internals carry, 'presentation' unless the control is its own */\n static ROLE = 'presentation';\n #control;\n #described;\n #descriptions = [];\n #errorId = null;\n #fieldError;\n #claims;\n #announces;\n #also = [];\n constructor() {\n super();\n //the base attached the internals: the platform allows one call per element\n this.internals.role = /** @type {typeof Field} */ (this.constructor).ROLE;\n }\n /** every element the claims mirror onto: the claim target, then the extra controls */\n #mirrors() {\n return [this.#claims ?? this.#control, ...this.#also].filter((el) => el);\n }\n /**\n * Takes what the build produced: keeps the pieces the base drives, wires the\n * aria and the label, and mounts the fragment.\n * @param {{fragment: any, control: any, error?: any, label?: any, described?: any,\n * claims?: any, announces?: any, freeze?: any, also?: any[]}} pieces\n */\n #wire({\n fragment,\n control,\n error,\n label = null,\n described = null,\n claims = null,\n announces = control,\n freeze = null,\n also = [],\n }) {\n this.#control = control;\n this.#fieldError = error;\n this.#claims = claims;\n this.#announces = announces;\n this.#also = also;\n if (freeze) {\n //a field with no usable native readOnly freezes by refusing the\n //gesture, not by inerting its subtree: inert takes the whole thing out\n //of the accessibility tree, so a readonly checkbox, radio group, filter\n //or file list was on screen and unreadable. Capturing, so it lands\n //before the control's own handlers and the platform's activation\n freeze.addEventListener(\n 'click',\n (evt) => {\n if (this.readonly) {\n evt.preventDefault();\n }\n },\n true,\n );\n }\n //the description lands on the control, or on the host where there is no\n //single control to describe (a radio group's legend names its fieldset)\n this.#described = described ?? control;\n if (error) {\n //named for what it is, the generic id being for whoever brings no name\n error.id = error.id || Attributes.uid('ful-field-error');\n this.#errorId = error.id;\n }\n //anything handed over before the field had a target lands here\n this.#describe();\n if (label) {\n Field.#name(this, label, control);\n }\n //the platform's implicit submission, stood in for where the field's own\n //protocol took it away: the inner controls carry form=\"\", so Enter in one\n //of them reaches no form and the platform submits nothing. Listening on the\n //host rather than the control means every listener the control has already\n //ran, so preventDefault is what it says: a ful-select accepting the\n //highlighted entry has consumed the key and no submit follows\n this.addEventListener('keydown', (evt) => {\n if (evt.key !== 'Enter' || evt.defaultPrevented || evt.isComposing) {\n return;\n }\n const target = /** @type {HTMLInputElement} */ (evt.target);\n //only where the platform cannot: a control still associated with the\n //form, an author's own input in a slot among them, submits on its own\n //and would otherwise submit twice\n if (target.form === this.internals.form || !Field.#submitsOnEnter(target)) {\n return;\n }\n this._requestSubmit();\n });\n this.replaceChildren(fragment);\n }\n /**\n * The platform's own rule for which control Enter submits from, measured on\n * Chromium, Firefox and WebKit: every input but the file picker and the\n * button-shaped ones, the checkbox and the radio included. A textarea takes\n * the newline, a select takes the key for its own list, and a button is\n * activated by it.\n */\n static #submitsOnEnter(el) {\n return el instanceof HTMLInputElement && !['file', 'button', 'submit', 'reset', 'image'].includes(el.type);\n }\n /**\n * Adds an element to the accessible description of the field's control and\n * answers whether the field took it.\n *\n * A field takes one whenever it is offered, before its own render as\n * readily as after: content slotted into a field is a custom element of its\n * own and may upgrade on either side of the field it stands in, which\n * happens in both directions in practice, a tooltip beating an async select\n * to its render while losing to a plain input. A description handed over\n * early waits here and is written the moment the field has somewhere to\n * write it, so the caller never has to know the order.\n *\n * The reference lands on the element handed over rather than on a wrapper\n * around it: a hidden element is included in a description only where it is\n * named directly, and content that reaches the description through a\n * wrapper is skipped while it is hidden. A popover closed until someone\n * opens it is exactly that, so the caller passes the popover itself.\n *\n * An attribute rather than `ariaDescribedByElements`: the property reflects\n * to nothing, so the description would live in the accessibility tree alone\n * and vanish entirely on a browser without aria element reflection.\n *\n * This is the field's half of the description protocol; `describable` in\n * `ful/descriptions.mjs` is the half the content uses to find the field.\n * @param {HTMLElement} el\n * @returns {boolean}\n */\n describedBy(el) {\n if (!el) {\n return false;\n }\n if (!el.id) {\n el.id = Attributes.uid('ful-described');\n }\n if (!this.#descriptions.includes(el.id)) {\n this.#descriptions.push(el.id);\n }\n this.#describe();\n return true;\n }\n /**\n * Writes the description the field has collected, the error region last:\n * the standing explanations are what the field always says, the problem is\n * the news. The field owns the attribute outright rather than appending to\n * whatever is there, so the order does not depend on who arrived when.\n */\n #describe() {\n if (!this.#described) {\n return;\n }\n const ids = [...this.#descriptions, this.#errorId].filter((id) => id);\n if (ids.length) {\n this.#described.setAttribute('aria-describedby', ids.join(' '));\n }\n }\n focus(options) {\n this.#control?.focus(options);\n }\n /**\n * Clears or reports one validation problem: the text lands on the field's\n * live region and the state on the element internals, driving `:invalid`\n * styling. Validation is the server's: the submit travels regardless, and\n * the problems come back pinned here. The error mapping pins on the most\n * specific field name a problem's context reaches, handing over the\n * remaining path ('' on an exact match): the base ignores it, a composite\n * field owning a whole subtree overrides to route the problem to the inner\n * control it names.\n * @param {string} [error]\n * @param {string} [context] the path below this field's name, '' when exact\n */\n setCustomValidity(error, context) {\n //the state rides the control the reader focuses, not only the element\n //internals: the host's role is presentation for most fields, so a\n //validity set there announces nothing where the caret actually is\n Attributes.set(this.#announces ?? this.#control, 'aria-invalid', error ? 'true' : null);\n if (!error) {\n this.internals.setValidity({});\n this.#fieldError.innerText = '';\n return;\n }\n this.internals.setValidity({ customError: true }, ' ');\n this.#fieldError.innerText = error;\n }\n /** Submits the associated form through its first submitter, as Enter on a native control would. */\n _requestSubmit() {\n const form = this.internals.form;\n if (!form) {\n return;\n }\n const candidates = /** @type {NodeListOf<HTMLButtonElement|HTMLInputElement>} */ (\n form.querySelectorAll('button:not(:disabled), input:not(:disabled)')\n );\n form.requestSubmit([...candidates].find((el) => el.type === 'submit' && el.form === form));\n }\n /**\n * Dispatches the field's change event: bubbling, not cancelable, the value\n * in the detail. Every field announces through this one method, and the detail\n * always carries the field's own `value`, so a listener can rely on\n * `el.value === evt.detail.value` whatever the field is. A field with more to\n * say adds keys beside it; none can replace it.\n * @param {Record<string, any>} [extras]\n */\n _notifyChange(extras = {}) {\n this.dispatchEvent(\n new CustomEvent('change', {\n bubbles: true,\n cancelable: false,\n detail: { value: this.value, ...extras },\n }),\n );\n }\n /** The html elements a label's `for` may point at, `input[type=hidden]` excepted. */\n static #LABELABLE = new Set(['BUTTON', 'INPUT', 'METER', 'OUTPUT', 'PROGRESS', 'SELECT', 'TEXTAREA']);\n /**\n * Names the control from the field's label, natively wherever the platform\n * allows it.\n *\n * `for` and `id` are the form the dom itself carries, so the association is\n * there for anything reading the markup rather than the accessibility tree:\n * an audit tool, the browser's autofill, a translation pass. It also makes\n * the label's click reach the control the way it does in a plain form, which\n * is focus for a text control and activation for a checkbox, so the field\n * needs no handler of its own.\n *\n * A control the platform will not let a label target, a composite carrying\n * `role=\"radiogroup\"` among them, takes `aria-labelledby` instead. That is an\n * attribute too, so the association is equally visible; what it does not carry\n * is the label's click, which is why the handler stays on that path only.\n *\n * Neither branch uses `ariaLabelledByElements`. The property reflects to no\n * attribute, so the name lived in the accessibility tree alone: nothing reading\n * the dom saw it, and on a browser without aria element reflection the\n * assignment is a silent expando and the field has no name at all.\n * @param {any} field\n * @param {HTMLElement} label\n * @param {any} control\n */\n static #name(field, label, control) {\n const labelable =\n Field.#LABELABLE.has(control.tagName) && control.getAttribute('type') !== 'hidden';\n if (!labelable) {\n if (!label.id) {\n label.id = Attributes.uid('ful-label');\n }\n control.setAttribute('aria-labelledby', label.id);\n //aria-labelledby carries the name but not the label's click\n label.addEventListener('click', () => field.focus());\n return;\n }\n if (!control.id) {\n control.id = Attributes.uid('ful-control');\n }\n label.setAttribute('for', control.id);\n }\n /**\n * Whether the field's chrome should answer a gesture. Badges, dropzones,\n * menus and labels are not form controls, so their handlers must ask the\n * effective state: matches(':disabled') covers the fieldset ancestry the\n * disabled property deliberately does not reflect, readonly the field's\n * own claim.\n */\n _interactive() {\n return !this.matches(':disabled') && !this.readonly;\n }\n /**\n * The field's value: every concrete field owns its semantics and overrides\n * this pair. The base pair exists so the form integration (the reset\n * protocol among others) has a member to write through; a custom field\n * forgetting its own keeps the base's inert one.\n * @type {any}\n */\n get value() {\n return undefined;\n }\n set value(v) {}\n /**\n * A reset restores the field's declared value, as a native control's reset\n * restores its markup default: the `value` attribute goes back through the\n * element's own mapper and value setter, so every field resets through its\n * own semantics. A field whose value is not attribute backed overrides this.\n */\n formResetCallback() {\n this.value = this.unmarshal('value', this.getAttribute('value'));\n }\n /**\n * The disabled protocol follows the semantics of a native form control:\n *\n * - the `disabled` attribute on the host is the field's own claim, and nothing\n * but its author ever writes or removes it, in markup or through the\n * property. The framework never claims on the form's behalf, so there is\n * nothing to unclaim and nothing to lose: a field declared disabled inside\n * a disabled `<fieldset>` stays disabled when the fieldset comes back,\n * exactly like a native input keeps its attribute.\n * - the effective state is the claim OR a disabled fieldset ancestry, which\n * the platform maintains on its own: `:disabled` matches both, a disabled\n * field is left out of the submitted values, and the inner native controls\n * are reached by the ancestry as descendants of the fieldset.\n * - the property reflects the claim only, like a native input's: a field\n * disabled by its ancestry reads `false` while `matches(':disabled')`\n * tells the effective state. Un-claiming inside a disabled fieldset\n * cannot enable the field.\n * - the inner controls mirror the claim and nothing else: the ancestry state\n * is never written anywhere, so it can never go stale, and the browser\n * composes the two on its own when it disables and re-enables a fieldset's\n * descendants. Subclass setters call super for the claim, then reach their\n * own controls, which mirror the claim like a native input's would.\n *\n * Because of this, formDisabledCallback carries nothing the framework needs\n * to apply, and the protocol does not define it.\n */\n get disabled() {\n //the claim only, like a native input: the effective state, claim or disabled\n //ancestry, is what :disabled matches\n return this.hasAttribute('disabled');\n }\n set disabled(d) {\n //the claim belongs to the author alone, nothing else ever writes it\n this.reflectTo('disabled', d);\n //the adopted pieces mirror the claim as a native input would: a disabled\n //fieldset ancestry is left to the browser, which reaches them as\n //descendants of the fieldset and re-enables them on its own\n for (const el of this.#mirrors()) {\n el.toggleAttribute('disabled', d);\n }\n }\n /**\n * A field is readonly through its control's native readOnly when it has one:\n * the control stays focusable and its text selectable, only editing is off.\n * Fields whose chrome must freeze too (popovers, buttons, label clicks) name\n * a `freeze` piece instead, whose gestures the base refuses while the claim\n * holds; the claim reflects on the host either way.\n */\n get readonly() {\n //the host attribute is the claim, as it is for disabled: every setter\n //reflects it, so one read answers however the field freezes\n return this.hasAttribute('readonly');\n }\n set readonly(v) {\n for (const el of this.#mirrors()) {\n el.readOnly = v;\n }\n //announced on the element whose role accepts it, not on whatever the\n //claims happen to ride: aria-readonly on a fieldset is dropped as invalid\n if (this.#announces) {\n Attributes.set(this.#announces, 'aria-readonly', v ? 'true' : null);\n }\n this.reflectTo('readonly', v);\n }\n /**\n * A field is required through aria: the claim reflects on the host, the\n * announcement lives on the adopted control.\n */\n get required() {\n //the claim, like disabled and readonly: the host attribute rather than\n //the projection, which a field with no role to announce on never carries\n return this.hasAttribute('required');\n }\n set required(d) {\n if (this.#announces) {\n Attributes.set(this.#announces, 'aria-required', d ? 'true' : null);\n }\n this.reflectTo('required', d);\n }\n /**\n * The field's render is the base's: the subclass builds its dom in `_build`\n * and hands back what it built, the base wiring the pieces, mounting the\n * fragment and applying the declared state. Nothing in the base is there to\n * be called from a subclass's build. `_build` may be async (a select\n * awaiting its prefetch); a field that builds synchronously stays so.\n */\n render(conf) {\n const built = /** @type {any} */ (this._build(conf));\n if (built instanceof Promise) {\n return built.then((pieces) => this.#settle(pieces));\n }\n this.#settle(built);\n return undefined;\n }\n #settle(pieces) {\n this.#wire(pieces);\n }\n /**\n * Builds the field's dom and answers the pieces the base drives. The one\n * method a concrete field implements beside its value pair, and the only\n * place its dom is created; the base does the wiring and the mounting.\n *\n * - `fragment` is mounted on the host\n * - `control` is the focusable target: focus, the aria and, by default, all\n * three claims reach it\n * - `error` is the field's live region\n * - `label`, when given, names the control and focuses it on click\n * - `described` moves the description off the control and onto another\n * element, the host where no single control can carry it: the error\n * region and anything `describedBy` is later handed both land there\n * - `claims` moves the three claims onto a wrapper the field disables as a\n * whole, leaving focus and aria on the control\n * - `announces` is the element whose role carries `aria-readonly` and\n * `aria-required`, the host where the widget role lives there; `null` for a\n * field whose control has no role that accepts them\n * - `freeze` is for a field with no usable native readOnly: the readonly\n * claim refuses the gestures inside it, leaving it focusable and readable\n * - `also` are further controls mirroring disabled and readOnly beside the\n * first\n *\n * A subclass extending another field's build spreads the pieces it answered\n * and overrides the keys it owns.\n * @param {{slots: any}} conf\n * @returns {any}\n */\n _build(conf) {\n throw new Error(`${this.constructor.name} must implement _build`);\n }\n}\n\nexport { Field };\n","import { Attributes, Localization, ParsedElement } from '../../ftl/index.mjs';\nimport { Failure } from '../../httpc/index.mjs';\nimport { Bindings } from './bindings.mjs';\nimport { AsyncEvents } from '../events/async.mjs';\n\n/** Submits a form's values as json to a url, mapping the request and the response through the configured mappers. */\nclass RemoteJsonFormLoader {\n #http;\n #url;\n #method;\n #requestMapper;\n #responseMapper;\n constructor(http, url, method, requestMapper, responseMapper) {\n this.#http = http;\n this.#url = url;\n this.#method = method;\n this.#requestMapper = requestMapper;\n this.#responseMapper = responseMapper;\n }\n prepare(values, form) {\n return this.#requestMapper(values, form);\n }\n async submit(request, form) {\n return await this.#http.request(this.#method, this.#url).json(request).fetch();\n }\n transform(response, form) {\n return this.#responseMapper(response, form);\n }\n}\n\n/** Submits a form without a request: the request mapper produces the result the response mapper then reads, for a form handled entirely on the page. */\nclass LocalFormLoader {\n #requestMapper;\n #responseMapper;\n constructor(requestMapper, responseMapper) {\n this.#requestMapper = requestMapper;\n this.#responseMapper = responseMapper;\n }\n async prepare(values, form) {\n return await this.#requestMapper(values, form);\n }\n async submit(request, form, response) {\n //nothing to send: whatever a submit:requested listener answered is the response\n return response;\n }\n async transform(response, form) {\n return await this.#responseMapper(response, form);\n }\n}\n\n/**\n * Builds the form's loader from its attributes: a local one when no action is\n * declared, a json post to it otherwise.\n *\n * A component registered under the `loader` attribute replaces this one and\n * must implement three methods, called in this order:\n *\n * - `prepare(values, form)` turns the extracted values into the request to send\n * - `submit(request, form, response)` performs it and returns the response. The\n * third argument is whatever a `submit:requested` listener already answered,\n * which is how a loader with nothing to send returns it unchanged\n * - `transform(response, form)` turns that response into the detail of the\n * `submit:success` event\n *\n * A rejection from any of the three is reported as a `submit:failure`.\n */\nclass FormLoader {\n static create(el, conf) {\n const http = el.component('http-client');\n const requestMapper = el.declared('request-mapper') ? el.component(el.declared('request-mapper')) : (v) => v;\n const responseMapper = el.declared('response-mapper') ? el.component(el.declared('response-mapper')) : (v) => v;\n const url = el.declared('action');\n if (!url) {\n return new LocalFormLoader(requestMapper, responseMapper);\n }\n const method = el.declared('method') ?? 'POST';\n return new RemoteJsonFormLoader(http, url, method, requestMapper, responseMapper);\n }\n}\n\n/**\n * Wraps its fields in a native form, extracts their values on submit and hands\n * them to a loader (loaders:form, or the action url as a json post),\n * announcing failures through the errors setter.\n */\nclass Form extends ParsedElement {\n //every one of these says how the form is built and submits, not what it holds:\n //the loader is named the same way ful-select and ful-table name theirs\n static attributes = [\n 'action',\n 'method',\n 'loader',\n 'request-mapper',\n 'response-mapper',\n 'clear-invalid-on-change:presence',\n 'scroll-on-error:presence',\n 'autocomplete',\n ];\n form;\n render() {\n const form = document.createElement('form');\n this.form = form;\n //the submit must travel regardless of validity: the server is the validation\n //authority, and the browser's own gate would block a resubmit behind\n //internals messages custom elements have no default UI for\n form.setAttribute('novalidate', '');\n Attributes.forward('form-', this, form);\n //the fields read it off whichever of the two they reach first, which depends\n //on whether they upgraded before or after this render: they cannot read it\n //off their own control, which carries form=\"\" and so has no form owner\n Attributes.set(form, 'autocomplete', this.declared('autocomplete'));\n form.replaceChildren(...this.childNodes);\n form.addEventListener('submit', async (e) => {\n e.preventDefault();\n e.stopPropagation();\n await this.submit(e.submitter ?? undefined);\n });\n //an aria-disabled control keeps its focus and its name, so the platform still\n //activates it: the refusal has to be ours, and capturing puts it ahead of\n //every listener the author registered on the button itself\n this.addEventListener(\n 'click',\n (evt) => {\n const target = /** @type Element */ (evt.target);\n if (!target.closest?.('[aria-disabled=\"true\"]')) {\n return;\n }\n evt.preventDefault();\n evt.stopImmediatePropagation();\n },\n true,\n );\n if (this.declared('clear-invalid-on-change')) {\n this.addEventListener('change', (/** @type any */ evt) => {\n evt.target.setCustomValidity?.('');\n });\n }\n this.replaceChildren(form);\n }\n #submitting = false;\n /**\n * Submits once: a submit while one is in flight is dropped before the\n * values are even extracted, so nothing fires and nothing travels; the\n * settled exchange re-arms the form. A write must not double behind a\n * second Enter or a programmatic call racing the first.\n * @param {HTMLElement} [submitter]\n * @returns\n */\n async submit(submitter) {\n if (this.#submitting) {\n return;\n }\n this.#submitting = true;\n this.spinner(true);\n //one try: building the loader and preparing the request are as much part of a\n //submit as sending it, and a mapper that throws is how a caller reports a\n //problem with the values\n let values;\n let request;\n try {\n const loader = this.component(this.declared('loader') ?? 'loaders:form').create(this);\n values = Bindings.extractFrom(this.form, submitter);\n request = await loader.prepare(values, this);\n const se = new CustomEvent('submit', {\n bubbles: true,\n cancelable: true,\n detail: { submitter, values, request },\n });\n if (!this.dispatchEvent(se)) {\n return;\n }\n this.errors = [];\n const sre = new CustomEvent('submit:requested', {\n bubbles: true,\n cancelable: false,\n detail: { submitter, values: se.detail.values, request: se.detail.request },\n });\n let response = await AsyncEvents.fireAsync(this, sre, { mode: 'pipeline' });\n request = sre.detail.request;\n\n response = await loader.submit(request, this, response);\n const mapped = await loader.transform(response, this);\n this.dispatchEvent(\n new CustomEvent('submit:success', {\n bubbles: true,\n cancelable: false,\n detail: { submitter, values, request, response: mapped },\n }),\n );\n } catch (e) {\n this.dispatchEvent(\n new CustomEvent('submit:failure', {\n bubbles: true,\n cancelable: false,\n detail: { submitter, values, request, exception: e },\n }),\n );\n if (e instanceof Failure) {\n this.errors = e.problems;\n }\n console.warn('failed to submit form', this, 'reason:', e);\n } finally {\n this.#submitting = false;\n this.spinner(false);\n }\n }\n /** The native reset, routing every field through its own value semantics. */\n reset() {\n this.form.reset();\n }\n #spinning = 0;\n /**\n * Reveals a spinner and gives it something to read. A spinner is a style-only\n * tag: the glyph is its own pseudo-element and the text is the author's, so one\n * carrying no text is a live region with nothing to announce. The label is\n * appended only where the author wrote none, and it is filled after the reveal,\n * a region mutated while hidden being announced unreliably.\n * @param {HTMLElement} el\n */\n #announce(el) {\n Attributes.defaultValue(el, 'role', 'status');\n el.hidden = false;\n if (el.textContent.trim() !== '') {\n return;\n }\n const label = document.createElement('span');\n label.className = 'ful-sr-only';\n label.dataset.ref = 'spinner-label';\n el.append(label);\n label.textContent = Localization.of().t('spinner.loading');\n }\n /** Shows the spinners and holds the submit buttons off, overlapping spins sharing one claim. */\n spinner(spin) {\n //spins can overlap (a caller's own spin may wrap a submit): only the\n //outermost one saves and restores the button states\n if (spin) {\n ++this.#spinning;\n if (this.#spinning !== 1) {\n return;\n }\n } else {\n this.#spinning = Math.max(0, this.#spinning - 1);\n if (this.#spinning !== 0) {\n return;\n }\n }\n //the form is the busy region: the table and the async sections say so the\n //same way, and a form that only dimmed its button said it to no one\n Attributes.set(this, 'aria-busy', spin ? 'true' : null);\n this.querySelectorAll('ful-spinner').forEach((el) => {\n const hel = /** @type HTMLElement */ (el);\n if (spin) {\n this.#announce(hel);\n return;\n }\n hel.hidden = true;\n hel.querySelector(':scope > [data-ref=spinner-label]')?.remove();\n });\n this.querySelectorAll('input,button').forEach((el) => {\n const hel = /** @type HTMLButtonElement|HTMLInputElement */ (el);\n if (hel.type !== 'submit' && hel.type !== 'reset') {\n return;\n }\n if (spin) {\n //aria-disabled, not disabled: the submitter is almost always the\n //focused element when a submit starts, and disabling what holds the\n //focus drops it to the body, losing the user's place mid transaction.\n //The refusal is the capturing handler below, and #submitting is the\n //guard that actually makes a second submit a no-op\n hel.dataset.wd = hel.getAttribute('aria-disabled') ?? '';\n hel.setAttribute('aria-disabled', 'true');\n } else {\n //a button that joined mid-spin was never saved: its authored state stands\n if (hel.dataset.wd === undefined) {\n return;\n }\n Attributes.set(hel, 'aria-disabled', hel.dataset.wd || null);\n delete hel.dataset.wd;\n }\n });\n }\n /** The values of the fields the form contains, extracted and filled back through Bindings. */\n set values(vs) {\n Bindings.mutateIn(this.form, vs);\n }\n get values() {\n return Bindings.extractFrom(this.form);\n }\n /** Pins problems to the fields they name, the banner taking the nameless ones. */\n set errors(es) {\n Bindings.errors(this.form, es, this.declared('scroll-on-error'));\n }\n}\n\nexport { FormLoader, Form };\n","import { Attributes, BoundedCache } from '../../ftl/index.mjs';\nimport { Field } from './field.mjs';\n\n//a null entry is a pattern that did not compile: cached like any other so the\n//warning is printed once rather than on every keystroke\nconst patternCache = new BoundedCache(100);\nconst compiled = (attr, pattern) =>\n patternCache.getOrCompute(`${attr}:${pattern}`, () => {\n try {\n return new RegExp(pattern, 'g');\n } catch (/** @type any */ e) {\n console.warn(`invalid ${attr} attribute`, pattern, e);\n return null;\n }\n });\n\n/**\n * The keystroke filter an input declares, as one function of the text.\n *\n * `keep` names the characters that survive and `reject` the ones that do not,\n * which are the same statement from either side: `keep=\"[0-9]\"` and\n * `reject=\"[^0-9]\"` both leave the digits. Keeping is the one worth reaching for,\n * the rejecting spelling of an allowed set being a double negative.\n */\n/**\n * The autofill token a field inherits from the form around it.\n *\n * A control is rendered with `form=\"\"` so that the host is the only thing that\n * submits, which also leaves it without a form owner, and the platform resolves\n * `autocomplete` through the form owner. So a form declaring it reaches nothing\n * on its own and the field reads the setting off the form element instead.\n *\n * The `form` a `ful-form` renders answers here, the host copying its token onto\n * it, and a plain `form` around ful fields answers too: the platform meant the\n * same thing by it, and its inheritance is broken here for the same reason. An\n * ancestor always upgrades before its descendants, so the rendered form is in\n * place by the time a field of its own builds.\n */\nconst inheritedAutocomplete = (el) => el.closest('form')?.getAttribute('autocomplete') ?? null;\n\nconst warnedBoth = new WeakSet();\nconst filterOf = (el) => {\n const keep = el.declared('keep');\n const reject = el.declared('reject');\n if (keep !== null && reject !== null && !warnedBoth.has(el)) {\n //the filter is read per keystroke, so the complaint is held per element\n warnedBoth.add(el);\n console.warn('a ful-input declares both keep and reject: keep is applied, reject is ignored', el);\n }\n if (keep !== null) {\n const re = compiled('keep', keep);\n //every match, concatenated: the attribute is a pattern rather than a\n //character class, so the kept text cannot be found by negating it\n return re && ((v) => (v.match(re) ?? []).join(''));\n }\n if (reject !== null) {\n const re = compiled('reject', reject);\n return re && ((v) => v.replace(re, ''));\n }\n return null;\n};\n\n/** A labelled text input over any native type or textarea; the temporal inputs are its subclasses. */\nclass Input extends Field {\n static observed = ['placeholder'];\n //configuration: the control is built from them and the value getter reads them,\n //but none of them is meant to change once the element is up\n static attributes = [\n 'type',\n 'v-type',\n 'keep',\n 'reject',\n 'uppercase:presence',\n 'trim:presence',\n 'autocomplete',\n ];\n static slots = true;\n static template = `\n <label>{{{{ slots.default }}}}</label>\n {{{{ slots.info }}}}\n <ful-control-group>\n <ful-affix data-tpl-if=\"slots.before\">{{{{ slots.before }}}}</ful-affix>\n <input data-tpl-if=\"type != 'textarea'\" data-tpl-type=\"type\" placeholder=\" \" form=\"\">\n <textarea data-tpl-if=\"type == 'textarea'\" placeholder=\" \" form=\"\"></textarea>\n <ful-affix data-tpl-if=\"slots.after\">{{{{ slots.after }}}}</ful-affix>\n </ful-control-group>\n <ful-field-error></ful-field-error>\n `;\n _input;\n _type() {\n //a numeric value wants the numeric widget (decimal normalization, the\n //right keyboard): v-type=number defaults the type, a declared one wins\n return this.declared('type') ?? (this.declared('v-type') === 'number' ? 'number' : 'text');\n }\n _build({ slots }) {\n const type = this._type();\n const fragment = this.template().withOverlay({ type, slots }).render();\n this._input = fragment.querySelector('input,textarea');\n\n //the browser reads autocomplete off the control it is classifying, so the\n //field's own token, or the form's where it declares none, is put there.\n //Set before the passthrough, which stays the last word\n Attributes.set(\n this._input,\n 'autocomplete',\n this.declared('autocomplete') ?? inheritedAutocomplete(this),\n );\n Attributes.forward('input-', this, this._input);\n this._input.addEventListener('input', (evt) => {\n const strip = filterOf(this);\n if (!strip) {\n return;\n }\n const before = evt.target.value;\n const after = strip(before);\n if (before === after) {\n return;\n }\n const start = evt.target.selectionStart;\n evt.target.value = after;\n if (start === null) {\n //email, number and the date types have no selection to restore\n return;\n }\n //the caret keeps its place among the characters that survived, so only the\n //ones stripped before it count\n const caret = strip(before.slice(0, start)).length;\n evt.target.setSelectionRange(caret, caret);\n });\n this._input.addEventListener('change', (evt) => {\n evt.stopPropagation();\n this._notifyChange();\n });\n return {\n fragment,\n control: this._input,\n error: fragment.querySelector('ful-field-error'),\n label: fragment.querySelector('label'),\n };\n }\n get value() {\n const uppercase = this.declared('uppercase');\n const trim = this.declared('trim');\n const v = this._input.value;\n const uppercased = uppercase ? v.toUpperCase() : v;\n const trimmed = trim ? uppercased.trim() : uppercased;\n if (trimmed === '') {\n return null;\n }\n if (this.declared('v-type') === 'number') {\n //typed values are an explicit opt in, as the select's k-type: blank\n //stays null, and a value that does not decode is kept as it is\n const n = Number(trimmed);\n return Number.isNaN(n) ? trimmed : n;\n }\n return trimmed;\n }\n set value(value) {\n this._input.value = value === '' || value === undefined ? null : value;\n }\n get placeholder() {\n const v = this._input.getAttribute('placeholder');\n return v === ' ' ? null : v;\n }\n set placeholder(d) {\n //without a placeholder :placeholder-shown never matches, and floating labels\n //rely on it, so a blank one stands in for none\n Attributes.set(this._input, 'placeholder', d ?? ' ');\n this.reflectTo('placeholder', d);\n }\n}\n\nexport { Input };\n","import { ParsedElement, Localization } from '../../ftl/index.mjs';\nimport { Input } from './input.mjs';\n\n/** Formats the yyyy-mm-dd date in its content in the page's locale, or the one its locale attribute names. */\nclass LocalDate extends ParsedElement {\n static attributes = ['locale', 'default'];\n render() {\n const content = this.textContent.trim();\n const [y, m, d] = content.split('-').map(Number);\n const parsed = content === '' ? null : new Date(y, m - 1, d);\n //content that does not name a date renders like none: formatting an\n //invalid date would throw and fail the upgrade over a template hole\n if (parsed === null || Number.isNaN(parsed.getTime())) {\n this.replaceChildren(this.declared('default') ?? '');\n return;\n }\n //the attribute wins, then the page's locale, then the platform default\n const { date } = Localization.of({ locale: this.declared('locale') ?? undefined });\n this.replaceChildren(date(parsed, { year: 'numeric', month: 'numeric', day: 'numeric' }));\n }\n}\n\n/** Formats the ISO instant in its content in the page's locale and timezone. */\nclass Instant extends ParsedElement {\n static attributes = ['locale', 'default'];\n render() {\n const content = this.textContent.trim();\n const parsed = content === '' ? null : new Date(Instant.isoToLocal(content));\n //content that does not name an instant renders like none, as ful-local-date\n if (parsed === null || Number.isNaN(parsed.getTime())) {\n this.replaceChildren(this.declared('default') ?? '');\n return;\n }\n const { date } = Localization.of({ locale: this.declared('locale') ?? undefined });\n this.replaceChildren(\n date(parsed, {\n year: 'numeric',\n month: 'numeric',\n day: 'numeric',\n hour: 'numeric',\n minute: 'numeric',\n second: 'numeric',\n hour12: false,\n }),\n );\n }\n //a date-only value names a calendar day, not a utc midnight: it is read in\n //the page's timezone, so the day it names is the day it lands on\n static #parse(v) {\n return /^\\d{4}-\\d{2}-\\d{2}$/.test(v) ? new Date(`${v}T00:00:00`) : new Date(v);\n }\n static isoToLocal(iso) {\n const d = Instant.#parse(iso);\n const pad = (n, v) => String(v).padStart(n, '0');\n const date = `${d.getFullYear()}-${pad(2, d.getMonth() + 1)}-${pad(2, d.getDate())}`;\n const time = `${pad(2, d.getHours())}:${pad(2, d.getMinutes())}:${pad(2, d.getSeconds())}.${pad(3, d.getMilliseconds())}`;\n return `${date}T${time}`;\n }\n static localToIso(local) {\n const d = Instant.#parse(local);\n return Number.isNaN(d.getTime()) ? null : d.toISOString();\n }\n}\n\n/** A date input whose bounds accept a date, now, or an offset such as +1d. */\nclass InputLocalDate extends Input {\n //declaration order is the application order: step first, since on a time\n //input min and max are snapped to its grid\n static observed = ['step', 'min', 'max'];\n _type() {\n return 'date';\n }\n get min() {\n const v = this._input.min;\n return v === '' ? null : v;\n }\n set min(v) {\n this._input.min = InputLocalDate.#fromIsoOrOffset(v);\n }\n get max() {\n const v = this._input.max;\n return v === '' ? null : v;\n }\n set max(v) {\n this._input.max = InputLocalDate.#fromIsoOrOffset(v);\n }\n get step() {\n const v = this._input.step;\n return v === '' ? null : v;\n }\n set step(v) {\n this._input.step = v ?? '';\n }\n static #fromIsoOrOffset(v) {\n if (!v) {\n return '';\n }\n //the offset is subtracted before formatting so the iso date is the local\n //calendar day, which toISOString alone would shift to utc\n const formatLocalDate = (date) =>\n new Date(date.getTime() - date.getTimezoneOffset() * 60000).toISOString().split('T')[0];\n if (v === 'now') {\n return formatLocalDate(new Date());\n }\n const re = /^([+-])(\\d+)([dmy])$/;\n const match = re.exec(v);\n if (!match) {\n return v;\n }\n const sign = match[1] === '-' ? -1 : 1;\n const offset = +match[2];\n const r = new Date();\n r.setHours(0, 0, 0, 0);\n switch (match[3]) {\n case 'd':\n r.setDate(r.getDate() + offset * sign);\n break;\n case 'm': {\n const originalDay = r.getDate();\n r.setMonth(r.getMonth() + offset * sign);\n if (r.getDate() !== originalDay) {\n r.setDate(0);\n }\n break;\n }\n case 'y':\n r.setFullYear(r.getFullYear() + offset * sign);\n break;\n }\n return formatLocalDate(r);\n }\n}\n\n/** A time input whose bounds accept a time, now, or an hour or minute offset, snapped to the step grid. */\nclass InputLocalTime extends InputLocalDate {\n _type() {\n return 'time';\n }\n get min() {\n const v = this._input.min;\n return v === '' ? null : v;\n }\n set min(v) {\n this._input.min = this.#fromNowOrOffset(v);\n }\n get max() {\n const v = this._input.max;\n return v === '' ? null : v;\n }\n set max(v) {\n this._input.max = this.#fromNowOrOffset(v);\n }\n /**\n * Resolves `now` and hour or minute offsets against the current time, wrapping\n * around midnight. `m` is minutes here, unlike the date offsets of the parent where\n * it is months: months mean nothing on a time. Anything else is passed through.\n */\n #fromNowOrOffset(v) {\n if (!v) {\n return '';\n }\n const resolved = new Date();\n if (v !== 'now') {\n const re = /^([+-])(\\d+)([hm])$/;\n const match = re.exec(v);\n if (!match) {\n return v;\n }\n const sign = match[1] === '-' ? -1 : 1;\n const offset = +match[2] * sign;\n if (match[3] === 'h') {\n resolved.setHours(resolved.getHours() + offset);\n } else {\n resolved.setMinutes(resolved.getMinutes() + offset);\n }\n }\n return InputLocalTime.#snapped(resolved, Number(this._input.step) || 60);\n }\n /**\n * Truncates a time to the step grid: min anchors that grid, so a bound that is not\n * on it makes every value on it invalid.\n */\n static #snapped(date, stepSeconds) {\n const pad = (n) => String(n).padStart(2, '0');\n const seconds = date.getHours() * 3600 + date.getMinutes() * 60 + date.getSeconds();\n const snapped = Math.floor(seconds / stepSeconds) * stepSeconds;\n const hh = pad(Math.floor(snapped / 3600));\n const mm = pad(Math.floor((snapped % 3600) / 60));\n return stepSeconds % 60 === 0 ? `${hh}:${mm}` : `${hh}:${mm}:${pad(snapped % 60)}`;\n }\n}\n\n/** A datetime input whose value is read and written as an ISO instant. */\nclass InputInstant extends Input {\n //declaration order is the application order: step first, since on a time\n //input min and max are snapped to its grid\n static observed = ['step', 'min', 'max'];\n _type() {\n return 'datetime-local';\n }\n get value() {\n return Instant.localToIso(this._input.value);\n }\n set value(v) {\n this._input.value = v ? Instant.isoToLocal(v) : '';\n }\n get min() {\n return Instant.localToIso(this._input.min);\n }\n set min(v) {\n this._input.min = v ? Instant.isoToLocal(v) : '';\n }\n get max() {\n return Instant.localToIso(this._input.max);\n }\n set max(v) {\n this._input.max = v ? Instant.isoToLocal(v) : '';\n }\n get step() {\n const v = this._input.step;\n return v === '' ? null : v;\n }\n set step(v) {\n this._input.step = v ?? '';\n }\n}\n\nexport { Instant, LocalDate, InputLocalDate, InputLocalTime, InputInstant };\n","import { Fragments, Localization, Templates } from '../../ftl/index.mjs';\nimport { Input } from './input.mjs';\n\n/** A file input with an optional dropzone and item list, enforcing the size and count limits it declares. */\nclass InputFile extends Input {\n /** how long a warning stands before the field retires it, matching the css fade */\n static WARNING_TIMEOUT = 5000;\n /**\n * A FileList holding exactly these files. The platform gives no way to\n * build one but through a DataTransfer, and every place that narrows a\n * selection rebuilt it by hand: five loops and three empty ones.\n * @param {Iterable<File>} [files]\n */\n static list(files = []) {\n const dt = new DataTransfer();\n for (const file of files) {\n dt.items.add(file);\n }\n return dt.files;\n }\n static observed = [\n 'placeholder',\n 'accept:csv',\n 'multiple:presence',\n 'item-list:presence',\n 'dropzone:presence',\n 'max-files:number',\n 'max-file-size:number',\n 'max-total-size:number',\n //re-declared so it lands after the constraints: assigning a value\n //validates the selection against them\n 'value',\n ];\n #accept;\n #items;\n #dropzone;\n #warnings;\n #group;\n _type() {\n return 'file';\n }\n static template = `\n <label>{{{{ slots.default }}}}</label>\n {{{{ slots.info }}}}\n <ful-control-group>\n <ful-affix data-tpl-if=\"slots.before\">{{{{ slots.before }}}}</ful-affix>\n <input data-tpl-type=\"type\" placeholder=\" \" form=\"\">\n <ful-affix data-tpl-if=\"slots.after\">{{{{ slots.after }}}}</ful-affix>\n </ful-control-group>\n <div data-ref=\"dropzone\" class=\"dropzone\" data-tpl-if=\"slots.dropzone\">\n {{{{ slots.dropzone }}}}\n </div>\n <div data-ref=\"dropzone\" class=\"default-dropzone\" data-tpl-if=\"!slots.dropzone\">\n {{ #l10n:t('files.dropzone-label') }}\n </div>\n <ful-item-list></ful-item-list>\n <ful-field-warnings role=\"status\" aria-live=\"polite\"></ful-field-warnings>\n <ful-field-error></ful-field-error>\n `;\n static templates = {\n items: `\n <ful-item data-tpl-each=\"files\" data-tpl-var=\"file\" data-tpl-data-name=\"file.name\">\n <div><span>{{ file.name }}</span><span>{{ #l10n:bytes(file.size) }}</span><button type=\"button\" data-tpl-aria-label=\"#l10n:t('files.remove')\"><ful-icon name=\"x-lg\" aria-hidden=\"true\"></ful-icon></button></div>\n </ful-item>\n `,\n warning: `<ful-field-warning>{{ #l10n:t(key, args) }}</ful-field-warning>`,\n };\n #itemstemplate;\n _build(conf) {\n const pieces = super._build(conf);\n const fragment = pieces.fragment;\n this.#items = fragment.querySelector('ful-item-list');\n //a slotted template replaces the stock item, the way a select's does: the\n //overlay is the same, so a custom item still reads the File it renders\n this.#itemstemplate =\n conf.slots?.items && !Fragments.isBlank(conf.slots.items) ? Templates.fromFragment(conf.slots.items) : null;\n this.#dropzone = fragment.querySelector('[data-ref=dropzone]');\n this.#warnings = fragment.querySelector('ful-field-warnings');\n this.#group = fragment.querySelector('ful-control-group');\n this.#warnings.addEventListener('animationend', (e) => {\n e.target.remove();\n });\n this.#items.addEventListener('click', (e) => {\n if (!e.target.closest('button')) {\n return;\n }\n if (!this._interactive()) {\n return;\n }\n const idx = [...this.#items.children].indexOf(e.target.closest('ful-item'));\n if (idx === -1) {\n return;\n }\n this.files = InputFile.list([...this.files].filter((f, i) => i !== idx));\n //the removal is the user's own gesture: it reports through change as the\n //picker's selection does, while the files setter stays silent like a native one\n this._notifyChange();\n });\n this.#dropzone.addEventListener('click', (e) => {\n if (!this._interactive()) {\n return;\n }\n this.querySelector('input')?.click();\n });\n\n this.#dropzone.addEventListener('dragover', (e) => {\n e.preventDefault();\n this.toggleAttribute('dragover', true);\n });\n this.#dropzone.addEventListener('dragleave', () => {\n this.toggleAttribute('dragover', false);\n });\n this.#dropzone.addEventListener('drop', (e) => {\n e.preventDefault();\n this.toggleAttribute('dragover', false);\n //the drop's default stays suppressed whatever the claims say: a\n //disabled field must not turn into a navigation target\n if (!this._interactive()) {\n return;\n }\n const dropped = [...e.dataTransfer.items].filter((i) => i.kind === 'file');\n const files = dropped.map((i) => i.getAsFile()).filter((f) => f !== null);\n if (files.length === 0 || (files.length > 1 && !this.multiple)) {\n return;\n }\n this.files = InputFile.list(files);\n //a drop is the user's own gesture too: a native file input receiving\n //one fires change on its own\n this._notifyChange();\n });\n this._input.addEventListener('change', (e) => {\n this.#update();\n });\n //a file input has no native freeze: readOnly does nothing to it, so the\n //control group is the frozen piece and the base's refusal of the click is\n //what keeps the picker shut. The dropzone and the item removals are\n //guarded on their own handlers\n return { ...pieces, freeze: this.#group };\n }\n /**\n * Re-reads the selection: the constraints run in order over what is there,\n * each dropping what it refuses, and the warnings and the item list are\n * rendered from what survives. Every path that changes the files ends here.\n */\n #update() {\n this.setCustomValidity();\n this.#warnings.replaceChildren();\n this.#ensureAcceptable();\n this.#ensureFileSizes();\n this.#ensureTotalSize();\n this.#ensureFilesCount();\n (this.#itemstemplate ?? this.template('items')).withOverlay({ files: this.files }).renderTo(this.#items);\n }\n warning(key, args) {\n this.template('warning').withOverlay({ key, args }).appendTo(this.#warnings);\n //the field retires its own warnings: the css fade is decoration, and a\n //theme that drops the keyframe, or a host stylesheet disabling animations,\n //used to leave them on screen until the next selection\n const warning = /** @type HTMLElement */ (this.#warnings.lastElementChild);\n setTimeout(() => warning.remove(), InputFile.WARNING_TIMEOUT);\n }\n /**\n * The native accept vocabulary: a dot-prefixed extension matches the file\n * name's suffix, a mime type (parameters stripped) matches the file's type,\n * and image/*, audio/*, video/* match their whole family. Anything else\n * matches nothing, as the native attribute ignores it.\n */\n #acceptable(file) {\n const name = file.name.toLowerCase();\n return this.#accept.some((token) => {\n const t = token.toLowerCase().split(';')[0].trim();\n if (t.startsWith('.')) {\n return name.endsWith(t);\n }\n if (t.endsWith('/*')) {\n return file.type.startsWith(`${t.slice(0, -1)}`);\n }\n return t.includes('/') && file.type === t;\n });\n }\n #ensureAcceptable() {\n if (!this.#accept.length) {\n return;\n }\n const unacceptable = [...this.files].filter((file) => !this.#acceptable(file));\n\n if (unacceptable.length === 0) {\n return;\n }\n this.warning('files.unacceptable-file-type', { types: this.#accept.join(', ') });\n this._input.files = InputFile.list([...this.files].filter((f) => !unacceptable.includes(f)));\n }\n #ensureFilesCount() {\n if (this.#maxFiles === null) {\n return;\n }\n if (this.files.length <= this.#maxFiles) {\n return;\n }\n this.warning('files.max-files-exceeded', { count: this.#maxFiles });\n this._input.files = InputFile.list();\n }\n\n #ensureFileSizes() {\n if (this.#maxFileSize === null) {\n return;\n }\n const oversized = [...this.files].filter((file) => file.size > this.#maxFileSize);\n if (oversized.length === 0) {\n return;\n }\n this.warning('files.max-file-size-exceeded', { size: Localization.of().bytes(this.#maxFileSize) });\n this._input.files = InputFile.list([...this.files].filter((f) => !oversized.includes(f)));\n }\n #ensureTotalSize() {\n if (this.#maxTotalSize === null) {\n return;\n }\n const totalSize = [...this.files].reduce((acc, file) => acc + file.size, 0);\n if (totalSize <= this.#maxTotalSize) {\n return;\n }\n this.warning('files.max-total-size-exceeded', { size: Localization.of().bytes(this.#maxTotalSize) });\n this._input.files = InputFile.list();\n }\n\n get accept() {\n return this.#accept;\n }\n set accept(vs) {\n this._input.accept = vs.join(',');\n this.#accept = vs;\n this.reflectTo('accept', vs);\n }\n get multiple() {\n return this._input.multiple;\n }\n set multiple(v) {\n this._input.multiple = v;\n this.reflectTo('multiple', v);\n }\n get files() {\n return this._input.files;\n }\n set files(vs) {\n this._input.files = vs;\n this.#update();\n }\n get file() {\n return this.files[0] ?? null;\n }\n set file(v) {\n this.files = InputFile.list(v ? [v] : []);\n }\n get value() {\n const names = Array.from(this._input.files).map((f) => f.name);\n return this.multiple ? names : (names[0] ?? null);\n }\n set value(v) {\n if (v) {\n return;\n }\n this.files = InputFile.list();\n }\n formResetCallback() {\n //a file selection's default is empty, as the platform's own reset: a\n //declared filename cannot be restored programmatically\n this.value = null;\n }\n get totalsize() {\n return Array.from(this.files).reduce((a, f) => a + f.size, 0);\n }\n #maxFiles;\n get maxFiles() {\n return this.#maxFiles;\n }\n set maxFiles(v) {\n this.#maxFiles = v;\n this.reflectTo('max-files', v);\n }\n #maxFileSize;\n get maxFileSize() {\n return this.#maxFileSize;\n }\n set maxFileSize(v) {\n this.#maxFileSize = v;\n this.reflectTo('max-file-size', v);\n }\n #maxTotalSize;\n get maxTotalSize() {\n return this.#maxTotalSize;\n }\n set maxTotalSize(v) {\n this.#maxTotalSize = v;\n this.reflectTo('max-total-size', v);\n }\n #useItemList;\n get itemList() {\n return this.#useItemList;\n }\n set itemList(v) {\n this.#useItemList = v;\n this.reflectTo('item-list', v);\n }\n #useDropzone;\n get dropzone() {\n return this.#useDropzone;\n }\n set dropzone(v) {\n this.#useDropzone = v;\n this.reflectTo('dropzone', v);\n }\n}\n\nexport { InputFile };\n","/**\n * The anchored popovers' fallback: where the platform lacks CSS anchor\n * positioning, the popovers ful wires on an invoker are placed beside it\n * by hand, the geometry the anchor css draws on its own. Where the\n * platform carries the css the wiring is a no-op: the stylesheet does\n * the work alone.\n */\n\nimport { Attributes } from '../../ftl/index.mjs';\n\n/** the viewport's breathing room when clamping, in pixels */\nconst PAD = 8;\nconst open = new Map();\nlet frame = 0;\nlet reflowWired = false;\n\nconst platformAnchors = () =>\n CSS.supports('anchor-name: --ful-probe') &&\n CSS.supports('position-anchor: --ful-probe') &&\n CSS.supports('position-area: bottom') &&\n CSS.supports('top: anchor(bottom)') &&\n CSS.supports('width: anchor-size(width)');\n\nconst clamp = (value, low, high) => Math.min(Math.max(value, low), Math.max(low, high));\n\n/** a note is the popover that draws a callout, and the only one these offsets serve */\nconst isNote = (popover) => popover.matches('ful-note, .ful-note, [placement]');\n\n/**\n * Reports where the invoker's centre falls inside the popover, which is what a\n * callout points at. The two are the same spot until the viewport pushes the\n * popover off its invoker, which the platform's own placement does as readily\n * as the hand placement below, so this is measured in both.\n */\nconst reportCallout = (popover, invoker) => {\n const box = invoker.getBoundingClientRect();\n const here = popover.getBoundingClientRect();\n //against the padding box, which is what a percentage inset resolves against\n popover.style.setProperty(\n '--ful-note-callout-inline',\n `${box.left + box.width / 2 - here.left - popover.clientLeft}px`,\n );\n popover.style.setProperty(\n '--ful-note-callout-block',\n `${box.top + box.height / 2 - here.top - popover.clientTop}px`,\n );\n};\n\nconst place = (popover, anchored) => {\n const { invoker, stretch } = anchored;\n const box = invoker.getBoundingClientRect();\n const viewport = document.documentElement;\n const vw = viewport.clientWidth;\n const vh = viewport.clientHeight;\n //the css gap lives in the margins, and the computed style is live: the\n //inline zero a previous placing left behind is dropped first so the numbers\n //read below are the stylesheet's own, not this function's own zero. Reading\n //them afterwards left every popover flush against its invoker\n popover.style.removeProperty('margin');\n const computed = getComputedStyle(popover);\n const gap = {\n top: parseFloat(computed.marginTop) || 0,\n right: parseFloat(computed.marginRight) || 0,\n bottom: parseFloat(computed.marginBottom) || 0,\n left: parseFloat(computed.marginLeft) || 0,\n };\n popover.style.right = 'auto';\n popover.style.bottom = 'auto';\n popover.style.margin = '0';\n if (stretch) {\n const width = Math.min(box.width, vw - 2 * PAD);\n popover.style.width = `${width}px`;\n popover.style.left = `${clamp(box.left, PAD, vw - width - PAD)}px`;\n const height = popover.getBoundingClientRect().height;\n popover.style.top = `${clamp(box.bottom + gap.top, PAD, vh - height - PAD)}px`;\n return;\n }\n //a popover wraps against the spot it lands on: the width is measured\n //wide open, the left clamped so it still fits, the vertical placed\n //against the height that width renders\n const note = isNote(popover);\n const placement = note ? (popover.getAttribute('placement') ?? 'bottom') : 'bottom';\n popover.style.removeProperty('max-width');\n const cap = Math.min(parseFloat(computed.maxWidth) || vw, vw - 2 * PAD);\n popover.style.maxWidth = `${cap}px`;\n popover.style.left = `${PAD}px`;\n const wide = popover.getBoundingClientRect().width;\n let left =\n placement === 'right'\n ? box.right + gap.left\n : placement === 'left'\n ? box.left - gap.right - wide\n : note\n ? box.left + box.width / 2 - wide / 2\n : box.left;\n left = clamp(left, PAD, vw - wide - PAD);\n popover.style.left = `${left}px`;\n popover.style.maxWidth = `${Math.min(cap, vw - PAD - left)}px`;\n const height = popover.getBoundingClientRect().height;\n const top =\n placement === 'top'\n ? box.top - gap.bottom - height\n : placement === 'right' || placement === 'left'\n ? box.top + box.height / 2 - height / 2\n : box.bottom + gap.top;\n popover.style.top = `${clamp(top, PAD, vh - height - PAD)}px`;\n if (note) {\n reportCallout(popover, invoker);\n }\n};\n\nconst unplace = (popover) => {\n for (const property of [\n 'top',\n 'left',\n 'right',\n 'bottom',\n 'margin',\n 'max-width',\n 'width',\n '--ful-note-callout-inline',\n '--ful-note-callout-block',\n ]) {\n popover.style.removeProperty(property);\n }\n};\n\nconst reflow = () => {\n frame = 0;\n for (const [popover, anchored] of open) {\n //the platform hides a popover removed while open without firing the\n //toggle that would have dropped its entry, so the pass that places the\n //open ones is also where a gone one is forgotten: it is the moment\n //anybody cares, and it needs no callback on either element's life\n if (!popover.isConnected || !anchored.invoker.isConnected) {\n open.delete(popover);\n continue;\n }\n place(popover, anchored);\n }\n};\n\nconst schedule = () => {\n if (!frame && open.size > 0) {\n frame = requestAnimationFrame(reflow);\n }\n};\n\n/**\n * CSS anchor positioning for a popover and the invoker it belongs to, with the\n * hand-placed fallback for the platforms that do not have it.\n */\nclass Anchors {\n /**\n * Anchors a popover to its invoker.\n *\n * The invoker is given an `anchor-name` and the popover a `position-anchor`\n * pointing at it, which is what a stylesheet needs to place the popover\n * itself: the library's own menus say `top: anchor(bottom); left:\n * anchor(left)`. **Writing that css is the caller's half of this.** Without\n * it the popover lands wherever the user agent puts a popover, which is not\n * beside the invoker.\n *\n * Where the platform has no anchor positioning the popover is placed here\n * instead, beside the invoker whenever it opens, clamped into the viewport,\n * following it on scroll and resize, and cleaned up on close. That placement\n * draws the geometry the css above describes, so the two agree.\n *\n * @param {HTMLElement} invoker the element the popover belongs to\n * @param {HTMLElement} popover the `[popover]` element to place\n * @param {object} [options]\n * @param {string} [options.prefix] prefixes the generated anchor name and id,\n * so the dom says which component a name belongs to\n * @param {boolean} [options.invoke] points the invoker's `popovertarget` at\n * the popover, giving toggle and light dismiss with no script of your own\n * @param {boolean} [options.expanded] keeps the invoker's `aria-expanded` in\n * step with the popover\n * @param {boolean} [options.stretch] widens the popover to its invoker, which\n * is what a combobox dropdown wants\n * @param {boolean} [options.handPlace] places here on every platform rather\n * than only as a fallback, which a popover asks for when it needs to know\n * where its invoker ended up: the tooltip's note points a callout at it, and\n * a pseudo-element cannot read an anchor outside its own containing block.\n * Such a popover declares no anchor placement in css, there being none to\n * agree with\n */\n static wire(\n invoker,\n popover,\n { prefix = 'ful-anchor', invoke = false, expanded = false, stretch = false, handPlace = false } = {},\n ) {\n const uid = Attributes.uid(prefix);\n if (invoke) {\n //popovertarget needs a target that can be named\n popover.id = popover.id || uid;\n invoker.setAttribute('popovertarget', popover.id);\n }\n const anchor = `--${uid}`;\n invoker.style.anchorName = anchor;\n popover.style.positionAnchor = anchor;\n if (expanded) {\n invoker.setAttribute('aria-expanded', 'false');\n popover.addEventListener('toggle', (/** @type any */ evt) => {\n invoker.setAttribute('aria-expanded', evt.newState === 'open' ? 'true' : 'false');\n });\n }\n //the naming above is what the stylesheet reads, so it happens either way:\n //only the hand placement below is the fallback, and only for a popover that\n //did not ask to be placed here whatever the platform offers\n if (!handPlace && platformAnchors()) {\n return;\n }\n const anchored = { invoker, stretch };\n popover.addEventListener('beforetoggle', (/** @type any */ evt) => {\n //placed before the showing, refined once laid out: the platform's\n //centered or corner spot never paints\n if (evt.newState === 'open') {\n place(popover, anchored);\n }\n });\n popover.addEventListener('toggle', (/** @type any */ evt) => {\n if (evt.newState === 'open') {\n open.set(popover, anchored);\n place(popover, anchored);\n } else {\n open.delete(popover);\n unplace(popover);\n }\n });\n if (!reflowWired) {\n reflowWired = true;\n document.addEventListener('scroll', schedule, true);\n window.addEventListener('resize', schedule);\n }\n }\n}\n\nexport { Anchors };\n","import { Attributes, Fragments, ParsedElement, Templates } from '../../ftl/index.mjs';\nimport { Claims } from '../claims.mjs';\nimport { Anchors } from '../disclosures/anchors.mjs';\nimport { Field } from './field.mjs';\nimport { VersionedLocalStorage } from '../storage.mjs';\nimport { Timing } from '../timing.mjs';\n\n/**\n * Fetches a select's whole vocabulary from a url and serves every later read\n * from it. Concurrent callers share one request, the options may be cached in\n * local storage under a revision, and reconfiguring the url discards both.\n */\nclass RemoteLoader {\n #http;\n #url;\n #method;\n #responseMapper;\n #prefetch;\n #revision;\n #data;\n #inFlight;\n #configs = new Claims();\n constructor({ http, url, method, responseMapper, prefetch, revision }) {\n this.#http = http;\n this.#url = url;\n this.#method = method;\n this.#responseMapper = responseMapper;\n this.#prefetch = prefetch;\n this.#revision = revision;\n this.#data = null;\n this.#inFlight = null;\n }\n async prefetch() {\n if (!this.#prefetch) {\n return;\n }\n await this.#ensureFetched();\n }\n async exact(...keys) {\n const data = await this.#ensureFetched();\n return data.filter(({ key }) => keys.some((r) => r == key));\n }\n async load(needle) {\n const data = await this.#ensureFetched();\n //includes would coerce a nullish needle to the string \"undefined\": no\n //needle means no filter, as the empty search the combobox opens with\n return data.filter(({ label }) => (label ?? '').toLowerCase().includes(needle?.toLowerCase() ?? ''));\n }\n /**\n * Drops the cached vocabulary so the next question refetches it. Any fetch\n * still in flight is detached: its outcome belongs to the configuration that\n * started it and must neither be served nor stored for the new one.\n */\n async invalidate() {\n this.#configs.invalidate();\n this.#data = null;\n this.#inFlight = null;\n }\n async reconfigureUrl(url) {\n await this.invalidate();\n this.#url = url;\n }\n async #ensureFetched() {\n if (this.#data === null) {\n if (this.#inFlight === null) {\n //held, not taken: concurrent fetch users share one configuration,\n //only a reconfiguration supersedes it\n const claim = this.#configs.hold();\n this.#inFlight = RemoteLoader.#revisionedData(this.#http, this.#method, this.#url, this.#revision)\n .then((raw) => {\n if (!claim.stale) {\n this.#data = this.#responseMapper(raw);\n }\n })\n .finally(() => {\n if (!claim.stale) {\n this.#inFlight = null;\n }\n });\n }\n await this.#inFlight;\n }\n if (this.#data === null) {\n throw new Error('superseded by a reconfiguration');\n }\n return this.#data;\n }\n static async #revisionedData(http, method, url, revision) {\n const storageKey = `${method}@${url}`;\n if (revision !== null) {\n const data = VersionedLocalStorage.load(storageKey, revision);\n if (data !== undefined) {\n return data;\n }\n }\n const data = await http.request(method, url).fetchJson();\n if (revision !== null) {\n try {\n VersionedLocalStorage.save(storageKey, revision, data);\n } catch (/** @type any */ e) {\n //the cache write is best effort: the fetched data is the answer,\n //a full quota must not fail the load that already succeeded\n console.warn('failed to cache the select options', e);\n }\n }\n return data;\n }\n}\n\n/** Asks the endpoint per query instead of fetching the vocabulary once, for a list too large to hold in memory. */\nclass PartialRemoteLoader {\n #http;\n #url;\n #method;\n #responseMapper;\n constructor({ http, url, method, responseMapper }) {\n this.#http = http;\n this.#url = url;\n this.#method = method;\n this.#responseMapper = responseMapper;\n }\n /**\n * Nothing is held between queries, so there is no cache to drop: the method\n * exists so a caller can invalidate any loader without knowing which it has.\n */\n async invalidate() {}\n async reconfigureUrl(url) {\n this.#url = url;\n }\n async exact(...keys) {\n const response = await this.#http\n .request(this.#method, this.#url)\n .param('k', ...keys)\n .fetchJson();\n return this.#responseMapper(response);\n }\n async load(needle) {\n const response = await this.#http.request(this.#method, this.#url).param('s', needle).fetchJson();\n return this.#responseMapper(response);\n }\n}\n\n/** Serves a select's options from an array held in memory, which is what the slotted `<option>` elements become. */\nclass InMemoryLoader {\n #data;\n constructor(data) {\n this.#data = data;\n }\n update(data) {\n this.#data = data;\n }\n /** The vocabulary is the data itself: update replaces it, so there is nothing to drop. */\n async invalidate() {}\n exact(...keys) {\n return this.#data.filter(({ key }) => keys.some((r) => r == key));\n }\n load(needle) {\n //no needle means no filter, as in RemoteLoader\n return this.#data.filter(({ label }) => (label ?? '').toLowerCase().includes(needle?.toLowerCase() ?? ''));\n }\n}\n\n/**\n * Builds the select's loader from its attributes: the slotted options in\n * memory, or a remote or chunked loader over src.\n *\n * A component registered under the `loader` attribute replaces this one and\n * must implement the same three methods, each answering `{ key, label,\n * metadata }` entries:\n *\n * - `prefetch()` warms the vocabulary if it can, and resolves either way\n * - `load(needle)` answers the entries matching the typed text, all of them\n * when the needle is nullish, which is the empty search the list opens with\n * - `exact(...keys)` answers the entries for those keys, used to label a value\n * assigned without going through the list\n */\nclass SelectLoader {\n /**\n * Builds a loader from a plain configuration, reading no dom: `data` alone\n * is the in-memory vocabulary, a `url` is fetched whole or, under\n * `mode: 'chunked'`, per query. A test, or a caller holding its own\n * configuration, builds a loader this way; `create` is the same thing with\n * an element's attributes parsed first.\n * @param {{ data?: any[], http?: any, url?: string, method?: string, mode?: string, prefetch?: boolean, revision?: string|null, responseMapper?: any }} conf\n */\n static from({ data, http, url, method = 'POST', mode, prefetch = false, revision = null, responseMapper }) {\n if (!url) {\n return new InMemoryLoader(data ?? []);\n }\n if ('chunked' === mode) {\n return new PartialRemoteLoader({ http, url, method, responseMapper });\n }\n return new RemoteLoader({ http, url, method, responseMapper, prefetch, revision });\n }\n static create(el, conf) {\n if (!el.declared('src')) {\n const els = Array.from(conf.options?.querySelectorAll('option') ?? []);\n return SelectLoader.from({\n data: els.map((e) => ({\n key: e.getAttribute('value') ?? e.innerText.trim(),\n label: e.innerText.trim(),\n metadata: undefined,\n })),\n });\n }\n return SelectLoader.from({\n http: el.component('http-client'),\n url: el.declared('src'),\n method: el.declared('method') ?? 'POST',\n mode: el.declared('mode'),\n prefetch: el.declared('preload'),\n revision: el.declared('revision'),\n responseMapper: SelectLoader.#responseMapperFrom(el),\n });\n }\n static #responseMapperFrom(el) {\n if (el.declared('k-expr') && el.declared('l-expr')) {\n return (response) => {\n const rows = el._registry\n .evaluator()\n .withOverlay(response)\n .evaluateExpression(el.declared('d-expr') ?? 'self');\n return rows.map((row) => {\n const evaluator = el._registry.evaluator().withOverlay(row);\n return {\n key: evaluator.evaluateExpression(el.declared('k-expr')),\n label: evaluator.evaluateExpression(el.declared('l-expr')),\n metadata: evaluator.evaluateExpression(el.declared('m-expr') ?? 'self'),\n };\n });\n };\n }\n if (el.declared('response-mapper')) {\n return el.component(el.declared('response-mapper'));\n }\n //the wire format servers send is the positional row: the default mapper\n //is what turns it into the entry the element speaks everywhere else\n return (/** @type any[] */ response) => response.map(([key, label, metadata]) => ({ key, label, metadata }));\n }\n}\n\n/** The options popup of a select: listbox semantics, one loading claim per show, a localized empty state. */\nclass Dropdown extends ParsedElement {\n static attributes = ['listbox'];\n static slots = true;\n static template = `\n <ful-spinner class=\"centered\" role=\"status\" hidden><span class=\"ful-sr-only\">{{ #l10n:t('spinner.loading') }}</span></ful-spinner>\n <p data-ref=\"empty\" aria-live=\"polite\" hidden>{{ #l10n:t('dropdown.empty') }}</p>\n <menu tabindex=\"-1\" role=\"listbox\" hidden></menu>\n `;\n static templates = {\n options: `\n <li data-tpl-each=\"self\" data-tpl-selected=\"index == 0\" data-tpl-value=\"index\" role=\"option\">\n {{ label }}\n </li>\n `,\n };\n #spinner;\n #menu;\n #empty;\n #optionstemplate;\n #options = new Map();\n #shows = new Claims();\n render({ slots }) {\n const fragment = this.template().render();\n this.#optionstemplate = Fragments.isBlank(slots.default)\n ? this.template('options')\n : Templates.fromFragment(slots.default);\n this.#spinner = fragment.querySelector('ful-spinner');\n this.#empty = fragment.querySelector('p[data-ref=empty]');\n this.#menu = fragment.querySelector('menu');\n //the listbox is named so a combobox can point aria-controls and\n //aria-activedescendant at it: a reference to an unnamed element resolves\n //to nothing, and the active option is announced to no one. The name comes\n //from the host when it gave one, since it has to set aria-controls before\n //this element upgrades\n this.#menu.id = this.declared('listbox') || Attributes.uid('ful-listbox');\n this.#menu.addEventListener('click', (evt) => {\n evt.stopPropagation();\n const li = evt.target.closest('li');\n if (!li) {\n this.hide();\n return;\n }\n this.#change(li);\n });\n this.replaceChildren(fragment);\n }\n #selected() {\n return this.#menu?.querySelector('[selected]') ?? this.#menu?.firstElementChild ?? null;\n }\n #highlight(li) {\n if (!li) {\n this.#activated(null);\n return;\n }\n for (const el of this.#menu.querySelectorAll('li')) {\n el.toggleAttribute('selected', el === li);\n }\n li.id ||= Attributes.uid('ful-option');\n this.#activated(li.id);\n li.scrollIntoView({\n block: 'nearest',\n behavior: matchMedia('(prefers-reduced-motion: reduce)').matches ? 'auto' : 'smooth',\n });\n }\n acceptSelection() {\n const selected = this.#selected();\n if (!selected) {\n return;\n }\n this.#change(selected);\n }\n update(values, keys = []) {\n if (values === undefined) {\n throw new Error('null data');\n }\n this.#options = new Map(values.map((v, i) => [String(i), v]));\n const data = values.map((entry, index) => ({ index, ...entry }));\n this.#optionstemplate.withOverlay(data).renderTo(this.#menu);\n for (const [index, li] of [...this.#menu.children].entries()) {\n const picked = keys.some((r) => r == values[index]?.key);\n li.toggleAttribute('picked', picked);\n //what is picked is what aria-selected means for a listbox: a tint alone\n //says it to whoever can see it and to no one else\n li.setAttribute('aria-selected', picked ? 'true' : 'false');\n }\n this.#empty.toggleAttribute('hidden', values.length !== 0);\n this.#menu.toggleAttribute('hidden', values.length === 0);\n const current = values.findIndex(({ key }) => keys.some((r) => r == key));\n this.#highlight(current >= 0 ? this.#menu.children[current] : this.#selected());\n }\n #change(target) {\n const index = target.getAttribute('value');\n const entry = this.#options.get(index);\n this.hide();\n this.dispatchEvent(\n new CustomEvent('change', {\n bubbles: true,\n cancelable: false,\n detail: { index, entry },\n }),\n );\n }\n hide() {\n //hiding ends the current claim: a search still in flight must neither\n //repopulate the list nor point the combobox at an option of a hidden dropdown\n this.#shows.invalidate();\n if (this.matches(':popover-open')) {\n this.hidePopover();\n }\n this.#activated(null);\n }\n /**\n * The option the reader is on, announced for whoever owns the combobox: the\n * dropdown is a view, so it names its active option and never reaches into\n * another element's aria to say so.\n */\n #activated(id) {\n this.dispatchEvent(new CustomEvent('activechange', { bubbles: false, cancelable: false, detail: { id } }));\n }\n\n get shown() {\n return this.matches(':popover-open');\n }\n async show(loader, keys = []) {\n //each show claims the dropdown: a search resolving after a newer show has\n //started, or after the dropdown was hidden again, is stale, and neither\n //renders nor highlights, whichever order the searches resolve in\n const claim = this.#shows.take();\n if (!this.matches(':popover-open')) {\n this.showPopover();\n }\n this.#menu.setAttribute('hidden', '');\n this.#spinner.removeAttribute('hidden');\n try {\n const data = await loader();\n if (claim.stale) {\n return;\n }\n this.update(data, keys);\n } catch (/** @type any */ e) {\n if (claim.stale) {\n //the newer show (or the hide that ended this one) owns the dropdown\n //and its outcome: a superseded failure is neither shown nor thrown\n return;\n }\n this.hide();\n throw e;\n } finally {\n if (!claim.stale) {\n this.#spinner.setAttribute('hidden', '');\n }\n }\n }\n async moveOrShow(forward, loader, keys = []) {\n if (this.shown) {\n const selected = this.#selected();\n const candidate = selected?.[`${forward ? 'next' : 'previous'}ElementSibling`];\n if (selected && candidate) {\n this.#highlight(candidate);\n }\n return;\n }\n await this.show(loader, keys);\n }\n jump(first) {\n const target = first ? this.#menu.firstElementChild : this.#menu.lastElementChild;\n if (target) {\n this.#highlight(target);\n }\n }\n page(forward) {\n const selected = this.#selected();\n if (!selected) {\n return;\n }\n const lis = Array.from(this.#menu.children);\n const step = this.#page();\n const target = lis[Math.max(0, Math.min(lis.length - 1, lis.indexOf(selected) + (forward ? step : -step)))];\n this.#highlight(target);\n }\n #page() {\n const first = this.#menu.firstElementChild;\n if (!first || first.offsetHeight === 0) {\n return 1;\n }\n return Math.max(1, Math.trunc(this.#menu.clientHeight / first.offsetHeight));\n }\n}\n\n/** A combobox acting like a select over a loader's vocabulary, single or multiple. */\nclass Select extends Field {\n //the loader's whole vocabulary is configuration, read once at the upgrade:\n //none of it is reactive, and declaring it here is what lets the loader be\n //built from a plain object rather than from an element\n static attributes = [\n 'name',\n 'loader',\n 'k-type',\n 'src',\n 'method',\n 'mode',\n 'preload:presence',\n 'revision',\n 'k-expr',\n 'l-expr',\n 'd-expr',\n 'm-expr',\n 'response-mapper',\n ];\n //the value attribute is a list of keys whether or not the select is multiple:\n //`set value` normalizes a list of one to a single key, and the getter answers a\n //scalar for a single select, so nothing downstream has to know which it was\n static observed = ['multiple:presence', 'item-list:presence', 'value:csv'];\n static slots = true;\n //a manual popover: the combobox keeps the focus on its input and owns\n //the whole lifecycle (typing, arrows, blur, Escape, Tab), so no light\n //dismiss and no popovertarget invoker; it anchors on its control group\n static template = `\n <label>{{{{ slots.default }}}}</label>\n {{{{ slots.info }}}}\n <ful-control-group>\n <ful-affix data-tpl-if=\"slots.before\">{{{{ slots.before }}}}</ful-affix>\n <ful-control>\n <input type=\"text\" form=\"\" autocomplete=\"off\" role=\"combobox\" aria-autocomplete=\"list\" aria-haspopup=\"listbox\" aria-expanded=\"false\">\n </ful-control>\n <ful-affix data-tpl-if=\"slots.after\">{{{{ slots.after }}}}</ful-affix>\n <ful-dropdown popover=\"manual\">{{{{ slots.dropdown }}}}</ful-dropdown>\n </ful-control-group>\n <ful-item-list></ful-item-list>\n <ful-field-error></ful-field-error>\n `;\n static templates = {\n items: `\n <ful-item data-tpl-each=\"entries\" data-tpl-var=\"entry\" data-tpl-data-key=\"entry.key\">\n <div><span>{{ entry.label }}</span><button type=\"button\" data-tpl-aria-label=\"#l10n:t('select.remove')\"><ful-icon name=\"x-lg\" aria-hidden=\"true\"></ful-icon></button></div>\n </ful-item>\n `,\n };\n #loader;\n #control;\n #ddmenu;\n #input;\n #items;\n #itemstemplate;\n #multiple;\n #warnedComma = false;\n #values = new Map();\n #assignments = new Claims();\n #editing = false;\n #dload;\n #abortdload;\n _build({ slots }) {\n const name = this.declared('name');\n this.#loader = this.component(this.declared('loader') ?? 'loaders:select').create(this, {\n options: slots.options,\n });\n\n this.#multiple = this.declared('multiple');\n //the prefetch is the vocabulary's concern, not the field's: the label, the\n //combobox and the error region paint at once and the properties go live with\n //them, where a slow endpoint used to hold up the whole upgrade. The loader\n //shares one in-flight fetch, so a first open during the prefetch joins it\n this.#loader.prefetch?.()?.catch((/** @type any */ e) => {\n console.warn('failed to prefetch select options', this, 'reason:', e);\n });\n const fragment = this.template().withOverlay({ slots, name }).render();\n this.#input = fragment.querySelector('input');\n this.#items = fragment.querySelector('ful-item-list');\n this.#itemstemplate =\n slots.items && !Fragments.isBlank(slots.items) ? Templates.fromFragment(slots.items) : null;\n Attributes.forward('input-', this, this.#input);\n this.#control = fragment.querySelector('ful-control');\n\n this.#ddmenu = fragment.querySelector('ful-dropdown');\n //named before it upgrades, so the combobox can control it from the start\n const listbox = Attributes.uid('ful-listbox');\n this.#ddmenu.setAttribute('listbox', listbox);\n this.#input.setAttribute('aria-controls', listbox);\n //one writer for the combobox's state: the dropdown says when it opens and\n //which option is active, the input's aria is the select's to keep\n this.#ddmenu.addEventListener('beforetoggle', (/** @type any */ e) => {\n const open = e.newState === 'open';\n this.#input.setAttribute('aria-expanded', open ? 'true' : 'false');\n if (!open) {\n this.#input.removeAttribute('aria-activedescendant');\n }\n });\n this.#ddmenu.addEventListener('activechange', (/** @type any */ e) => {\n Attributes.set(this.#input, 'aria-activedescendant', e.detail.id);\n });\n //each pair carries its own anchor: two selects on a page must not share one\n const group = fragment.querySelector('ful-control-group');\n Anchors.wire(group, this.#ddmenu, { prefix: 'ful-select', stretch: true });\n [this.#dload, this.#abortdload] = Timing.throttle(400, () => this.#open());\n this.#wireChrome();\n this.#wireChips();\n this.#wireInput();\n this.#wireSelection();\n return {\n fragment,\n control: this.#input,\n error: fragment.querySelector('ful-field-error'),\n label: fragment.querySelector('label'),\n };\n }\n /**\n * Pointer interaction: the element toggles the dropdown, the item list's\n * remove buttons and the control's badges drop their entry.\n */\n #wireChrome() {\n this.addEventListener('click', (/** @type any */ e) => {\n if (!this._interactive()) {\n return;\n }\n if (this.#ddmenu.shown) {\n this.#close();\n return;\n }\n this.#input.focus();\n this.#dload();\n });\n this.#items.addEventListener('click', (e) => {\n e.stopPropagation();\n if (!e.target.closest('button')) {\n return;\n }\n if (!this._interactive()) {\n return;\n }\n this.#removeKeyAt([...this.#items.children].indexOf(e.target.closest('ful-item')));\n });\n this.#control.addEventListener('click', (e) => {\n const badge = e.target instanceof Element ? e.target.closest('ful-badge') : null;\n if (!badge) {\n return;\n }\n e.stopPropagation();\n this.#removeBadge(badge);\n });\n }\n /**\n * Keyboard interaction over the chips: Enter/Space/Backspace/Delete remove,\n * arrows move between badges and the input, Escape returns to the input.\n */\n #wireChips() {\n this.addEventListener('keydown', (/** @type any */ e) => {\n const badge = e.target instanceof Element ? e.target.closest('ful-badge') : null;\n if (badge) {\n this.#chipKeydown(e, badge);\n return;\n }\n //the caret cannot move further left: hand the focus over to the chips,\n //as the backspace at the same spot already hands over the last entry\n if (\n 'ArrowLeft' === e.code &&\n e.target === this.#input &&\n this.#input.selectionStart === 0 &&\n this.#input.selectionEnd === 0\n ) {\n this.#badges().at(-1)?.focus();\n }\n });\n }\n #wireInput() {\n this.#input.addEventListener('change', (e) => {\n e.stopPropagation();\n });\n this.#input.addEventListener('focus', () => {\n if (this.#editing) {\n return;\n }\n this.#input.select();\n });\n this.#input.addEventListener('blur', (e) => {\n e.stopPropagation();\n if (e.relatedTarget && this.contains(e.relatedTarget)) {\n return;\n }\n this.#abortdload();\n this.#close();\n });\n this.#input.addEventListener('keydown', (e) => {\n if (!this._interactive()) {\n return;\n }\n this.#comboboxKeydown(e);\n });\n this.#input.addEventListener('input', (e) => {\n e.stopPropagation();\n if (!this._interactive()) {\n return;\n }\n this.#editing = true;\n this.#dload();\n });\n }\n #wireSelection() {\n this.#ddmenu.addEventListener('change', (e) => {\n e.stopPropagation();\n //a claim landing while the dropdown is open must not accept a pick:\n //disabled closes the list on its own (the focused input blurs), readonly\n //leaves it open, so the guard lives here\n if (!this._interactive()) {\n this.#close();\n return;\n }\n if (!this.#multiple) {\n this.#values.clear();\n }\n this.#editing = false;\n this.#values.set(this.#coerceKey(e.detail.entry.key), e.detail.entry);\n this.#changed();\n this.#syncBadges();\n this.#input.focus();\n this.#ddmenu.hide();\n if (!this.#multiple) {\n this.#input.select();\n }\n });\n }\n /** Hands the loader to the callback, for runtime reconfigurations. */\n async withLoader(fn) {\n return await fn(this.#loader);\n }\n /**\n * Drops whatever the loader is holding and asks it about the current selection\n * again, which is what a select whose vocabulary depends on another control\n * needs when that control changes. A key the loader no longer knows is dropped\n * from the selection, so a value invalidated by the change does not survive it,\n * and one it still knows keeps its place with a fresh label.\n *\n * Pass a url first where the vocabulary lives at a different address:\n *\n * citta.addEventListener('change', async () => {\n * await cap.withLoader((l) => l.reconfigureUrl(`/api/cap?citta=${citta.value}`));\n * await cap.reload();\n * });\n */\n async reload() {\n await this.#loader.invalidate?.();\n //the prefetch is a warm-up: a select configured to preload warms the new\n //vocabulary now rather than on the next open, as it did at the upgrade\n await this.#loader.prefetch?.();\n const keys = [...this.#values.keys()];\n if (keys.length === 0) {\n return;\n }\n await this.#resolve(keys, this.#assignments.take());\n }\n #badges() {\n return Array.from(this.#control.querySelectorAll(':scope > ful-badge'));\n }\n #removeBadge(badge) {\n if (!this._interactive()) {\n return;\n }\n this.#removeKeyAt(this.#badges().indexOf(badge));\n }\n /**\n * Drops the entry at the given index, if any: badges and item list entries\n * share the value map's ordering.\n */\n #removeKeyAt(index) {\n const key = Array.from(this.#values.keys())[index];\n if (key === undefined) {\n return;\n }\n this.#values.delete(key);\n this.#changed();\n this.#syncBadges();\n }\n #chipKeydown(e, badge) {\n switch (e.code) {\n case 'NumpadEnter':\n case 'Enter':\n case 'Space':\n case 'Backspace':\n case 'Delete': {\n e.preventDefault();\n this.#removeBadge(badge);\n this.#input.focus();\n break;\n }\n case 'ArrowLeft': {\n e.preventDefault();\n (this.#badges()[this.#badges().indexOf(badge) - 1] ?? this.#input).focus();\n break;\n }\n case 'ArrowRight': {\n e.preventDefault();\n (this.#badges()[this.#badges().indexOf(badge) + 1] ?? this.#input).focus();\n break;\n }\n case 'Escape': {\n this.#input.focus();\n break;\n }\n }\n }\n /**\n * The combobox keyboard contract: arrows browse and move, Home/End and\n * PageUp/PageDown navigate the open list, Enter accepts or submits,\n * Escape/Tab close, Backspace at the caret's leftmost spot drops the last\n * entry.\n */\n #comboboxKeydown(e) {\n switch (e.code) {\n case 'ArrowUp':\n case 'ArrowDown': {\n e.preventDefault();\n this.#arrowKeydown(e);\n break;\n }\n case 'Home': {\n if (this.#ddmenu.shown) {\n e.preventDefault();\n this.#ddmenu.jump(true);\n }\n break;\n }\n case 'End': {\n if (this.#ddmenu.shown) {\n e.preventDefault();\n this.#ddmenu.jump(false);\n }\n break;\n }\n case 'PageDown':\n case 'PageUp': {\n if (this.#ddmenu.shown) {\n e.preventDefault();\n this.#ddmenu.page('PageDown' === e.code);\n }\n break;\n }\n case 'Escape': {\n this.#abortdload();\n this.#close();\n break;\n }\n //both physical Enter keys: the switch reads e.code, which tells the\n //numpad's apart, and the base submits from either one\n case 'NumpadEnter':\n case 'Enter': {\n if (!this.#ddmenu.shown) {\n //nothing to accept: the key is left alone and the base submits\n //the form, as it does for every field whose control is detached\n return;\n }\n e.preventDefault();\n this.#editing = false;\n this.#display();\n this.#ddmenu.acceptSelection();\n break;\n }\n case 'Backspace': {\n //only where there is no text to delete first, and nothing selected:\n //backspace belongs to the search until the caret runs out of it\n if (this.#input.selectionStart === 0 && this.#input.selectionEnd === 0) {\n this.#removeKeyAt(this.#values.size - 1);\n }\n break;\n }\n case 'Tab': {\n this.#abortdload();\n this.#close();\n break;\n }\n }\n }\n #arrowKeydown(e) {\n const forward = 'ArrowDown' === e.code;\n //alt-down opens, alt-up closes\n if (e.altKey) {\n if (forward && !this.#ddmenu.shown) {\n this.#open();\n } else if (!forward && this.#ddmenu.shown) {\n this.#close();\n }\n return;\n }\n this.#browse();\n this.#ddmenu.moveOrShow(forward, () => this.#loader.load(this.#input.value), [...this.#values.keys()]);\n }\n #close() {\n this.#ddmenu.hide();\n this.#editing = false;\n this.#display();\n }\n /**\n * Opens the dropdown over the entries matching the input: typing filters,\n * browsing starts from the whole vocabulary, the selected keys are always\n * highlighted.\n */\n #open() {\n this.#browse();\n return this.#ddmenu.show(() => this.#loader.load(this.#input.value), [...this.#values.keys()]);\n }\n #browse() {\n if (this.#editing) {\n return;\n }\n this.#input.value = '';\n }\n #display() {\n const entry = this.#values.values().next().value;\n this.#input.value = this.#multiple ? '' : (entry?.label ?? '');\n }\n /** The selection in its one vocabulary: the change detail and the items overlay both speak it. */\n #selection() {\n return [...this.#values.values()];\n }\n #changed() {\n //the detail carries the keys the value property answers with, as every\n //other field's does, and the labeled selection beside them\n this._notifyChange({ entry: this.entry });\n }\n #syncBadges() {\n const badges = this.#multiple\n ? Array.from(this.#values.entries()).map(([k, entry], index) => {\n const b = document.createElement('ful-badge');\n b.setAttribute('role', 'button');\n //a roving tab stop: without one the chips are reachable only from\n //the input's caret, so Tab never finds them\n b.setAttribute('tabindex', index === 0 ? '0' : '-1');\n b.setAttribute('value', k);\n b.innerText = entry.label;\n return b;\n })\n : [];\n for (const b of this.#control.querySelectorAll(':scope > ful-badge')) {\n b.remove();\n }\n this.#input.before(...badges);\n if (!this.#editing) {\n this.#display();\n }\n this.#items.replaceChildren();\n (this.#itemstemplate ?? this.template('items'))\n .withOverlay({ entries: this.#selection() })\n .renderTo(this.#items);\n }\n /**\n * Coerces a key to the type declared by `k-type`. Keys reach the element from\n * both worlds: the `value` attribute is text, a loader returns whatever its\n * endpoint carries. One canonical type keeps the internal Map, which compares\n * keys strictly, consistent. A key that does not decode is left as it is.\n */\n #coerceKey(k) {\n switch (this.declared('k-type')) {\n case 'number': {\n const n = k === '' ? Number.NaN : Number(k);\n return Number.isNaN(n) ? k : n;\n }\n case 'boolean': {\n if (k === true || k === 'true') {\n return true;\n }\n if (k === false || k === 'false') {\n return false;\n }\n return k;\n }\n default:\n return String(k);\n }\n }\n\n set value(vs) {\n //the csv mapper yields [] for an absent attribute; an empty string assigned\n //through the property is left alone, being a usable key for an <option value=\"\">\n const keys = (vs == null ? [] : Array.isArray(vs) ? vs : [vs]).map((k) => this.#coerceKey(k));\n //a key is what the value attribute carries, and that attribute is a comma\n //separated list: a key holding a comma cannot be written back into markup, so\n //a server rendered page could never preselect it. Said once and kept, rather\n //than split here, where splitting would quietly truncate a single select\n if (!this.#warnedComma && keys.some((k) => typeof k === 'string' && k.includes(','))) {\n //once per element, not once per page: a loop assigning bad keys to one\n //select is one mistake, where fifty selects holding one each are fifty\n this.#warnedComma = true;\n console.warn('a ful-select key cannot contain a comma: it is unexpressible in the value attribute', this);\n }\n //the keys are known synchronously and are all `value` reads, so they are applied\n //now: only the labels need the loader, until then a key stands in for its own\n this.#values = new Map(keys.map((k) => [k, { key: k, label: k, metadata: undefined }]));\n const claim = this.#assignments.take();\n if (!this.#control) {\n return;\n }\n this.#syncBadges();\n if (keys.length === 0) {\n return;\n }\n this.#resolve(keys, claim);\n }\n /**\n * Resolves the labels of the assigned keys. A failed lookup is left to reject so\n * that it is reported like any other failure: the keys stay applied either way.\n */\n async #resolve(keys, claim) {\n const entries = await this.#loader.exact(...keys);\n if (claim.stale) {\n //a newer assignment has been made in the meantime\n return;\n }\n //label the keys that are still selected: a removal made while the lookup was in\n //flight must not be undone by it, and a key the loader does not know is dropped\n //the loader keys are coerced too, so they line up with the assigned ones\n const resolved = new Map(entries.map((e) => [this.#coerceKey(e.key), e]));\n for (const key of keys) {\n if (!this.#values.has(key)) {\n continue;\n }\n if (resolved.has(key)) {\n this.#values.set(key, resolved.get(key));\n } else {\n this.#values.delete(key);\n }\n }\n this.#syncBadges();\n }\n get value() {\n if (this.#multiple) {\n return [...this.#values.keys()];\n }\n return [...this.#values.keys()][0] ?? null;\n }\n /** The selection as {key, label, metadata} entries, the change detail's vocabulary: the only one for a single select, every one when multiple. */\n get entry() {\n const selection = this.#selection();\n if (this.#multiple) {\n return selection;\n }\n return selection[0] ?? null;\n }\n #useItemList;\n get multiple() {\n return this.#multiple;\n }\n set multiple(v) {\n this.#multiple = v;\n this.reflectTo('multiple', v);\n }\n get itemList() {\n return this.#useItemList;\n }\n set itemList(v) {\n this.#useItemList = v;\n this.reflectTo('item-list', v);\n }\n}\n\nexport { Dropdown, Select, SelectLoader };\n","import { Attributes, Fragments } from '../../ftl/index.mjs';\nimport { Field } from './field.mjs';\n\n/** A group of radios declared as ful-radio children, a fieldset carrying the group semantics. */\nclass RadioGroup extends Field {\n static attributes = ['name', 'type'];\n static slots = true;\n static ROLE = 'radiogroup';\n static template = `\n <fieldset>\n <legend>\n {{{{ slots.default }}}}\n </legend>\n <header data-tpl-if=\"slots.header\">\n {{{{ slots.header }}}}\n </header>\n <ful-radio-list>\n <div class=\"label-wrapper\" data-tpl-each=\"inputsAndLabels\" data-tpl-var=\"ial\">\n <label>\n {{{{ ial[0] }}}}\n <div>{{{{ ial[1] }}}}</div>\n </label>\n </div>\n </ful-radio-list>\n <ful-field-error></ful-field-error>\n <footer data-tpl-if=\"slots.footer\">\n {{{{ slots.footer }}}}\n </footer>\n </fieldset>\n `;\n #fieldset;\n #firstRadio;\n #booleanType;\n /**\n * @param {{slots: any}} conf\n * @returns {any}\n */\n _build({ slots }) {\n const name = this.declared('name') ?? Attributes.uid('ful-radiogroup');\n const radioEls = Array.from(slots.default.querySelectorAll('ful-radio'));\n const inputsAndLabels = radioEls.map((el) => {\n const input = document.createElement('input');\n input.setAttribute('type', 'radio');\n Attributes.forward('input-', this, input);\n Attributes.forward('', el, input);\n input.setAttribute('name', `${name}-ignore`);\n input.setAttribute('form', ``);\n input.addEventListener('change', (evt) => {\n evt.stopPropagation();\n this._notifyChange();\n });\n const label = Fragments.fromChildNodes(el);\n return [input, label];\n });\n\n radioEls.forEach((el) => {\n el.remove();\n });\n const fragment = this.template().withOverlay({ name, slots, inputsAndLabels }).render();\n this.#fieldset = /** @type HTMLElement */ (fragment.firstElementChild);\n this.#firstRadio = fragment.querySelector('input[type=radio]');\n this.#booleanType = this.declared('type') === 'boolean';\n //the group claims through its own fieldset, which carries disabled like a\n //native control, is the piece readonly freezes (radios have no editable\n //text to preserve) and announces the requirement; focus stays on the first radio,\n //and the host itself is described, there being no single control to name\n //and the legend being a fieldset's own label\n return {\n fragment,\n control: this.#firstRadio,\n error: fragment.querySelector('ful-field-error'),\n described: this,\n claims: this.#fieldset,\n //the radiogroup role is the host's, so the claims announce there: a\n //fieldset is a group, which accepts neither aria-readonly nor\n //aria-required\n announces: this,\n freeze: this.#fieldset,\n };\n }\n get value() {\n /** @type {HTMLInputElement|null} */\n const checked = this.querySelector('input[type=radio]:checked');\n return checked ? (this.#booleanType ? checked.value === 'true' : checked.value) : null;\n }\n set value(value) {\n const radios = this.querySelectorAll(`input[type=radio]`);\n const clear = () => {\n radios.forEach((el) => {\n /** @type {HTMLInputElement} */ (el).checked = false;\n });\n };\n if (value === null) {\n clear();\n return;\n }\n /** @type {HTMLInputElement|null} */\n const el = this.querySelector(`input[type=radio][value=${CSS.escape(String(value))}]`);\n //an unknown key clears, like a null assignment and like the select's\n //unknown keys: a stale radio must not keep answering for it\n if (el === null) {\n clear();\n return;\n }\n el.checked = true;\n }\n}\n\nexport { RadioGroup };\n","import { Attributes } from '../../ftl/index.mjs';\nimport { Field } from './field.mjs';\n\n/** A checkbox, or a switch under the type=switch claim. */\nclass Checkbox extends Field {\n static attributes = ['type'];\n static observed = ['value:bool'];\n static slots = true;\n static template = `\n <ful-choice data-tpl-switch=\"isSwitch\">\n <input type=\"checkbox\" data-tpl-role=\"isSwitch ? 'switch' : false\" form=\"\" placeholder=\" \">\n <label>{{{{ slots.default }}}}</label>\n {{{{ slots.info }}}}\n </ful-choice>\n <ful-field-error></ful-field-error>\n `;\n #container;\n #input;\n _build({ slots }) {\n const isSwitch = this.declared('type') === 'switch';\n const fragment = this.template().withOverlay({ slots, isSwitch }).render();\n this.#container = fragment.firstElementChild;\n this.#input = fragment.querySelector('input');\n Attributes.forward('input-', this, this.#input);\n this.#input.addEventListener('change', (evt) => {\n evt.stopPropagation();\n this._notifyChange();\n });\n //the base points the label at the input with for/id, so the click toggles\n //the way it does in a plain form: the input's own change listener above\n //carries the notification, and readonly is refused by the freeze below\n const label = fragment.querySelector('label');\n //a checkbox has no editable text to preserve, so readonly freezes the\n //whole choice, label click included: the container is the frozen piece\n return {\n fragment,\n control: this.#input,\n error: fragment.querySelector('ful-field-error'),\n label,\n freeze: this.#container,\n };\n }\n get value() {\n return this.#input.checked;\n }\n set value(value) {\n this.#input.checked = value;\n }\n}\n\nexport { Checkbox };\n","import { Attributes, Fragments, Nodes, ParsedElement, Rendering } from '../../ftl/index.mjs';\nimport { Claims } from '../claims.mjs';\nimport { Failure } from '../../httpc/index.mjs';\n\n/** The sort control of a table header: focusable, keyboard-activated, walking asc, desc, unsorted. */\nclass SortButton extends ParsedElement {\n static attributes = ['sorter'];\n static observed = ['order'];\n #order;\n render() {\n const sorter = this.declared('sorter');\n const orders = ['asc', 'desc', null];\n this.setAttribute('role', 'button');\n this.setAttribute('tabindex', '0');\n this.addEventListener('click', () => {\n const nextOrder = orders[(orders.indexOf(this.order) + 1) % 3];\n this.dispatchEvent(\n new CustomEvent('sort:requested', {\n bubbles: true,\n cancelable: true,\n detail: {\n value: { sorter, order: nextOrder },\n },\n }),\n );\n });\n this.addEventListener('keydown', (/** @type any */ evt) => {\n if (evt.code !== 'Enter' && evt.code !== 'Space') {\n return;\n }\n evt.preventDefault();\n this.click();\n });\n }\n\n get order() {\n return this.#order || null;\n }\n\n set order(value) {\n this.#order = value || null;\n this.reflectTo('order', this.#order);\n //the column announces the sort, not this button: an attribute on another\n //element is not a reflection and has no business inside the guard\n const th = this.closest('th');\n if (!th) {\n return;\n }\n Attributes.set(th, 'aria-sort', this.#order ? ('asc' === this.#order ? 'ascending' : 'descending') : null);\n }\n}\n\n/** The pager: a window of page links around the current one, and the reload control. */\nclass Pagination extends ParsedElement {\n static observed = ['total:number', 'current:number'];\n static attributes = ['pages:number'];\n static config = {\n prevIcon: 'chevron-left',\n nextIcon: 'chevron-right',\n reloadIcon: 'arrow-clockwise',\n };\n static template = `\n <ful-pagination-bar role=\"navigation\" data-tpl-aria-label=\"#l10n:t('pagination.navigation')\">\n <ul>\n <li data-ref=\"index\"> {{ #l10n:t('pagination.showing', { 'current': curr.label, 'total': total }) }}</li>\n <li data-ref=\"reload\"><button type=\"button\" data-tpl-aria-label=\"#l10n:t('pagination.reload')\"><ful-icon data-tpl-name=\"config.reloadIcon\" aria-hidden=\"true\"></ful-icon></button></li>\n <li data-ref=\"prev\">\n <button type=\"button\" data-tpl-disabled=\"prev.enabled ? false : true\" data-tpl-aria-label=\"#l10n:t('pagination.previous')\" data-tpl-data-page=\"prev.index\">\n <ful-icon data-tpl-name=\"config.prevIcon\" aria-hidden=\"true\"></ful-icon>\n </button>\n </li>\n <li data-ref=\"page\" data-tpl-each=\"pages\" data-tpl-var=\"page\">\n <button type=\"button\" data-tpl-aria-current=\"curr.index == page.index ? 'page' : false\" data-tpl-data-page=\"page.index\" >\n {{ page.label }}\n </button>\n </li>\n <li data-ref=\"next\">\n <button type=\"button\" data-tpl-disabled=\"next.enabled ? false : true\" data-tpl-aria-label=\"#l10n:t('pagination.next')\" data-tpl-data-page=\"next.index\">\n <ful-icon data-tpl-name=\"config.nextIcon\" aria-hidden=\"true\"></ful-icon>\n </button>\n </li>\n </ul>\n </ful-pagination-bar>\n `;\n #total = 0;\n #current = 0;\n render() {\n this.addEventListener('click', (/** @type any */ evt) => {\n const el = evt.target.closest('button');\n if (!el || el.hasAttribute('disabled')) {\n //a disabled button leads nowhere: the page it would ask for does not exist\n return;\n }\n if (el.getAttribute('aria-current') === 'page') {\n //the page already shown stays focusable and announced, so it is a\n //real control: it just has nothing to ask for\n return;\n }\n this.dispatchEvent(\n new CustomEvent('page:requested', {\n bubbles: true,\n cancelable: true,\n detail: {\n value: Number(el.dataset.page ?? this.#current),\n },\n }),\n );\n });\n }\n /**\n * Moves the pager to a page, a page count, or both, and repaints once. The\n * two are one state: writing them one at a time repainted the bar twice per\n * load, the first pass drawing the new page against the old count.\n * @param {{ current?: number|null, total?: number|null }} [state]\n */\n update({ current: toCurrent, total: toTotal } = {}) {\n if (toCurrent !== undefined) {\n this.#current = toCurrent ?? 0;\n }\n if (toTotal !== undefined) {\n this.#total = toTotal ?? 0;\n }\n this.reflectTo('current', this.#current);\n this.reflectTo('total', this.#total);\n const current = this.#current;\n const total = this.#total;\n const maxRender = this.declared('pages') ?? 5;\n //an empty table is one empty page: everything downstream renders it like\n //any single page result\n const pageCount = Math.max(total, 1);\n const hasPrev = current > 0;\n const hasNext = current + 1 < pageCount;\n //a disabled arrow carries no page: there is nothing valid for it to point at\n const prev = { index: hasPrev ? current - 1 : null, enabled: hasPrev };\n const curr = { index: current, label: current + 1 };\n const next = { index: hasNext ? current + 1 : null, enabled: hasNext };\n //the window holds at most maxRender pages, centered on the current one and slid\n //back towards the end so it stays full on the last pages\n const rendered = Math.max(1, Math.min(maxRender, pageCount));\n const first = Math.max(0, Math.min(current - Math.floor((rendered - 1) / 2), pageCount - rendered));\n const pages = Array.from({ length: rendered }, (_, offset) => ({\n index: first + offset,\n label: first + offset + 1,\n }));\n //the whole bar is replaced, so the control the reader activated is gone\n //by the time the new one paints: the focus follows it to its equivalent\n const focused = this.contains(document.activeElement)\n ? /** @type HTMLElement */ (document.activeElement).closest('li')?.getAttribute('data-ref')\n : null;\n const page = focused === 'page' ? /** @type any */ (document.activeElement).dataset.page : null;\n this.template().withOverlay({ total: pageCount, prev, curr, next, pages }).renderTo(this);\n if (!focused) {\n return;\n }\n const back =\n (page === null ? null : this.querySelector(`li[data-ref=page] button[data-page=\"${page}\"]`)) ??\n this.querySelector(`li[data-ref=${focused}] button:not(:disabled)`) ??\n this.querySelector('li[data-ref=page] button[aria-current=page]');\n /** @type HTMLElement */ (back)?.focus();\n }\n get total() {\n return this.#total;\n }\n set total(value) {\n //an absent attribute declares no pages, not a NaN one\n this.update({ total: value });\n }\n get current() {\n return this.#current;\n }\n set current(value) {\n this.update({ current: value });\n }\n}\n\n/** Reads the schema declaration into the header and row templates a table renders from. */\nclass TableSchemaParser {\n static parse(nodeOrFragment, template) {\n //nodeOrFragment is undefined when the slot is missing altogether\n const schema = nodeOrFragment ? Nodes.queryChildren(nodeOrFragment, 'schema') : null;\n if (!schema) {\n throw new Error('missing expected <schema>: ful-table needs a <template slot=\"schema\"> holding one');\n }\n const headersTr = document.createElement('tr');\n const rowsTr = document.createElement('tr');\n rowsTr.setAttribute('data-tpl-each', 'rows');\n for (const attr of schema.getAttributeNames()) {\n const value = schema.getAttribute(attr);\n headersTr.setAttribute(attr, value ?? '');\n rowsTr.setAttribute(attr, value ?? '');\n }\n const columns = Nodes.queryChildrenAll(schema, 'column');\n //only a sortable column carries the initial sort: an order without its\n //sorter would ask the backend for a \"null\" property\n const sort =\n columns\n .filter((v) => v.hasAttribute('order') && v.hasAttribute('sorter'))\n .map((v) => ({ sorter: v.getAttribute('sorter'), order: v.getAttribute('order') }))[0] ?? null;\n for (var column of columns) {\n const maybeTitleTag = Nodes.queryChildren(column, 'title');\n const sorter = column.getAttribute('sorter');\n const order = column.getAttribute('order');\n const titleNode = maybeTitleTag ?? document.createTextNode(column.getAttribute('title') ?? '');\n maybeTitleTag?.remove();\n column.removeAttribute('sorter');\n column.removeAttribute('order');\n column.removeAttribute('title');\n const wrappedTitleNode =\n !sorter && !order\n ? titleNode\n : (() => {\n const fulSorter = document.createElement('ful-sorter');\n if (sorter) {\n fulSorter.setAttribute('sorter', sorter);\n }\n if (order) {\n fulSorter.setAttribute('order', order);\n }\n fulSorter.append(titleNode);\n return fulSorter;\n })();\n const th = document.createElement('th');\n const td = document.createElement('td');\n //a column's attributes land on both cells, so a `data-tpl-*` written\n //once applies to the header and the body alike. `inHeaders` and\n //`inRows` are how an author tells them apart when that is not what\n //they meant: both templates carry the pair, so a column can say\n //`data-tpl-if=\"inRows\"` and appear in the body only\n for (const attr of column.getAttributeNames()) {\n const value = column.getAttribute(attr);\n th.setAttribute(attr, value ?? '');\n td.setAttribute(attr, value ?? '');\n }\n th.append(wrappedTitleNode);\n td.append(...column.childNodes);\n headersTr.append(th);\n rowsTr.append(td);\n }\n\n return {\n headersTemplate: template\n .withOverlay({ inHeaders: true, inRows: false })\n .withFragment(Fragments.from(headersTr)),\n rowsTemplate: template.withOverlay({ inHeaders: false, inRows: true }).withFragment(Fragments.from(rowsTr)),\n sort: sort,\n length: columns.length,\n };\n }\n}\n\n/** Serves a table's rows from an array held in memory, applying the sort and the paging itself. */\nclass InMemoryTableLoader {\n #data;\n constructor(data) {\n this.#data = data;\n }\n async load(pageRequest, sortRequest, filterRequest) {\n //the header renders a sorter per sortable column whatever the loader is,\n //so the local one answers it rather than leaving it inert\n const rows = this.#sorted(sortRequest);\n const begin = pageRequest.page * pageRequest.size;\n const end = begin + pageRequest.size;\n const page = rows.slice(begin, end);\n const totalElements = rows.length;\n return {\n data: page,\n size: totalElements,\n };\n }\n #sorted(sortRequest) {\n if (!sortRequest?.sorter) {\n return this.#data;\n }\n const { sorter, order } = sortRequest;\n const sign = order === 'desc' ? -1 : 1;\n return [...this.#data].sort((l, r) => {\n const a = l?.[sorter];\n const b = r?.[sorter];\n if (a === b) {\n return 0;\n }\n //a missing value sorts last whichever way the column points\n if (a == null) {\n return 1;\n }\n if (b == null) {\n return -1;\n }\n return (a < b ? -1 : 1) * sign;\n });\n }\n update(data) {\n this.#data = data;\n }\n}\n\n/** Requests one page of rows from a url, passing the page, the sort and the filters to the endpoint. */\nclass RemoteTableLoader {\n #http;\n #url;\n #method;\n #responseMapper;\n constructor(http, url, method, responseMapper = (response) => response) {\n this.#http = http;\n this.#url = url;\n this.#method = method;\n this.#responseMapper = responseMapper;\n }\n async load(pageRequest, sortRequest, filterRequest) {\n const filters = Object.entries(filterRequest).filter(([k, v]) => v);\n return await this.#http\n .request(this.#method, this.#url)\n .param('page', pageRequest.page)\n .param('size', pageRequest.size)\n .param('sort', sortRequest ? `${sortRequest.sorter},${sortRequest.order}` : null)\n .param('filters', filters.length > 0 ? JSON.stringify(Object.fromEntries(filters)) : null)\n .fetchJson()\n .then((response) => this.#responseMapper(response));\n }\n}\n\n/**\n * Builds the table's loader from its attributes: an in-memory one, or the\n * remote loader over src.\n *\n * A component registered under the `loader` attribute replaces this one and\n * must implement `load(pageRequest, sortRequest, filterRequest)`, answering\n * `{ data, page, size }` for the requested page. `pageRequest` carries the page\n * index and its size, `sortRequest` the column and direction, and\n * `filterRequest` the values of the filters in the slot.\n */\nclass TableLoader {\n static create(el, conf) {\n const url = el.getAttribute('src');\n if (url) {\n const http = el.component('http-client');\n const method = el.getAttribute('method') ?? 'GET';\n const responseMapper = el.hasAttribute('response-mapper')\n ? el.component(el.getAttribute('response-mapper'))\n : (/** @type any */ response) => response;\n return new RemoteTableLoader(http, url, method, responseMapper);\n }\n return new InMemoryTableLoader([]);\n }\n}\n\n/** A table loading its rows from a loader, with sorting, pagination and an optional filter form. */\nclass Table extends ParsedElement {\n static attributes = ['loader', 'autoload:presence'];\n /**\n * The page size stays live: a rows-per-page control is a normal thing to\n * put next to a table, and the size is the one piece of the request an\n * author changes after the table is up. The rest of the request is the\n * table's own state, moved by the pager, the sorters and the filter form.\n */\n static observed = ['page-size:number'];\n static slots = true;\n static config = {\n searchIcon: 'search',\n };\n static template = `\n <ful-form data-tpl-if=\"slots.filters\">\n {{{{ slots.filters }}}}\n </ful-form>\n <ful-table-wrapper>\n <table>\n <caption data-tpl-if=\"slots.caption\">{{{{ slots.caption }}}}</caption>\n <thead></thead>\n <tbody></tbody>\n <tbody data-ref=\"initial\">\n <tr>\n <td data-tpl-colspan=\"schema.length\">\n <div>\n <p data-tpl-if=\"config.searchIcon\"><ful-icon data-tpl-name=\"config.searchIcon\" aria-hidden=\"true\"></ful-icon></p>\n {{ #l10n:t('table.initial') }}\n </div>\n </td>\n </tr>\n </tbody>\n <tbody data-ref=\"loading\" hidden>\n <tr>\n <td data-tpl-colspan=\"schema.length\">\n <ful-spinner class=\"big\" role=\"status\"><span class=\"ful-sr-only\">{{ #l10n:t('spinner.loading') }}</span></ful-spinner>\n </td>\n </tr>\n </tbody>\n <tbody data-ref=\"feedback\" hidden>\n <tr>\n <td data-tpl-colspan=\"schema.length\">\n <div role=\"alert\">\n <p>{{ #l10n:t('table.error') }}</p>\n <div data-ref=\"feedback-error\"></div>\n </div>\n </td>\n </tr>\n </tbody>\n <tfoot data-tpl-if=\"slots.footer\">\n {{{{ slots.footer }}}}\n </tfoot>\n </table>\n </ful-table-wrapper>\n <ful-pagination current=\"0\" total=\"1\"></ful-pagination>\n `;\n static templates = {\n row: `\n <tr data-tpl-if=\"pageResponse.data.length == 0\">\n <td data-tpl-colspan=\"schema.length\">\n {{ #l10n:t('table.no-data') }}\n </td>\n </tr>\n {{{{ schema.rowsTemplate.withOverlay({'rows': pageResponse.data}).render() }}}}\n `,\n };\n #loader;\n #schema;\n #body;\n #loading;\n #noAutoload;\n #feedback;\n #paginator;\n #sorters;\n //initialised before the render so the size can be read and written on an\n //element the page has only just created\n /** @type {{ pageRequest: { page: number, size: number }, sortRequest: any, filterRequest: any }} */\n #latestRequest = { pageRequest: { page: 0, size: 10 }, sortRequest: null, filterRequest: {} };\n /** whether a load has been asked for, by autoload or by a caller */\n #loadRequested = false;\n #loads = new Claims();\n /** How many rows a page asks the loader for: the size the next load will carry. */\n get pageSize() {\n return this.#latestRequest.pageRequest.size;\n }\n /**\n * Changes the page size and reloads from the first page, the current index\n * meaning nothing under a new size. A table that has not loaded yet only\n * records it: writing the size is not a request to start loading, which is\n * what `autoload` and `reload()` are for.\n *\n * Absent or null is the default of ten, so removing the attribute restores\n * it rather than asking the loader for NaN rows.\n */\n set pageSize(value) {\n const size = value ?? 10;\n if (size === this.#latestRequest.pageRequest.size) {\n return;\n }\n this.#latestRequest = { ...this.#latestRequest, pageRequest: { page: 0, size } };\n if (!this.#loadRequested) {\n return;\n }\n //the rejection escapes on purpose, as it does for the page, sort and\n //filter listeners: load renders its own error state and the unhandled\n //rejection is what reports the failure\n this.reload();\n }\n async render({ slots }) {\n const template = this.template();\n const schema = TableSchemaParser.parse(slots.schema, template);\n const fragment = template.withOverlay({ slots, schema }).render();\n const tableWrapper = /** @type HTMLTableElement */ (Nodes.queryChildren(fragment, 'ful-table-wrapper'));\n const table = /** @type HTMLTableElement */ (tableWrapper.querySelector('table'));\n Attributes.forward('table-', this, table);\n this.#loader = this.component(this.declared('loader') ?? 'loaders:table').create(this);\n\n this.#schema = schema;\n this.#body = table.querySelector(':scope > tbody');\n this.#loading = table.querySelector(':scope > tbody[data-ref=loading]');\n this.#noAutoload = table.querySelector(':scope > tbody[data-ref=initial]');\n this.#feedback = table.querySelector(':scope > tbody[data-ref=feedback]');\n this.#paginator = Nodes.queryChildren(fragment, 'ful-pagination');\n this.replaceChildren(fragment);\n const thead = /** @type HTMLTableSectionElement */ (this.querySelector('thead'));\n schema.headersTemplate.renderTo(thead);\n this.#sorters = thead.querySelectorAll('ful-sorter');\n await Rendering.waitForChildren(this);\n\n const maybeForm = /** @type any */ (Nodes.queryChildren(this, 'ful-form'));\n //the declared size lands here rather than through the setter: the base\n //applies the observed values after the render returns, and by then the\n //autoload below has already asked for the first page\n this.#latestRequest = {\n pageRequest: {\n page: 0,\n size: this.declared('page-size') ?? 10,\n },\n sortRequest: schema.sort,\n filterRequest: maybeForm?.values ?? {},\n };\n //the page, sort and filter listeners let load's rejection escape on purpose:\n //load renders its own error state, and the unhandled rejection is what\n //reports the failure (the autoload below reports the same way)\n maybeForm?.addEventListener('submit:success', async (evt) => {\n await this.load(\n {\n page: 0,\n size: this.#latestRequest.pageRequest.size,\n },\n this.#latestRequest.sortRequest,\n evt.detail.request,\n );\n });\n this.addEventListener('page:requested', async (/** @type any */ e) => {\n await this.load(\n {\n page: e.detail.value,\n size: this.#latestRequest.pageRequest.size,\n },\n this.#latestRequest.sortRequest,\n this.#latestRequest.filterRequest,\n );\n });\n this.addEventListener('sort:requested', async (/** @type any */ e) => {\n const sortRequest = e.detail.value.order ? e.detail.value : null;\n await this.load(this.#latestRequest.pageRequest, sortRequest, this.#latestRequest.filterRequest);\n //only the load that still owns the table commits the header: a superseded\n //sort must not wipe the arrows of the one that won, and a failed one\n //leaves them where they were\n if (this.#latestRequest.sortRequest !== sortRequest) {\n return;\n }\n this.#sorters.forEach((s) => {\n s.order = null;\n });\n e.target.order = e.detail.value.order;\n });\n if (this.declared('autoload')) {\n //not awaited: the first load must not hold up the upgrade, and a loader that\n //fails or never answers must not keep ftl:ready from firing for the page.\n //load renders its own error state and lets the failure reject, so it is reported\n this.reload();\n }\n }\n\n async reload() {\n return await this.load(\n this.#latestRequest.pageRequest,\n this.#latestRequest.sortRequest,\n this.#latestRequest.filterRequest,\n );\n }\n async load(pageRequest, sortRequest, filterRequest) {\n //marked before the await, not when a response comes back: a size written\n //while the first load is still in flight has to reload rather than be\n //overwritten by the answer to the request it replaced\n this.#loadRequested = true;\n //each load claims the table: a response resolving after a newer load has\n //started is stale, and neither renders nor updates the request a later\n //reload replays, whichever order the responses arrive in\n const claim = this.#loads.take();\n this.#body.replaceChildren();\n this.#loading.removeAttribute('hidden');\n this.#feedback.setAttribute('hidden', '');\n this.#noAutoload.setAttribute('hidden', '');\n this.setAttribute('aria-busy', 'true');\n try {\n const pageResponse = await this.#loader.load(pageRequest, sortRequest, filterRequest);\n if (claim.stale) {\n return;\n }\n this.#latestRequest = { pageRequest, sortRequest, filterRequest };\n this.#update(pageRequest, sortRequest, filterRequest, pageResponse);\n } catch (/** @type any */ error) {\n if (claim.stale) {\n //the newer load owns the table and its outcome: a superseded\n //failure is neither shown nor thrown\n return;\n }\n this.#loading.setAttribute('hidden', '');\n this.#feedback.removeAttribute('hidden');\n this.#feedback.querySelector('[data-ref=feedback-error]').textContent = Failure.problemsText(\n error,\n `${error}`,\n );\n throw error;\n } finally {\n //a superseded load owns nothing, the newer one's busy state included\n if (!claim.stale) {\n this.removeAttribute('aria-busy');\n }\n }\n }\n /** Hands the loader to the callback, for runtime reconfigurations. */\n async withLoader(fn) {\n return await fn(this.#loader);\n }\n async resetWithFilter(filterRequest) {\n return await this.load(\n {\n page: 0,\n size: this.#latestRequest.pageRequest.size,\n },\n this.#latestRequest.sortRequest,\n filterRequest,\n );\n }\n #update(pageRequest, sortRequest, filterRequest, pageResponse) {\n const pages = Math.ceil(pageResponse.size / pageRequest.size);\n const lastPage = Math.max(0, pages - 1);\n if (pageRequest.page > lastPage) {\n //the data shrank behind the page being answered: the last page that\n //still exists is loaded instead of an out-of-range empty one\n this.load({ page: lastPage, size: pageRequest.size }, sortRequest, filterRequest);\n return;\n }\n this.#loading.setAttribute('hidden', '');\n this.#body.replaceChildren(\n this.template('row')\n .withOverlay({\n schema: this.#schema,\n pageRequest,\n filterRequest,\n pageResponse,\n })\n .render(),\n );\n //one move, one repaint: the page and the count are the same state\n this.#paginator.update({ current: pageRequest.page, total: pages });\n }\n}\n\nexport { TableLoader, SortButton, Table, TableSchemaParser, Pagination };\n","import { Attributes } from '../../ftl/index.mjs';\nimport { Anchors } from '../disclosures/anchors.mjs';\n\n/**\n * An invoker button paired with the `ul[popover][role=menu]` that follows it:\n * the chrome behind every filter's operator, sensitivity and boolean value.\n *\n * It fills the menu from a vocabulary, wires it the first time more than one\n * choice survives the whitelist, pins the button to a static glyph when a\n * single one does, owns the roving focus and the Escape/Enter handling, and\n * keeps the button's value, glyph and aria-label in step. A pick that changes\n * the value calls back; the host decides what that means.\n *\n * The button's `value` attribute is the store, as it is for a native control:\n * the menu protocol finds the current item by it, and nothing mirrors it.\n */\nclass ChoiceButton {\n /** The declared choices narrowed to a vocabulary; an empty or unknown set means all of it. */\n static narrow(declared, vocabulary) {\n const narrowed = (declared ?? []).filter((choice) => vocabulary.includes(choice));\n return narrowed.length > 0 ? narrowed : [...vocabulary];\n }\n #button;\n #menu;\n #vocabulary;\n #glyphs;\n #labelFor;\n #display;\n #interactive;\n #onPick;\n #allowed;\n #claimed = false;\n #wired = false;\n /**\n * @param {HTMLElement} button the invoker, whose next sibling is its menu\n * @param {{vocabulary: string[], glyphs?: Record<string,string>, labelFor?: (v: string) => string,\n * display?: ((v: string) => string)|null, interactive?: () => boolean, onPick?: (v: string) => void}} conf\n */\n constructor(\n button,\n { vocabulary, glyphs = {}, labelFor = (v) => v, display = null, interactive = () => true, onPick = () => {} },\n ) {\n this.#button = button;\n this.#menu = /** @type HTMLElement */ (button.nextElementSibling);\n this.#vocabulary = vocabulary;\n this.#glyphs = glyphs;\n this.#labelFor = labelFor;\n //the button shows the compact glyph by default; a menu whose choices have\n //no glyph shows the word instead\n this.#display = display ?? ((choice) => glyphs[choice] ?? choice);\n this.#interactive = interactive;\n this.#onPick = onPick;\n this.#allowed = [...vocabulary];\n this.#menu.addEventListener('click', (evt) => {\n const target = /** @type HTMLElement */ (evt.target);\n const item = /** @type HTMLElement | null */ (target.closest('li > a'));\n if (!item || !this.#interactive()) {\n return;\n }\n const picked = /** @type string */ (item.getAttribute('value'));\n const previous = this.value;\n this.value = picked;\n /** @type any */ (this.#menu).hidePopover?.();\n if (previous !== picked) {\n this.#onPick(picked);\n }\n });\n }\n /** The choices the host declared, narrowed to the vocabulary; an empty or unknown set means all of it. */\n get allowed() {\n return this.#allowed;\n }\n set allowed(declared) {\n this.#allowed = ChoiceButton.narrow(declared, this.#vocabulary);\n this.#fill();\n if (!this.#wired && this.#allowed.length > 1) {\n this.#wire();\n this.#wired = true;\n }\n this.#sync();\n if (this.pinned) {\n this.value = this.#allowed[0];\n }\n }\n /** A single surviving choice pins the button: a static glyph, no popup, and every read answers it. */\n get pinned() {\n return this.#allowed.length < 2;\n }\n get value() {\n return this.#button.getAttribute('value');\n }\n set value(choice) {\n this.#button.setAttribute('value', choice);\n //the button carries the compact glyph, announced through its label: the\n //menu is where the localized words live\n this.#button.textContent = this.#display(choice);\n Attributes.set(this.#button, 'aria-label', this.#labelFor(choice));\n }\n /** The host's disabled claim, composed with the pin: lifting one cannot lift the other. */\n set claimed(claimed) {\n this.#claimed = claimed;\n this.#sync();\n }\n #fill() {\n this.#menu.replaceChildren(\n ...this.#allowed.map((choice) => {\n const li = document.createElement('li');\n li.setAttribute('role', 'none');\n const a = document.createElement('a');\n a.setAttribute('role', 'menuitem');\n a.setAttribute('tabindex', '-1');\n a.setAttribute('value', choice);\n const word = this.#labelFor(choice);\n const glyph = this.#glyphs[choice] ?? choice;\n if (word === choice && glyph === choice) {\n a.innerText = choice;\n } else {\n const glyphSpan = document.createElement('span');\n glyphSpan.innerText = glyph;\n const wordSpan = document.createElement('span');\n wordSpan.innerText = word;\n a.append(glyphSpan, wordSpan);\n }\n li.append(a);\n return li;\n }),\n );\n }\n #sync() {\n const pinned = this.pinned;\n this.#button.toggleAttribute('disabled', pinned || this.#claimed);\n Attributes.set(this.#button, 'aria-haspopup', pinned ? null : 'true');\n Attributes.set(this.#button, 'aria-expanded', pinned ? null : 'false');\n if (pinned) {\n this.#button.removeAttribute('popovertarget');\n } else if (this.#menu.id) {\n //the menu is wired once, its link is what a pin may break: lifting the\n //pin re-links the invoker to the menu it already owns\n this.#button.setAttribute('popovertarget', this.#menu.id);\n }\n }\n #items() {\n return Array.from(this.#menu.querySelectorAll('li > a'), (a) => /** @type HTMLAnchorElement */ (a));\n }\n #wire() {\n const button = this.#button;\n const menu = this.#menu;\n Anchors.wire(button, menu, { prefix: 'ful-filter-menu', invoke: true, expanded: true });\n menu.addEventListener('toggle', (/** @type any */ evt) => {\n if (evt.newState !== 'open') {\n //give the invoker back the focus the menu had borrowed, without\n //stealing it from wherever else the close came from\n if (menu.contains(document.activeElement)) {\n button.focus();\n }\n return;\n }\n const items = this.#items();\n (items.find((a) => a.getAttribute('value') === this.value) ?? items[0])?.focus();\n });\n menu.addEventListener('keydown', (evt) => {\n const target = /** @type HTMLElement */ (evt.target);\n const item = /** @type HTMLAnchorElement | null */ (target.closest('li > a'));\n if (!item) {\n return;\n }\n const items = this.#items();\n const at = items.indexOf(item);\n switch (evt.code) {\n case 'ArrowDown': {\n evt.preventDefault();\n items[(at + 1) % items.length]?.focus();\n break;\n }\n case 'ArrowUp': {\n evt.preventDefault();\n items[(at - 1 + items.length) % items.length]?.focus();\n break;\n }\n case 'Home': {\n evt.preventDefault();\n items[0]?.focus();\n break;\n }\n case 'End': {\n evt.preventDefault();\n items[items.length - 1]?.focus();\n break;\n }\n case 'Enter':\n case 'Space': {\n evt.preventDefault();\n item.click();\n button.focus();\n break;\n }\n case 'Escape': {\n //the platform's close request hides the menu, the focus is placed\n //on the invoker before the focused item is detached from it\n button.focus();\n break;\n }\n }\n });\n }\n}\n\nexport { ChoiceButton };\n","import { Localization } from '../../ftl/index.mjs';\nimport { ChoiceButton } from './choice-button.mjs';\nimport { Field } from './field.mjs';\nimport { Instant } from './temporals.mjs';\nimport { Input } from './input.mjs';\n\nconst GLYPHS = {\n EQ: '=',\n NEQ: '≠',\n LT: '<',\n GT: '>',\n LTE: '≤',\n GTE: '≥',\n BETWEEN: '↔',\n CONTAINS: '…a…',\n STARTS_WITH: 'a…',\n ENDS_WITH: '…a',\n};\nconst COMPARE_OPERATORS = ['EQ', 'NEQ', 'LT', 'GT', 'LTE', 'GTE', 'BETWEEN'];\nconst TEXT_OPERATORS = [...COMPARE_OPERATORS, 'CONTAINS', 'STARTS_WITH', 'ENDS_WITH'];\nconst SENSITIVITIES = ['IGNORE_CASE', 'CASE_SENSITIVE'];\n\nconst SENSITIVITY_GLYPHS = {\n IGNORE_CASE: 'aa',\n CASE_SENSITIVE: 'Aa',\n};\n\n/** the labels live in the built-in translations, resolved through the same localization every template uses */\nconst { t } = Localization.of();\nconst operatorLabel = (op) => t(`filters.op.${op}`);\nconst sensitivityLabel = (sensitivity) => t(`filters.sensitivity.${sensitivity}`);\nconst booleanValueLabel = (token) => t(token === '' ? 'filters.boolean.any' : `filters.boolean.${token}`);\n\n/**\n * The shared shape of every operator-and-operands filter: an operator menu, one\n * or two operands of the type the subclass declares, and a tuple that mirrors\n * the data-jpa compare annotations.\n */\nclass CompareFilter extends Input {\n static observed = ['value:json', 'operators:csv'];\n static OPERATORS = COMPARE_OPERATORS;\n static DEFAULT_OPERATOR = 'EQ';\n static template = `\n <label>{{{{ slots.default }}}}</label>\n {{{{ slots.info }}}}\n <ful-control-group>\n <ful-affix data-tpl-if=\"slots.before\">{{{{ slots.before }}}}</ful-affix>\n <ful-affix>\n <button data-ref=\"operator\" type=\"button\" form=\"\" aria-expanded=\"false\" aria-haspopup=\"true\"></button>\n <ul popover role=\"menu\"></ul>\n </ful-affix>\n <ful-control>\n <input data-ref=\"value1\" data-tpl-type=\"type\" form=\"\">\n <input data-ref=\"value2\" data-tpl-type=\"type\" form=\"\" hidden>\n </ful-control>\n <ful-affix data-tpl-if=\"slots.after\">{{{{ slots.after }}}}</ful-affix>\n </ful-control-group>\n <ful-field-error></ful-field-error>\n `;\n _operator;\n _container;\n _value1;\n _value2;\n _build(conf) {\n const pieces = super._build(conf);\n const fragment = pieces.fragment;\n this._container = fragment.querySelector('ful-control-group');\n this._value1 = fragment.querySelector('[data-ref=value1]');\n this._value2 = fragment.querySelector('[data-ref=value2]');\n this._operator = new ChoiceButton(/** @type HTMLElement */ (fragment.querySelector('[data-ref=operator]')), {\n vocabulary: this._vocabulary(),\n glyphs: GLYPHS,\n labelFor: operatorLabel,\n interactive: () => this._interactive(),\n onPick: () => {\n this._syncBetween();\n this._notifyChange();\n },\n });\n //the default operator below reads the whitelist, so it is resolved here\n //rather than waiting for the base's declared pass\n this.operators = this.declared('operators');\n //Input.render only re-dispatches changes coming from the first operand\n this._value2.addEventListener('change', (evt) => {\n evt.stopPropagation();\n this._notifyChange();\n });\n if (this._operator.value === null) {\n this._showDefaultOperator();\n }\n //the second operand mirrors the claims like the first one does, and the\n //freeze reaches the operator and sensitivity buttons, whose popovers an\n //input's readOnly cannot touch\n return { ...pieces, freeze: this._container, also: [this._value2] };\n }\n _showDefaultOperator() {\n const preferred = this._defaultOperator();\n const allowed = this._operator.allowed;\n this._showOperator(allowed.includes(preferred) ? preferred : allowed[0]);\n }\n formResetCallback() {\n //a declared tuple restores its operator through the base's assignment; a\n //valueless reset also brings the operator back to the default it rendered with\n super.formResetCallback();\n if (!this.hasAttribute('value')) {\n this._showDefaultOperator();\n }\n }\n _type() {\n return 'text';\n }\n _serialize(v) {\n return v;\n }\n _deserialize(v) {\n return v;\n }\n _defaultOperator() {\n return 'EQ';\n }\n _vocabulary() {\n return COMPARE_OPERATORS;\n }\n _declaredOperators;\n get operators() {\n //a page may whitelist before the upgrade: the narrowed set is held until\n //the button exists, and the declared attribute lands over it when the\n //base applies the declared state\n return this._operator ? this._operator.allowed : this._declaredOperators;\n }\n set operators(declared) {\n if (!this._operator) {\n this._declaredOperators = ChoiceButton.narrow(declared, this._vocabulary());\n return;\n }\n this._operator.allowed = declared;\n this._syncBetween();\n }\n get value() {\n return this._tuple();\n }\n set value(v) {\n this._applyTuple(v);\n }\n _tuple() {\n const operator = this._operator.value;\n const values = operator === 'BETWEEN' ? [this._value1.value, this._value2.value] : [this._value1.value];\n return values.some((v) => v === '') ? null : [operator, ...values.map((v) => this._serialize(v))];\n }\n _applyTuple(v) {\n if (v == null) {\n this._value1.value = '';\n this._value2.value = '';\n return;\n }\n const [declared, ...values] = v;\n //a pinned operator wins over whatever the tuple carries\n const operator = this._operator.pinned ? this._operator.allowed[0] : declared;\n this._showOperator(operator);\n //a tuple shorter than the operands leaves the missing ones empty: the DOM\n //would stringify a nullish assignment to \"undefined\"\n this._value1.value = values[0] ? this._deserialize(values[0]) : (values[0] ?? '');\n this._value2.value = values[1] ? this._deserialize(values[1]) : (values[1] ?? '');\n }\n _showOperator(operator) {\n this._operator.value = operator;\n this._syncBetween();\n }\n /** only a BETWEEN carries a second operand */\n _syncBetween() {\n this._value2.toggleAttribute('hidden', this._operator.value !== 'BETWEEN');\n }\n get disabled() {\n return super.disabled;\n }\n set disabled(d) {\n //the claim and both operands are the base's; the chrome buttons are not,\n //frozen by a pin, disabled by the claim, or both\n super.disabled = d;\n for (const choice of this._choices()) {\n choice.claimed = d;\n }\n }\n /** every menu button the filter composes, so one claim reaches them all */\n _choices() {\n return [this._operator].filter((c) => c);\n }\n}\n\n/** The compare filter over ISO instants, defaulting to LTE. */\nclass InstantFilter extends CompareFilter {\n _defaultOperator() {\n return 'LTE';\n }\n _type() {\n return 'datetime-local';\n }\n _serialize(v) {\n return Instant.localToIso(v);\n }\n _deserialize(v) {\n return Instant.isoToLocal(v);\n }\n}\n\n/** The compare filter over dates. */\nclass LocalDateFilter extends CompareFilter {\n _type() {\n return 'date';\n }\n}\n\n/** The compare filter over numbers. */\nclass NumberFilter extends CompareFilter {\n _type() {\n return 'number';\n }\n}\n\n/** The compare filter over text, carrying a case sensitivity beside the operator. */\nclass TextFilter extends CompareFilter {\n static observed = ['sensitivities:csv'];\n static template = `\n <label>{{{{ slots.default }}}}</label>\n {{{{ slots.info }}}}\n <ful-control-group>\n <ful-affix data-tpl-if=\"slots.before\">{{{{ slots.before }}}}</ful-affix>\n <ful-affix>\n <button data-ref=\"operator\" type=\"button\" form=\"\" aria-expanded=\"false\" aria-haspopup=\"true\"></button>\n <ul popover role=\"menu\"></ul>\n <button data-ref=\"sensitivity\" type=\"button\" form=\"\" aria-expanded=\"false\" aria-haspopup=\"true\"></button>\n <ul popover role=\"menu\"></ul>\n </ful-affix>\n <ful-control>\n <input data-ref=\"value1\" data-tpl-type=\"type\" form=\"\">\n <input data-ref=\"value2\" data-tpl-type=\"type\" form=\"\" hidden>\n </ful-control>\n <ful-affix data-tpl-if=\"slots.after\">{{{{ slots.after }}}}</ful-affix>\n </ful-control-group>\n <ful-field-error></ful-field-error>\n `;\n _defaultOperator() {\n return 'CONTAINS';\n }\n _vocabulary() {\n return TEXT_OPERATORS;\n }\n //the sensitivity is carried through from whoever set the value, switched\n //through its own menu, or pinned to the single mode the sensitivities\n //attribute whitelists\n _sensitivityButton;\n _build(conf) {\n const pieces = super._build(conf);\n this._sensitivityButton = new ChoiceButton(\n /** @type HTMLElement */ (pieces.fragment.querySelector('[data-ref=sensitivity]')),\n {\n vocabulary: SENSITIVITIES,\n glyphs: SENSITIVITY_GLYPHS,\n labelFor: sensitivityLabel,\n interactive: () => this._interactive(),\n onPick: () => this._notifyChange(),\n },\n );\n this._sensitivityButton.allowed = null;\n this._sensitivityButton.value = SENSITIVITIES[0];\n return pieces;\n }\n _choices() {\n return [...super._choices(), this._sensitivityButton].filter((c) => c);\n }\n get _sensitivity() {\n return this._sensitivityButton.value;\n }\n _declaredSensitivities;\n get sensitivities() {\n return this._sensitivityButton ? this._sensitivityButton.allowed : this._declaredSensitivities;\n }\n set sensitivities(declared) {\n if (!this._sensitivityButton) {\n this._declaredSensitivities = ChoiceButton.narrow(declared, SENSITIVITIES);\n return;\n }\n const previous = this._sensitivityButton.value;\n this._sensitivityButton.allowed = declared;\n if (!this._sensitivityButton.allowed.includes(previous)) {\n this._sensitivityButton.value = this._sensitivityButton.allowed[0];\n }\n }\n get value() {\n const tuple = this._tuple();\n return tuple == null ? null : [tuple[0], this._sensitivity, ...tuple.slice(1)];\n }\n set value(v) {\n if (v == null) {\n this._applyTuple(v);\n return;\n }\n if (this._sensitivityButton.allowed.includes(v[1])) {\n this._sensitivityButton.value = v[1];\n }\n this._applyTuple([v[0], ...v.slice(2)]);\n }\n formResetCallback() {\n //a declared tuple restores its sensitivity through the value assignment;\n //a valueless reset brings it back to the default it rendered with, the\n //class default normalized against the whitelist\n super.formResetCallback();\n if (!this.hasAttribute('value')) {\n const allowed = this._sensitivityButton.allowed;\n this._sensitivityButton.value = allowed.includes('IGNORE_CASE') ? 'IGNORE_CASE' : allowed[0];\n }\n }\n}\n\nconst BOOLEAN_VALUES = ['', 'true', 'false'];\nconst BOOLEAN_VALUE_GLYPHS = { true: '✓', false: '✗' };\n\n/** The boolean filter: an EQ or NEQ operator and an any/yes/no menu. */\nclass BooleanFilter extends Field {\n static observed = ['value:json', 'operators:csv'];\n static slots = true;\n static OPERATORS = ['EQ', 'NEQ'];\n static DEFAULT_OPERATOR = 'EQ';\n static template = `\n <label>{{{{ slots.default }}}}</label>\n {{{{ slots.info }}}}\n <ful-control-group>\n <ful-affix data-tpl-if=\"slots.before\">{{{{ slots.before }}}}</ful-affix>\n <ful-affix>\n <button data-ref=\"operator\" type=\"button\" form=\"\" aria-expanded=\"false\" aria-haspopup=\"true\"></button>\n <ul popover role=\"menu\"></ul>\n </ful-affix>\n <button data-ref=\"value\" type=\"button\" form=\"\"></button>\n <ul popover role=\"menu\"></ul>\n <ful-affix data-tpl-if=\"slots.after\">{{{{ slots.after }}}}</ful-affix>\n </ful-control-group>\n <ful-field-error></ful-field-error>\n `;\n _operator;\n _value;\n _container;\n _build({ slots }) {\n const fragment = this.template().withOverlay({ slots }).render();\n this._container = fragment.querySelector('ful-control-group');\n const valueButton = fragment.querySelector('[data-ref=value]');\n this._operator = new ChoiceButton(fragment.querySelector('[data-ref=operator]'), {\n vocabulary: BooleanFilter.OPERATORS,\n glyphs: GLYPHS,\n labelFor: operatorLabel,\n interactive: () => this._interactive(),\n onPick: () => this._notifyChange(),\n });\n //the value button carries the word rather than a glyph: 'any' has none\n this._value = new ChoiceButton(valueButton, {\n vocabulary: BOOLEAN_VALUES,\n glyphs: BOOLEAN_VALUE_GLYPHS,\n labelFor: booleanValueLabel,\n display: booleanValueLabel,\n interactive: () => this._interactive(),\n onPick: () => this._notifyChange(),\n });\n this.operators = this.declared('operators');\n const allowed = this._operator.allowed;\n this._operator.value = allowed.includes(BooleanFilter.DEFAULT_OPERATOR)\n ? BooleanFilter.DEFAULT_OPERATOR\n : allowed[0];\n this._value.allowed = null;\n this._value.value = '';\n return {\n fragment,\n control: valueButton,\n error: fragment.querySelector('ful-field-error'),\n label: fragment.querySelector('label'),\n //a button accepts neither aria-readonly nor aria-required\n announces: null,\n freeze: this._container,\n };\n }\n _declaredOperators;\n get operators() {\n //a page may whitelist before the upgrade: the narrowed set is held until\n //the button exists, and the declared attribute lands over it when the\n //base applies the declared state\n return this._operator ? this._operator.allowed : this._declaredOperators;\n }\n set operators(declared) {\n if (!this._operator) {\n this._declaredOperators = ChoiceButton.narrow(declared, this._vocabulary());\n return;\n }\n this._operator.allowed = declared;\n }\n _vocabulary() {\n return BooleanFilter.OPERATORS;\n }\n get value() {\n return this._value.value === '' ? null : [this._operator.value, this._value.value];\n }\n set value(v) {\n if (v == null) {\n this._value.value = '';\n return;\n }\n //a pinned operator wins over whatever the tuple carries\n this._operator.value = this._operator.pinned ? this._operator.allowed[0] : v[0];\n this._value.value = v[1] ?? '';\n }\n get disabled() {\n return super.disabled;\n }\n set disabled(d) {\n super.disabled = d;\n //the menu buttons are frozen by a pin, disabled by the claim, or both\n for (const choice of [this._operator, this._value].filter((c) => c)) {\n choice.claimed = d;\n }\n }\n}\n\nexport { BooleanFilter, CompareFilter, InstantFilter, LocalDateFilter, NumberFilter, TextFilter };\n","import { Failure } from '../../httpc/index.mjs';\nimport { Claims } from '../claims.mjs';\n\n/**\n * The async section machinery shared by ful-tabs, ful-wizard, ful-dialog and\n * ful-drawer: every activation of a section fires the section:requested family\n * on the host component (bubbling: the generic type, the #index type, and the\n * data-step name when present) and awaits the union of the answers, wherever\n * they were registered. The event's target is the component, whose local name\n * telling the family, e.target === e.currentTarget separating a host's own\n * sections from a nested component's, while detail.section stays the write\n * target. No listener is a plain pass-through, and the first-entry flag is not\n * even spent, so a listener attached later still sees the first activation. A\n * pending answer shows the loading chrome a frame late (answers that never\n * pend never flash) and declares the section aria-busy; a delivery superseded\n * by a newer activation of the same section owns no chrome; a rejection paints\n * the section's error chrome, replacing whatever a previous answer had\n * painted, and travels to the caller.\n */\nclass SectionRequests {\n #entered = new WeakSet();\n /** one generation of claims per section: the sections contend separately */\n #claims = new WeakMap();\n\n /**\n * @param {Element} host\n * @param {Element} section\n * @param {string|null} name\n * @param {number|null} index\n * @returns {Promise<any[]|undefined>} the union of the answers, or undefined when nobody listened\n */\n async request(host, section, name, index) {\n const first = !this.#entered.has(section);\n const detail = { name, section, index, first };\n const types = [\n 'section:requested',\n ...(index !== null && index !== undefined ? [`section:requested:#${index}`] : []),\n ...(name ? [`section:requested:${name}`] : []),\n ];\n const promises = [];\n for (const type of types) {\n const evt = /** @type {CustomEvent & { async?: { promises: Promise<any>[] } }} */ (\n new CustomEvent(type, { bubbles: true, detail })\n );\n host.dispatchEvent(evt);\n promises.push(...(evt.async?.promises ?? []));\n }\n if (promises.length === 0) {\n return undefined;\n }\n this.#entered.add(section);\n let claims = this.#claims.get(section);\n if (!claims) {\n claims = new Claims();\n this.#claims.set(section, claims);\n }\n const claim = claims.take();\n const owned = () => !claim.stale;\n section.querySelector(':scope > .ful-section-error')?.remove();\n const frame = requestAnimationFrame(() => {\n if (owned()) {\n section.toggleAttribute('loading', true);\n section.setAttribute('aria-busy', 'true');\n }\n });\n try {\n return await Promise.all(promises);\n } catch (cause) {\n if (owned()) {\n this.#paintError(section, cause);\n }\n throw cause;\n } finally {\n cancelAnimationFrame(frame);\n if (owned()) {\n section.toggleAttribute('loading', false);\n section.removeAttribute('aria-busy');\n }\n }\n }\n\n #paintError(section, cause) {\n section.querySelector(':scope > .ful-section-error')?.remove();\n const error = document.createElement('div');\n error.className = 'ful-section-error';\n error.setAttribute('role', 'alert');\n error.textContent = Failure.problemsText(cause);\n section.prepend(error);\n }\n}\n\nexport { SectionRequests };\n","/**\n * The dialog-target delegation, shared by the dialog and the drawer: any\n * element carrying dialog-target set to a dialog-bearing ful element's id\n * opens it, clones included. Wired once per document.\n */\nlet targetsWired = false;\nconst wireTargets = () => {\n if (targetsWired) {\n return;\n }\n targetsWired = true;\n document.addEventListener('click', (/** @type any */ e) => {\n const trigger = e.target.closest?.('[dialog-target]');\n if (!trigger) {\n return;\n }\n /** @type {any} */ (document.getElementById(trigger.getAttribute('dialog-target')))?.open?.();\n });\n};\n\nexport { wireTargets };\n","import { ParsedElement } from '../../ftl/index.mjs';\nimport { describable } from '../descriptions.mjs';\nimport { SectionRequests } from '../events/sections.mjs';\nimport { Anchors } from './anchors.mjs';\nimport { wireTargets } from './targets.mjs';\n\n/**\n * An info icon button toggling a popover with a short explanation.\n *\n * The marker is the page's `config.icon`, and the `icon` attribute names a\n * `ful-icon` for the tooltip that means something other than plain information:\n * a caveat, a warning, a setting. A name the library does not paint is the\n * page's own, declared as `ful-icon[name='...'] { mask-image: ... }`.\n *\n * `describes` is for the tooltip standing in a field: the note becomes part of\n * the accessible description of that field's control, so it is announced on\n * reaching the field rather than only on opening the marker, and the marker\n * leaves the tab order, so a form of hinted fields costs no extra keystrokes to\n * walk. The marker stays clickable, and stays a tab stop wherever the note was\n * not taken, a tooltip claiming `describes` outside a field among them: the\n * stop only goes where something else delivers the content.\n */\nclass Tooltip extends ParsedElement {\n static slots = true;\n static attributes = ['placement', 'icon', 'describes:presence'];\n static config = {\n icon: 'info-circle-fill',\n };\n static template = `\n <button type=\"button\" class=\"ful-tip\" data-ref=\"trigger\" data-tpl-aria-label=\"#l10n:t('info.tooltip')\"><ful-icon data-tpl-name=\"icon ?? config.icon\" aria-hidden=\"true\"></ful-icon></button>\n <ful-note popover data-ref=\"content\">{{{{ slots.default }}}}</ful-note>\n `;\n render({ slots }) {\n const fragment = this.template().withOverlay({ slots, icon: this.declared('icon') }).render();\n const trigger = fragment.querySelector('[data-ref=trigger]');\n const content = fragment.querySelector('[data-ref=content]');\n //placed here rather than by the anchor css: the note draws a callout that\n //has to point at the trigger wherever the viewport left room for the note,\n //which is a measurement the stylesheet cannot make for a pseudo-element\n Anchors.wire(trigger, content, { prefix: 'ful-tooltip', invoke: true, expanded: true, handPlace: true });\n //above the marker by default: a note opening downwards covers the control\n //the marker explains, the marker riding the field's label\n content.setAttribute('placement', this.declared('placement') ?? 'top');\n this.replaceChildren(fragment);\n if (this.declared('describes')) {\n Tooltip.#describe(this, trigger, content);\n }\n }\n /**\n * Offers the note to the field the tooltip stands in, and takes the trigger\n * out of the tab order only where the offer was accepted: a note nothing\n * carries is reachable by the keyboard through the marker alone, so\n * dropping the stop there would leave it reachable by nothing at all.\n *\n * The offer goes through the description protocol rather than naming a\n * field, the library's own arrow running from the forms to the disclosures.\n */\n static #describe(tooltip, trigger, content) {\n if (!describable(tooltip)?.describedBy(content)) {\n console.warn('a ful-tooltip declares describes but stands in nothing that takes a description', tooltip);\n return;\n }\n trigger.tabIndex = -1;\n }\n}\n\n/** A modal dialog on the native platform, open()/ask() resolving with the closer's data-result. */\nclass Dialog extends ParsedElement {\n static attributes = ['header'];\n static slots = true;\n static template = `\n <dialog data-ref=\"dialog\" class=\"ful-dialog\">\n <header data-tpl-if=\"header\"><h2>{{ header }}</h2></header>\n <div data-ref=\"body\">{{{{ slots.default }}}}</div>\n <footer>\n <button type=\"button\" data-ref=\"acknowledge\" data-result=\"acknowledged\" data-tpl-if=\"!slots.buttons\" data-tpl-aria-label=\"#l10n:t('dialog.acknowledge')\">{{ #l10n:t('dialog.acknowledge') }}</button>\n {{{{ slots.buttons }}}}\n </footer>\n </dialog>\n `;\n #dialog;\n #body;\n #requests = new SectionRequests();\n #resolvers = [];\n render({ slots }) {\n const fragment = this.template()\n .withOverlay({ slots, header: this.declared('header') ?? '' })\n .render();\n this.#dialog = fragment.querySelector('[data-ref=dialog]');\n this.#body = fragment.querySelector('[data-ref=body]');\n this.#dialog.addEventListener('close', () => {\n this.dispatchEvent(\n new CustomEvent('close', {\n detail: { result: this.#dialog.returnValue === '' ? null : this.#dialog.returnValue },\n }),\n );\n this.#settle();\n });\n this.#dialog.addEventListener('click', (/** @type any */ e) => {\n const result = e.target.closest('button[data-result]')?.dataset.result;\n if (result !== undefined) {\n this.#dialog.close(result);\n }\n });\n this.replaceChildren(fragment);\n wireTargets();\n }\n //answers every waiter with the dialog's own answer: null while still open\n //or closed without a result, which is also the unanswered answer a dialog\n //leaving the document owes its waiters instead of hanging them\n #settle() {\n const resolvers = this.#resolvers;\n this.#resolvers = [];\n for (const resolve of resolvers) {\n resolve(this.#dialog.returnValue === '' ? null : this.#dialog.returnValue);\n }\n }\n disconnectedCallback() {\n this.#settle();\n }\n open() {\n return this.ask();\n }\n ask() {\n if (!this.#dialog.open) {\n this.#dialog.returnValue = '';\n this.#dialog.showModal();\n this.#request();\n }\n return new Promise((resolve) => {\n this.#resolvers.push(resolve);\n });\n }\n #request() {\n this.#requests.request(this, this.#body, null, null)?.catch(() => undefined);\n }\n /**\n * Re-fires section:requested on the body, open or closed: the explicit\n * request for a body that wants refreshing. A failed refresh paints its\n * problems, nothing rejects: there is no caller to reject towards.\n */\n refresh() {\n return this.#requests.request(this, this.#body, null, null)?.then(undefined, () => undefined);\n }\n close(result) {\n this.#dialog.close(result ?? '');\n }\n}\n\nexport { Tooltip, Dialog };\n","import { ParsedElement } from '../../ftl/index.mjs';\nimport { Claims } from '../claims.mjs';\nimport { SectionRequests } from '../events/sections.mjs';\nimport { Failure } from '../../httpc/index.mjs';\nimport { wireTargets } from './targets.mjs';\n\n/**\n * A side panel drawer on the native dialog platform, update() owning its\n * open-deliver cycle.\n *\n * The `header` slot is content beside the title, before it: an icon, a badge, a\n * status. It sits outside the heading rather than in it because `update()` sets\n * the title through `textContent`, which would take anything nested there with\n * it.\n */\nclass Drawer extends ParsedElement {\n static attributes = ['title', 'placement'];\n static slots = true;\n static template = `\n <dialog data-ref=\"dialog\" class=\"ful-drawer\">\n <header>\n {{{{ slots.header }}}}\n <h2 data-ref=\"title\">{{ title }}</h2>\n <button type=\"button\" data-ref=\"close\" data-tpl-aria-label=\"#l10n:t('drawer.close')\"><ful-icon name=\"x-lg\" aria-hidden=\"true\"></ful-icon></button>\n </header>\n <section data-ref=\"loading\" hidden><ful-spinner class=\"centered\" role=\"status\"><span class=\"ful-sr-only\">{{ #l10n:t('spinner.loading') }}</span></ful-spinner></section>\n <section data-ref=\"error\" role=\"alert\" hidden></section>\n <section data-ref=\"content\">{{{{ slots.default }}}}</section>\n </dialog>\n `;\n #dialog;\n #title;\n #loading;\n #error;\n #content;\n #requests = new SectionRequests();\n #updates = new Claims();\n render({ slots }) {\n const fragment = this.template()\n .withOverlay({ slots, title: this.declared('title') ?? '' })\n .render();\n this.#dialog = fragment.querySelector('[data-ref=dialog]');\n this.#title = fragment.querySelector('[data-ref=title]');\n this.#loading = fragment.querySelector('[data-ref=loading]');\n this.#error = fragment.querySelector('[data-ref=error]');\n this.#content = fragment.querySelector('[data-ref=content]');\n const placement = this.declared('placement');\n if (placement) {\n this.#dialog.setAttribute('placement', placement);\n }\n fragment.querySelector('[data-ref=close]').addEventListener('click', () => this.close());\n this.#dialog.addEventListener('close', () => {\n this.dispatchEvent(new CustomEvent('close'));\n });\n this.replaceChildren(fragment);\n wireTargets();\n }\n get title() {\n return this.#title.textContent;\n }\n set title(v) {\n this.#title.textContent = v ?? '';\n }\n /**\n * Opens the drawer under the given title and waits for the callback: a\n * resolved value paints the content section (which is returned), a\n * rejection paints the problems and travels to the caller, and an update\n * superseded by a newer one paints nothing.\n */\n async update(title, cb) {\n //the claim detaches any update still in flight: its outcome belongs to\n //an abandoned opening and must neither be painted nor own the drawer\n const claim = this.#updates.take();\n this.title = title;\n this.#content.replaceChildren();\n this.#restChrome();\n this.#loading.removeAttribute('hidden');\n this.#content.setAttribute('hidden', '');\n //update owns its own open-answer-deliver cycle, so it shows the dialog\n //without going through open(): a user reopen during the wait is a\n //real open and goes through open()\n this.#show();\n try {\n const delivered = await cb();\n if (claim.stale) {\n return this.#content;\n }\n this.#content.replaceChildren(delivered);\n this.#loading.setAttribute('hidden', '');\n this.#content.removeAttribute('hidden');\n return this.#content;\n } catch (/** @type any */ e) {\n if (!claim.stale) {\n //revealed before it is filled, so the live region announces the\n //change rather than being revealed already holding it\n this.#error.removeAttribute('hidden');\n this.#error.textContent = Failure.problemsText(e);\n this.#loading.setAttribute('hidden', '');\n this.#content.setAttribute('hidden', '');\n }\n throw e;\n }\n }\n /**\n * Re-fires section:requested on the content, open or closed: the explicit\n * request for a body that wants refreshing. A failed refresh paints its\n * problems, nothing rejects: update() stays the rejecting call.\n */\n refresh() {\n return this.#requests.request(this, this.#content, null, null)?.then(undefined, () => undefined);\n }\n open() {\n if (!this.#show()) {\n return;\n }\n this.#restChrome();\n this.#requests.request(this, this.#content, null, null)?.catch(() => undefined);\n }\n close() {\n this.#dialog.close();\n }\n /** Shows the modal, answering whether this call is the one that opened it. */\n #show() {\n if (this.#dialog.open) {\n return false;\n }\n this.#dialog.showModal();\n return true;\n }\n #restChrome() {\n this.#error.replaceChildren();\n this.#error.setAttribute('hidden', '');\n this.#loading.setAttribute('hidden', '');\n this.#content.removeAttribute('hidden');\n }\n}\n\nexport { Drawer };\n","import { Localization, ParsedElement } from '../../ftl/index.mjs';\nimport { Failure } from '../../httpc/index.mjs';\n\nconst SEVERITIES = ['info', 'success', 'warning', 'error'];\n\n//the regions alive in the document: the show-toast listener is wired once and\n//forwards to each of them, so a re-hosted or second region never doubles a toast\nconst REGIONS = new Set();\nlet listenerWired = false;\n\n/** A transient feedback region: each show() stacks a toast that retires on its own timer. */\nclass Toasts extends ParsedElement {\n static attributes = ['timeout:number'];\n #timeout;\n connectedCallback() {\n super.connectedCallback();\n if (this.rendered) {\n REGIONS.add(this);\n }\n }\n disconnectedCallback() {\n REGIONS.delete(this);\n }\n render() {\n this.#timeout = this.declared('timeout') || 5000;\n this.setAttribute('role', 'region');\n //focusable only programmatically, so a retiring toast can hand its focus back\n this.setAttribute('tabindex', '-1');\n this.setAttribute('aria-label', Localization.of().t('toast.region'));\n if (!listenerWired) {\n listenerWired = true;\n document.addEventListener('show-toast', (/** @type any */ e) => {\n for (const region of REGIONS) {\n region.show(e.detail.message, e.detail);\n }\n });\n }\n REGIONS.add(this);\n }\n /**\n * Appends a toast carrying the message (a Failure shows its problems'\n * reasons, one per line), severity picking the theme and the announcement,\n * the toast retiring through its own timer or its dismiss button.\n * @param {any} message\n * @param {any} [options] severity and timeout\n * @returns {HTMLElement}\n */\n show(message, options = {}) {\n const severity = SEVERITIES.includes(options.severity) ? options.severity : 'info';\n const item = document.createElement('ful-toast');\n item.classList.add(severity);\n item.setAttribute('role', severity === 'error' ? 'alert' : 'status');\n const body = document.createElement('div');\n body.textContent = Failure.problemsText(message, `${message ?? ''}`);\n const dismiss = document.createElement('button');\n dismiss.type = 'button';\n dismiss.setAttribute('aria-label', Localization.of().t('toast.dismiss'));\n const icon = document.createElement('ful-icon');\n icon.setAttribute('name', 'x-lg');\n icon.setAttribute('aria-hidden', 'true');\n dismiss.append(icon);\n item.append(body, dismiss);\n item.addEventListener('animationend', () => {\n if (item.classList.contains('ful-toast-out')) {\n item.remove();\n }\n });\n const retire = () => {\n //the toast may hold the focus, on its own dismiss button: handing it\n //back to the region keeps the reader somewhere rather than on <body>\n if (item.contains(document.activeElement)) {\n /** @type HTMLElement */ (this).focus();\n }\n if (matchMedia('(prefers-reduced-motion: reduce)').matches) {\n item.remove();\n return;\n }\n item.classList.add('ful-toast-out');\n if (item.getAnimations().length === 0) {\n item.remove();\n }\n };\n dismiss.addEventListener('click', retire);\n this.append(item);\n setTimeout(retire, options.timeout ?? this.#timeout);\n return item;\n }\n}\n\nexport { Toasts };\n","import { Attributes, ParsedElement } from '../../ftl/index.mjs';\nimport { SectionRequests } from '../events/sections.mjs';\n\n/**\n * A tab panel: one visible panel at a time, announced through the tab pattern\n * (a tablist of tab buttons, each panel a tabpanel named by its tab). The tabs\n * are declared as <tab> elements in the tabs slot, the panels as the slotless\n * children, paired in order. Entering a panel fires the section:requested\n * family on it (generic and #index, panels being nameless) and awaits the\n * answers, so a panel can deliver itself asynchronously.\n */\nclass Tabs extends ParsedElement {\n static slots = true;\n static observed = ['active:number'];\n static template = `\n <ful-tablist role=\"tablist\">{{{{ slots.tabs }}}}</ful-tablist>\n {{{{ slots.default }}}}\n `;\n #tablist;\n #tabs = [];\n #panels = [];\n #requests = new SectionRequests();\n #active = 0;\n render({ slots }) {\n const fragment = this.template().withOverlay({ slots }).render();\n this.#tablist = fragment.querySelector('ful-tablist');\n const declared = [...this.#tablist.children];\n this.#panels = [...fragment.children].filter((el) => el !== this.#tablist);\n if (declared.length !== this.#panels.length) {\n console.warn(\n `ful-tabs: ${declared.length} tabs declared for ${this.#panels.length} panels, the surplus is left alone`,\n );\n }\n const count = Math.min(declared.length, this.#panels.length);\n this.#tabs = [];\n for (let i = 0; i !== count; ++i) {\n const panel = this.#panels[i];\n const tab = document.createElement('button');\n tab.type = 'button';\n tab.role = 'tab';\n tab.id = Attributes.uid('ful-tab');\n //an author-named panel keeps its name: the wiring adopts it\n if (!panel.id) {\n panel.id = Attributes.uid('ful-tabpanel');\n }\n tab.setAttribute('aria-controls', panel.id);\n panel.role = 'tabpanel';\n panel.setAttribute('aria-labelledby', tab.id);\n //the visible panel joins the tab order: keyboard and reader users\n //reach its content right after its tab, hidden ones stay out\n panel.tabIndex = 0;\n tab.append(...declared[i].childNodes);\n tab.addEventListener('click', () => {\n this.active = i;\n });\n declared[i].replaceWith(tab);\n this.#tabs.push(tab);\n }\n this.#tablist.addEventListener('keydown', (e) => {\n const current = this.#active;\n /** @type {number|null} */\n let target = null;\n if (e.key === 'ArrowRight') {\n target = (current + 1) % this.#tabs.length;\n } else if (e.key === 'ArrowLeft') {\n target = (current - 1 + this.#tabs.length) % this.#tabs.length;\n } else if (e.key === 'Home') {\n target = 0;\n } else if (e.key === 'End') {\n target = this.#tabs.length - 1;\n }\n if (target === null || target === current) {\n return;\n }\n e.preventDefault();\n this.active = target;\n this.#tabs[target].focus();\n });\n this.replaceChildren(fragment);\n }\n get active() {\n return this.#active;\n }\n /**\n * Re-fires the section:requested family on the panel (by index or the\n * panel element itself), whether active or not: the explicit request for a\n * content that wants refreshing. A failed refresh paints its problems,\n * nothing rejects: there is no caller to reject towards.\n */\n refresh(ref) {\n const index = ref instanceof Element ? this.#panels.indexOf(ref) : Number.isInteger(ref) ? ref : NaN;\n const panel = this.#panels[index];\n if (!panel) {\n console.warn(`ful-tabs: no panel answers to \"${ref}\"`);\n return undefined;\n }\n return this.#requests.request(this, panel, null, index)?.then(undefined, () => undefined);\n }\n set active(v) {\n const index = Math.min(Math.max(0, Number(v) || 0), Math.max(0, this.#tabs.length - 1));\n const previous = this.#active;\n for (const [i, tab] of this.#tabs.entries()) {\n tab.setAttribute('aria-selected', i === index ? 'true' : 'false');\n tab.tabIndex = i === index ? 0 : -1;\n this.#panels[i].hidden = i !== index;\n }\n this.#active = index;\n this.reflectTo('active', index);\n if (this.rendered && index !== previous) {\n this.dispatchEvent(new CustomEvent('change', { detail: { active: index, previous } }));\n }\n if (this.#panels.length > 0 && (index !== previous || !this.rendered)) {\n //the activation is the reader's own gesture: the chrome reports a\n //failed delivery, there is no caller to reject towards\n this.#requests.request(this, this.#panels[index], null, index)?.catch(() => undefined);\n }\n }\n}\n\nexport { Tabs };\n","import { Attributes, ParsedElement } from '../../ftl/index.mjs';\n\n/**\n * An accordion over native details/summary disclosures: the platform carries\n * the semantics, the keyboard and the toggling, the chrome paints the group.\n * With the exclusive claim the render assigns one shared name to every panel,\n * which is the platform's own exclusive grouping: opening one closes the others.\n */\nclass Accordion extends ParsedElement {\n static slots = true;\n static observed = ['exclusive:presence'];\n static template = `\n <ful-accordion-group>{{{{ slots.default }}}}</ful-accordion-group>\n `;\n #group;\n #exclusive = false;\n render({ slots }) {\n const fragment = this.template().withOverlay({ slots }).render();\n this.#group = fragment.querySelector('ful-accordion-group');\n this.replaceChildren(fragment);\n }\n get exclusive() {\n return this.#exclusive;\n }\n set exclusive(v) {\n this.#exclusive = v === true;\n this.reflectTo('exclusive', this.#exclusive);\n const name = this.#exclusive ? Attributes.uid('ful-accordion') : null;\n for (const details of this.#group.querySelectorAll(':scope > details')) {\n if (name === null) {\n details.removeAttribute('name');\n } else {\n details.setAttribute('name', name);\n }\n }\n }\n}\n\nexport { Accordion };\n","import { ParsedElement } from '../../ftl/index.mjs';\nimport { SectionRequests } from '../events/sections.mjs';\n\n/**\n * A wizard: a progress of steps over one-of-N sections, the homeinsurance\n * layout distilled. The steps are declared as <step> elements in the steps\n * slot, the sections as the slotless children, paired in order; each section\n * may carry a data-step name, which is what move() answers to. The current\n * step is the aria-current=step claim, carried in lockstep by the step and\n * its section: the chrome (including which section is shown) follows the\n * claim alone, so the markup state and the style can never disagree. The\n * progress chrome shows the current step alone by default; the progress\n * attribute picks another shape over the same claims (timeline, dots, none).\n * Entering a section\n * fires the section:requested family on it and awaits the answers, so a\n * section can deliver itself asynchronously; move() resolves when the entered\n * section is painted, and rejects when its delivery fails.\n */\nclass Wizard extends ParsedElement {\n static slots = true;\n static observed = ['progress'];\n static template = `\n <ful-steps><ol data-tpl-aria-label=\"#l10n:t('wizard.progress')\">{{{{ slots.steps }}}}</ol></ful-steps>\n {{{{ slots.default }}}}\n `;\n #steps = [];\n #sections = [];\n #requests = new SectionRequests();\n #index = 0;\n #progress;\n render({ slots }) {\n const fragment = this.template().withOverlay({ slots }).render();\n const list = fragment.querySelector('ful-steps ol');\n const declared = [...list.children];\n this.#sections = [...fragment.children].filter((el) => el.localName !== 'ful-steps');\n if (declared.length !== this.#sections.length) {\n console.warn(\n `ful-wizard: ${declared.length} steps declared for ${this.#sections.length} sections, the surplus is left alone`,\n );\n }\n const count = Math.min(declared.length, this.#sections.length);\n this.#steps = [];\n for (let i = 0; i !== count; ++i) {\n const li = document.createElement('li');\n li.append(...declared[i].childNodes);\n declared[i].replaceWith(li);\n this.#steps.push(li);\n //the section is the focus target of a move: the step that just\n //became current must receive it, the button that moved it having\n //left the document with its own section\n this.#sections[i].tabIndex = -1;\n }\n this.replaceChildren(fragment);\n if (count > 0) {\n //a section already carrying the claim keeps it: server-rendered state wins\n const claimed = this.#sections.findIndex((s) => s.getAttribute('aria-current') === 'step');\n this.#apply(claimed === -1 ? 0 : Math.min(claimed, count - 1));\n this.#enter(this.#index)?.catch(() => undefined);\n }\n }\n get index() {\n return this.#index;\n }\n get step() {\n return this.#sections[this.#index]?.getAttribute('data-step') ?? null;\n }\n get progress() {\n return this.#progress;\n }\n set progress(v) {\n this.#progress = v;\n this.reflectTo('progress', v);\n }\n next() {\n return this.#move(this.#index + 1);\n }\n prev() {\n return this.#move(this.#index - 1);\n }\n move(ref) {\n const index = this.#sections.findIndex((s) => s.getAttribute('data-step') === ref);\n if (index === -1) {\n console.warn(`ful-wizard: no section carries data-step=\"${ref}\"`);\n return undefined;\n }\n return this.#move(index);\n }\n /**\n * Re-fires the section:requested family on the named section (or the\n * section element itself), whether active or not: the explicit request for a\n * content that wants refreshing. A failed refresh paints its problems,\n * nothing rejects: move() stays the rejecting call.\n */\n refresh(ref) {\n const section =\n ref instanceof Element\n ? ref\n : typeof ref === 'string'\n ? this.#sections.find((s) => s.getAttribute('data-step') === ref)\n : undefined;\n const index = this.#sections.indexOf(section);\n if (index === -1) {\n console.warn(`ful-wizard: no section answers to \"${ref}\"`);\n return undefined;\n }\n return this.#enter(index)?.then(undefined, () => undefined);\n }\n #enter(index) {\n return this.#requests.request(\n this,\n this.#sections[index],\n this.#sections[index].getAttribute('data-step'),\n index,\n );\n }\n #move(index) {\n const clamped = Math.min(Math.max(0, index), Math.max(0, this.#steps.length - 1));\n if (clamped === this.#index) {\n return undefined;\n }\n this.#apply(clamped);\n //the moving control lived in the section that just hid: focus follows\n //the step, or the reader lands on the body knowing nothing happened\n this.#sections[this.#index].focus();\n if (this.rendered) {\n this.dispatchEvent(new CustomEvent('change', { detail: { index: this.#index, step: this.step } }));\n }\n return this.#enter(clamped);\n }\n #apply(index) {\n for (const [i, step] of this.#steps.entries()) {\n if (i === index) {\n step.setAttribute('aria-current', 'step');\n this.#sections[i].setAttribute('aria-current', 'step');\n } else {\n step.removeAttribute('aria-current');\n this.#sections[i].removeAttribute('aria-current');\n }\n }\n this.#index = index;\n }\n}\n\nexport { Wizard };\n","import { HttpClient } from '../httpc/index.mjs';\nimport { Localization } from '../ftl/index.mjs';\nimport { Checkbox } from './forms/checkbox.mjs';\nimport { LocalDate, Instant, InputLocalDate, InputLocalTime, InputInstant } from './forms/temporals.mjs';\nimport { BooleanFilter, InstantFilter, LocalDateFilter, NumberFilter, TextFilter } from './forms/filters.mjs';\nimport { FormLoader, Form } from './forms/form.mjs';\nimport { Input } from './forms/input.mjs';\nimport { InputFile } from './forms/files.mjs';\nimport { RadioGroup } from './forms/radio.mjs';\nimport { SelectLoader, Dropdown, Select } from './forms/select.mjs';\nimport { Tooltip, Dialog } from './disclosures/info.mjs';\nimport { Drawer } from './disclosures/drawer.mjs';\nimport { Toasts } from './disclosures/toast.mjs';\nimport { Tabs } from './navigation/tabs.mjs';\nimport { Accordion } from './disclosures/accordion.mjs';\nimport { Wizard } from './navigation/wizard.mjs';\nimport { TableLoader, Table, Pagination, SortButton } from './navigation/table.mjs';\nimport en from './l10n/en.mjs';\nimport it from './l10n/it.mjs';\nimport es from './l10n/es.mjs';\nimport fr from './l10n/fr.mjs';\n\nconst BUILTIN = { en, it, es, fr };\n\n/**\n * Registers everything ful provides on a registry: the elements, the loader\n * components, an http client, and the translations for the configured\n * language. A page calls `registry.plugin(new Plugin({…})).configure()` once.\n */\nclass Plugin {\n #language;\n #translations;\n #httpClient;\n\n /**\n * @param {{ language?: string, translations?: Record<string, any>, httpClient?: any }} [options]\n * `language` is fixed for the page: a full BCP-47 tag or a primary subtag,\n * defaulting to the browser's language. `translations` is a flat\n * active-language map applied over the built-in translations: reword built-in\n * keys ('pagination.showing', …) or add your own ('checkout.total', …).\n * `httpClient` is the client every ful component fetches through, registered\n * as the `http-client` component: where an unauthorized session goes is an\n * application decision, so a page that does not want the default's redirect\n * to '/' builds its own.\n */\n constructor(options = {}) {\n this.#language = options.language ?? navigator?.language ?? 'en';\n this.#translations = options.translations ?? {};\n this.#httpClient = options.httpClient ?? null;\n }\n\n configure(registry) {\n const httpClient =\n this.#httpClient ?? HttpClient.builder().withCsrfToken().withRedirectOnUnauthorized('/').build();\n //the fallback chain is baked here: en, the active language, the consumer's own strings\n const language = this.#language.split('-')[0];\n const l10n = { ...BUILTIN.en, ...BUILTIN[language], ...this.#translations };\n registry\n .defineModule('l10n', Localization)\n .defineComponent('http-client', httpClient)\n .defineElement('ful-tooltip', Tooltip)\n .defineElement('ful-dialog', Dialog)\n .defineElement('ful-drawer', Drawer)\n .defineElement('ful-toasts', Toasts)\n .defineElement('ful-tabs', Tabs)\n .defineElement('ful-accordion', Accordion)\n .defineElement('ful-wizard', Wizard)\n .defineElement('ful-form', Form)\n .defineElement('ful-checkbox', Checkbox)\n .defineElement('ful-input', Input)\n .defineElement('ful-input-file', InputFile)\n .defineElement('ful-local-date', LocalDate)\n .defineElement('ful-instant', Instant)\n .defineElement('ful-input-local-date', InputLocalDate)\n .defineElement('ful-input-local-time', InputLocalTime)\n .defineElement('ful-input-instant', InputInstant)\n .defineElement('ful-radio-group', RadioGroup)\n .defineElement('ful-table', Table)\n .defineElement('ful-pagination', Pagination)\n .defineElement('ful-sorter', SortButton)\n .defineElement('ful-filter-instant', InstantFilter)\n .defineElement('ful-filter-local-date', LocalDateFilter)\n .defineElement('ful-filter-number', NumberFilter)\n .defineElement('ful-filter-boolean', BooleanFilter)\n .defineElement('ful-filter-text', TextFilter)\n .defineElement('ful-select', Select)\n .defineElement('ful-dropdown', Dropdown)\n .defineComponent('loaders:select', SelectLoader)\n .defineComponent('loaders:form', FormLoader)\n .defineComponent('loaders:table', TableLoader)\n //the two names a template and the l10n facade resolve: the messages,\n //and the locale every formatter needs. The primary subtag is not a\n //third: it exists to pick the built-in bundle above, and publishing\n //it put a bare name nothing reads into the scope of every template\n .defineOverlay({\n l10n,\n locale: this.#language,\n });\n }\n}\n\nexport { Plugin };\n","export default {\n 'pagination.showing': 'Page {current} of {total}',\n 'pagination.navigation': 'Page navigation',\n 'pagination.previous': 'Previous',\n 'pagination.next': 'Next',\n 'pagination.reload': 'Reload',\n 'table.initial': 'Start searching to see results.',\n 'table.error': 'Error while loading data:',\n 'table.no-data': 'No elements found.',\n 'dropdown.empty': 'No results',\n 'select.remove': 'Remove',\n 'files.dropzone-label': 'Click or drop your files here',\n 'files.remove': 'Remove',\n 'files.unacceptable-file-type': 'Only files of type {types} are supported',\n 'files.max-file-size-exceeded': 'Maximum supported file size is {size}',\n 'files.max-total-size-exceeded': 'Maximum supported total file size is {size}',\n 'files.max-files-exceeded': { one: 'Maximum of {count} file exceeded', other: 'Maximum of {count} files exceeded' },\n 'filters.op.EQ': 'Equals',\n 'filters.op.NEQ': 'Not equal',\n 'filters.op.LT': 'Less than',\n 'filters.op.GT': 'Greater than',\n 'filters.op.LTE': 'At most',\n 'filters.op.GTE': 'At least',\n 'filters.op.BETWEEN': 'Between',\n 'filters.op.CONTAINS': 'Contains',\n 'filters.op.STARTS_WITH': 'Starts with',\n 'filters.op.ENDS_WITH': 'Ends with',\n 'filters.sensitivity.IGNORE_CASE': 'Ignore case',\n 'filters.sensitivity.CASE_SENSITIVE': 'Case sensitive',\n 'filters.boolean.any': 'Any',\n 'filters.boolean.true': 'Yes',\n 'filters.boolean.false': 'No',\n 'info.tooltip': 'More information',\n 'dialog.acknowledge': 'Got it',\n 'drawer.close': 'Close',\n 'spinner.loading': 'Loading…',\n 'toast.region': 'Notifications',\n 'toast.dismiss': 'Dismiss',\n 'wizard.progress': 'Progress',\n};\n","export default {\n 'pagination.showing': 'Pagina {current} di {total}',\n 'pagination.navigation': 'Navigazione pagine',\n 'pagination.previous': 'Precedente',\n 'pagination.next': 'Successivo',\n 'pagination.reload': 'Ricarica',\n 'table.initial': 'Avvia la ricerca per visualizzare i risultati.',\n 'table.error': 'Errore nel caricamento dei dati:',\n 'table.no-data': 'Nessun elemento trovato.',\n 'dropdown.empty': 'Nessun risultato',\n 'select.remove': 'Rimuovi',\n 'files.dropzone-label': 'Clicca o trascina i file qui',\n 'files.remove': 'Rimuovi',\n 'files.unacceptable-file-type': 'Solo i file di tipo {types} sono supportati',\n 'files.max-file-size-exceeded': 'La dimensione massima di un file è di {size}',\n 'files.max-total-size-exceeded': 'La dimensione massima complessiva dei file è di {size}',\n 'files.max-files-exceeded': { other: 'Superato il numero massimo di {count} file' },\n 'filters.op.EQ': 'Uguale',\n 'filters.op.NEQ': 'Diverso',\n 'filters.op.LT': 'Minore',\n 'filters.op.GT': 'Maggiore',\n 'filters.op.LTE': 'Al massimo',\n 'filters.op.GTE': 'Almeno',\n 'filters.op.BETWEEN': 'Tra',\n 'filters.op.CONTAINS': 'Contiene',\n 'filters.op.STARTS_WITH': 'Inizia con',\n 'filters.op.ENDS_WITH': 'Termina con',\n 'filters.sensitivity.IGNORE_CASE': 'Ignora maiuscole',\n 'filters.sensitivity.CASE_SENSITIVE': 'Distingui maiuscole',\n 'filters.boolean.any': 'Qualsiasi',\n 'filters.boolean.true': 'Sì',\n 'filters.boolean.false': 'No',\n 'info.tooltip': 'Maggiori informazioni',\n 'dialog.acknowledge': 'Ho capito',\n 'drawer.close': 'Chiudi',\n 'spinner.loading': 'Caricamento…',\n 'toast.region': 'Notifiche',\n 'toast.dismiss': 'Chiudi',\n 'wizard.progress': 'Avanzamento',\n};\n","export default {\n 'pagination.showing': 'Página {current} de {total}',\n 'pagination.navigation': 'Navegación de páginas',\n 'pagination.previous': 'Anterior',\n 'pagination.next': 'Siguiente',\n 'pagination.reload': 'Recargar',\n 'table.initial': 'Inicia la búsqueda para ver los resultados.',\n 'table.error': 'Error al cargar los datos:',\n 'table.no-data': 'No se encontraron elementos.',\n 'dropdown.empty': 'Sin resultados',\n 'select.remove': 'Eliminar',\n 'files.dropzone-label': 'Haz clic o arrastra tus archivos aquí',\n 'files.remove': 'Eliminar',\n 'files.unacceptable-file-type': 'Solo se admiten archivos de tipo {types}',\n 'files.max-file-size-exceeded': 'El tamaño máximo de archivo admitido es {size}',\n 'files.max-total-size-exceeded': 'El tamaño total máximo admitido es {size}',\n 'files.max-files-exceeded': { other: 'Se ha superado el número máximo de {count} archivos' },\n 'filters.op.EQ': 'Igual',\n 'filters.op.NEQ': 'Distinto',\n 'filters.op.LT': 'Menor',\n 'filters.op.GT': 'Mayor',\n 'filters.op.LTE': 'Como máximo',\n 'filters.op.GTE': 'Al menos',\n 'filters.op.BETWEEN': 'Entre',\n 'filters.op.CONTAINS': 'Contiene',\n 'filters.op.STARTS_WITH': 'Empieza por',\n 'filters.op.ENDS_WITH': 'Termina por',\n 'filters.sensitivity.IGNORE_CASE': 'Ignorar mayúsculas',\n 'filters.sensitivity.CASE_SENSITIVE': 'Distinguir mayúsculas',\n 'filters.boolean.any': 'Cualquiera',\n 'filters.boolean.true': 'Sí',\n 'filters.boolean.false': 'No',\n 'info.tooltip': 'Más información',\n 'dialog.acknowledge': 'Entendido',\n 'drawer.close': 'Cerrar',\n 'spinner.loading': 'Cargando…',\n 'toast.region': 'Notificaciones',\n 'toast.dismiss': 'Cerrar',\n 'wizard.progress': 'Progreso',\n};\n","export default {\n 'pagination.showing': 'Page {current} sur {total}',\n 'pagination.navigation': 'Navigation des pages',\n 'pagination.previous': 'Précédent',\n 'pagination.next': 'Suivant',\n 'pagination.reload': 'Recharger',\n 'table.initial': 'Lancez la recherche pour voir les résultats.',\n 'table.error': 'Erreur lors du chargement des données :',\n 'table.no-data': 'Aucun élément trouvé.',\n 'dropdown.empty': 'Aucun résultat',\n 'select.remove': 'Retirer',\n 'files.dropzone-label': 'Cliquez ou déposez vos fichiers ici',\n 'files.remove': 'Retirer',\n 'files.unacceptable-file-type': 'Seuls les fichiers de type {types} sont pris en charge',\n 'files.max-file-size-exceeded': 'La taille maximale de fichier prise en charge est {size}',\n 'files.max-total-size-exceeded': 'La taille totale maximale prise en charge est {size}',\n 'files.max-files-exceeded': {\n one: 'Nombre maximal de {count} fichier dépassé',\n other: 'Nombre maximal de {count} fichiers dépassé',\n },\n 'filters.op.EQ': 'Égal',\n 'filters.op.NEQ': 'Différent',\n 'filters.op.LT': 'Inférieur',\n 'filters.op.GT': 'Supérieur',\n 'filters.op.LTE': 'Au plus',\n 'filters.op.GTE': 'Au moins',\n 'filters.op.BETWEEN': 'Entre',\n 'filters.op.CONTAINS': 'Contient',\n 'filters.op.STARTS_WITH': 'Commence par',\n 'filters.op.ENDS_WITH': 'Finit par',\n 'filters.sensitivity.IGNORE_CASE': 'Ignorer la casse',\n 'filters.sensitivity.CASE_SENSITIVE': 'Respecter la casse',\n 'filters.boolean.any': 'Indifférent',\n 'filters.boolean.true': 'Oui',\n 'filters.boolean.false': 'Non',\n 'info.tooltip': 'Plus d’informations',\n 'dialog.acknowledge': 'J’ai compris',\n 'drawer.close': 'Fermer',\n 'spinner.loading': 'Chargement…',\n 'toast.region': 'Notifications',\n 'toast.dismiss': 'Fermer',\n 'wizard.progress': 'Progression',\n};\n"],"names":["storage","backing","remove","k","removeItem","load","got","getItem","JSON","parse","save","v","setItem","stringify","pop","decoded","versioned","store","key","revision","data","stored","LocalStorage","localStorage","SessionStorage","sessionStorage","VersionedLocalStorage","VersionedSessionStorage","AsyncEvents","fireAsync","el","evt","options","dispatchEvent","promises","async","mode","length","Promise","all","catch","Error","type","resolve","asyncOn","fn","listener","event","ae","promise","reject","withResolvers","push","e","addEventListener","asyncOff","removeEventListener","mixInto","classes","Object","assign","prototype","this","Claims","generation","take","hold","held","claims","stale","invalidate","describable","at","parentElement","Timing","sleep","ms","setTimeout","debounce","timeoutMs","func","immediate","tid","args","previousTimestamp","later","elapsed","performance","now","called","clearTimeout","undefined","throttle","leading","trailing","remaining","Bindings","flatten","obj","prefix","stops","keys","reduce","acc","pre","has","static","Set","providePath","result","path","value","split","map","test","FORBIDDEN","current","previous","i","ckey","pkey","Number","isInteger","Array","isArray","extract","getAttribute","checked","dataset","fulBindType","tagName","multiple","from","selectedOptions","o","submits","extractFrom","form","submitter","elements","hasAttribute","matches","mutate","raw","values","String","forEach","selected","includes","mutateIn","names","filter","n","flattenedKey","entries","querySelectorAll","CSS","escape","errors","es","scrollOnError","setAttribute","pinned","context","fieldErrors","globalErrors","setCustomValidity","replaceChildren","unmatched","parts","replace","slice","join","targets","input","reason","bannered","hel","removeAttribute","innerText","sort","a","b","getBoundingClientRect","y","focus","Field","ParsedElement","control","described","descriptions","errorId","fieldError","announces","also","constructor","super","internals","role","ROLE","mirrors","wire","fragment","error","label","freeze","readonly","preventDefault","id","Attributes","uid","describe","name","defaultPrevented","isComposing","target","submitsOnEnter","_requestSubmit","HTMLInputElement","describedBy","ids","set","setValidity","customError","candidates","requestSubmit","find","_notifyChange","extras","CustomEvent","bubbles","cancelable","detail","field","LABELABLE","_interactive","formResetCallback","unmarshal","disabled","d","reflectTo","toggleAttribute","readOnly","required","render","conf","built","_build","then","pieces","settle","RemoteJsonFormLoader","http","url","method","requestMapper","responseMapper","prepare","submit","request","json","fetch","transform","response","LocalFormLoader","FormLoader","create","component","declared","Form","document","createElement","forward","childNodes","stopPropagation","closest","stopImmediatePropagation","submitting","spinner","loader","se","sre","mapped","exception","Failure","problems","console","warn","reset","spinning","announce","defaultValue","hidden","textContent","trim","className","ref","append","Localization","of","t","spin","Math","max","querySelector","wd","vs","patternCache","BoundedCache","compiled","attr","pattern","getOrCompute","RegExp","warnedBoth","WeakSet","Input","_input","_type","slots","template","withOverlay","strip","keep","add","re","match","filterOf","before","after","start","selectionStart","caret","setSelectionRange","uppercase","uppercased","toUpperCase","trimmed","isNaN","placeholder","LocalDate","content","m","parsed","Date","getTime","date","locale","year","month","day","Instant","isoToLocal","hour","minute","second","hour12","iso","pad","padStart","getFullYear","getMonth","getDate","getHours","getMinutes","getSeconds","getMilliseconds","localToIso","local","toISOString","InputLocalDate","min","fromIsoOrOffset","step","formatLocalDate","getTimezoneOffset","exec","sign","offset","r","setHours","setDate","originalDay","setMonth","setFullYear","InputLocalTime","fromNowOrOffset","resolved","setMinutes","snapped","stepSeconds","seconds","floor","hh","mm","InputInstant","InputFile","list","files","dt","DataTransfer","file","items","accept","dropzone","warnings","group","warning","itemstemplate","Fragments","isBlank","Templates","fromFragment","idx","children","indexOf","f","click","dataTransfer","kind","getAsFile","update","ensureAcceptable","ensureFileSizes","ensureTotalSize","ensureFilesCount","renderTo","appendTo","WARNING_TIMEOUT","acceptable","toLowerCase","some","token","startsWith","endsWith","unacceptable","types","maxFiles","count","maxFileSize","oversized","size","bytes","maxTotalSize","totalsize","useItemList","itemList","useDropzone","open","Map","frame","reflowWired","clamp","low","high","place","popover","anchored","invoker","stretch","box","viewport","documentElement","vw","clientWidth","vh","clientHeight","style","removeProperty","computed","getComputedStyle","gap","parseFloat","marginTop","marginRight","marginBottom","marginLeft","right","bottom","margin","width","left","height","top","note","isNote","placement","cap","maxWidth","wide","here","setProperty","clientLeft","clientTop","reportCallout","reflow","isConnected","delete","schedule","requestAnimationFrame","Anchors","invoke","expanded","handPlace","anchor","anchorName","positionAnchor","newState","supports","property","unplace","window","RemoteLoader","prefetch","inFlight","configs","ensureFetched","exact","needle","reconfigureUrl","claim","revisionedData","finally","storageKey","fetchJson","PartialRemoteLoader","param","InMemoryLoader","SelectLoader","els","metadata","responseMapperFrom","_registry","evaluator","evaluateExpression","row","Dropdown","menu","empty","optionstemplate","shows","default","li","change","hide","firstElementChild","highlight","activated","scrollIntoView","block","behavior","matchMedia","acceptSelection","entry","index","picked","findIndex","get","hidePopover","shown","show","showPopover","moveOrShow","candidate","jump","first","lastElementChild","page","lis","offsetHeight","trunc","Select","ddmenu","warnedComma","assignments","editing","dload","abortdload","listbox","wireChrome","wireChips","wireInput","wireSelection","close","removeKeyAt","badge","Element","removeBadge","chipKeydown","code","selectionEnd","badges","select","relatedTarget","contains","comboboxKeydown","clear","coerceKey","changed","syncBadges","withLoader","reload","arrowKeydown","display","altKey","browse","next","selection","NaN","RadioGroup","fieldset","firstRadio","booleanType","radioEls","inputsAndLabels","fromChildNodes","radios","Checkbox","container","isSwitch","SortButton","order","sorter","orders","nextOrder","th","Pagination","prevIcon","nextIcon","reloadIcon","total","toCurrent","toTotal","maxRender","pageCount","hasPrev","hasNext","prev","enabled","curr","rendered","pages","_","focused","activeElement","back","TableSchemaParser","nodeOrFragment","schema","Nodes","queryChildren","headersTr","rowsTr","getAttributeNames","columns","queryChildrenAll","column","maybeTitleTag","titleNode","createTextNode","wrappedTitleNode","fulSorter","td","headersTemplate","inHeaders","inRows","withFragment","rowsTemplate","InMemoryTableLoader","pageRequest","sortRequest","filterRequest","rows","sorted","begin","end","l","RemoteTableLoader","filters","fromEntries","TableLoader","Table","searchIcon","body","loading","noAutoload","feedback","paginator","sorters","latestRequest","loadRequested","loads","pageSize","table","thead","Rendering","waitForChildren","maybeForm","s","pageResponse","problemsText","resetWithFilter","ceil","lastPage","ChoiceButton","narrow","vocabulary","narrowed","choice","button","glyphs","labelFor","interactive","onPick","allowed","claimed","wired","item","fill","sync","word","glyph","glyphSpan","wordSpan","GLYPHS","EQ","NEQ","LT","GT","LTE","GTE","BETWEEN","CONTAINS","STARTS_WITH","ENDS_WITH","COMPARE_OPERATORS","TEXT_OPERATORS","SENSITIVITIES","SENSITIVITY_GLYPHS","IGNORE_CASE","CASE_SENSITIVE","operatorLabel","op","sensitivityLabel","sensitivity","booleanValueLabel","CompareFilter","_operator","_container","_value1","_value2","_vocabulary","_syncBetween","operators","_showDefaultOperator","preferred","_defaultOperator","_showOperator","_serialize","_deserialize","_declaredOperators","_tuple","_applyTuple","operator","_choices","c","InstantFilter","LocalDateFilter","NumberFilter","TextFilter","_sensitivityButton","_sensitivity","_declaredSensitivities","sensitivities","tuple","BOOLEAN_VALUES","BOOLEAN_VALUE_GLYPHS","true","false","BooleanFilter","_value","valueButton","OPERATORS","DEFAULT_OPERATOR","SectionRequests","entered","WeakMap","host","section","owned","cause","paintError","cancelAnimationFrame","prepend","targetsWired","wireTargets","trigger","getElementById","Tooltip","icon","tooltip","tabIndex","Dialog","dialog","requests","resolvers","header","returnValue","disconnectedCallback","ask","showModal","refresh","Drawer","title","updates","cb","restChrome","delivered","SEVERITIES","REGIONS","listenerWired","Toasts","timeout","connectedCallback","region","message","severity","classList","dismiss","retire","getAnimations","Tabs","tablist","tabs","panels","active","panel","tab","replaceWith","Accordion","exclusive","details","Wizard","steps","sections","progress","localName","apply","enter","move","clamped","BUILTIN","en","one","other","it","fr","language","translations","httpClient","navigator","configure","registry","HttpClient","builder","withCsrfToken","withRedirectOnUnauthorized","build","l10n","defineModule","defineComponent","defineElement","defineOverlay"],"mappings":"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"}
1
+ {"version":3,"file":"ful.iife.min.js","sources":["../src/ful/storage.mjs","../src/ful/events/async.mjs","../src/ful/claims.mjs","../src/ful/descriptions.mjs","../src/ful/timing.mjs","../src/ful/forms/bindings.mjs","../src/ful/forms/field.mjs","../src/ful/forms/form.mjs","../src/ful/forms/input.mjs","../src/ful/forms/temporals.mjs","../src/ful/forms/files.mjs","../src/ful/disclosures/anchors.mjs","../src/ful/forms/select.mjs","../src/ful/forms/radio.mjs","../src/ful/forms/checkbox.mjs","../src/ful/navigation/table.mjs","../src/ful/forms/choice-button.mjs","../src/ful/forms/filters.mjs","../src/ful/events/sections.mjs","../src/ful/disclosures/targets.mjs","../src/ful/disclosures/info.mjs","../src/ful/disclosures/drawer.mjs","../src/ful/disclosures/toast.mjs","../src/ful/navigation/tabs.mjs","../src/ful/disclosures/accordion.mjs","../src/ful/navigation/wizard.mjs","../src/ful/plugin.mjs","../src/ful/l10n/en.mjs","../src/ful/l10n/it.mjs","../src/ful/l10n/es.mjs","../src/ful/l10n/fr.mjs"],"sourcesContent":["/**\n * Builds a json-encoding wrapper over one of the page's storages. The backing\n * is deferred (an accessor, not the storage itself): where storage is denied\n * (blocked cookies, some embedded or private contexts) the accessor itself\n * throws, and must do so per call, never at module load. The methods are bound\n * to nothing: destructuring keeps them working.\n * @param {() => globalThis.Storage} backing\n */\nconst storage = (backing) => {\n const remove = (k) => {\n try {\n backing().removeItem(k);\n } catch {\n //nothing to remove where storage is unreachable\n }\n };\n const load = (k) => {\n let got;\n try {\n got = backing().getItem(k);\n } catch {\n //storage can be unreachable altogether (blocked cookies, embedded or\n //private contexts): a read that cannot reach it is a miss, not a failure\n return undefined;\n }\n if (got === null) {\n return undefined;\n }\n try {\n return JSON.parse(got);\n } catch {\n //not what save wrote: drop it, otherwise every later read fails the same way\n remove(k);\n return undefined;\n }\n };\n const save = (k, v) => {\n backing().setItem(k, JSON.stringify(v));\n };\n const pop = (k) => {\n const decoded = load(k);\n remove(k);\n return decoded;\n };\n return { save, load, remove, pop };\n};\n\n/**\n * Builds a revision-guarded view over a storage wrapper: a load under a\n * revision other than the stored one is a miss that also evicts the entry.\n * @param {ReturnType<typeof storage>} store\n */\nconst versioned = (store) => ({\n save(key, revision, data) {\n store.save(key, { revision, data });\n },\n load(key, revision) {\n const stored = store.load(key);\n if (stored == null || typeof stored !== 'object' || stored.revision !== revision) {\n store.remove(key);\n return undefined;\n }\n return stored.data;\n },\n});\n\nconst LocalStorage = storage(() => localStorage);\nconst SessionStorage = storage(() => sessionStorage);\nconst VersionedLocalStorage = versioned(LocalStorage);\nconst VersionedSessionStorage = versioned(SessionStorage);\n\nexport { LocalStorage, VersionedLocalStorage, SessionStorage, VersionedSessionStorage };\n","/**\n * @typedef {Object} AsyncExtension\n * @property {Promise<any>[]} promises\n * @typedef {Event & { async?: AsyncExtension }} AsyncEvent\n */\n/**\n * Dispatching an event and waiting for what its listeners answer. A listener\n * registered through `asyncOn` attaches its promise to the event, and\n * `fireAsync` resolves once they have all settled: `broadcast` collects every\n * answer, `pipeline` allows at most one, `delegate` requires exactly one.\n */\nclass AsyncEvents {\n /**\n * Dispatches an event and handles asynchronous resolution based on the execution mode.\n * @param {HTMLElement} el - The target element dispatching the event.\n * @param {AsyncEvent} evt - The event instance.\n * @param {{mode?: 'broadcast' | 'pipeline' | 'delegate'}} [options] - Configuration options (defaults to 'broadcast').\n * @returns {Promise<any>} Resolves with an array of values for broadcasts, a single value for pipelines/delegates, or undefined.\n */\n static async fireAsync(el, evt, options) {\n el.dispatchEvent(evt);\n const promises = evt.async?.promises ?? [];\n const mode = options?.mode ?? 'broadcast';\n if ((mode === 'pipeline' && promises.length > 1) || (mode === 'delegate' && promises.length !== 1)) {\n //the listeners ran under a broken configuration: nothing legitimately\n //awaits their outcome, and their failures are not page errors\n Promise.all(promises).catch(() => {});\n throw new Error(\n mode === 'pipeline'\n ? `[AsyncEvents] Event \"${evt.type}\" is configured in 'pipeline' mode and expects at most one async listener, but ${promises.length} listeners were triggered on this element.`\n : `[AsyncEvents] Event \"${evt.type}\" is configured in 'delegate' mode and requires exactly one async listener, but ${promises.length} were registered.`,\n );\n }\n return mode === 'broadcast' ? Promise.all(promises) : Promise.resolve(promises[0]);\n }\n\n /**\n * Registers an asynchronous event listener wrapper.\n * @param {HTMLElement} el - The target element.\n * @param {string} type - The event name/type.\n * @param {Function} fn - The async listener middleware function returning the execution result.\n * @param {AddEventListenerOptions} [options] - Native addEventListener options.\n * @returns {EventListener} The underlying proxy listener function needed for cleanup via asyncOff.\n */\n static asyncOn(el, type, fn, options) {\n /** @type {(evt: Event) => Promise<void>} */\n const listener = async (event) => {\n const ae = /** @type {AsyncEvent} */ (event);\n if (!ae.async) {\n ae.async = { promises: [] };\n }\n const { promise, resolve, reject } = Promise.withResolvers();\n ae.async.promises.push(promise);\n try {\n resolve(await fn(ae));\n } catch (e) {\n reject(e);\n }\n };\n\n el.addEventListener(type, listener, options);\n return listener;\n }\n\n /**\n * Unregisters an asynchronous event listener proxy.\n * @param {HTMLElement} el - The target element.\n * @param {string} type - The event name/type.\n * @param {EventListener} listener - The proxy listener instance previously returned by asyncOn.\n * @param {EventListenerOptions} [options] - Native removeEventListener options.\n */\n static asyncOff(el, type, listener, options) {\n el.removeEventListener(type, listener, options);\n }\n /**\n * Mixes the asynchronous execution engine extensions into target class prototypes.\n * @param {...Function} classes - The target class constructors to decorate.\n */\n static mixInto(...classes) {\n for (const k of classes) {\n Object.assign(k.prototype, {\n /**\n * @this {HTMLElement}\n * @param {AsyncEvent} evt\n * @param {{mode?: 'broadcast' | 'pipeline' | 'delegate'}} [options]\n * @returns {Promise<any>}\n */\n async fireAsync(evt, options) {\n return await AsyncEvents.fireAsync(this, evt, options);\n },\n\n /**\n * @this {HTMLElement}\n * @param {string} type\n * @param {Function} fn\n * @param {AddEventListenerOptions} [options]\n * @returns {EventListener}\n */\n asyncOn(type, fn, options) {\n return AsyncEvents.asyncOn(this, type, fn, options);\n },\n\n /**\n * @this {HTMLElement}\n * @param {string} type\n * @param {EventListener} listener\n * @param {EventListenerOptions} [options]\n * @returns {void}\n */\n asyncOff(type, listener, options) {\n AsyncEvents.asyncOff(this, type, listener, options);\n },\n });\n }\n }\n}\n\nexport { AsyncEvents };\n","/**\n * @typedef {{ readonly stale: boolean }} Claim\n */\n/**\n * The generations of claims over one contended resource. Every take() starts a\n * new generation, superseding every claim before it, and a holder asks its\n * claim `stale` before painting chrome, storing state or throwing towards a\n * caller: a superseded outcome owns nothing. hold() joins the current\n * generation without superseding it (a fetch that any later reconfiguration\n * must detach), and invalidate() supersedes without claiming (a hide ending\n * every pending show). One Claims per contended resource: a component whose\n * dropdown, value labels and loader configuration contend separately holds one\n * each.\n */\nclass Claims {\n #generation = 0;\n /**\n * Starts a new generation, superseding every earlier claim, and holds it.\n * @returns {Claim}\n */\n take() {\n ++this.#generation;\n return this.hold();\n }\n /**\n * Holds the current generation without superseding anything.\n * @returns {Claim}\n */\n hold() {\n const held = this.#generation;\n const claims = this;\n return {\n /** true once a later take() or invalidate() superseded this claim */\n get stale() {\n return held !== claims.#generation;\n },\n };\n }\n /** Supersedes every claim without holding a new one. */\n invalidate() {\n ++this.#generation;\n }\n}\n\nexport { Claims };\n","/**\n * The protocol by which content standing inside a field becomes part of the\n * accessible description of that field's control.\n *\n * A field owns its control's `aria-describedby`: it is the only thing that\n * knows which element the description belongs on, and it already writes the\n * entry for its own error region. Content the author slotted into the field\n * cannot write that attribute itself without becoming a second owner of it, and\n * it cannot be wired by the field either, because a slotted custom element\n * renders after the field has mounted and has nothing to point at when the\n * field looks.\n *\n * So the content asks, once it has something to offer. `describable(el)`\n * answers the nearest ancestor that accepts a description, and the caller hands\n * its element to that ancestor's `describedBy`, which answers whether it was\n * taken. Nothing here names a field or a tooltip: the relation is expressed as\n * a capability, so the two ends need not import each other, which matters\n * because the library's own arrow runs from the forms to the disclosures.\n *\n * The lookup lives here rather than at its one call site so the protocol has a\n * name, a place to be documented and a single definition to change.\n */\n\n/**\n * @typedef {{ describedBy(el: HTMLElement): boolean }} Describable\n */\n\n/**\n * The nearest ancestor of `el` that accepts elements into the description of\n * whatever it considers its control, or null when nothing in the ancestry does.\n * @param {Element} el\n * @returns {(Element & Describable) | null}\n */\nconst describable = (el) => {\n for (let at = el.parentElement; at; at = at.parentElement) {\n if (typeof (/** @type {any} */ (at).describedBy) === 'function') {\n return /** @type {any} */ (at);\n }\n }\n return null;\n};\n\nexport { describable };\n","/**\n * Sleeping, debouncing and throttling. Debounce and throttle both return the\n * wrapped function together with a cancel function.\n */\nclass Timing {\n /** Resolves after the given milliseconds. @param {number} ms */\n static sleep(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n /**\n * Executes only after a period of inactivity (pause in events).\n * Respond to the \"end\" of a series of events.\n * @param {number} timeoutMs\n * @param {function} func\n * @param {{ immediate?: boolean }} [options] - immediate fires on the leading edge instead of the trailing one\n * @returns {[function, function]}\n */\n static debounce(timeoutMs, func, options) {\n const immediate = options?.immediate ?? false;\n let tid = /** @type {number | null} */ (null);\n let args = [];\n let previousTimestamp = 0;\n\n const later = () => {\n const elapsed = performance.now() - previousTimestamp;\n if (timeoutMs > elapsed) {\n tid = setTimeout(later, timeoutMs - elapsed);\n return;\n }\n tid = null;\n if (!immediate) {\n func(...args);\n }\n //func may have called debounced again, arming a new timer with new args:\n //clearing them then would drop the call that is now pending\n if (tid === null) {\n args = [];\n }\n };\n\n const debounced = (...called) => {\n args = called;\n previousTimestamp = performance.now();\n if (tid === null) {\n tid = setTimeout(later, timeoutMs);\n if (immediate) {\n func(...args);\n }\n }\n };\n const abort = () => {\n clearTimeout(tid ?? undefined);\n tid = null;\n args = [];\n };\n return [debounced, abort];\n }\n /**\n * Executes at most once per specified time interval, regardless of ongoing events.\n * @param {number} timeoutMs\n * @param {function} func\n * @param {{ leading?: boolean, trailing?: boolean }} [options] - which edges of the interval call, both by default\n * @returns {[function, function]}\n */\n static throttle(timeoutMs, func, options) {\n const leading = options?.leading ?? true;\n const trailing = options?.trailing ?? true;\n let tid = /** @type {number | null} */ (null);\n let args = [];\n let previousTimestamp = 0;\n\n const later = () => {\n previousTimestamp = leading ? performance.now() : 0;\n tid = null;\n func(...args);\n if (tid === null) {\n args = [];\n }\n };\n const throttled = (...called) => {\n const now = performance.now();\n if (!previousTimestamp && !leading) {\n previousTimestamp = now;\n }\n const remaining = previousTimestamp === 0 ? 0 : timeoutMs - (now - previousTimestamp);\n args = called;\n if (remaining <= 0 || remaining > timeoutMs) {\n if (tid !== null) {\n clearTimeout(tid);\n tid = null;\n }\n previousTimestamp = now;\n func(...args);\n if (tid === null) {\n args = [];\n }\n } else if (tid === null && trailing) {\n tid = setTimeout(later, remaining);\n }\n };\n const abort = () => {\n clearTimeout(tid ?? undefined);\n tid = null;\n args = [];\n };\n return [throttled, abort];\n }\n}\n\nexport { Timing };\n","/** Field wiring: extracting and filling values, pinning problems to the fields they name. */\nclass Bindings {\n /**\n * Flattens a nested object into dotted keys, stopping wherever `stops` names\n * a key: a field named `address` takes the whole object, while one named\n * `address.city` takes the leaf.\n * @param {{ [x: string]: any; }} obj\n * @param {string} prefix\n * @param {Set<String>} stops - the names the form actually has fields for\n * @return {{ [x: string]: any; }}\n */\n static flatten(obj, prefix, stops) {\n return Object.keys(obj).reduce((acc, k) => {\n const pre = prefix.length ? `${prefix}.${k}` : k;\n if (!stops.has(pre) && typeof obj[k] === 'object' && obj[k] !== null) {\n Object.assign(acc, Bindings.flatten(obj[k], pre, stops));\n } else {\n acc[pre] = obj[k];\n }\n return acc;\n }, {});\n }\n\n /**\n * Walking a dotted name would otherwise descend into `Object.prototype`:\n * `__proto__` passes the `typeof === 'object'` test below and becomes the\n * walk's target, so `providePath({}, '__proto__.x', v)` would write on every\n * object in the page. A field name reaching here is author markup, but it can\n * be bound from data through `data-tpl-name` and `providePath` is public, so\n * the segments that can reach the prototype chain are refused outright rather\n * than left to the caller to prove unreachable.\n */\n static #FORBIDDEN = new Set(['__proto__', 'prototype', 'constructor']);\n /**\n * Writes a value into an object at a dotted path, creating the intermediate\n * objects and arrays the path implies. A numeric segment makes an array.\n * @param {any} result\n * @param {string} path - a field name, `a.b` or `a[0].b`\n * @param {any} value\n */\n static providePath(result, path, value) {\n const keys = path.split('.').map((k) => (/^[0-9]+$/.test(k) ? +k : k));\n for (const key of keys) {\n if (Bindings.#FORBIDDEN.has(/** @type any */ (key))) {\n throw new Error(`unsupported name segment '${key}' in '${path}'`);\n }\n }\n let current = result ?? {};\n let previous = /** @type {any} */ (null);\n for (let i = 0; ; ++i) {\n const ckey = keys[i];\n const pkey = keys[i - 1];\n if (Number.isInteger(ckey) && !Array.isArray(current)) {\n if (previous !== null) {\n previous[pkey] = current = [];\n } else {\n result = current = [];\n }\n }\n if (i === keys.length - 1) {\n //an undefined value declares the path without filling it: an entry\n //already there is left alone, a missing one is created null\n current[ckey] = value !== undefined ? value : ckey in current ? current[ckey] : null;\n return result;\n }\n //an overlapping name (a before a.b) leaves a scalar or a null here:\n //the later, more specific name rebuilds the container, exactly as the\n //reverse order always replaced the container with the scalar\n if (typeof current[ckey] !== 'object' || current[ckey] === null) {\n current[ckey] = {};\n }\n previous = current;\n current = current[ckey];\n }\n }\n /**\n * Reads one control's value the way its kind demands: an unchecked radio\n * answers undefined so it contributes nothing, a checkbox answers its\n * checked state, a multiple select answers its selected values, and a blank\n * native control answers null rather than an empty string.\n * @param {Element & {dataset?: any} & {checked?: boolean} & {value?: any}} el\n * @returns {any} the value, or undefined where the control contributes none\n */\n static extract(el) {\n if (el.getAttribute('type') === 'radio') {\n if (!el.checked) {\n return undefined;\n }\n return el.dataset.fulBindType === 'boolean' ? el.value === 'true' : el.value;\n }\n if (el.getAttribute('type') === 'checkbox') {\n return el.checked;\n }\n if (el.dataset.fulBindType === 'boolean') {\n return !el.value ? null : el.value === 'true';\n }\n if (el.tagName === 'SELECT' && /** @type {HTMLSelectElement} */ (el).multiple) {\n return Array.from(/** @type {HTMLSelectElement} */ (el).selectedOptions).map((o) => o.value);\n }\n if (el.tagName === 'INPUT' || el.tagName === 'SELECT' || el.tagName === 'TEXTAREA') {\n return el.value === '' || el.value === undefined ? null : el.value;\n }\n return el.value;\n }\n\n /**\n * Reads every named, enabled control of a form into a nested object, the\n * dotted field names deciding its shape.\n * @param {HTMLFormElement} form\n * @param {HTMLElement} [submitter]\n * @returns\n */\n /**\n * Whether a control is one of a form's buttons, whose name travels only when it\n * is the one that submitted.\n * @param {Element & {type?: string}} el\n */\n static #submits(el) {\n return el.type === 'submit' || el.type === 'reset' || el.type === 'button';\n }\n static extractFrom(form, submitter) {\n let result = {};\n for (const el of form.elements) {\n if (!el.hasAttribute('name')) {\n continue;\n }\n //a form submits the name of the button that submitted it and of no other,\n //which is the platform's own rule. It used to fall out of the spinner\n //having disabled every button by the time the values were read, so the\n //affordance was quietly load-bearing for the payload\n if (Bindings.#submits(el) && el !== submitter) {\n continue;\n }\n //the submitter is exempt from the disabled check: a form holds its buttons\n //off while submitting, and its own submitter still names a value\n if (el.matches(':disabled') && el !== submitter) {\n continue;\n }\n result = Bindings.providePath(\n result,\n /** @type {string} */ (el.getAttribute('name')),\n Bindings.extract(el),\n );\n }\n return result;\n }\n\n /**\n * Writes a value into one control, the inverse of `extract`: a radio is\n * checked when its own value matches, a checkbox takes the value as its\n * checked state, and a multiple select selects the options the list names.\n * @param {Element & {dataset?: any} & {checked?: boolean} & {value?: any}} el\n * @param {any} raw the value as it arrived, coerced per control kind\n */\n static mutate(el, raw) {\n if (el.getAttribute('type') === 'radio') {\n //values are matched as strings, as ful-radio-group does: extract decodes\n //boolean radios, and payloads carry numbers where the attribute is text\n el.checked = raw != null && el.getAttribute('value') === String(raw);\n return;\n }\n if (el.getAttribute('type') === 'checkbox') {\n el.checked = raw;\n return;\n }\n if (el.tagName === 'SELECT' && /** @type {HTMLSelectElement} */ (el).multiple) {\n const values = Array.isArray(raw) ? raw.map(String) : raw == null ? [] : [String(raw)];\n Array.from(/** @type {HTMLSelectElement} */ (el).options).forEach((o) => {\n o.selected = values.includes(o.value);\n });\n return;\n }\n el.value = raw;\n }\n\n static mutateIn(form, values) {\n const names = Array.from(form.elements)\n .map((el) => el.getAttribute('name'))\n .filter((n) => n);\n for (const [flattenedKey, value] of Object.entries(Bindings.flatten(values, '', new Set(names)))) {\n for (const el of form.querySelectorAll(`[name='${CSS.escape(flattenedKey)}']`)) {\n Bindings.mutate(el, value);\n }\n }\n }\n\n static errors(form, es, scrollOnError) {\n //focus management announces the error of the field it lands on through\n //aria-describedby: a live region on top of that would read everything twice,\n //so the polite announcement exists only when nothing takes the focus\n form.querySelectorAll('ful-field-error').forEach((el) => {\n el.setAttribute('aria-live', scrollOnError ? 'off' : 'polite');\n });\n const pinned = (e) => (e.type === 'FIELD_ERROR' || e.type === 'INVALID_FORMAT') && e.context;\n const fieldErrors = es.filter(pinned);\n const globalErrors = es.filter((e) => !pinned(e));\n form.querySelectorAll(`[name]`).forEach((el) => {\n el.setCustomValidity?.('');\n });\n form.querySelectorAll('ful-errors').forEach((el) => {\n el.setAttribute('role', 'alert');\n el.replaceChildren();\n el.setAttribute('hidden', '');\n });\n const unmatched = [];\n fieldErrors.forEach((e) => {\n const name = e.context.replace(/\\[/g, '.').replace(/\\]\\./g, '.').replace(/\\]/g, '');\n const parts = name.split('.');\n for (let i = parts.length; i !== 0; --i) {\n const prefix = parts.slice(0, i).join('.');\n const targets = form.querySelectorAll(`[name='${CSS.escape(prefix)}']`);\n if (targets.length === 0) {\n continue;\n }\n //the most specific name wins: the walk exists so a composite field\n //owning a whole subtree catches its inner contexts, not so an outer\n //field doubles a problem an exact one already shows. The remaining\n //path rides along ('' on an exact match), so a composite can route\n //the problem to the inner control it names\n const context = parts.slice(i).join('.');\n targets.forEach((input) => {\n input.setCustomValidity?.(e.reason, context);\n });\n return;\n }\n //a context naming no field must not vanish: it reads in the banner\n unmatched.push(e);\n });\n const bannered = [...globalErrors, ...unmatched];\n form.querySelectorAll('ful-errors').forEach((el) => {\n const hel = /** @type HTMLElement} */ (el);\n if (bannered.length === 0) {\n hel.innerText = '';\n return;\n }\n //revealed before it is filled: a live region mutated while hidden and\n //shown afterwards is announced unreliably, the change having happened\n //where nothing was watching\n el.removeAttribute('hidden');\n hel.innerText = bannered.map((e) => e.reason).join('\\n');\n });\n if (es.length === 0 || !scrollOnError) {\n return;\n }\n Array.from(form.querySelectorAll(`:invalid`))\n .sort((a, b) => a.getBoundingClientRect().y - b.getBoundingClientRect().y)[0]\n ?.focus();\n }\n}\n\nexport { Bindings };\n","import { Attributes, ParsedElement } from '../../ftl/index.mjs';\n\n/**\n * The base of every form-associated ful field: a form-associated custom element\n * carrying the validity protocol, the field error live region, focus\n * delegation, the label chrome and the disabled, readonly and required claims.\n *\n * A subclass owns its template, its value semantics and its change events. It\n * implements `_build(conf)`, which builds its dom and returns the pieces the\n * base drives: the control, the error region, the label, and the optional\n * `claims`, `announces`, `freeze` and `also`. The base does the wiring,\n * the mounting and the application of the declared state. Nothing in the base\n * is there to be called from a subclass's build.\n *\n * The pieces are the contract: the claim setters, the validity protocol and\n * the aria wiring all act on them, so a field with no native control returns a\n * focusable piece of its own chrome as the control. The getters and `focus()`\n * are the only members that tolerate a not-yet-rendered element, where page\n * code may read a claim or ask for the focus before the upgrade; the\n * properties go live only after the render, as ParsedElement documents. The\n * base references no ful vocabulary, only what its subclasses return to it.\n */\nclass Field extends ParsedElement {\n static formAssociated = true;\n /**\n * The claim attributes and the value are observed here so every field,\n * including the custom ones, keeps them live after the upgrade: the\n * attribute is a third way to author a claim, beside the markup and the\n * property,\n * exactly as a native input's. The value defaults to the string mapper and\n * every field with its own vocabulary overrides it (`value:bool`,\n * `value:csv`, `value:json`).\n */\n static observed = ['disabled:presence', 'readonly:presence', 'required:presence', 'value'];\n /** the role the element internals carry, 'presentation' unless the control is its own */\n static ROLE = 'presentation';\n #control;\n #described;\n #descriptions = [];\n #errorId = null;\n #fieldError;\n #claims;\n #announces;\n #also = [];\n constructor() {\n super();\n //the base attached the internals: the platform allows one call per element\n this.internals.role = /** @type {typeof Field} */ (this.constructor).ROLE;\n }\n /** every element the claims mirror onto: the claim target, then the extra controls */\n #mirrors() {\n return [this.#claims ?? this.#control, ...this.#also].filter((el) => el);\n }\n /**\n * Takes what the build produced: keeps the pieces the base drives, wires the\n * aria and the label, and mounts the fragment.\n * @param {{fragment: any, control: any, error?: any, label?: any, described?: any,\n * claims?: any, announces?: any, freeze?: any, also?: any[]}} pieces\n */\n #wire({\n fragment,\n control,\n error,\n label = null,\n described = null,\n claims = null,\n announces = control,\n freeze = null,\n also = [],\n }) {\n this.#control = control;\n this.#fieldError = error;\n this.#claims = claims;\n this.#announces = announces;\n this.#also = also;\n if (freeze) {\n //a field with no usable native readOnly freezes by refusing the\n //gesture, not by inerting its subtree: inert takes the whole thing out\n //of the accessibility tree, so a readonly checkbox, radio group, filter\n //or file list was on screen and unreadable. Capturing, so it lands\n //before the control's own handlers and the platform's activation\n freeze.addEventListener(\n 'click',\n (evt) => {\n if (this.readonly) {\n evt.preventDefault();\n }\n },\n true,\n );\n }\n //the description lands on the control, or on the host where there is no\n //single control to describe (a radio group's legend names its fieldset)\n this.#described = described ?? control;\n if (error) {\n //named for what it is, the generic id being for whoever brings no name\n error.id = error.id || Attributes.uid('ful-field-error');\n this.#errorId = error.id;\n }\n //anything handed over before the field had a target lands here\n this.#describe();\n if (label) {\n Field.#name(this, label, control);\n }\n //the platform's implicit submission, stood in for where the field's own\n //protocol took it away: the inner controls carry form=\"\", so Enter in one\n //of them reaches no form and the platform submits nothing. Listening on the\n //host rather than the control means every listener the control has already\n //ran, so preventDefault is what it says: a ful-select accepting the\n //highlighted entry has consumed the key and no submit follows\n this.addEventListener('keydown', (evt) => {\n if (evt.key !== 'Enter' || evt.defaultPrevented || evt.isComposing) {\n return;\n }\n const target = /** @type {HTMLInputElement} */ (evt.target);\n //only where the platform cannot: a control still associated with the\n //form, an author's own input in a slot among them, submits on its own\n //and would otherwise submit twice\n if (target.form === this.internals.form || !Field.#submitsOnEnter(target)) {\n return;\n }\n this._requestSubmit();\n });\n this.replaceChildren(fragment);\n }\n /**\n * The platform's own rule for which control Enter submits from, measured on\n * Chromium, Firefox and WebKit: every input but the file picker and the\n * button-shaped ones, the checkbox and the radio included. A textarea takes\n * the newline, a select takes the key for its own list, and a button is\n * activated by it.\n */\n static #submitsOnEnter(el) {\n return el instanceof HTMLInputElement && !['file', 'button', 'submit', 'reset', 'image'].includes(el.type);\n }\n /**\n * Adds an element to the accessible description of the field's control and\n * answers whether the field took it.\n *\n * A field takes one whenever it is offered, before its own render as\n * readily as after: content slotted into a field is a custom element of its\n * own and may upgrade on either side of the field it stands in, which\n * happens in both directions in practice, a tooltip beating an async select\n * to its render while losing to a plain input. A description handed over\n * early waits here and is written the moment the field has somewhere to\n * write it, so the caller never has to know the order.\n *\n * The reference lands on the element handed over rather than on a wrapper\n * around it: a hidden element is included in a description only where it is\n * named directly, and content that reaches the description through a\n * wrapper is skipped while it is hidden. A popover closed until someone\n * opens it is exactly that, so the caller passes the popover itself.\n *\n * An attribute rather than `ariaDescribedByElements`: the property reflects\n * to nothing, so the description would live in the accessibility tree alone\n * and vanish entirely on a browser without aria element reflection.\n *\n * This is the field's half of the description protocol; `describable` in\n * `ful/descriptions.mjs` is the half the content uses to find the field.\n * @param {HTMLElement} el\n * @returns {boolean}\n */\n describedBy(el) {\n if (!el) {\n return false;\n }\n if (!el.id) {\n el.id = Attributes.uid('ful-described');\n }\n if (!this.#descriptions.includes(el.id)) {\n this.#descriptions.push(el.id);\n }\n this.#describe();\n return true;\n }\n /**\n * Writes the description the field has collected, the error region last:\n * the standing explanations are what the field always says, the problem is\n * the news. The field owns the attribute outright rather than appending to\n * whatever is there, so the order does not depend on who arrived when.\n */\n #describe() {\n if (!this.#described) {\n return;\n }\n const ids = [...this.#descriptions, this.#errorId].filter((id) => id);\n if (ids.length) {\n this.#described.setAttribute('aria-describedby', ids.join(' '));\n }\n }\n focus(options) {\n this.#control?.focus(options);\n }\n /**\n * Clears or reports one validation problem: the text lands on the field's\n * live region and the state on the element internals, driving `:invalid`\n * styling. Validation is the server's: the submit travels regardless, and\n * the problems come back pinned here. The error mapping pins on the most\n * specific field name a problem's context reaches, handing over the\n * remaining path ('' on an exact match): the base ignores it, a composite\n * field owning a whole subtree overrides to route the problem to the inner\n * control it names.\n * @param {string} [error]\n * @param {string} [context] the path below this field's name, '' when exact\n */\n setCustomValidity(error, context) {\n //the state rides the control the reader focuses, not only the element\n //internals: the host's role is presentation for most fields, so a\n //validity set there announces nothing where the caret actually is\n Attributes.set(this.#announces ?? this.#control, 'aria-invalid', error ? 'true' : null);\n if (!error) {\n this.internals.setValidity({});\n this.#fieldError.innerText = '';\n return;\n }\n this.internals.setValidity({ customError: true }, ' ');\n this.#fieldError.innerText = error;\n }\n /** Submits the associated form through its first submitter, as Enter on a native control would. */\n _requestSubmit() {\n const form = this.internals.form;\n if (!form) {\n return;\n }\n const candidates = /** @type {NodeListOf<HTMLButtonElement|HTMLInputElement>} */ (\n form.querySelectorAll('button:not(:disabled), input:not(:disabled)')\n );\n form.requestSubmit([...candidates].find((el) => el.type === 'submit' && el.form === form));\n }\n /**\n * Dispatches the field's change event: bubbling, not cancelable, the value\n * in the detail. Every field announces through this one method, and the detail\n * always carries the field's own `value`, so a listener can rely on\n * `el.value === evt.detail.value` whatever the field is. A field with more to\n * say adds keys beside it; none can replace it.\n * @param {Record<string, any>} [extras]\n */\n _notifyChange(extras = {}) {\n this.dispatchEvent(\n new CustomEvent('change', {\n bubbles: true,\n cancelable: false,\n detail: { value: this.value, ...extras },\n }),\n );\n }\n /** The html elements a label's `for` may point at, `input[type=hidden]` excepted. */\n static #LABELABLE = new Set(['BUTTON', 'INPUT', 'METER', 'OUTPUT', 'PROGRESS', 'SELECT', 'TEXTAREA']);\n /**\n * Names the control from the field's label, natively wherever the platform\n * allows it.\n *\n * `for` and `id` are the form the dom itself carries, so the association is\n * there for anything reading the markup rather than the accessibility tree:\n * an audit tool, the browser's autofill, a translation pass. It also makes\n * the label's click reach the control the way it does in a plain form, which\n * is focus for a text control and activation for a checkbox, so the field\n * needs no handler of its own.\n *\n * A control the platform will not let a label target, a composite carrying\n * `role=\"radiogroup\"` among them, takes `aria-labelledby` instead. That is an\n * attribute too, so the association is equally visible; what it does not carry\n * is the label's click, which is why the handler stays on that path only.\n *\n * Neither branch uses `ariaLabelledByElements`. The property reflects to no\n * attribute, so the name lived in the accessibility tree alone: nothing reading\n * the dom saw it, and on a browser without aria element reflection the\n * assignment is a silent expando and the field has no name at all.\n * @param {any} field\n * @param {HTMLElement} label\n * @param {any} control\n */\n static #name(field, label, control) {\n const labelable =\n Field.#LABELABLE.has(control.tagName) && control.getAttribute('type') !== 'hidden';\n if (!labelable) {\n if (!label.id) {\n label.id = Attributes.uid('ful-label');\n }\n control.setAttribute('aria-labelledby', label.id);\n //aria-labelledby carries the name but not the label's click\n label.addEventListener('click', () => field.focus());\n return;\n }\n if (!control.id) {\n control.id = Attributes.uid('ful-control');\n }\n label.setAttribute('for', control.id);\n }\n /**\n * Whether the field's chrome should answer a gesture. Badges, dropzones,\n * menus and labels are not form controls, so their handlers must ask the\n * effective state: matches(':disabled') covers the fieldset ancestry the\n * disabled property deliberately does not reflect, readonly the field's\n * own claim.\n */\n _interactive() {\n return !this.matches(':disabled') && !this.readonly;\n }\n /**\n * The field's value: every concrete field owns its semantics and overrides\n * this pair. The base pair exists so the form integration (the reset\n * protocol among others) has a member to write through; a custom field\n * forgetting its own keeps the base's inert one.\n * @type {any}\n */\n get value() {\n return undefined;\n }\n set value(v) {}\n /**\n * A reset restores the field's declared value, as a native control's reset\n * restores its markup default: the `value` attribute goes back through the\n * element's own mapper and value setter, so every field resets through its\n * own semantics. A field whose value is not attribute backed overrides this.\n */\n formResetCallback() {\n this.value = this.unmarshal('value', this.getAttribute('value'));\n }\n /**\n * The disabled protocol follows the semantics of a native form control:\n *\n * - the `disabled` attribute on the host is the field's own claim, and nothing\n * but its author ever writes or removes it, in markup or through the\n * property. The framework never claims on the form's behalf, so there is\n * nothing to unclaim and nothing to lose: a field declared disabled inside\n * a disabled `<fieldset>` stays disabled when the fieldset comes back,\n * exactly like a native input keeps its attribute.\n * - the effective state is the claim OR a disabled fieldset ancestry, which\n * the platform maintains on its own: `:disabled` matches both, a disabled\n * field is left out of the submitted values, and the inner native controls\n * are reached by the ancestry as descendants of the fieldset.\n * - the property reflects the claim only, like a native input's: a field\n * disabled by its ancestry reads `false` while `matches(':disabled')`\n * tells the effective state. Un-claiming inside a disabled fieldset\n * cannot enable the field.\n * - the inner controls mirror the claim and nothing else: the ancestry state\n * is never written anywhere, so it can never go stale, and the browser\n * composes the two on its own when it disables and re-enables a fieldset's\n * descendants. Subclass setters call super for the claim, then reach their\n * own controls, which mirror the claim like a native input's would.\n *\n * Because of this, formDisabledCallback carries nothing the framework needs\n * to apply, and the protocol does not define it.\n */\n get disabled() {\n //the claim only, like a native input: the effective state, claim or disabled\n //ancestry, is what :disabled matches\n return this.hasAttribute('disabled');\n }\n set disabled(d) {\n //the claim belongs to the author alone, nothing else ever writes it\n this.reflectTo('disabled', d);\n //the adopted pieces mirror the claim as a native input would: a disabled\n //fieldset ancestry is left to the browser, which reaches them as\n //descendants of the fieldset and re-enables them on its own\n for (const el of this.#mirrors()) {\n el.toggleAttribute('disabled', d);\n }\n }\n /**\n * A field is readonly through its control's native readOnly when it has one:\n * the control stays focusable and its text selectable, only editing is off.\n * Fields whose chrome must freeze too (popovers, buttons, label clicks) name\n * a `freeze` piece instead, whose gestures the base refuses while the claim\n * holds; the claim reflects on the host either way.\n */\n get readonly() {\n //the host attribute is the claim, as it is for disabled: every setter\n //reflects it, so one read answers however the field freezes\n return this.hasAttribute('readonly');\n }\n set readonly(v) {\n for (const el of this.#mirrors()) {\n el.readOnly = v;\n }\n //announced on the element whose role accepts it, not on whatever the\n //claims happen to ride: aria-readonly on a fieldset is dropped as invalid\n if (this.#announces) {\n Attributes.set(this.#announces, 'aria-readonly', v ? 'true' : null);\n }\n this.reflectTo('readonly', v);\n }\n /**\n * A field is required through aria: the claim reflects on the host, the\n * announcement lives on the adopted control.\n */\n get required() {\n //the claim, like disabled and readonly: the host attribute rather than\n //the projection, which a field with no role to announce on never carries\n return this.hasAttribute('required');\n }\n set required(d) {\n if (this.#announces) {\n Attributes.set(this.#announces, 'aria-required', d ? 'true' : null);\n }\n this.reflectTo('required', d);\n }\n /**\n * The field's render is the base's: the subclass builds its dom in `_build`\n * and hands back what it built, the base wiring the pieces, mounting the\n * fragment and applying the declared state. Nothing in the base is there to\n * be called from a subclass's build. `_build` may be async (a select\n * awaiting its prefetch); a field that builds synchronously stays so.\n */\n render(conf) {\n const built = /** @type {any} */ (this._build(conf));\n if (built instanceof Promise) {\n return built.then((pieces) => this.#settle(pieces));\n }\n this.#settle(built);\n return undefined;\n }\n #settle(pieces) {\n this.#wire(pieces);\n }\n /**\n * Builds the field's dom and answers the pieces the base drives. The one\n * method a concrete field implements beside its value pair, and the only\n * place its dom is created; the base does the wiring and the mounting.\n *\n * - `fragment` is mounted on the host\n * - `control` is the focusable target: focus, the aria and, by default, all\n * three claims reach it\n * - `error` is the field's live region\n * - `label`, when given, names the control and focuses it on click\n * - `described` moves the description off the control and onto another\n * element, the host where no single control can carry it: the error\n * region and anything `describedBy` is later handed both land there\n * - `claims` moves the three claims onto a wrapper the field disables as a\n * whole, leaving focus and aria on the control\n * - `announces` is the element whose role carries `aria-readonly` and\n * `aria-required`, the host where the widget role lives there; `null` for a\n * field whose control has no role that accepts them\n * - `freeze` is for a field with no usable native readOnly: the readonly\n * claim refuses the gestures inside it, leaving it focusable and readable\n * - `also` are further controls mirroring disabled and readOnly beside the\n * first\n *\n * A subclass extending another field's build spreads the pieces it answered\n * and overrides the keys it owns.\n * @param {{slots: any}} conf\n * @returns {any}\n */\n _build(conf) {\n throw new Error(`${this.constructor.name} must implement _build`);\n }\n}\n\nexport { Field };\n","import { Attributes, Localization, ParsedElement } from '../../ftl/index.mjs';\nimport { Failure } from '../../httpc/index.mjs';\nimport { Bindings } from './bindings.mjs';\nimport { AsyncEvents } from '../events/async.mjs';\n\n/** Submits a form's values as json to a url, mapping the request and the response through the configured mappers. */\nclass RemoteJsonFormLoader {\n #http;\n #url;\n #method;\n #requestMapper;\n #responseMapper;\n constructor(http, url, method, requestMapper, responseMapper) {\n this.#http = http;\n this.#url = url;\n this.#method = method;\n this.#requestMapper = requestMapper;\n this.#responseMapper = responseMapper;\n }\n prepare(values, form) {\n return this.#requestMapper(values, form);\n }\n async submit(request, form) {\n return await this.#http.request(this.#method, this.#url).json(request).fetch();\n }\n transform(response, form) {\n return this.#responseMapper(response, form);\n }\n}\n\n/** Submits a form without a request: the request mapper produces the result the response mapper then reads, for a form handled entirely on the page. */\nclass LocalFormLoader {\n #requestMapper;\n #responseMapper;\n constructor(requestMapper, responseMapper) {\n this.#requestMapper = requestMapper;\n this.#responseMapper = responseMapper;\n }\n async prepare(values, form) {\n return await this.#requestMapper(values, form);\n }\n async submit(request, form, response) {\n //nothing to send: whatever a submit:requested listener answered is the response\n return response;\n }\n async transform(response, form) {\n return await this.#responseMapper(response, form);\n }\n}\n\n/**\n * Builds the form's loader from its attributes: a local one when no action is\n * declared, a json post to it otherwise.\n *\n * A component registered under the `loader` attribute replaces this one and\n * must implement three methods, called in this order:\n *\n * - `prepare(values, form)` turns the extracted values into the request to send\n * - `submit(request, form, response)` performs it and returns the response. The\n * third argument is whatever a `submit:requested` listener already answered,\n * which is how a loader with nothing to send returns it unchanged\n * - `transform(response, form)` turns that response into the detail of the\n * `submit:success` event\n *\n * A rejection from any of the three is reported as a `submit:failure`.\n */\nclass FormLoader {\n static create(el, conf) {\n const http = el.component('http-client');\n const requestMapper = el.declared('request-mapper') ? el.component(el.declared('request-mapper')) : (v) => v;\n const responseMapper = el.declared('response-mapper') ? el.component(el.declared('response-mapper')) : (v) => v;\n const url = el.declared('action');\n if (!url) {\n return new LocalFormLoader(requestMapper, responseMapper);\n }\n const method = el.declared('method') ?? 'POST';\n return new RemoteJsonFormLoader(http, url, method, requestMapper, responseMapper);\n }\n}\n\n/**\n * Wraps its fields in a native form, extracts their values on submit and hands\n * them to a loader (loaders:form, or the action url as a json post),\n * announcing failures through the errors setter.\n */\nclass Form extends ParsedElement {\n //every one of these says how the form is built and submits, not what it holds:\n //the loader is named the same way ful-select and ful-table name theirs\n static attributes = [\n 'action',\n 'method',\n 'loader',\n 'request-mapper',\n 'response-mapper',\n 'clear-invalid-on-change:presence',\n 'scroll-on-error:presence',\n 'autocomplete',\n ];\n form;\n render() {\n const form = document.createElement('form');\n this.form = form;\n //the submit must travel regardless of validity: the server is the validation\n //authority, and the browser's own gate would block a resubmit behind\n //internals messages custom elements have no default UI for\n form.setAttribute('novalidate', '');\n Attributes.forward('form-', this, form);\n //the fields read it off whichever of the two they reach first, which depends\n //on whether they upgraded before or after this render: they cannot read it\n //off their own control, which carries form=\"\" and so has no form owner\n Attributes.set(form, 'autocomplete', this.declared('autocomplete'));\n form.replaceChildren(...this.childNodes);\n form.addEventListener('submit', async (e) => {\n e.preventDefault();\n e.stopPropagation();\n await this.submit(e.submitter ?? undefined);\n });\n //an aria-disabled control keeps its focus and its name, so the platform still\n //activates it: the refusal has to be ours, and capturing puts it ahead of\n //every listener the author registered on the button itself\n this.addEventListener(\n 'click',\n (evt) => {\n const target = /** @type Element */ (evt.target);\n if (!target.closest?.('[aria-disabled=\"true\"]')) {\n return;\n }\n evt.preventDefault();\n evt.stopImmediatePropagation();\n },\n true,\n );\n if (this.declared('clear-invalid-on-change')) {\n this.addEventListener('change', (/** @type any */ evt) => {\n evt.target.setCustomValidity?.('');\n });\n }\n this.replaceChildren(form);\n }\n #submitting = false;\n /**\n * Submits once: a submit while one is in flight is dropped before the\n * values are even extracted, so nothing fires and nothing travels; the\n * settled exchange re-arms the form. A write must not double behind a\n * second Enter or a programmatic call racing the first.\n * @param {HTMLElement} [submitter]\n * @returns\n */\n async submit(submitter) {\n if (this.#submitting) {\n return;\n }\n this.#submitting = true;\n this.spinner(true);\n //one try: building the loader and preparing the request are as much part of a\n //submit as sending it, and a mapper that throws is how a caller reports a\n //problem with the values\n let values;\n let request;\n try {\n const loader = this.component(this.declared('loader') ?? 'loaders:form').create(this);\n values = Bindings.extractFrom(this.form, submitter);\n request = await loader.prepare(values, this);\n const se = new CustomEvent('submit', {\n bubbles: true,\n cancelable: true,\n detail: { submitter, values, request },\n });\n if (!this.dispatchEvent(se)) {\n return;\n }\n this.errors = [];\n const sre = new CustomEvent('submit:requested', {\n bubbles: true,\n cancelable: false,\n detail: { submitter, values: se.detail.values, request: se.detail.request },\n });\n let response = await AsyncEvents.fireAsync(this, sre, { mode: 'pipeline' });\n request = sre.detail.request;\n\n response = await loader.submit(request, this, response);\n const mapped = await loader.transform(response, this);\n this.dispatchEvent(\n new CustomEvent('submit:success', {\n bubbles: true,\n cancelable: false,\n detail: { submitter, values, request, response: mapped },\n }),\n );\n } catch (e) {\n this.dispatchEvent(\n new CustomEvent('submit:failure', {\n bubbles: true,\n cancelable: false,\n detail: { submitter, values, request, exception: e },\n }),\n );\n if (e instanceof Failure) {\n this.errors = e.problems;\n }\n console.warn('failed to submit form', this, 'reason:', e);\n } finally {\n this.#submitting = false;\n this.spinner(false);\n }\n }\n /** The native reset, routing every field through its own value semantics. */\n reset() {\n this.form.reset();\n }\n #spinning = 0;\n /**\n * Reveals a spinner and gives it something to read. A spinner is a style-only\n * tag: the glyph is its own pseudo-element and the text is the author's, so one\n * carrying no text is a live region with nothing to announce. The label is\n * appended only where the author wrote none, and it is filled after the reveal,\n * a region mutated while hidden being announced unreliably.\n * @param {HTMLElement} el\n */\n #announce(el) {\n Attributes.defaultValue(el, 'role', 'status');\n el.hidden = false;\n if (el.textContent.trim() !== '') {\n return;\n }\n const label = document.createElement('span');\n label.className = 'ful-sr-only';\n label.dataset.ref = 'spinner-label';\n el.append(label);\n label.textContent = Localization.of().t('spinner.loading');\n }\n /** Shows the spinners and holds the submit buttons off, overlapping spins sharing one claim. */\n spinner(spin) {\n //spins can overlap (a caller's own spin may wrap a submit): only the\n //outermost one saves and restores the button states\n if (spin) {\n ++this.#spinning;\n if (this.#spinning !== 1) {\n return;\n }\n } else {\n this.#spinning = Math.max(0, this.#spinning - 1);\n if (this.#spinning !== 0) {\n return;\n }\n }\n //the form is the busy region: the table and the async sections say so the\n //same way, and a form that only dimmed its button said it to no one\n Attributes.set(this, 'aria-busy', spin ? 'true' : null);\n this.querySelectorAll('ful-spinner').forEach((el) => {\n const hel = /** @type HTMLElement */ (el);\n if (spin) {\n this.#announce(hel);\n return;\n }\n hel.hidden = true;\n hel.querySelector(':scope > [data-ref=spinner-label]')?.remove();\n });\n this.querySelectorAll('input,button').forEach((el) => {\n const hel = /** @type HTMLButtonElement|HTMLInputElement */ (el);\n if (hel.type !== 'submit' && hel.type !== 'reset') {\n return;\n }\n if (spin) {\n //aria-disabled, not disabled: the submitter is almost always the\n //focused element when a submit starts, and disabling what holds the\n //focus drops it to the body, losing the user's place mid transaction.\n //The refusal is the capturing handler below, and #submitting is the\n //guard that actually makes a second submit a no-op\n hel.dataset.wd = hel.getAttribute('aria-disabled') ?? '';\n hel.setAttribute('aria-disabled', 'true');\n } else {\n //a button that joined mid-spin was never saved: its authored state stands\n if (hel.dataset.wd === undefined) {\n return;\n }\n Attributes.set(hel, 'aria-disabled', hel.dataset.wd || null);\n delete hel.dataset.wd;\n }\n });\n }\n /** The values of the fields the form contains, extracted and filled back through Bindings. */\n set values(vs) {\n Bindings.mutateIn(this.form, vs);\n }\n get values() {\n return Bindings.extractFrom(this.form);\n }\n /** Pins problems to the fields they name, the banner taking the nameless ones. */\n set errors(es) {\n Bindings.errors(this.form, es, this.declared('scroll-on-error'));\n }\n}\n\nexport { FormLoader, Form };\n","import { Attributes, BoundedCache } from '../../ftl/index.mjs';\nimport { Field } from './field.mjs';\n\n//a null entry is a pattern that did not compile: cached like any other so the\n//warning is printed once rather than on every keystroke\nconst patternCache = new BoundedCache(100);\nconst compiled = (attr, pattern) =>\n patternCache.getOrCompute(`${attr}:${pattern}`, () => {\n try {\n return new RegExp(pattern, 'g');\n } catch (/** @type any */ e) {\n console.warn(`invalid ${attr} attribute`, pattern, e);\n return null;\n }\n });\n\n/**\n * The keystroke filter an input declares, as one function of the text.\n *\n * `keep` names the characters that survive and `reject` the ones that do not,\n * which are the same statement from either side: `keep=\"[0-9]\"` and\n * `reject=\"[^0-9]\"` both leave the digits. Keeping is the one worth reaching for,\n * the rejecting spelling of an allowed set being a double negative.\n */\n/**\n * The autofill token a field inherits from the form around it.\n *\n * A control is rendered with `form=\"\"` so that the host is the only thing that\n * submits, which also leaves it without a form owner, and the platform resolves\n * `autocomplete` through the form owner. So a form declaring it reaches nothing\n * on its own and the field reads the setting off the form element instead.\n *\n * The `form` a `ful-form` renders answers here, the host copying its token onto\n * it, and a plain `form` around ful fields answers too: the platform meant the\n * same thing by it, and its inheritance is broken here for the same reason. An\n * ancestor always upgrades before its descendants, so the rendered form is in\n * place by the time a field of its own builds.\n */\nconst inheritedAutocomplete = (el) => el.closest('form')?.getAttribute('autocomplete') ?? null;\n\nconst warnedBoth = new WeakSet();\nconst filterOf = (el) => {\n const keep = el.declared('keep');\n const reject = el.declared('reject');\n if (keep !== null && reject !== null && !warnedBoth.has(el)) {\n //the filter is read per keystroke, so the complaint is held per element\n warnedBoth.add(el);\n console.warn('a ful-input declares both keep and reject: keep is applied, reject is ignored', el);\n }\n if (keep !== null) {\n const re = compiled('keep', keep);\n //every match, concatenated: the attribute is a pattern rather than a\n //character class, so the kept text cannot be found by negating it\n return re && ((v) => (v.match(re) ?? []).join(''));\n }\n if (reject !== null) {\n const re = compiled('reject', reject);\n return re && ((v) => v.replace(re, ''));\n }\n return null;\n};\n\n/** A labelled text input over any native type or textarea; the temporal inputs are its subclasses. */\nclass Input extends Field {\n static observed = ['placeholder'];\n //configuration: the control is built from them and the value getter reads them,\n //but none of them is meant to change once the element is up\n static attributes = [\n 'type',\n 'v-type',\n 'keep',\n 'reject',\n 'uppercase:presence',\n 'trim:presence',\n 'autocomplete',\n ];\n static slots = true;\n static template = `\n <label>{{{{ slots.default }}}}</label>\n {{{{ slots.info }}}}\n <ful-control-group>\n <ful-affix data-tpl-if=\"slots.before\">{{{{ slots.before }}}}</ful-affix>\n <input data-tpl-if=\"type != 'textarea'\" data-tpl-type=\"type\" placeholder=\" \" form=\"\">\n <textarea data-tpl-if=\"type == 'textarea'\" placeholder=\" \" form=\"\"></textarea>\n <ful-affix data-tpl-if=\"slots.after\">{{{{ slots.after }}}}</ful-affix>\n </ful-control-group>\n <ful-field-error></ful-field-error>\n `;\n _input;\n _type() {\n //a numeric value wants the numeric widget (decimal normalization, the\n //right keyboard): v-type=number defaults the type, a declared one wins\n return this.declared('type') ?? (this.declared('v-type') === 'number' ? 'number' : 'text');\n }\n _build({ slots }) {\n const type = this._type();\n const fragment = this.template().withOverlay({ type, slots }).render();\n this._input = fragment.querySelector('input,textarea');\n\n //the browser reads autocomplete off the control it is classifying, so the\n //field's own token, or the form's where it declares none, is put there.\n //Set before the passthrough, which stays the last word\n Attributes.set(\n this._input,\n 'autocomplete',\n this.declared('autocomplete') ?? inheritedAutocomplete(this),\n );\n Attributes.forward('input-', this, this._input);\n this._input.addEventListener('input', (evt) => {\n const strip = filterOf(this);\n if (!strip) {\n return;\n }\n const before = evt.target.value;\n const after = strip(before);\n if (before === after) {\n return;\n }\n const start = evt.target.selectionStart;\n evt.target.value = after;\n if (start === null) {\n //email, number and the date types have no selection to restore\n return;\n }\n //the caret keeps its place among the characters that survived, so only the\n //ones stripped before it count\n const caret = strip(before.slice(0, start)).length;\n evt.target.setSelectionRange(caret, caret);\n });\n this._input.addEventListener('change', (evt) => {\n evt.stopPropagation();\n this._notifyChange();\n });\n return {\n fragment,\n control: this._input,\n error: fragment.querySelector('ful-field-error'),\n label: fragment.querySelector('label'),\n };\n }\n get value() {\n const uppercase = this.declared('uppercase');\n const trim = this.declared('trim');\n const v = this._input.value;\n const uppercased = uppercase ? v.toUpperCase() : v;\n const trimmed = trim ? uppercased.trim() : uppercased;\n if (trimmed === '') {\n return null;\n }\n if (this.declared('v-type') === 'number') {\n //typed values are an explicit opt in, as the select's k-type: blank\n //stays null, and a value that does not decode is kept as it is\n const n = Number(trimmed);\n return Number.isNaN(n) ? trimmed : n;\n }\n return trimmed;\n }\n set value(value) {\n this._input.value = value === '' || value === undefined ? null : value;\n }\n get placeholder() {\n const v = this._input.getAttribute('placeholder');\n return v === ' ' ? null : v;\n }\n set placeholder(d) {\n //without a placeholder :placeholder-shown never matches, and floating labels\n //rely on it, so a blank one stands in for none\n Attributes.set(this._input, 'placeholder', d ?? ' ');\n this.reflectTo('placeholder', d);\n }\n}\n\nexport { Input };\n","import { ParsedElement, Localization } from '../../ftl/index.mjs';\nimport { Input } from './input.mjs';\n\n/** Formats the yyyy-mm-dd date in its content in the page's locale, or the one its locale attribute names. */\nclass LocalDate extends ParsedElement {\n static attributes = ['locale', 'default'];\n render() {\n const content = this.textContent.trim();\n const [y, m, d] = content.split('-').map(Number);\n const parsed = content === '' ? null : new Date(y, m - 1, d);\n //content that does not name a date renders like none: formatting an\n //invalid date would throw and fail the upgrade over a template hole\n if (parsed === null || Number.isNaN(parsed.getTime())) {\n this.replaceChildren(this.declared('default') ?? '');\n return;\n }\n //the attribute wins, then the page's locale, then the platform default\n const { date } = Localization.of({ locale: this.declared('locale') ?? undefined });\n this.replaceChildren(date(parsed, { year: 'numeric', month: 'numeric', day: 'numeric' }));\n }\n}\n\n/** Formats the ISO instant in its content in the page's locale and timezone. */\nclass Instant extends ParsedElement {\n static attributes = ['locale', 'default'];\n render() {\n const content = this.textContent.trim();\n const parsed = content === '' ? null : new Date(Instant.isoToLocal(content));\n //content that does not name an instant renders like none, as ful-local-date\n if (parsed === null || Number.isNaN(parsed.getTime())) {\n this.replaceChildren(this.declared('default') ?? '');\n return;\n }\n const { date } = Localization.of({ locale: this.declared('locale') ?? undefined });\n this.replaceChildren(\n date(parsed, {\n year: 'numeric',\n month: 'numeric',\n day: 'numeric',\n hour: 'numeric',\n minute: 'numeric',\n second: 'numeric',\n hour12: false,\n }),\n );\n }\n //a date-only value names a calendar day, not a utc midnight: it is read in\n //the page's timezone, so the day it names is the day it lands on\n static #parse(v) {\n return /^\\d{4}-\\d{2}-\\d{2}$/.test(v) ? new Date(`${v}T00:00:00`) : new Date(v);\n }\n static isoToLocal(iso) {\n const d = Instant.#parse(iso);\n const pad = (n, v) => String(v).padStart(n, '0');\n const date = `${d.getFullYear()}-${pad(2, d.getMonth() + 1)}-${pad(2, d.getDate())}`;\n const time = `${pad(2, d.getHours())}:${pad(2, d.getMinutes())}:${pad(2, d.getSeconds())}.${pad(3, d.getMilliseconds())}`;\n return `${date}T${time}`;\n }\n static localToIso(local) {\n const d = Instant.#parse(local);\n return Number.isNaN(d.getTime()) ? null : d.toISOString();\n }\n}\n\n/** A date input whose bounds accept a date, now, or an offset such as +1d. */\nclass InputLocalDate extends Input {\n //declaration order is the application order: step first, since on a time\n //input min and max are snapped to its grid\n static observed = ['step', 'min', 'max'];\n _type() {\n return 'date';\n }\n get min() {\n const v = this._input.min;\n return v === '' ? null : v;\n }\n set min(v) {\n this._input.min = InputLocalDate.#fromIsoOrOffset(v);\n }\n get max() {\n const v = this._input.max;\n return v === '' ? null : v;\n }\n set max(v) {\n this._input.max = InputLocalDate.#fromIsoOrOffset(v);\n }\n get step() {\n const v = this._input.step;\n return v === '' ? null : v;\n }\n set step(v) {\n this._input.step = v ?? '';\n }\n static #fromIsoOrOffset(v) {\n if (!v) {\n return '';\n }\n //the offset is subtracted before formatting so the iso date is the local\n //calendar day, which toISOString alone would shift to utc\n const formatLocalDate = (date) =>\n new Date(date.getTime() - date.getTimezoneOffset() * 60000).toISOString().split('T')[0];\n if (v === 'now') {\n return formatLocalDate(new Date());\n }\n const re = /^([+-])(\\d+)([dmy])$/;\n const match = re.exec(v);\n if (!match) {\n return v;\n }\n const sign = match[1] === '-' ? -1 : 1;\n const offset = +match[2];\n const r = new Date();\n r.setHours(0, 0, 0, 0);\n switch (match[3]) {\n case 'd':\n r.setDate(r.getDate() + offset * sign);\n break;\n case 'm': {\n const originalDay = r.getDate();\n r.setMonth(r.getMonth() + offset * sign);\n if (r.getDate() !== originalDay) {\n r.setDate(0);\n }\n break;\n }\n case 'y':\n r.setFullYear(r.getFullYear() + offset * sign);\n break;\n }\n return formatLocalDate(r);\n }\n}\n\n/** A time input whose bounds accept a time, now, or an hour or minute offset, snapped to the step grid. */\nclass InputLocalTime extends InputLocalDate {\n _type() {\n return 'time';\n }\n get min() {\n const v = this._input.min;\n return v === '' ? null : v;\n }\n set min(v) {\n this._input.min = this.#fromNowOrOffset(v);\n }\n get max() {\n const v = this._input.max;\n return v === '' ? null : v;\n }\n set max(v) {\n this._input.max = this.#fromNowOrOffset(v);\n }\n /**\n * Resolves `now` and hour or minute offsets against the current time, wrapping\n * around midnight. `m` is minutes here, unlike the date offsets of the parent where\n * it is months: months mean nothing on a time. Anything else is passed through.\n */\n #fromNowOrOffset(v) {\n if (!v) {\n return '';\n }\n const resolved = new Date();\n if (v !== 'now') {\n const re = /^([+-])(\\d+)([hm])$/;\n const match = re.exec(v);\n if (!match) {\n return v;\n }\n const sign = match[1] === '-' ? -1 : 1;\n const offset = +match[2] * sign;\n if (match[3] === 'h') {\n resolved.setHours(resolved.getHours() + offset);\n } else {\n resolved.setMinutes(resolved.getMinutes() + offset);\n }\n }\n return InputLocalTime.#snapped(resolved, Number(this._input.step) || 60);\n }\n /**\n * Truncates a time to the step grid: min anchors that grid, so a bound that is not\n * on it makes every value on it invalid.\n */\n static #snapped(date, stepSeconds) {\n const pad = (n) => String(n).padStart(2, '0');\n const seconds = date.getHours() * 3600 + date.getMinutes() * 60 + date.getSeconds();\n const snapped = Math.floor(seconds / stepSeconds) * stepSeconds;\n const hh = pad(Math.floor(snapped / 3600));\n const mm = pad(Math.floor((snapped % 3600) / 60));\n return stepSeconds % 60 === 0 ? `${hh}:${mm}` : `${hh}:${mm}:${pad(snapped % 60)}`;\n }\n}\n\n/** A datetime input whose value is read and written as an ISO instant. */\nclass InputInstant extends Input {\n //declaration order is the application order: step first, since on a time\n //input min and max are snapped to its grid\n static observed = ['step', 'min', 'max'];\n _type() {\n return 'datetime-local';\n }\n get value() {\n return Instant.localToIso(this._input.value);\n }\n set value(v) {\n this._input.value = v ? Instant.isoToLocal(v) : '';\n }\n get min() {\n return Instant.localToIso(this._input.min);\n }\n set min(v) {\n this._input.min = v ? Instant.isoToLocal(v) : '';\n }\n get max() {\n return Instant.localToIso(this._input.max);\n }\n set max(v) {\n this._input.max = v ? Instant.isoToLocal(v) : '';\n }\n get step() {\n const v = this._input.step;\n return v === '' ? null : v;\n }\n set step(v) {\n this._input.step = v ?? '';\n }\n}\n\nexport { Instant, LocalDate, InputLocalDate, InputLocalTime, InputInstant };\n","import { Fragments, Localization, Templates } from '../../ftl/index.mjs';\nimport { Input } from './input.mjs';\n\n/** A file input with an optional dropzone and item list, enforcing the size and count limits it declares. */\nclass InputFile extends Input {\n /** how long a warning stands before the field retires it, matching the css fade */\n static WARNING_TIMEOUT = 5000;\n /**\n * A FileList holding exactly these files. The platform gives no way to\n * build one but through a DataTransfer, and every place that narrows a\n * selection rebuilt it by hand: five loops and three empty ones.\n * @param {Iterable<File>} [files]\n */\n static list(files = []) {\n const dt = new DataTransfer();\n for (const file of files) {\n dt.items.add(file);\n }\n return dt.files;\n }\n static observed = [\n 'placeholder',\n 'accept:csv',\n 'multiple:presence',\n 'item-list:presence',\n 'dropzone:presence',\n 'max-files:number',\n 'max-file-size:number',\n 'max-total-size:number',\n //re-declared so it lands after the constraints: assigning a value\n //validates the selection against them\n 'value',\n ];\n #accept;\n #items;\n #dropzone;\n #warnings;\n #group;\n _type() {\n return 'file';\n }\n static template = `\n <label>{{{{ slots.default }}}}</label>\n {{{{ slots.info }}}}\n <ful-control-group>\n <ful-affix data-tpl-if=\"slots.before\">{{{{ slots.before }}}}</ful-affix>\n <input data-tpl-type=\"type\" placeholder=\" \" form=\"\">\n <ful-affix data-tpl-if=\"slots.after\">{{{{ slots.after }}}}</ful-affix>\n </ful-control-group>\n <div data-ref=\"dropzone\" class=\"dropzone\" data-tpl-if=\"slots.dropzone\">\n {{{{ slots.dropzone }}}}\n </div>\n <div data-ref=\"dropzone\" class=\"default-dropzone\" data-tpl-if=\"!slots.dropzone\">\n {{ #l10n:t('files.dropzone-label') }}\n </div>\n <ful-item-list></ful-item-list>\n <ful-field-warnings role=\"status\" aria-live=\"polite\"></ful-field-warnings>\n <ful-field-error></ful-field-error>\n `;\n static templates = {\n items: `\n <ful-item data-tpl-each=\"files\" data-tpl-var=\"file\" data-tpl-data-name=\"file.name\">\n <div><span>{{ file.name }}</span><span>{{ #l10n:bytes(file.size) }}</span><button type=\"button\" data-tpl-aria-label=\"#l10n:t('files.remove')\"><ful-icon name=\"x-lg\" aria-hidden=\"true\"></ful-icon></button></div>\n </ful-item>\n `,\n warning: `<ful-field-warning>{{ #l10n:t(key, args) }}</ful-field-warning>`,\n };\n #itemstemplate;\n _build(conf) {\n const pieces = super._build(conf);\n const fragment = pieces.fragment;\n this.#items = fragment.querySelector('ful-item-list');\n //a slotted template replaces the stock item, the way a select's does: the\n //overlay is the same, so a custom item still reads the File it renders\n this.#itemstemplate =\n conf.slots?.items && !Fragments.isBlank(conf.slots.items) ? Templates.fromFragment(conf.slots.items) : null;\n this.#dropzone = fragment.querySelector('[data-ref=dropzone]');\n this.#warnings = fragment.querySelector('ful-field-warnings');\n this.#group = fragment.querySelector('ful-control-group');\n this.#warnings.addEventListener('animationend', (e) => {\n e.target.remove();\n });\n this.#items.addEventListener('click', (e) => {\n if (!e.target.closest('button')) {\n return;\n }\n if (!this._interactive()) {\n return;\n }\n const idx = [...this.#items.children].indexOf(e.target.closest('ful-item'));\n if (idx === -1) {\n return;\n }\n this.files = InputFile.list([...this.files].filter((f, i) => i !== idx));\n //the removal is the user's own gesture: it reports through change as the\n //picker's selection does, while the files setter stays silent like a native one\n this._notifyChange();\n });\n this.#dropzone.addEventListener('click', (e) => {\n if (!this._interactive()) {\n return;\n }\n this.querySelector('input')?.click();\n });\n\n this.#dropzone.addEventListener('dragover', (e) => {\n e.preventDefault();\n this.toggleAttribute('dragover', true);\n });\n this.#dropzone.addEventListener('dragleave', () => {\n this.toggleAttribute('dragover', false);\n });\n this.#dropzone.addEventListener('drop', (e) => {\n e.preventDefault();\n this.toggleAttribute('dragover', false);\n //the drop's default stays suppressed whatever the claims say: a\n //disabled field must not turn into a navigation target\n if (!this._interactive()) {\n return;\n }\n const dropped = [...e.dataTransfer.items].filter((i) => i.kind === 'file');\n const files = dropped.map((i) => i.getAsFile()).filter((f) => f !== null);\n if (files.length === 0 || (files.length > 1 && !this.multiple)) {\n return;\n }\n this.files = InputFile.list(files);\n //a drop is the user's own gesture too: a native file input receiving\n //one fires change on its own\n this._notifyChange();\n });\n this._input.addEventListener('change', (e) => {\n this.#update();\n });\n //a file input has no native freeze: readOnly does nothing to it, so the\n //control group is the frozen piece and the base's refusal of the click is\n //what keeps the picker shut. The dropzone and the item removals are\n //guarded on their own handlers\n return { ...pieces, freeze: this.#group };\n }\n /**\n * Re-reads the selection: the constraints run in order over what is there,\n * each dropping what it refuses, and the warnings and the item list are\n * rendered from what survives. Every path that changes the files ends here.\n */\n #update() {\n this.setCustomValidity();\n this.#warnings.replaceChildren();\n this.#ensureAcceptable();\n this.#ensureFileSizes();\n this.#ensureTotalSize();\n this.#ensureFilesCount();\n (this.#itemstemplate ?? this.template('items')).withOverlay({ files: this.files }).renderTo(this.#items);\n }\n warning(key, args) {\n this.template('warning').withOverlay({ key, args }).appendTo(this.#warnings);\n //the field retires its own warnings: the css fade is decoration, and a\n //theme that drops the keyframe, or a host stylesheet disabling animations,\n //used to leave them on screen until the next selection\n const warning = /** @type HTMLElement */ (this.#warnings.lastElementChild);\n setTimeout(() => warning.remove(), InputFile.WARNING_TIMEOUT);\n }\n /**\n * The native accept vocabulary: a dot-prefixed extension matches the file\n * name's suffix, a mime type (parameters stripped) matches the file's type,\n * and image/*, audio/*, video/* match their whole family. Anything else\n * matches nothing, as the native attribute ignores it.\n */\n #acceptable(file) {\n const name = file.name.toLowerCase();\n return this.#accept.some((token) => {\n const t = token.toLowerCase().split(';')[0].trim();\n if (t.startsWith('.')) {\n return name.endsWith(t);\n }\n if (t.endsWith('/*')) {\n return file.type.startsWith(`${t.slice(0, -1)}`);\n }\n return t.includes('/') && file.type === t;\n });\n }\n #ensureAcceptable() {\n if (!this.#accept.length) {\n return;\n }\n const unacceptable = [...this.files].filter((file) => !this.#acceptable(file));\n\n if (unacceptable.length === 0) {\n return;\n }\n this.warning('files.unacceptable-file-type', { types: this.#accept.join(', ') });\n this._input.files = InputFile.list([...this.files].filter((f) => !unacceptable.includes(f)));\n }\n #ensureFilesCount() {\n if (this.#maxFiles === null) {\n return;\n }\n if (this.files.length <= this.#maxFiles) {\n return;\n }\n this.warning('files.max-files-exceeded', { count: this.#maxFiles });\n this._input.files = InputFile.list();\n }\n\n #ensureFileSizes() {\n if (this.#maxFileSize === null) {\n return;\n }\n const oversized = [...this.files].filter((file) => file.size > this.#maxFileSize);\n if (oversized.length === 0) {\n return;\n }\n this.warning('files.max-file-size-exceeded', { size: Localization.of().bytes(this.#maxFileSize) });\n this._input.files = InputFile.list([...this.files].filter((f) => !oversized.includes(f)));\n }\n #ensureTotalSize() {\n if (this.#maxTotalSize === null) {\n return;\n }\n const totalSize = [...this.files].reduce((acc, file) => acc + file.size, 0);\n if (totalSize <= this.#maxTotalSize) {\n return;\n }\n this.warning('files.max-total-size-exceeded', { size: Localization.of().bytes(this.#maxTotalSize) });\n this._input.files = InputFile.list();\n }\n\n get accept() {\n return this.#accept;\n }\n set accept(vs) {\n this._input.accept = vs.join(',');\n this.#accept = vs;\n this.reflectTo('accept', vs);\n }\n get multiple() {\n return this._input.multiple;\n }\n set multiple(v) {\n this._input.multiple = v;\n this.reflectTo('multiple', v);\n }\n get files() {\n return this._input.files;\n }\n set files(vs) {\n this._input.files = vs;\n this.#update();\n }\n get file() {\n return this.files[0] ?? null;\n }\n set file(v) {\n this.files = InputFile.list(v ? [v] : []);\n }\n get value() {\n const names = Array.from(this._input.files).map((f) => f.name);\n return this.multiple ? names : (names[0] ?? null);\n }\n set value(v) {\n if (v) {\n return;\n }\n this.files = InputFile.list();\n }\n formResetCallback() {\n //a file selection's default is empty, as the platform's own reset: a\n //declared filename cannot be restored programmatically\n this.value = null;\n }\n get totalsize() {\n return Array.from(this.files).reduce((a, f) => a + f.size, 0);\n }\n #maxFiles;\n get maxFiles() {\n return this.#maxFiles;\n }\n set maxFiles(v) {\n this.#maxFiles = v;\n this.reflectTo('max-files', v);\n }\n #maxFileSize;\n get maxFileSize() {\n return this.#maxFileSize;\n }\n set maxFileSize(v) {\n this.#maxFileSize = v;\n this.reflectTo('max-file-size', v);\n }\n #maxTotalSize;\n get maxTotalSize() {\n return this.#maxTotalSize;\n }\n set maxTotalSize(v) {\n this.#maxTotalSize = v;\n this.reflectTo('max-total-size', v);\n }\n #useItemList;\n get itemList() {\n return this.#useItemList;\n }\n set itemList(v) {\n this.#useItemList = v;\n this.reflectTo('item-list', v);\n }\n #useDropzone;\n get dropzone() {\n return this.#useDropzone;\n }\n set dropzone(v) {\n this.#useDropzone = v;\n this.reflectTo('dropzone', v);\n }\n}\n\nexport { InputFile };\n","/**\n * The anchored popovers' fallback: where the platform lacks CSS anchor\n * positioning, the popovers ful wires on an invoker are placed beside it\n * by hand, the geometry the anchor css draws on its own. Where the\n * platform carries the css the wiring is a no-op: the stylesheet does\n * the work alone.\n */\n\nimport { Attributes } from '../../ftl/index.mjs';\n\n/** the viewport's breathing room when clamping, in pixels */\nconst PAD = 8;\nconst open = new Map();\nlet frame = 0;\nlet reflowWired = false;\n\nconst platformAnchors = () =>\n CSS.supports('anchor-name: --ful-probe') &&\n CSS.supports('position-anchor: --ful-probe') &&\n CSS.supports('position-area: bottom') &&\n CSS.supports('top: anchor(bottom)') &&\n CSS.supports('width: anchor-size(width)');\n\nconst clamp = (value, low, high) => Math.min(Math.max(value, low), Math.max(low, high));\n\n/** a note is the popover that draws a callout, and the only one these offsets serve */\nconst isNote = (popover) => popover.matches('ful-note, .ful-note, [placement]');\n\n/**\n * Reports where the invoker's centre falls inside the popover, which is what a\n * callout points at. The two are the same spot until the viewport pushes the\n * popover off its invoker, which the platform's own placement does as readily\n * as the hand placement below, so this is measured in both.\n */\nconst reportCallout = (popover, invoker) => {\n const box = invoker.getBoundingClientRect();\n const here = popover.getBoundingClientRect();\n //against the padding box, which is what a percentage inset resolves against\n popover.style.setProperty(\n '--ful-note-callout-inline',\n `${box.left + box.width / 2 - here.left - popover.clientLeft}px`,\n );\n popover.style.setProperty(\n '--ful-note-callout-block',\n `${box.top + box.height / 2 - here.top - popover.clientTop}px`,\n );\n};\n\nconst place = (popover, anchored) => {\n const { invoker, stretch } = anchored;\n const box = invoker.getBoundingClientRect();\n const viewport = document.documentElement;\n const vw = viewport.clientWidth;\n const vh = viewport.clientHeight;\n //the css gap lives in the margins, and the computed style is live: the\n //inline zero a previous placing left behind is dropped first so the numbers\n //read below are the stylesheet's own, not this function's own zero. Reading\n //them afterwards left every popover flush against its invoker\n popover.style.removeProperty('margin');\n const computed = getComputedStyle(popover);\n const gap = {\n top: parseFloat(computed.marginTop) || 0,\n right: parseFloat(computed.marginRight) || 0,\n bottom: parseFloat(computed.marginBottom) || 0,\n left: parseFloat(computed.marginLeft) || 0,\n };\n popover.style.right = 'auto';\n popover.style.bottom = 'auto';\n popover.style.margin = '0';\n if (stretch) {\n const width = Math.min(box.width, vw - 2 * PAD);\n popover.style.width = `${width}px`;\n popover.style.left = `${clamp(box.left, PAD, vw - width - PAD)}px`;\n const height = popover.getBoundingClientRect().height;\n popover.style.top = `${clamp(box.bottom + gap.top, PAD, vh - height - PAD)}px`;\n return;\n }\n //a popover wraps against the spot it lands on: the width is measured\n //wide open, the left clamped so it still fits, the vertical placed\n //against the height that width renders\n const note = isNote(popover);\n const placement = note ? (popover.getAttribute('placement') ?? 'bottom') : 'bottom';\n popover.style.removeProperty('max-width');\n const cap = Math.min(parseFloat(computed.maxWidth) || vw, vw - 2 * PAD);\n popover.style.maxWidth = `${cap}px`;\n popover.style.left = `${PAD}px`;\n const wide = popover.getBoundingClientRect().width;\n let left =\n placement === 'right'\n ? box.right + gap.left\n : placement === 'left'\n ? box.left - gap.right - wide\n : note\n ? box.left + box.width / 2 - wide / 2\n : box.left;\n left = clamp(left, PAD, vw - wide - PAD);\n popover.style.left = `${left}px`;\n popover.style.maxWidth = `${Math.min(cap, vw - PAD - left)}px`;\n const height = popover.getBoundingClientRect().height;\n const top =\n placement === 'top'\n ? box.top - gap.bottom - height\n : placement === 'right' || placement === 'left'\n ? box.top + box.height / 2 - height / 2\n : box.bottom + gap.top;\n popover.style.top = `${clamp(top, PAD, vh - height - PAD)}px`;\n if (note) {\n reportCallout(popover, invoker);\n }\n};\n\nconst unplace = (popover) => {\n for (const property of [\n 'top',\n 'left',\n 'right',\n 'bottom',\n 'margin',\n 'max-width',\n 'width',\n '--ful-note-callout-inline',\n '--ful-note-callout-block',\n ]) {\n popover.style.removeProperty(property);\n }\n};\n\nconst reflow = () => {\n frame = 0;\n for (const [popover, anchored] of open) {\n //the platform hides a popover removed while open without firing the\n //toggle that would have dropped its entry, so the pass that places the\n //open ones is also where a gone one is forgotten: it is the moment\n //anybody cares, and it needs no callback on either element's life\n if (!popover.isConnected || !anchored.invoker.isConnected) {\n open.delete(popover);\n continue;\n }\n place(popover, anchored);\n }\n};\n\nconst schedule = () => {\n if (!frame && open.size > 0) {\n frame = requestAnimationFrame(reflow);\n }\n};\n\n/**\n * CSS anchor positioning for a popover and the invoker it belongs to, with the\n * hand-placed fallback for the platforms that do not have it.\n */\nclass Anchors {\n /**\n * Anchors a popover to its invoker.\n *\n * The invoker is given an `anchor-name` and the popover a `position-anchor`\n * pointing at it, which is what a stylesheet needs to place the popover\n * itself: the library's own menus say `top: anchor(bottom); left:\n * anchor(left)`. **Writing that css is the caller's half of this.** Without\n * it the popover lands wherever the user agent puts a popover, which is not\n * beside the invoker.\n *\n * Where the platform has no anchor positioning the popover is placed here\n * instead, beside the invoker whenever it opens, clamped into the viewport,\n * following it on scroll and resize, and cleaned up on close. That placement\n * draws the geometry the css above describes, so the two agree.\n *\n * @param {HTMLElement} invoker the element the popover belongs to\n * @param {HTMLElement} popover the `[popover]` element to place\n * @param {object} [options]\n * @param {string} [options.prefix] prefixes the generated anchor name and id,\n * so the dom says which component a name belongs to\n * @param {boolean} [options.invoke] points the invoker's `popovertarget` at\n * the popover, giving toggle and light dismiss with no script of your own\n * @param {boolean} [options.expanded] keeps the invoker's `aria-expanded` in\n * step with the popover\n * @param {boolean} [options.stretch] widens the popover to its invoker, which\n * is what a combobox dropdown wants\n * @param {boolean} [options.handPlace] places here on every platform rather\n * than only as a fallback, which a popover asks for when it needs to know\n * where its invoker ended up: the tooltip's note points a callout at it, and\n * a pseudo-element cannot read an anchor outside its own containing block.\n * Such a popover declares no anchor placement in css, there being none to\n * agree with\n */\n static wire(\n invoker,\n popover,\n { prefix = 'ful-anchor', invoke = false, expanded = false, stretch = false, handPlace = false } = {},\n ) {\n const uid = Attributes.uid(prefix);\n if (invoke) {\n //popovertarget needs a target that can be named\n popover.id = popover.id || uid;\n invoker.setAttribute('popovertarget', popover.id);\n }\n const anchor = `--${uid}`;\n invoker.style.anchorName = anchor;\n popover.style.positionAnchor = anchor;\n if (expanded) {\n invoker.setAttribute('aria-expanded', 'false');\n popover.addEventListener('toggle', (/** @type any */ evt) => {\n invoker.setAttribute('aria-expanded', evt.newState === 'open' ? 'true' : 'false');\n });\n }\n //the naming above is what the stylesheet reads, so it happens either way:\n //only the hand placement below is the fallback, and only for a popover that\n //did not ask to be placed here whatever the platform offers\n if (!handPlace && platformAnchors()) {\n return;\n }\n const anchored = { invoker, stretch };\n popover.addEventListener('beforetoggle', (/** @type any */ evt) => {\n //placed before the showing, refined once laid out: the platform's\n //centered or corner spot never paints\n if (evt.newState === 'open') {\n place(popover, anchored);\n }\n });\n popover.addEventListener('toggle', (/** @type any */ evt) => {\n if (evt.newState === 'open') {\n open.set(popover, anchored);\n place(popover, anchored);\n } else {\n open.delete(popover);\n unplace(popover);\n }\n });\n if (!reflowWired) {\n reflowWired = true;\n document.addEventListener('scroll', schedule, true);\n window.addEventListener('resize', schedule);\n }\n }\n}\n\nexport { Anchors };\n","import { Attributes, Fragments, ParsedElement, Templates } from '../../ftl/index.mjs';\nimport { Claims } from '../claims.mjs';\nimport { Anchors } from '../disclosures/anchors.mjs';\nimport { Field } from './field.mjs';\nimport { VersionedLocalStorage } from '../storage.mjs';\nimport { Timing } from '../timing.mjs';\n\n/**\n * Fetches a select's whole vocabulary from a url and serves every later read\n * from it. Concurrent callers share one request, the options may be cached in\n * local storage under a revision, and reconfiguring the url discards both.\n */\nclass RemoteLoader {\n #http;\n #url;\n #method;\n #responseMapper;\n #prefetch;\n #revision;\n #data;\n #inFlight;\n #configs = new Claims();\n constructor({ http, url, method, responseMapper, prefetch, revision }) {\n this.#http = http;\n this.#url = url;\n this.#method = method;\n this.#responseMapper = responseMapper;\n this.#prefetch = prefetch;\n this.#revision = revision;\n this.#data = null;\n this.#inFlight = null;\n }\n async prefetch() {\n if (!this.#prefetch) {\n return;\n }\n await this.#ensureFetched();\n }\n async exact(...keys) {\n const data = await this.#ensureFetched();\n return data.filter(({ key }) => keys.some((r) => r == key));\n }\n async load(needle) {\n const data = await this.#ensureFetched();\n //includes would coerce a nullish needle to the string \"undefined\": no\n //needle means no filter, as the empty search the combobox opens with\n return data.filter(({ label }) => (label ?? '').toLowerCase().includes(needle?.toLowerCase() ?? ''));\n }\n /**\n * Drops the cached vocabulary so the next question refetches it. Any fetch\n * still in flight is detached: its outcome belongs to the configuration that\n * started it and must neither be served nor stored for the new one.\n */\n async invalidate() {\n this.#configs.invalidate();\n this.#data = null;\n this.#inFlight = null;\n }\n async reconfigureUrl(url) {\n await this.invalidate();\n this.#url = url;\n }\n async #ensureFetched() {\n if (this.#data === null) {\n if (this.#inFlight === null) {\n //held, not taken: concurrent fetch users share one configuration,\n //only a reconfiguration supersedes it\n const claim = this.#configs.hold();\n this.#inFlight = RemoteLoader.#revisionedData(this.#http, this.#method, this.#url, this.#revision)\n .then((raw) => {\n if (!claim.stale) {\n this.#data = this.#responseMapper(raw);\n }\n })\n .finally(() => {\n if (!claim.stale) {\n this.#inFlight = null;\n }\n });\n }\n await this.#inFlight;\n }\n if (this.#data === null) {\n throw new Error('superseded by a reconfiguration');\n }\n return this.#data;\n }\n static async #revisionedData(http, method, url, revision) {\n const storageKey = `${method}@${url}`;\n if (revision !== null) {\n const data = VersionedLocalStorage.load(storageKey, revision);\n if (data !== undefined) {\n return data;\n }\n }\n const data = await http.request(method, url).fetchJson();\n if (revision !== null) {\n try {\n VersionedLocalStorage.save(storageKey, revision, data);\n } catch (/** @type any */ e) {\n //the cache write is best effort: the fetched data is the answer,\n //a full quota must not fail the load that already succeeded\n console.warn('failed to cache the select options', e);\n }\n }\n return data;\n }\n}\n\n/** Asks the endpoint per query instead of fetching the vocabulary once, for a list too large to hold in memory. */\nclass PartialRemoteLoader {\n #http;\n #url;\n #method;\n #responseMapper;\n constructor({ http, url, method, responseMapper }) {\n this.#http = http;\n this.#url = url;\n this.#method = method;\n this.#responseMapper = responseMapper;\n }\n /**\n * Nothing is held between queries, so there is no cache to drop: the method\n * exists so a caller can invalidate any loader without knowing which it has.\n */\n async invalidate() {}\n async reconfigureUrl(url) {\n this.#url = url;\n }\n async exact(...keys) {\n const response = await this.#http\n .request(this.#method, this.#url)\n .param('k', ...keys)\n .fetchJson();\n return this.#responseMapper(response);\n }\n async load(needle) {\n const response = await this.#http.request(this.#method, this.#url).param('s', needle).fetchJson();\n return this.#responseMapper(response);\n }\n}\n\n/** Serves a select's options from an array held in memory, which is what the slotted `<option>` elements become. */\nclass InMemoryLoader {\n #data;\n constructor(data) {\n this.#data = data;\n }\n update(data) {\n this.#data = data;\n }\n /** The vocabulary is the data itself: update replaces it, so there is nothing to drop. */\n async invalidate() {}\n exact(...keys) {\n return this.#data.filter(({ key }) => keys.some((r) => r == key));\n }\n load(needle) {\n //no needle means no filter, as in RemoteLoader\n return this.#data.filter(({ label }) => (label ?? '').toLowerCase().includes(needle?.toLowerCase() ?? ''));\n }\n}\n\n/**\n * Builds the select's loader from its attributes: the slotted options in\n * memory, or a remote or chunked loader over src.\n *\n * A component registered under the `loader` attribute replaces this one and\n * must implement the same three methods, each answering `{ key, label,\n * metadata }` entries:\n *\n * - `prefetch()` warms the vocabulary if it can, and resolves either way\n * - `load(needle)` answers the entries matching the typed text, all of them\n * when the needle is nullish, which is the empty search the list opens with\n * - `exact(...keys)` answers the entries for those keys, used to label a value\n * assigned without going through the list\n */\nclass SelectLoader {\n /**\n * Builds a loader from a plain configuration, reading no dom: `data` alone\n * is the in-memory vocabulary, a `url` is fetched whole or, under\n * `mode: 'chunked'`, per query. A test, or a caller holding its own\n * configuration, builds a loader this way; `create` is the same thing with\n * an element's attributes parsed first.\n * @param {{ data?: any[], http?: any, url?: string, method?: string, mode?: string, prefetch?: boolean, revision?: string|null, responseMapper?: any }} conf\n */\n static from({ data, http, url, method = 'POST', mode, prefetch = false, revision = null, responseMapper }) {\n if (!url) {\n return new InMemoryLoader(data ?? []);\n }\n if ('chunked' === mode) {\n return new PartialRemoteLoader({ http, url, method, responseMapper });\n }\n return new RemoteLoader({ http, url, method, responseMapper, prefetch, revision });\n }\n static create(el, conf) {\n if (!el.declared('src')) {\n const els = Array.from(conf.options?.querySelectorAll('option') ?? []);\n return SelectLoader.from({\n data: els.map((e) => ({\n key: e.getAttribute('value') ?? e.innerText.trim(),\n label: e.innerText.trim(),\n metadata: undefined,\n })),\n });\n }\n return SelectLoader.from({\n http: el.component('http-client'),\n url: el.declared('src'),\n method: el.declared('method') ?? 'POST',\n mode: el.declared('mode'),\n prefetch: el.declared('preload'),\n revision: el.declared('revision'),\n responseMapper: SelectLoader.#responseMapperFrom(el),\n });\n }\n static #responseMapperFrom(el) {\n if (el.declared('k-expr') && el.declared('l-expr')) {\n return (response) => {\n const rows = el._registry\n .evaluator()\n .withOverlay(response)\n .evaluateExpression(el.declared('d-expr') ?? 'self');\n return rows.map((row) => {\n const evaluator = el._registry.evaluator().withOverlay(row);\n return {\n key: evaluator.evaluateExpression(el.declared('k-expr')),\n label: evaluator.evaluateExpression(el.declared('l-expr')),\n metadata: evaluator.evaluateExpression(el.declared('m-expr') ?? 'self'),\n };\n });\n };\n }\n if (el.declared('response-mapper')) {\n return el.component(el.declared('response-mapper'));\n }\n //the wire format servers send is the positional row: the default mapper\n //is what turns it into the entry the element speaks everywhere else\n return (/** @type any[] */ response) => response.map(([key, label, metadata]) => ({ key, label, metadata }));\n }\n}\n\n/** The options popup of a select: listbox semantics, one loading claim per show, a localized empty state. */\nclass Dropdown extends ParsedElement {\n static attributes = ['listbox'];\n static slots = true;\n static template = `\n <ful-spinner class=\"centered\" role=\"status\" hidden><span class=\"ful-sr-only\">{{ #l10n:t('spinner.loading') }}</span></ful-spinner>\n <p data-ref=\"empty\" aria-live=\"polite\" hidden>{{ #l10n:t('dropdown.empty') }}</p>\n <menu tabindex=\"-1\" role=\"listbox\" hidden></menu>\n `;\n static templates = {\n options: `\n <li data-tpl-each=\"self\" data-tpl-selected=\"index == 0\" data-tpl-value=\"index\" role=\"option\">\n {{ label }}\n </li>\n `,\n };\n #spinner;\n #menu;\n #empty;\n #optionstemplate;\n #options = new Map();\n #shows = new Claims();\n render({ slots }) {\n const fragment = this.template().render();\n this.#optionstemplate = Fragments.isBlank(slots.default)\n ? this.template('options')\n : Templates.fromFragment(slots.default);\n this.#spinner = fragment.querySelector('ful-spinner');\n this.#empty = fragment.querySelector('p[data-ref=empty]');\n this.#menu = fragment.querySelector('menu');\n //the listbox is named so a combobox can point aria-controls and\n //aria-activedescendant at it: a reference to an unnamed element resolves\n //to nothing, and the active option is announced to no one. The name comes\n //from the host when it gave one, since it has to set aria-controls before\n //this element upgrades\n this.#menu.id = this.declared('listbox') || Attributes.uid('ful-listbox');\n this.#menu.addEventListener('click', (evt) => {\n evt.stopPropagation();\n const li = evt.target.closest('li');\n if (!li) {\n this.hide();\n return;\n }\n this.#change(li);\n });\n this.replaceChildren(fragment);\n }\n #selected() {\n return this.#menu?.querySelector('[selected]') ?? this.#menu?.firstElementChild ?? null;\n }\n #highlight(li) {\n if (!li) {\n this.#activated(null);\n return;\n }\n for (const el of this.#menu.querySelectorAll('li')) {\n el.toggleAttribute('selected', el === li);\n }\n li.id ||= Attributes.uid('ful-option');\n this.#activated(li.id);\n li.scrollIntoView({\n block: 'nearest',\n behavior: matchMedia('(prefers-reduced-motion: reduce)').matches ? 'auto' : 'smooth',\n });\n }\n acceptSelection() {\n const selected = this.#selected();\n if (!selected) {\n return;\n }\n this.#change(selected);\n }\n update(values, keys = []) {\n if (values === undefined) {\n throw new Error('null data');\n }\n this.#options = new Map(values.map((v, i) => [String(i), v]));\n const data = values.map((entry, index) => ({ index, ...entry }));\n this.#optionstemplate.withOverlay(data).renderTo(this.#menu);\n for (const [index, li] of [...this.#menu.children].entries()) {\n const picked = keys.some((r) => r == values[index]?.key);\n li.toggleAttribute('picked', picked);\n //what is picked is what aria-selected means for a listbox: a tint alone\n //says it to whoever can see it and to no one else\n li.setAttribute('aria-selected', picked ? 'true' : 'false');\n }\n this.#empty.toggleAttribute('hidden', values.length !== 0);\n this.#menu.toggleAttribute('hidden', values.length === 0);\n const current = values.findIndex(({ key }) => keys.some((r) => r == key));\n this.#highlight(current >= 0 ? this.#menu.children[current] : this.#selected());\n }\n #change(target) {\n const index = target.getAttribute('value');\n const entry = this.#options.get(index);\n this.hide();\n this.dispatchEvent(\n new CustomEvent('change', {\n bubbles: true,\n cancelable: false,\n detail: { index, entry },\n }),\n );\n }\n hide() {\n //hiding ends the current claim: a search still in flight must neither\n //repopulate the list nor point the combobox at an option of a hidden dropdown\n this.#shows.invalidate();\n if (this.matches(':popover-open')) {\n this.hidePopover();\n }\n this.#activated(null);\n }\n /**\n * The option the reader is on, announced for whoever owns the combobox: the\n * dropdown is a view, so it names its active option and never reaches into\n * another element's aria to say so.\n */\n #activated(id) {\n this.dispatchEvent(new CustomEvent('activechange', { bubbles: false, cancelable: false, detail: { id } }));\n }\n\n get shown() {\n return this.matches(':popover-open');\n }\n async show(loader, keys = []) {\n //each show claims the dropdown: a search resolving after a newer show has\n //started, or after the dropdown was hidden again, is stale, and neither\n //renders nor highlights, whichever order the searches resolve in\n const claim = this.#shows.take();\n if (!this.matches(':popover-open')) {\n this.showPopover();\n }\n this.#menu.setAttribute('hidden', '');\n this.#spinner.removeAttribute('hidden');\n try {\n const data = await loader();\n if (claim.stale) {\n return;\n }\n this.update(data, keys);\n } catch (/** @type any */ e) {\n if (claim.stale) {\n //the newer show (or the hide that ended this one) owns the dropdown\n //and its outcome: a superseded failure is neither shown nor thrown\n return;\n }\n this.hide();\n throw e;\n } finally {\n if (!claim.stale) {\n this.#spinner.setAttribute('hidden', '');\n }\n }\n }\n async moveOrShow(forward, loader, keys = []) {\n if (this.shown) {\n const selected = this.#selected();\n const candidate = selected?.[`${forward ? 'next' : 'previous'}ElementSibling`];\n if (selected && candidate) {\n this.#highlight(candidate);\n }\n return;\n }\n await this.show(loader, keys);\n }\n jump(first) {\n const target = first ? this.#menu.firstElementChild : this.#menu.lastElementChild;\n if (target) {\n this.#highlight(target);\n }\n }\n page(forward) {\n const selected = this.#selected();\n if (!selected) {\n return;\n }\n const lis = Array.from(this.#menu.children);\n const step = this.#page();\n const target = lis[Math.max(0, Math.min(lis.length - 1, lis.indexOf(selected) + (forward ? step : -step)))];\n this.#highlight(target);\n }\n #page() {\n const first = this.#menu.firstElementChild;\n if (!first || first.offsetHeight === 0) {\n return 1;\n }\n return Math.max(1, Math.trunc(this.#menu.clientHeight / first.offsetHeight));\n }\n}\n\n/** A combobox acting like a select over a loader's vocabulary, single or multiple. */\nclass Select extends Field {\n //the loader's whole vocabulary is configuration, read once at the upgrade:\n //none of it is reactive, and declaring it here is what lets the loader be\n //built from a plain object rather than from an element\n static attributes = [\n 'name',\n 'loader',\n 'k-type',\n 'src',\n 'method',\n 'mode',\n 'preload:presence',\n 'revision',\n 'k-expr',\n 'l-expr',\n 'd-expr',\n 'm-expr',\n 'response-mapper',\n ];\n //the value attribute is a list of keys whether or not the select is multiple:\n //`set value` normalizes a list of one to a single key, and the getter answers a\n //scalar for a single select, so nothing downstream has to know which it was\n static observed = ['multiple:presence', 'item-list:presence', 'value:csv'];\n static slots = true;\n //a manual popover: the combobox keeps the focus on its input and owns\n //the whole lifecycle (typing, arrows, blur, Escape, Tab), so no light\n //dismiss and no popovertarget invoker; it anchors on its control group\n static template = `\n <label>{{{{ slots.default }}}}</label>\n {{{{ slots.info }}}}\n <ful-control-group>\n <ful-affix data-tpl-if=\"slots.before\">{{{{ slots.before }}}}</ful-affix>\n <ful-control>\n <input type=\"text\" form=\"\" autocomplete=\"off\" role=\"combobox\" aria-autocomplete=\"list\" aria-haspopup=\"listbox\" aria-expanded=\"false\">\n </ful-control>\n <ful-affix data-tpl-if=\"slots.after\">{{{{ slots.after }}}}</ful-affix>\n <ful-dropdown popover=\"manual\">{{{{ slots.dropdown }}}}</ful-dropdown>\n </ful-control-group>\n <ful-item-list></ful-item-list>\n <ful-field-error></ful-field-error>\n `;\n static templates = {\n items: `\n <ful-item data-tpl-each=\"entries\" data-tpl-var=\"entry\" data-tpl-data-key=\"entry.key\">\n <div><span>{{ entry.label }}</span><button type=\"button\" data-tpl-aria-label=\"#l10n:t('select.remove')\"><ful-icon name=\"x-lg\" aria-hidden=\"true\"></ful-icon></button></div>\n </ful-item>\n `,\n };\n #loader;\n #control;\n #ddmenu;\n #input;\n #items;\n #itemstemplate;\n #multiple;\n #warnedComma = false;\n #values = new Map();\n #assignments = new Claims();\n #editing = false;\n #dload;\n #abortdload;\n _build({ slots }) {\n const name = this.declared('name');\n this.#loader = this.component(this.declared('loader') ?? 'loaders:select').create(this, {\n options: slots.options,\n });\n\n this.#multiple = this.declared('multiple');\n //the prefetch is the vocabulary's concern, not the field's: the label, the\n //combobox and the error region paint at once and the properties go live with\n //them, where a slow endpoint used to hold up the whole upgrade. The loader\n //shares one in-flight fetch, so a first open during the prefetch joins it\n this.#loader.prefetch?.()?.catch((/** @type any */ e) => {\n console.warn('failed to prefetch select options', this, 'reason:', e);\n });\n const fragment = this.template().withOverlay({ slots, name }).render();\n this.#input = fragment.querySelector('input');\n this.#items = fragment.querySelector('ful-item-list');\n this.#itemstemplate =\n slots.items && !Fragments.isBlank(slots.items) ? Templates.fromFragment(slots.items) : null;\n Attributes.forward('input-', this, this.#input);\n this.#control = fragment.querySelector('ful-control');\n\n this.#ddmenu = fragment.querySelector('ful-dropdown');\n //named before it upgrades, so the combobox can control it from the start\n const listbox = Attributes.uid('ful-listbox');\n this.#ddmenu.setAttribute('listbox', listbox);\n this.#input.setAttribute('aria-controls', listbox);\n //one writer for the combobox's state: the dropdown says when it opens and\n //which option is active, the input's aria is the select's to keep\n this.#ddmenu.addEventListener('beforetoggle', (/** @type any */ e) => {\n const open = e.newState === 'open';\n this.#input.setAttribute('aria-expanded', open ? 'true' : 'false');\n if (!open) {\n this.#input.removeAttribute('aria-activedescendant');\n }\n });\n this.#ddmenu.addEventListener('activechange', (/** @type any */ e) => {\n Attributes.set(this.#input, 'aria-activedescendant', e.detail.id);\n });\n //each pair carries its own anchor: two selects on a page must not share one\n const group = fragment.querySelector('ful-control-group');\n Anchors.wire(group, this.#ddmenu, { prefix: 'ful-select', stretch: true });\n [this.#dload, this.#abortdload] = Timing.throttle(400, () => this.#open());\n this.#wireChrome();\n this.#wireChips();\n this.#wireInput();\n this.#wireSelection();\n return {\n fragment,\n control: this.#input,\n error: fragment.querySelector('ful-field-error'),\n label: fragment.querySelector('label'),\n };\n }\n /**\n * Pointer interaction: the element toggles the dropdown, the item list's\n * remove buttons and the control's badges drop their entry.\n */\n #wireChrome() {\n this.addEventListener('click', (/** @type any */ e) => {\n if (!this._interactive()) {\n return;\n }\n if (this.#ddmenu.shown) {\n this.#close();\n return;\n }\n this.#input.focus();\n this.#dload();\n });\n this.#items.addEventListener('click', (e) => {\n e.stopPropagation();\n if (!e.target.closest('button')) {\n return;\n }\n if (!this._interactive()) {\n return;\n }\n this.#removeKeyAt([...this.#items.children].indexOf(e.target.closest('ful-item')));\n });\n this.#control.addEventListener('click', (e) => {\n const badge = e.target instanceof Element ? e.target.closest('ful-badge') : null;\n if (!badge) {\n return;\n }\n e.stopPropagation();\n this.#removeBadge(badge);\n });\n }\n /**\n * Keyboard interaction over the chips: Enter/Space/Backspace/Delete remove,\n * arrows move between badges and the input, Escape returns to the input.\n */\n #wireChips() {\n this.addEventListener('keydown', (/** @type any */ e) => {\n const badge = e.target instanceof Element ? e.target.closest('ful-badge') : null;\n if (badge) {\n this.#chipKeydown(e, badge);\n return;\n }\n //the caret cannot move further left: hand the focus over to the chips,\n //as the backspace at the same spot already hands over the last entry\n if (\n 'ArrowLeft' === e.code &&\n e.target === this.#input &&\n this.#input.selectionStart === 0 &&\n this.#input.selectionEnd === 0\n ) {\n this.#badges().at(-1)?.focus();\n }\n });\n }\n #wireInput() {\n this.#input.addEventListener('change', (e) => {\n e.stopPropagation();\n });\n this.#input.addEventListener('focus', () => {\n if (this.#editing) {\n return;\n }\n this.#input.select();\n });\n this.#input.addEventListener('blur', (e) => {\n e.stopPropagation();\n if (e.relatedTarget && this.contains(e.relatedTarget)) {\n return;\n }\n this.#abortdload();\n this.#close();\n });\n this.#input.addEventListener('keydown', (e) => {\n if (!this._interactive()) {\n return;\n }\n this.#comboboxKeydown(e);\n });\n this.#input.addEventListener('input', (e) => {\n e.stopPropagation();\n if (!this._interactive()) {\n return;\n }\n this.#editing = true;\n this.#dload();\n });\n }\n #wireSelection() {\n this.#ddmenu.addEventListener('change', (e) => {\n e.stopPropagation();\n //a claim landing while the dropdown is open must not accept a pick:\n //disabled closes the list on its own (the focused input blurs), readonly\n //leaves it open, so the guard lives here\n if (!this._interactive()) {\n this.#close();\n return;\n }\n if (!this.#multiple) {\n this.#values.clear();\n }\n this.#editing = false;\n this.#values.set(this.#coerceKey(e.detail.entry.key), e.detail.entry);\n this.#changed();\n this.#syncBadges();\n this.#input.focus();\n this.#ddmenu.hide();\n if (!this.#multiple) {\n this.#input.select();\n }\n });\n }\n /** Hands the loader to the callback, for runtime reconfigurations. */\n async withLoader(fn) {\n return await fn(this.#loader);\n }\n /**\n * Drops whatever the loader is holding and asks it about the current selection\n * again, which is what a select whose vocabulary depends on another control\n * needs when that control changes. A key the loader no longer knows is dropped\n * from the selection, so a value invalidated by the change does not survive it,\n * and one it still knows keeps its place with a fresh label.\n *\n * Pass a url first where the vocabulary lives at a different address:\n *\n * citta.addEventListener('change', async () => {\n * await cap.withLoader((l) => l.reconfigureUrl(`/api/cap?citta=${citta.value}`));\n * await cap.reload();\n * });\n */\n async reload() {\n await this.#loader.invalidate?.();\n //the prefetch is a warm-up: a select configured to preload warms the new\n //vocabulary now rather than on the next open, as it did at the upgrade\n await this.#loader.prefetch?.();\n const keys = [...this.#values.keys()];\n if (keys.length === 0) {\n return;\n }\n await this.#resolve(keys, this.#assignments.take());\n }\n #badges() {\n return Array.from(this.#control.querySelectorAll(':scope > ful-badge'));\n }\n #removeBadge(badge) {\n if (!this._interactive()) {\n return;\n }\n this.#removeKeyAt(this.#badges().indexOf(badge));\n }\n /**\n * Drops the entry at the given index, if any: badges and item list entries\n * share the value map's ordering.\n */\n #removeKeyAt(index) {\n const key = Array.from(this.#values.keys())[index];\n if (key === undefined) {\n return;\n }\n this.#values.delete(key);\n this.#changed();\n this.#syncBadges();\n }\n #chipKeydown(e, badge) {\n switch (e.code) {\n case 'NumpadEnter':\n case 'Enter':\n case 'Space':\n case 'Backspace':\n case 'Delete': {\n e.preventDefault();\n this.#removeBadge(badge);\n this.#input.focus();\n break;\n }\n case 'ArrowLeft': {\n e.preventDefault();\n (this.#badges()[this.#badges().indexOf(badge) - 1] ?? this.#input).focus();\n break;\n }\n case 'ArrowRight': {\n e.preventDefault();\n (this.#badges()[this.#badges().indexOf(badge) + 1] ?? this.#input).focus();\n break;\n }\n case 'Escape': {\n this.#input.focus();\n break;\n }\n }\n }\n /**\n * The combobox keyboard contract: arrows browse and move, Home/End and\n * PageUp/PageDown navigate the open list, Enter accepts or submits,\n * Escape/Tab close, Backspace at the caret's leftmost spot drops the last\n * entry.\n */\n #comboboxKeydown(e) {\n switch (e.code) {\n case 'ArrowUp':\n case 'ArrowDown': {\n e.preventDefault();\n this.#arrowKeydown(e);\n break;\n }\n case 'Home': {\n if (this.#ddmenu.shown) {\n e.preventDefault();\n this.#ddmenu.jump(true);\n }\n break;\n }\n case 'End': {\n if (this.#ddmenu.shown) {\n e.preventDefault();\n this.#ddmenu.jump(false);\n }\n break;\n }\n case 'PageDown':\n case 'PageUp': {\n if (this.#ddmenu.shown) {\n e.preventDefault();\n this.#ddmenu.page('PageDown' === e.code);\n }\n break;\n }\n case 'Escape': {\n this.#abortdload();\n this.#close();\n break;\n }\n //both physical Enter keys: the switch reads e.code, which tells the\n //numpad's apart, and the base submits from either one\n case 'NumpadEnter':\n case 'Enter': {\n if (!this.#ddmenu.shown) {\n //nothing to accept: the key is left alone and the base submits\n //the form, as it does for every field whose control is detached\n return;\n }\n e.preventDefault();\n this.#editing = false;\n this.#display();\n this.#ddmenu.acceptSelection();\n break;\n }\n case 'Backspace': {\n //only where there is no text to delete first, and nothing selected:\n //backspace belongs to the search until the caret runs out of it\n if (this.#input.selectionStart === 0 && this.#input.selectionEnd === 0) {\n this.#removeKeyAt(this.#values.size - 1);\n }\n break;\n }\n case 'Tab': {\n this.#abortdload();\n this.#close();\n break;\n }\n }\n }\n #arrowKeydown(e) {\n const forward = 'ArrowDown' === e.code;\n //alt-down opens, alt-up closes\n if (e.altKey) {\n if (forward && !this.#ddmenu.shown) {\n this.#open();\n } else if (!forward && this.#ddmenu.shown) {\n this.#close();\n }\n return;\n }\n this.#browse();\n this.#ddmenu.moveOrShow(forward, () => this.#loader.load(this.#input.value), [...this.#values.keys()]);\n }\n #close() {\n this.#ddmenu.hide();\n this.#editing = false;\n this.#display();\n }\n /**\n * Opens the dropdown over the entries matching the input: typing filters,\n * browsing starts from the whole vocabulary, the selected keys are always\n * highlighted.\n */\n #open() {\n this.#browse();\n return this.#ddmenu.show(() => this.#loader.load(this.#input.value), [...this.#values.keys()]);\n }\n #browse() {\n if (this.#editing) {\n return;\n }\n this.#input.value = '';\n }\n #display() {\n const entry = this.#values.values().next().value;\n this.#input.value = this.#multiple ? '' : (entry?.label ?? '');\n }\n /** The selection in its one vocabulary: the change detail and the items overlay both speak it. */\n #selection() {\n return [...this.#values.values()];\n }\n #changed() {\n //the detail carries the keys the value property answers with, as every\n //other field's does, and the labeled selection beside them\n this._notifyChange({ entry: this.entry });\n }\n #syncBadges() {\n const badges = this.#multiple\n ? Array.from(this.#values.entries()).map(([k, entry], index) => {\n const b = document.createElement('ful-badge');\n b.setAttribute('role', 'button');\n //a roving tab stop: without one the chips are reachable only from\n //the input's caret, so Tab never finds them\n b.setAttribute('tabindex', index === 0 ? '0' : '-1');\n b.setAttribute('value', k);\n b.innerText = entry.label;\n return b;\n })\n : [];\n for (const b of this.#control.querySelectorAll(':scope > ful-badge')) {\n b.remove();\n }\n this.#input.before(...badges);\n if (!this.#editing) {\n this.#display();\n }\n this.#items.replaceChildren();\n (this.#itemstemplate ?? this.template('items'))\n .withOverlay({ entries: this.#selection() })\n .renderTo(this.#items);\n }\n /**\n * Coerces a key to the type declared by `k-type`. Keys reach the element from\n * both worlds: the `value` attribute is text, a loader returns whatever its\n * endpoint carries. One canonical type keeps the internal Map, which compares\n * keys strictly, consistent. A key that does not decode is left as it is.\n */\n #coerceKey(k) {\n switch (this.declared('k-type')) {\n case 'number': {\n const n = k === '' ? Number.NaN : Number(k);\n return Number.isNaN(n) ? k : n;\n }\n case 'boolean': {\n if (k === true || k === 'true') {\n return true;\n }\n if (k === false || k === 'false') {\n return false;\n }\n return k;\n }\n default:\n return String(k);\n }\n }\n\n set value(vs) {\n //the csv mapper yields [] for an absent attribute; an empty string assigned\n //through the property is left alone, being a usable key for an <option value=\"\">\n const keys = (vs == null ? [] : Array.isArray(vs) ? vs : [vs]).map((k) => this.#coerceKey(k));\n //a key is what the value attribute carries, and that attribute is a comma\n //separated list: a key holding a comma cannot be written back into markup, so\n //a server rendered page could never preselect it. Said once and kept, rather\n //than split here, where splitting would quietly truncate a single select\n if (!this.#warnedComma && keys.some((k) => typeof k === 'string' && k.includes(','))) {\n //once per element, not once per page: a loop assigning bad keys to one\n //select is one mistake, where fifty selects holding one each are fifty\n this.#warnedComma = true;\n console.warn('a ful-select key cannot contain a comma: it is unexpressible in the value attribute', this);\n }\n //the keys are known synchronously and are all `value` reads, so they are applied\n //now: only the labels need the loader, until then a key stands in for its own\n this.#values = new Map(keys.map((k) => [k, { key: k, label: k, metadata: undefined }]));\n const claim = this.#assignments.take();\n if (!this.#control) {\n return;\n }\n this.#syncBadges();\n if (keys.length === 0) {\n return;\n }\n this.#resolve(keys, claim);\n }\n /**\n * Resolves the labels of the assigned keys. A failed lookup is left to reject so\n * that it is reported like any other failure: the keys stay applied either way.\n */\n async #resolve(keys, claim) {\n const entries = await this.#loader.exact(...keys);\n if (claim.stale) {\n //a newer assignment has been made in the meantime\n return;\n }\n //label the keys that are still selected: a removal made while the lookup was in\n //flight must not be undone by it, and a key the loader does not know is dropped\n //the loader keys are coerced too, so they line up with the assigned ones\n const resolved = new Map(entries.map((e) => [this.#coerceKey(e.key), e]));\n for (const key of keys) {\n if (!this.#values.has(key)) {\n continue;\n }\n if (resolved.has(key)) {\n this.#values.set(key, resolved.get(key));\n } else {\n this.#values.delete(key);\n }\n }\n this.#syncBadges();\n }\n get value() {\n if (this.#multiple) {\n return [...this.#values.keys()];\n }\n return [...this.#values.keys()][0] ?? null;\n }\n /** The selection as {key, label, metadata} entries, the change detail's vocabulary: the only one for a single select, every one when multiple. */\n get entry() {\n const selection = this.#selection();\n if (this.#multiple) {\n return selection;\n }\n return selection[0] ?? null;\n }\n #useItemList;\n get multiple() {\n return this.#multiple;\n }\n set multiple(v) {\n this.#multiple = v;\n this.reflectTo('multiple', v);\n }\n get itemList() {\n return this.#useItemList;\n }\n set itemList(v) {\n this.#useItemList = v;\n this.reflectTo('item-list', v);\n }\n}\n\nexport { Dropdown, Select, SelectLoader };\n","import { Attributes, Fragments } from '../../ftl/index.mjs';\nimport { Field } from './field.mjs';\n\n/** A group of radios declared as ful-radio children, a fieldset carrying the group semantics. */\nclass RadioGroup extends Field {\n static attributes = ['name', 'type'];\n static slots = true;\n static ROLE = 'radiogroup';\n static template = `\n <fieldset>\n <legend>\n {{{{ slots.default }}}}\n </legend>\n <header data-tpl-if=\"slots.header\">\n {{{{ slots.header }}}}\n </header>\n <ful-radio-list>\n <div class=\"label-wrapper\" data-tpl-each=\"inputsAndLabels\" data-tpl-var=\"ial\">\n <label>\n {{{{ ial[0] }}}}\n <div>{{{{ ial[1] }}}}</div>\n </label>\n </div>\n </ful-radio-list>\n <ful-field-error></ful-field-error>\n <footer data-tpl-if=\"slots.footer\">\n {{{{ slots.footer }}}}\n </footer>\n </fieldset>\n `;\n #fieldset;\n #firstRadio;\n #booleanType;\n /**\n * @param {{slots: any}} conf\n * @returns {any}\n */\n _build({ slots }) {\n const name = this.declared('name') ?? Attributes.uid('ful-radiogroup');\n const radioEls = Array.from(slots.default.querySelectorAll('ful-radio'));\n const inputsAndLabels = radioEls.map((el) => {\n const input = document.createElement('input');\n input.setAttribute('type', 'radio');\n Attributes.forward('input-', this, input);\n Attributes.forward('', el, input);\n input.setAttribute('name', `${name}-ignore`);\n input.setAttribute('form', ``);\n input.addEventListener('change', (evt) => {\n evt.stopPropagation();\n this._notifyChange();\n });\n const label = Fragments.fromChildNodes(el);\n return [input, label];\n });\n\n radioEls.forEach((el) => {\n el.remove();\n });\n const fragment = this.template().withOverlay({ name, slots, inputsAndLabels }).render();\n this.#fieldset = /** @type HTMLElement */ (fragment.firstElementChild);\n this.#firstRadio = fragment.querySelector('input[type=radio]');\n this.#booleanType = this.declared('type') === 'boolean';\n //the group claims through its own fieldset, which carries disabled like a\n //native control, is the piece readonly freezes (radios have no editable\n //text to preserve) and announces the requirement; focus stays on the first radio,\n //and the host itself is described, there being no single control to name\n //and the legend being a fieldset's own label\n return {\n fragment,\n control: this.#firstRadio,\n error: fragment.querySelector('ful-field-error'),\n described: this,\n claims: this.#fieldset,\n //the radiogroup role is the host's, so the claims announce there: a\n //fieldset is a group, which accepts neither aria-readonly nor\n //aria-required\n announces: this,\n freeze: this.#fieldset,\n };\n }\n get value() {\n /** @type {HTMLInputElement|null} */\n const checked = this.querySelector('input[type=radio]:checked');\n return checked ? (this.#booleanType ? checked.value === 'true' : checked.value) : null;\n }\n set value(value) {\n const radios = this.querySelectorAll(`input[type=radio]`);\n const clear = () => {\n radios.forEach((el) => {\n /** @type {HTMLInputElement} */ (el).checked = false;\n });\n };\n if (value === null) {\n clear();\n return;\n }\n /** @type {HTMLInputElement|null} */\n const el = this.querySelector(`input[type=radio][value=${CSS.escape(String(value))}]`);\n //an unknown key clears, like a null assignment and like the select's\n //unknown keys: a stale radio must not keep answering for it\n if (el === null) {\n clear();\n return;\n }\n el.checked = true;\n }\n}\n\nexport { RadioGroup };\n","import { Attributes } from '../../ftl/index.mjs';\nimport { Field } from './field.mjs';\n\n/** A checkbox, or a switch under the type=switch claim. */\nclass Checkbox extends Field {\n static attributes = ['type'];\n static observed = ['value:bool'];\n static slots = true;\n static template = `\n <ful-choice data-tpl-switch=\"isSwitch\">\n <input type=\"checkbox\" data-tpl-role=\"isSwitch ? 'switch' : false\" form=\"\" placeholder=\" \">\n <label>{{{{ slots.default }}}}</label>\n {{{{ slots.info }}}}\n </ful-choice>\n <ful-field-error></ful-field-error>\n `;\n #container;\n #input;\n _build({ slots }) {\n const isSwitch = this.declared('type') === 'switch';\n const fragment = this.template().withOverlay({ slots, isSwitch }).render();\n this.#container = fragment.firstElementChild;\n this.#input = fragment.querySelector('input');\n Attributes.forward('input-', this, this.#input);\n this.#input.addEventListener('change', (evt) => {\n evt.stopPropagation();\n this._notifyChange();\n });\n //the base points the label at the input with for/id, so the click toggles\n //the way it does in a plain form: the input's own change listener above\n //carries the notification, and readonly is refused by the freeze below\n const label = fragment.querySelector('label');\n //a checkbox has no editable text to preserve, so readonly freezes the\n //whole choice, label click included: the container is the frozen piece\n return {\n fragment,\n control: this.#input,\n error: fragment.querySelector('ful-field-error'),\n label,\n freeze: this.#container,\n };\n }\n get value() {\n return this.#input.checked;\n }\n set value(value) {\n this.#input.checked = value;\n }\n}\n\nexport { Checkbox };\n","import { Attributes, Fragments, Nodes, ParsedElement, Rendering } from '../../ftl/index.mjs';\nimport { Claims } from '../claims.mjs';\nimport { Failure } from '../../httpc/index.mjs';\n\n/** The sort control of a table header: focusable, keyboard-activated, walking asc, desc, unsorted. */\nclass SortButton extends ParsedElement {\n static attributes = ['sorter'];\n static observed = ['order'];\n #order;\n render() {\n const sorter = this.declared('sorter');\n const orders = ['asc', 'desc', null];\n this.setAttribute('role', 'button');\n this.setAttribute('tabindex', '0');\n this.addEventListener('click', () => {\n const nextOrder = orders[(orders.indexOf(this.order) + 1) % 3];\n this.dispatchEvent(\n new CustomEvent('sort:requested', {\n bubbles: true,\n cancelable: true,\n detail: {\n value: { sorter, order: nextOrder },\n },\n }),\n );\n });\n this.addEventListener('keydown', (/** @type any */ evt) => {\n if (evt.code !== 'Enter' && evt.code !== 'Space') {\n return;\n }\n evt.preventDefault();\n this.click();\n });\n }\n\n get order() {\n return this.#order || null;\n }\n\n set order(value) {\n this.#order = value || null;\n this.reflectTo('order', this.#order);\n //the column announces the sort, not this button: an attribute on another\n //element is not a reflection and has no business inside the guard\n const th = this.closest('th');\n if (!th) {\n return;\n }\n Attributes.set(th, 'aria-sort', this.#order ? ('asc' === this.#order ? 'ascending' : 'descending') : null);\n }\n}\n\n/** The pager: a window of page links around the current one, and the reload control. */\nclass Pagination extends ParsedElement {\n static observed = ['total:number', 'current:number'];\n static attributes = ['pages:number'];\n static config = {\n prevIcon: 'chevron-left',\n nextIcon: 'chevron-right',\n reloadIcon: 'arrow-clockwise',\n };\n static template = `\n <ful-pagination-bar role=\"navigation\" data-tpl-aria-label=\"#l10n:t('pagination.navigation')\">\n <ul>\n <li data-ref=\"index\"> {{ #l10n:t('pagination.showing', { 'current': curr.label, 'total': total }) }}</li>\n <li data-ref=\"reload\"><button type=\"button\" data-tpl-aria-label=\"#l10n:t('pagination.reload')\"><ful-icon data-tpl-name=\"config.reloadIcon\" aria-hidden=\"true\"></ful-icon></button></li>\n <li data-ref=\"prev\">\n <button type=\"button\" data-tpl-disabled=\"prev.enabled ? false : true\" data-tpl-aria-label=\"#l10n:t('pagination.previous')\" data-tpl-data-page=\"prev.index\">\n <ful-icon data-tpl-name=\"config.prevIcon\" aria-hidden=\"true\"></ful-icon>\n </button>\n </li>\n <li data-ref=\"page\" data-tpl-each=\"pages\" data-tpl-var=\"page\">\n <button type=\"button\" data-tpl-aria-current=\"curr.index == page.index ? 'page' : false\" data-tpl-data-page=\"page.index\" >\n {{ page.label }}\n </button>\n </li>\n <li data-ref=\"next\">\n <button type=\"button\" data-tpl-disabled=\"next.enabled ? false : true\" data-tpl-aria-label=\"#l10n:t('pagination.next')\" data-tpl-data-page=\"next.index\">\n <ful-icon data-tpl-name=\"config.nextIcon\" aria-hidden=\"true\"></ful-icon>\n </button>\n </li>\n </ul>\n </ful-pagination-bar>\n `;\n #total = 0;\n #current = 0;\n render() {\n this.addEventListener('click', (/** @type any */ evt) => {\n const el = evt.target.closest('button');\n if (!el || el.hasAttribute('disabled')) {\n //a disabled button leads nowhere: the page it would ask for does not exist\n return;\n }\n if (el.getAttribute('aria-current') === 'page') {\n //the page already shown stays focusable and announced, so it is a\n //real control: it just has nothing to ask for\n return;\n }\n this.dispatchEvent(\n new CustomEvent('page:requested', {\n bubbles: true,\n cancelable: true,\n detail: {\n value: Number(el.dataset.page ?? this.#current),\n },\n }),\n );\n });\n }\n /**\n * Moves the pager to a page, a page count, or both, and repaints once. The\n * two are one state: writing them one at a time repainted the bar twice per\n * load, the first pass drawing the new page against the old count.\n * @param {{ current?: number|null, total?: number|null }} [state]\n */\n update({ current: toCurrent, total: toTotal } = {}) {\n if (toCurrent !== undefined) {\n this.#current = toCurrent ?? 0;\n }\n if (toTotal !== undefined) {\n this.#total = toTotal ?? 0;\n }\n this.reflectTo('current', this.#current);\n this.reflectTo('total', this.#total);\n const current = this.#current;\n const total = this.#total;\n const maxRender = this.declared('pages') ?? 5;\n //an empty table is one empty page: everything downstream renders it like\n //any single page result\n const pageCount = Math.max(total, 1);\n const hasPrev = current > 0;\n const hasNext = current + 1 < pageCount;\n //a disabled arrow carries no page: there is nothing valid for it to point at\n const prev = { index: hasPrev ? current - 1 : null, enabled: hasPrev };\n const curr = { index: current, label: current + 1 };\n const next = { index: hasNext ? current + 1 : null, enabled: hasNext };\n //the window holds at most maxRender pages, centered on the current one and slid\n //back towards the end so it stays full on the last pages\n const rendered = Math.max(1, Math.min(maxRender, pageCount));\n const first = Math.max(0, Math.min(current - Math.floor((rendered - 1) / 2), pageCount - rendered));\n const pages = Array.from({ length: rendered }, (_, offset) => ({\n index: first + offset,\n label: first + offset + 1,\n }));\n //the whole bar is replaced, so the control the reader activated is gone\n //by the time the new one paints: the focus follows it to its equivalent\n const focused = this.contains(document.activeElement)\n ? /** @type HTMLElement */ (document.activeElement).closest('li')?.getAttribute('data-ref')\n : null;\n const page = focused === 'page' ? /** @type any */ (document.activeElement).dataset.page : null;\n this.template().withOverlay({ total: pageCount, prev, curr, next, pages }).renderTo(this);\n if (!focused) {\n return;\n }\n const back =\n (page === null ? null : this.querySelector(`li[data-ref=page] button[data-page=\"${page}\"]`)) ??\n this.querySelector(`li[data-ref=${focused}] button:not(:disabled)`) ??\n this.querySelector('li[data-ref=page] button[aria-current=page]');\n /** @type HTMLElement */ (back)?.focus();\n }\n get total() {\n return this.#total;\n }\n set total(value) {\n //an absent attribute declares no pages, not a NaN one\n this.update({ total: value });\n }\n get current() {\n return this.#current;\n }\n set current(value) {\n this.update({ current: value });\n }\n}\n\n/** Reads the schema declaration into the header and row templates a table renders from. */\nclass TableSchemaParser {\n static parse(nodeOrFragment, template) {\n //nodeOrFragment is undefined when the slot is missing altogether\n const schema = nodeOrFragment ? Nodes.queryChildren(nodeOrFragment, 'schema') : null;\n if (!schema) {\n throw new Error('missing expected <schema>: ful-table needs a <template slot=\"schema\"> holding one');\n }\n const headersTr = document.createElement('tr');\n const rowsTr = document.createElement('tr');\n rowsTr.setAttribute('data-tpl-each', 'rows');\n for (const attr of schema.getAttributeNames()) {\n const value = schema.getAttribute(attr);\n headersTr.setAttribute(attr, value ?? '');\n rowsTr.setAttribute(attr, value ?? '');\n }\n const columns = Nodes.queryChildrenAll(schema, 'column');\n //only a sortable column carries the initial sort: an order without its\n //sorter would ask the backend for a \"null\" property\n const sort =\n columns\n .filter((v) => v.hasAttribute('order') && v.hasAttribute('sorter'))\n .map((v) => ({ sorter: v.getAttribute('sorter'), order: v.getAttribute('order') }))[0] ?? null;\n for (var column of columns) {\n const maybeTitleTag = Nodes.queryChildren(column, 'title');\n const sorter = column.getAttribute('sorter');\n const order = column.getAttribute('order');\n const titleNode = maybeTitleTag ?? document.createTextNode(column.getAttribute('title') ?? '');\n maybeTitleTag?.remove();\n column.removeAttribute('sorter');\n column.removeAttribute('order');\n column.removeAttribute('title');\n const wrappedTitleNode =\n !sorter && !order\n ? titleNode\n : (() => {\n const fulSorter = document.createElement('ful-sorter');\n if (sorter) {\n fulSorter.setAttribute('sorter', sorter);\n }\n if (order) {\n fulSorter.setAttribute('order', order);\n }\n fulSorter.append(titleNode);\n return fulSorter;\n })();\n const th = document.createElement('th');\n const td = document.createElement('td');\n //a column's attributes land on both cells, so a `data-tpl-*` written\n //once applies to the header and the body alike. `inHeaders` and\n //`inRows` are how an author tells them apart when that is not what\n //they meant: both templates carry the pair, so a column can say\n //`data-tpl-if=\"inRows\"` and appear in the body only\n for (const attr of column.getAttributeNames()) {\n const value = column.getAttribute(attr);\n th.setAttribute(attr, value ?? '');\n td.setAttribute(attr, value ?? '');\n }\n th.append(wrappedTitleNode);\n td.append(...column.childNodes);\n headersTr.append(th);\n rowsTr.append(td);\n }\n\n return {\n headersTemplate: template\n .withOverlay({ inHeaders: true, inRows: false })\n .withFragment(Fragments.from(headersTr)),\n rowsTemplate: template.withOverlay({ inHeaders: false, inRows: true }).withFragment(Fragments.from(rowsTr)),\n sort: sort,\n length: columns.length,\n };\n }\n}\n\n/** Serves a table's rows from an array held in memory, applying the sort and the paging itself. */\nclass InMemoryTableLoader {\n #data;\n constructor(data) {\n this.#data = data;\n }\n async load(pageRequest, sortRequest, filterRequest) {\n //the header renders a sorter per sortable column whatever the loader is,\n //so the local one answers it rather than leaving it inert\n const rows = this.#sorted(sortRequest);\n const begin = pageRequest.page * pageRequest.size;\n const end = begin + pageRequest.size;\n const page = rows.slice(begin, end);\n const totalElements = rows.length;\n return {\n data: page,\n size: totalElements,\n };\n }\n #sorted(sortRequest) {\n if (!sortRequest?.sorter) {\n return this.#data;\n }\n const { sorter, order } = sortRequest;\n const sign = order === 'desc' ? -1 : 1;\n return [...this.#data].sort((l, r) => {\n const a = l?.[sorter];\n const b = r?.[sorter];\n if (a === b) {\n return 0;\n }\n //a missing value sorts last whichever way the column points\n if (a == null) {\n return 1;\n }\n if (b == null) {\n return -1;\n }\n return (a < b ? -1 : 1) * sign;\n });\n }\n update(data) {\n this.#data = data;\n }\n}\n\n/** Requests one page of rows from a url, passing the page, the sort and the filters to the endpoint. */\nclass RemoteTableLoader {\n #http;\n #url;\n #method;\n #responseMapper;\n constructor(http, url, method, responseMapper = (response) => response) {\n this.#http = http;\n this.#url = url;\n this.#method = method;\n this.#responseMapper = responseMapper;\n }\n async load(pageRequest, sortRequest, filterRequest) {\n const filters = Object.entries(filterRequest).filter(([k, v]) => v);\n return await this.#http\n .request(this.#method, this.#url)\n .param('page', pageRequest.page)\n .param('size', pageRequest.size)\n .param('sort', sortRequest ? `${sortRequest.sorter},${sortRequest.order}` : null)\n .param('filters', filters.length > 0 ? JSON.stringify(Object.fromEntries(filters)) : null)\n .fetchJson()\n .then((response) => this.#responseMapper(response));\n }\n}\n\n/**\n * Builds the table's loader from its attributes: an in-memory one, or the\n * remote loader over src.\n *\n * A component registered under the `loader` attribute replaces this one and\n * must implement `load(pageRequest, sortRequest, filterRequest)`, answering\n * `{ data, page, size }` for the requested page. `pageRequest` carries the page\n * index and its size, `sortRequest` the column and direction, and\n * `filterRequest` the values of the filters in the slot.\n */\nclass TableLoader {\n static create(el, conf) {\n const url = el.getAttribute('src');\n if (url) {\n const http = el.component('http-client');\n const method = el.getAttribute('method') ?? 'GET';\n const responseMapper = el.hasAttribute('response-mapper')\n ? el.component(el.getAttribute('response-mapper'))\n : (/** @type any */ response) => response;\n return new RemoteTableLoader(http, url, method, responseMapper);\n }\n return new InMemoryTableLoader([]);\n }\n}\n\n/** A table loading its rows from a loader, with sorting, pagination and an optional filter form. */\nclass Table extends ParsedElement {\n static attributes = ['loader', 'autoload:presence'];\n /**\n * The page size stays live: a rows-per-page control is a normal thing to\n * put next to a table, and the size is the one piece of the request an\n * author changes after the table is up. The rest of the request is the\n * table's own state, moved by the pager, the sorters and the filter form.\n */\n static observed = ['page-size:number'];\n static slots = true;\n static config = {\n searchIcon: 'search',\n };\n static template = `\n <ful-form data-tpl-if=\"slots.filters\">\n {{{{ slots.filters }}}}\n </ful-form>\n <ful-table-wrapper>\n <table>\n <caption data-tpl-if=\"slots.caption\">{{{{ slots.caption }}}}</caption>\n <thead></thead>\n <tbody></tbody>\n <tbody data-ref=\"initial\">\n <tr>\n <td data-tpl-colspan=\"schema.length\">\n <div>\n <p data-tpl-if=\"config.searchIcon\"><ful-icon data-tpl-name=\"config.searchIcon\" aria-hidden=\"true\"></ful-icon></p>\n {{ #l10n:t('table.initial') }}\n </div>\n </td>\n </tr>\n </tbody>\n <tbody data-ref=\"loading\" hidden>\n <tr>\n <td data-tpl-colspan=\"schema.length\">\n <ful-spinner class=\"big\" role=\"status\"><span class=\"ful-sr-only\">{{ #l10n:t('spinner.loading') }}</span></ful-spinner>\n </td>\n </tr>\n </tbody>\n <tbody data-ref=\"feedback\" hidden>\n <tr>\n <td data-tpl-colspan=\"schema.length\">\n <div role=\"alert\">\n <p>{{ #l10n:t('table.error') }}</p>\n <div data-ref=\"feedback-error\"></div>\n </div>\n </td>\n </tr>\n </tbody>\n <tfoot data-tpl-if=\"slots.footer\">\n {{{{ slots.footer }}}}\n </tfoot>\n </table>\n </ful-table-wrapper>\n <ful-pagination current=\"0\" total=\"1\"></ful-pagination>\n `;\n static templates = {\n row: `\n <tr data-tpl-if=\"pageResponse.data.length == 0\">\n <td data-tpl-colspan=\"schema.length\">\n {{ #l10n:t('table.no-data') }}\n </td>\n </tr>\n {{{{ schema.rowsTemplate.withOverlay({'rows': pageResponse.data}).render() }}}}\n `,\n };\n #loader;\n #schema;\n #body;\n #loading;\n #noAutoload;\n #feedback;\n #paginator;\n #sorters;\n //initialised before the render so the size can be read and written on an\n //element the page has only just created\n /** @type {{ pageRequest: { page: number, size: number }, sortRequest: any, filterRequest: any }} */\n #latestRequest = { pageRequest: { page: 0, size: 10 }, sortRequest: null, filterRequest: {} };\n /** whether a load has been asked for, by autoload or by a caller */\n #loadRequested = false;\n #loads = new Claims();\n /** How many rows a page asks the loader for: the size the next load will carry. */\n get pageSize() {\n return this.#latestRequest.pageRequest.size;\n }\n /**\n * Changes the page size and reloads from the first page, the current index\n * meaning nothing under a new size. A table that has not loaded yet only\n * records it: writing the size is not a request to start loading, which is\n * what `autoload` and `reload()` are for.\n *\n * Absent or null is the default of ten, so removing the attribute restores\n * it rather than asking the loader for NaN rows.\n */\n set pageSize(value) {\n const size = value ?? 10;\n if (size === this.#latestRequest.pageRequest.size) {\n return;\n }\n this.#latestRequest = { ...this.#latestRequest, pageRequest: { page: 0, size } };\n if (!this.#loadRequested) {\n return;\n }\n //the rejection escapes on purpose, as it does for the page, sort and\n //filter listeners: load renders its own error state and the unhandled\n //rejection is what reports the failure\n this.reload();\n }\n async render({ slots }) {\n const template = this.template();\n const schema = TableSchemaParser.parse(slots.schema, template);\n const fragment = template.withOverlay({ slots, schema }).render();\n const tableWrapper = /** @type HTMLTableElement */ (Nodes.queryChildren(fragment, 'ful-table-wrapper'));\n const table = /** @type HTMLTableElement */ (tableWrapper.querySelector('table'));\n Attributes.forward('table-', this, table);\n this.#loader = this.component(this.declared('loader') ?? 'loaders:table').create(this);\n\n this.#schema = schema;\n this.#body = table.querySelector(':scope > tbody');\n this.#loading = table.querySelector(':scope > tbody[data-ref=loading]');\n this.#noAutoload = table.querySelector(':scope > tbody[data-ref=initial]');\n this.#feedback = table.querySelector(':scope > tbody[data-ref=feedback]');\n this.#paginator = Nodes.queryChildren(fragment, 'ful-pagination');\n this.replaceChildren(fragment);\n const thead = /** @type HTMLTableSectionElement */ (this.querySelector('thead'));\n schema.headersTemplate.renderTo(thead);\n this.#sorters = thead.querySelectorAll('ful-sorter');\n await Rendering.waitForChildren(this);\n\n const maybeForm = /** @type any */ (Nodes.queryChildren(this, 'ful-form'));\n //the declared size lands here rather than through the setter: the base\n //applies the observed values after the render returns, and by then the\n //autoload below has already asked for the first page\n this.#latestRequest = {\n pageRequest: {\n page: 0,\n size: this.declared('page-size') ?? 10,\n },\n sortRequest: schema.sort,\n filterRequest: maybeForm?.values ?? {},\n };\n //the page, sort and filter listeners let load's rejection escape on purpose:\n //load renders its own error state, and the unhandled rejection is what\n //reports the failure (the autoload below reports the same way)\n maybeForm?.addEventListener('submit:success', async (evt) => {\n await this.load(\n {\n page: 0,\n size: this.#latestRequest.pageRequest.size,\n },\n this.#latestRequest.sortRequest,\n evt.detail.request,\n );\n });\n this.addEventListener('page:requested', async (/** @type any */ e) => {\n await this.load(\n {\n page: e.detail.value,\n size: this.#latestRequest.pageRequest.size,\n },\n this.#latestRequest.sortRequest,\n this.#latestRequest.filterRequest,\n );\n });\n this.addEventListener('sort:requested', async (/** @type any */ e) => {\n const sortRequest = e.detail.value.order ? e.detail.value : null;\n await this.load(this.#latestRequest.pageRequest, sortRequest, this.#latestRequest.filterRequest);\n //only the load that still owns the table commits the header: a superseded\n //sort must not wipe the arrows of the one that won, and a failed one\n //leaves them where they were\n if (this.#latestRequest.sortRequest !== sortRequest) {\n return;\n }\n this.#sorters.forEach((s) => {\n s.order = null;\n });\n e.target.order = e.detail.value.order;\n });\n if (this.declared('autoload')) {\n //not awaited: the first load must not hold up the upgrade, and a loader that\n //fails or never answers must not keep ftl:ready from firing for the page.\n //load renders its own error state and lets the failure reject, so it is reported\n this.reload();\n }\n }\n\n async reload() {\n return await this.load(\n this.#latestRequest.pageRequest,\n this.#latestRequest.sortRequest,\n this.#latestRequest.filterRequest,\n );\n }\n async load(pageRequest, sortRequest, filterRequest) {\n //marked before the await, not when a response comes back: a size written\n //while the first load is still in flight has to reload rather than be\n //overwritten by the answer to the request it replaced\n this.#loadRequested = true;\n //each load claims the table: a response resolving after a newer load has\n //started is stale, and neither renders nor updates the request a later\n //reload replays, whichever order the responses arrive in\n const claim = this.#loads.take();\n this.#body.replaceChildren();\n this.#loading.removeAttribute('hidden');\n this.#feedback.setAttribute('hidden', '');\n this.#noAutoload.setAttribute('hidden', '');\n this.setAttribute('aria-busy', 'true');\n try {\n const pageResponse = await this.#loader.load(pageRequest, sortRequest, filterRequest);\n if (claim.stale) {\n return;\n }\n this.#latestRequest = { pageRequest, sortRequest, filterRequest };\n this.#update(pageRequest, sortRequest, filterRequest, pageResponse);\n } catch (/** @type any */ error) {\n if (claim.stale) {\n //the newer load owns the table and its outcome: a superseded\n //failure is neither shown nor thrown\n return;\n }\n this.#loading.setAttribute('hidden', '');\n this.#feedback.removeAttribute('hidden');\n this.#feedback.querySelector('[data-ref=feedback-error]').textContent = Failure.problemsText(\n error,\n `${error}`,\n );\n throw error;\n } finally {\n //a superseded load owns nothing, the newer one's busy state included\n if (!claim.stale) {\n this.removeAttribute('aria-busy');\n }\n }\n }\n /** Hands the loader to the callback, for runtime reconfigurations. */\n async withLoader(fn) {\n return await fn(this.#loader);\n }\n async resetWithFilter(filterRequest) {\n return await this.load(\n {\n page: 0,\n size: this.#latestRequest.pageRequest.size,\n },\n this.#latestRequest.sortRequest,\n filterRequest,\n );\n }\n #update(pageRequest, sortRequest, filterRequest, pageResponse) {\n const pages = Math.ceil(pageResponse.size / pageRequest.size);\n const lastPage = Math.max(0, pages - 1);\n if (pageRequest.page > lastPage) {\n //the data shrank behind the page being answered: the last page that\n //still exists is loaded instead of an out-of-range empty one\n this.load({ page: lastPage, size: pageRequest.size }, sortRequest, filterRequest);\n return;\n }\n this.#loading.setAttribute('hidden', '');\n this.#body.replaceChildren(\n this.template('row')\n .withOverlay({\n schema: this.#schema,\n pageRequest,\n filterRequest,\n pageResponse,\n })\n .render(),\n );\n //one move, one repaint: the page and the count are the same state\n this.#paginator.update({ current: pageRequest.page, total: pages });\n }\n}\n\nexport { TableLoader, SortButton, Table, TableSchemaParser, Pagination };\n","import { Attributes } from '../../ftl/index.mjs';\nimport { Anchors } from '../disclosures/anchors.mjs';\n\n/**\n * An invoker button paired with the `ul[popover][role=menu]` that follows it:\n * the chrome behind every filter's operator, sensitivity and boolean value.\n *\n * It fills the menu from a vocabulary, wires it the first time more than one\n * choice survives the whitelist, pins the button to a static glyph when a\n * single one does, owns the roving focus and the Escape/Enter handling, and\n * keeps the button's value, glyph and aria-label in step. A pick that changes\n * the value calls back; the host decides what that means.\n *\n * The button's `value` attribute is the store, as it is for a native control:\n * the menu protocol finds the current item by it, and nothing mirrors it.\n */\nclass ChoiceButton {\n /** The declared choices narrowed to a vocabulary; an empty or unknown set means all of it. */\n static narrow(declared, vocabulary) {\n const narrowed = (declared ?? []).filter((choice) => vocabulary.includes(choice));\n return narrowed.length > 0 ? narrowed : [...vocabulary];\n }\n #button;\n #menu;\n #vocabulary;\n #glyphs;\n #labelFor;\n #display;\n #interactive;\n #onPick;\n #allowed;\n #claimed = false;\n #wired = false;\n /**\n * @param {HTMLElement} button the invoker, whose next sibling is its menu\n * @param {{vocabulary: string[], glyphs?: Record<string,string>, labelFor?: (v: string) => string,\n * display?: ((v: string) => string)|null, interactive?: () => boolean, onPick?: (v: string) => void}} conf\n */\n constructor(\n button,\n { vocabulary, glyphs = {}, labelFor = (v) => v, display = null, interactive = () => true, onPick = () => {} },\n ) {\n this.#button = button;\n this.#menu = /** @type HTMLElement */ (button.nextElementSibling);\n this.#vocabulary = vocabulary;\n this.#glyphs = glyphs;\n this.#labelFor = labelFor;\n //the button shows the compact glyph by default; a menu whose choices have\n //no glyph shows the word instead\n this.#display = display ?? ((choice) => glyphs[choice] ?? choice);\n this.#interactive = interactive;\n this.#onPick = onPick;\n this.#allowed = [...vocabulary];\n this.#menu.addEventListener('click', (evt) => {\n const target = /** @type HTMLElement */ (evt.target);\n const item = /** @type HTMLElement | null */ (target.closest('li > a'));\n if (!item || !this.#interactive()) {\n return;\n }\n const picked = /** @type string */ (item.getAttribute('value'));\n const previous = this.value;\n this.value = picked;\n /** @type any */ (this.#menu).hidePopover?.();\n if (previous !== picked) {\n this.#onPick(picked);\n }\n });\n }\n /** The choices the host declared, narrowed to the vocabulary; an empty or unknown set means all of it. */\n get allowed() {\n return this.#allowed;\n }\n set allowed(declared) {\n this.#allowed = ChoiceButton.narrow(declared, this.#vocabulary);\n this.#fill();\n if (!this.#wired && this.#allowed.length > 1) {\n this.#wire();\n this.#wired = true;\n }\n this.#sync();\n if (this.pinned) {\n this.value = this.#allowed[0];\n }\n }\n /** A single surviving choice pins the button: a static glyph, no popup, and every read answers it. */\n get pinned() {\n return this.#allowed.length < 2;\n }\n get value() {\n return this.#button.getAttribute('value');\n }\n set value(choice) {\n this.#button.setAttribute('value', choice);\n //the button carries the compact glyph, announced through its label: the\n //menu is where the localized words live\n this.#button.textContent = this.#display(choice);\n Attributes.set(this.#button, 'aria-label', this.#labelFor(choice));\n }\n /** The host's disabled claim, composed with the pin: lifting one cannot lift the other. */\n set claimed(claimed) {\n this.#claimed = claimed;\n this.#sync();\n }\n #fill() {\n this.#menu.replaceChildren(\n ...this.#allowed.map((choice) => {\n const li = document.createElement('li');\n li.setAttribute('role', 'none');\n const a = document.createElement('a');\n a.setAttribute('role', 'menuitem');\n a.setAttribute('tabindex', '-1');\n a.setAttribute('value', choice);\n const word = this.#labelFor(choice);\n const glyph = this.#glyphs[choice] ?? choice;\n if (word === choice && glyph === choice) {\n a.innerText = choice;\n } else {\n const glyphSpan = document.createElement('span');\n glyphSpan.innerText = glyph;\n const wordSpan = document.createElement('span');\n wordSpan.innerText = word;\n a.append(glyphSpan, wordSpan);\n }\n li.append(a);\n return li;\n }),\n );\n }\n #sync() {\n const pinned = this.pinned;\n this.#button.toggleAttribute('disabled', pinned || this.#claimed);\n Attributes.set(this.#button, 'aria-haspopup', pinned ? null : 'true');\n Attributes.set(this.#button, 'aria-expanded', pinned ? null : 'false');\n if (pinned) {\n this.#button.removeAttribute('popovertarget');\n } else if (this.#menu.id) {\n //the menu is wired once, its link is what a pin may break: lifting the\n //pin re-links the invoker to the menu it already owns\n this.#button.setAttribute('popovertarget', this.#menu.id);\n }\n }\n #items() {\n return Array.from(this.#menu.querySelectorAll('li > a'), (a) => /** @type HTMLAnchorElement */ (a));\n }\n #wire() {\n const button = this.#button;\n const menu = this.#menu;\n Anchors.wire(button, menu, { prefix: 'ful-filter-menu', invoke: true, expanded: true });\n menu.addEventListener('toggle', (/** @type any */ evt) => {\n if (evt.newState !== 'open') {\n //give the invoker back the focus the menu had borrowed, without\n //stealing it from wherever else the close came from\n if (menu.contains(document.activeElement)) {\n button.focus();\n }\n return;\n }\n const items = this.#items();\n (items.find((a) => a.getAttribute('value') === this.value) ?? items[0])?.focus();\n });\n menu.addEventListener('keydown', (evt) => {\n const target = /** @type HTMLElement */ (evt.target);\n const item = /** @type HTMLAnchorElement | null */ (target.closest('li > a'));\n if (!item) {\n return;\n }\n const items = this.#items();\n const at = items.indexOf(item);\n switch (evt.code) {\n case 'ArrowDown': {\n evt.preventDefault();\n items[(at + 1) % items.length]?.focus();\n break;\n }\n case 'ArrowUp': {\n evt.preventDefault();\n items[(at - 1 + items.length) % items.length]?.focus();\n break;\n }\n case 'Home': {\n evt.preventDefault();\n items[0]?.focus();\n break;\n }\n case 'End': {\n evt.preventDefault();\n items[items.length - 1]?.focus();\n break;\n }\n case 'Enter':\n case 'Space': {\n evt.preventDefault();\n item.click();\n button.focus();\n break;\n }\n case 'Escape': {\n //the platform's close request hides the menu, the focus is placed\n //on the invoker before the focused item is detached from it\n button.focus();\n break;\n }\n }\n });\n }\n}\n\nexport { ChoiceButton };\n","import { Localization } from '../../ftl/index.mjs';\nimport { ChoiceButton } from './choice-button.mjs';\nimport { Field } from './field.mjs';\nimport { Instant } from './temporals.mjs';\nimport { Input } from './input.mjs';\n\nconst GLYPHS = {\n EQ: '=',\n NEQ: '≠',\n LT: '<',\n GT: '>',\n LTE: '≤',\n GTE: '≥',\n BETWEEN: '↔',\n CONTAINS: '…a…',\n STARTS_WITH: 'a…',\n ENDS_WITH: '…a',\n};\nconst COMPARE_OPERATORS = ['EQ', 'NEQ', 'LT', 'GT', 'LTE', 'GTE', 'BETWEEN'];\nconst TEXT_OPERATORS = [...COMPARE_OPERATORS, 'CONTAINS', 'STARTS_WITH', 'ENDS_WITH'];\nconst SENSITIVITIES = ['IGNORE_CASE', 'CASE_SENSITIVE'];\n\nconst SENSITIVITY_GLYPHS = {\n IGNORE_CASE: 'aa',\n CASE_SENSITIVE: 'Aa',\n};\n\n/** the labels live in the built-in translations, resolved through the same localization every template uses */\nconst { t } = Localization.of();\nconst operatorLabel = (op) => t(`filters.op.${op}`);\nconst sensitivityLabel = (sensitivity) => t(`filters.sensitivity.${sensitivity}`);\nconst booleanValueLabel = (token) => t(token === '' ? 'filters.boolean.any' : `filters.boolean.${token}`);\n\n/**\n * The shared shape of every operator-and-operands filter: an operator menu, one\n * or two operands of the type the subclass declares, and a tuple that mirrors\n * the data-jpa compare annotations.\n */\nclass CompareFilter extends Input {\n static observed = ['value:json', 'operators:csv'];\n static OPERATORS = COMPARE_OPERATORS;\n static DEFAULT_OPERATOR = 'EQ';\n static template = `\n <label>{{{{ slots.default }}}}</label>\n {{{{ slots.info }}}}\n <ful-control-group>\n <ful-affix data-tpl-if=\"slots.before\">{{{{ slots.before }}}}</ful-affix>\n <ful-affix>\n <button data-ref=\"operator\" type=\"button\" form=\"\" aria-expanded=\"false\" aria-haspopup=\"true\"></button>\n <ul popover role=\"menu\"></ul>\n </ful-affix>\n <ful-control>\n <input data-ref=\"value1\" data-tpl-type=\"type\" form=\"\">\n <input data-ref=\"value2\" data-tpl-type=\"type\" form=\"\" hidden>\n </ful-control>\n <ful-affix data-tpl-if=\"slots.after\">{{{{ slots.after }}}}</ful-affix>\n </ful-control-group>\n <ful-field-error></ful-field-error>\n `;\n _operator;\n _container;\n _value1;\n _value2;\n _build(conf) {\n const pieces = super._build(conf);\n const fragment = pieces.fragment;\n this._container = fragment.querySelector('ful-control-group');\n this._value1 = fragment.querySelector('[data-ref=value1]');\n this._value2 = fragment.querySelector('[data-ref=value2]');\n this._operator = new ChoiceButton(/** @type HTMLElement */ (fragment.querySelector('[data-ref=operator]')), {\n vocabulary: this._vocabulary(),\n glyphs: GLYPHS,\n labelFor: operatorLabel,\n interactive: () => this._interactive(),\n onPick: () => {\n this._syncBetween();\n this._notifyChange();\n },\n });\n //the default operator below reads the whitelist, so it is resolved here\n //rather than waiting for the base's declared pass\n this.operators = this.declared('operators');\n //Input.render only re-dispatches changes coming from the first operand\n this._value2.addEventListener('change', (evt) => {\n evt.stopPropagation();\n this._notifyChange();\n });\n if (this._operator.value === null) {\n this._showDefaultOperator();\n }\n //the second operand mirrors the claims like the first one does, and the\n //freeze reaches the operator and sensitivity buttons, whose popovers an\n //input's readOnly cannot touch\n return { ...pieces, freeze: this._container, also: [this._value2] };\n }\n _showDefaultOperator() {\n const preferred = this._defaultOperator();\n const allowed = this._operator.allowed;\n this._showOperator(allowed.includes(preferred) ? preferred : allowed[0]);\n }\n formResetCallback() {\n //a declared tuple restores its operator through the base's assignment; a\n //valueless reset also brings the operator back to the default it rendered with\n super.formResetCallback();\n if (!this.hasAttribute('value')) {\n this._showDefaultOperator();\n }\n }\n _type() {\n return 'text';\n }\n _serialize(v) {\n return v;\n }\n _deserialize(v) {\n return v;\n }\n _defaultOperator() {\n return 'EQ';\n }\n _vocabulary() {\n return COMPARE_OPERATORS;\n }\n _declaredOperators;\n get operators() {\n //a page may whitelist before the upgrade: the narrowed set is held until\n //the button exists, and the declared attribute lands over it when the\n //base applies the declared state\n return this._operator ? this._operator.allowed : this._declaredOperators;\n }\n set operators(declared) {\n if (!this._operator) {\n this._declaredOperators = ChoiceButton.narrow(declared, this._vocabulary());\n return;\n }\n this._operator.allowed = declared;\n this._syncBetween();\n }\n get value() {\n return this._tuple();\n }\n set value(v) {\n this._applyTuple(v);\n }\n _tuple() {\n const operator = this._operator.value;\n const values = operator === 'BETWEEN' ? [this._value1.value, this._value2.value] : [this._value1.value];\n return values.some((v) => v === '') ? null : [operator, ...values.map((v) => this._serialize(v))];\n }\n _applyTuple(v) {\n if (v == null) {\n this._value1.value = '';\n this._value2.value = '';\n return;\n }\n const [declared, ...values] = v;\n //a pinned operator wins over whatever the tuple carries\n const operator = this._operator.pinned ? this._operator.allowed[0] : declared;\n this._showOperator(operator);\n //a tuple shorter than the operands leaves the missing ones empty: the DOM\n //would stringify a nullish assignment to \"undefined\"\n this._value1.value = values[0] ? this._deserialize(values[0]) : (values[0] ?? '');\n this._value2.value = values[1] ? this._deserialize(values[1]) : (values[1] ?? '');\n }\n _showOperator(operator) {\n this._operator.value = operator;\n this._syncBetween();\n }\n /** only a BETWEEN carries a second operand */\n _syncBetween() {\n this._value2.toggleAttribute('hidden', this._operator.value !== 'BETWEEN');\n }\n get disabled() {\n return super.disabled;\n }\n set disabled(d) {\n //the claim and both operands are the base's; the chrome buttons are not,\n //frozen by a pin, disabled by the claim, or both\n super.disabled = d;\n for (const choice of this._choices()) {\n choice.claimed = d;\n }\n }\n /** every menu button the filter composes, so one claim reaches them all */\n _choices() {\n return [this._operator].filter((c) => c);\n }\n}\n\n/** The compare filter over ISO instants, defaulting to LTE. */\nclass InstantFilter extends CompareFilter {\n _defaultOperator() {\n return 'LTE';\n }\n _type() {\n return 'datetime-local';\n }\n _serialize(v) {\n return Instant.localToIso(v);\n }\n _deserialize(v) {\n return Instant.isoToLocal(v);\n }\n}\n\n/** The compare filter over dates. */\nclass LocalDateFilter extends CompareFilter {\n _type() {\n return 'date';\n }\n}\n\n/** The compare filter over numbers. */\nclass NumberFilter extends CompareFilter {\n _type() {\n return 'number';\n }\n}\n\n/** The compare filter over text, carrying a case sensitivity beside the operator. */\nclass TextFilter extends CompareFilter {\n static observed = ['sensitivities:csv'];\n static template = `\n <label>{{{{ slots.default }}}}</label>\n {{{{ slots.info }}}}\n <ful-control-group>\n <ful-affix data-tpl-if=\"slots.before\">{{{{ slots.before }}}}</ful-affix>\n <ful-affix>\n <button data-ref=\"operator\" type=\"button\" form=\"\" aria-expanded=\"false\" aria-haspopup=\"true\"></button>\n <ul popover role=\"menu\"></ul>\n <button data-ref=\"sensitivity\" type=\"button\" form=\"\" aria-expanded=\"false\" aria-haspopup=\"true\"></button>\n <ul popover role=\"menu\"></ul>\n </ful-affix>\n <ful-control>\n <input data-ref=\"value1\" data-tpl-type=\"type\" form=\"\">\n <input data-ref=\"value2\" data-tpl-type=\"type\" form=\"\" hidden>\n </ful-control>\n <ful-affix data-tpl-if=\"slots.after\">{{{{ slots.after }}}}</ful-affix>\n </ful-control-group>\n <ful-field-error></ful-field-error>\n `;\n _defaultOperator() {\n return 'CONTAINS';\n }\n _vocabulary() {\n return TEXT_OPERATORS;\n }\n //the sensitivity is carried through from whoever set the value, switched\n //through its own menu, or pinned to the single mode the sensitivities\n //attribute whitelists\n _sensitivityButton;\n _build(conf) {\n const pieces = super._build(conf);\n this._sensitivityButton = new ChoiceButton(\n /** @type HTMLElement */ (pieces.fragment.querySelector('[data-ref=sensitivity]')),\n {\n vocabulary: SENSITIVITIES,\n glyphs: SENSITIVITY_GLYPHS,\n labelFor: sensitivityLabel,\n interactive: () => this._interactive(),\n onPick: () => this._notifyChange(),\n },\n );\n this._sensitivityButton.allowed = null;\n this._sensitivityButton.value = SENSITIVITIES[0];\n return pieces;\n }\n _choices() {\n return [...super._choices(), this._sensitivityButton].filter((c) => c);\n }\n get _sensitivity() {\n return this._sensitivityButton.value;\n }\n _declaredSensitivities;\n get sensitivities() {\n return this._sensitivityButton ? this._sensitivityButton.allowed : this._declaredSensitivities;\n }\n set sensitivities(declared) {\n if (!this._sensitivityButton) {\n this._declaredSensitivities = ChoiceButton.narrow(declared, SENSITIVITIES);\n return;\n }\n const previous = this._sensitivityButton.value;\n this._sensitivityButton.allowed = declared;\n if (!this._sensitivityButton.allowed.includes(previous)) {\n this._sensitivityButton.value = this._sensitivityButton.allowed[0];\n }\n }\n get value() {\n const tuple = this._tuple();\n return tuple == null ? null : [tuple[0], this._sensitivity, ...tuple.slice(1)];\n }\n set value(v) {\n if (v == null) {\n this._applyTuple(v);\n return;\n }\n if (this._sensitivityButton.allowed.includes(v[1])) {\n this._sensitivityButton.value = v[1];\n }\n this._applyTuple([v[0], ...v.slice(2)]);\n }\n formResetCallback() {\n //a declared tuple restores its sensitivity through the value assignment;\n //a valueless reset brings it back to the default it rendered with, the\n //class default normalized against the whitelist\n super.formResetCallback();\n if (!this.hasAttribute('value')) {\n const allowed = this._sensitivityButton.allowed;\n this._sensitivityButton.value = allowed.includes('IGNORE_CASE') ? 'IGNORE_CASE' : allowed[0];\n }\n }\n}\n\nconst BOOLEAN_VALUES = ['', 'true', 'false'];\nconst BOOLEAN_VALUE_GLYPHS = { true: '✓', false: '✗' };\n\n/** The boolean filter: an EQ or NEQ operator and an any/yes/no menu. */\nclass BooleanFilter extends Field {\n static observed = ['value:json', 'operators:csv'];\n static slots = true;\n static OPERATORS = ['EQ', 'NEQ'];\n static DEFAULT_OPERATOR = 'EQ';\n static template = `\n <label>{{{{ slots.default }}}}</label>\n {{{{ slots.info }}}}\n <ful-control-group>\n <ful-affix data-tpl-if=\"slots.before\">{{{{ slots.before }}}}</ful-affix>\n <ful-affix>\n <button data-ref=\"operator\" type=\"button\" form=\"\" aria-expanded=\"false\" aria-haspopup=\"true\"></button>\n <ul popover role=\"menu\"></ul>\n </ful-affix>\n <button data-ref=\"value\" type=\"button\" form=\"\"></button>\n <ul popover role=\"menu\"></ul>\n <ful-affix data-tpl-if=\"slots.after\">{{{{ slots.after }}}}</ful-affix>\n </ful-control-group>\n <ful-field-error></ful-field-error>\n `;\n _operator;\n _value;\n _container;\n _build({ slots }) {\n const fragment = this.template().withOverlay({ slots }).render();\n this._container = fragment.querySelector('ful-control-group');\n const valueButton = fragment.querySelector('[data-ref=value]');\n this._operator = new ChoiceButton(fragment.querySelector('[data-ref=operator]'), {\n vocabulary: BooleanFilter.OPERATORS,\n glyphs: GLYPHS,\n labelFor: operatorLabel,\n interactive: () => this._interactive(),\n onPick: () => this._notifyChange(),\n });\n //the value button carries the word rather than a glyph: 'any' has none\n this._value = new ChoiceButton(valueButton, {\n vocabulary: BOOLEAN_VALUES,\n glyphs: BOOLEAN_VALUE_GLYPHS,\n labelFor: booleanValueLabel,\n display: booleanValueLabel,\n interactive: () => this._interactive(),\n onPick: () => this._notifyChange(),\n });\n this.operators = this.declared('operators');\n const allowed = this._operator.allowed;\n this._operator.value = allowed.includes(BooleanFilter.DEFAULT_OPERATOR)\n ? BooleanFilter.DEFAULT_OPERATOR\n : allowed[0];\n this._value.allowed = null;\n this._value.value = '';\n return {\n fragment,\n control: valueButton,\n error: fragment.querySelector('ful-field-error'),\n label: fragment.querySelector('label'),\n //a button accepts neither aria-readonly nor aria-required\n announces: null,\n freeze: this._container,\n };\n }\n _declaredOperators;\n get operators() {\n //a page may whitelist before the upgrade: the narrowed set is held until\n //the button exists, and the declared attribute lands over it when the\n //base applies the declared state\n return this._operator ? this._operator.allowed : this._declaredOperators;\n }\n set operators(declared) {\n if (!this._operator) {\n this._declaredOperators = ChoiceButton.narrow(declared, this._vocabulary());\n return;\n }\n this._operator.allowed = declared;\n }\n _vocabulary() {\n return BooleanFilter.OPERATORS;\n }\n get value() {\n return this._value.value === '' ? null : [this._operator.value, this._value.value];\n }\n set value(v) {\n if (v == null) {\n this._value.value = '';\n return;\n }\n //a pinned operator wins over whatever the tuple carries\n this._operator.value = this._operator.pinned ? this._operator.allowed[0] : v[0];\n this._value.value = v[1] ?? '';\n }\n get disabled() {\n return super.disabled;\n }\n set disabled(d) {\n super.disabled = d;\n //the menu buttons are frozen by a pin, disabled by the claim, or both\n for (const choice of [this._operator, this._value].filter((c) => c)) {\n choice.claimed = d;\n }\n }\n}\n\nexport { BooleanFilter, CompareFilter, InstantFilter, LocalDateFilter, NumberFilter, TextFilter };\n","import { Failure } from '../../httpc/index.mjs';\nimport { Claims } from '../claims.mjs';\n\n/**\n * The async section machinery shared by ful-tabs, ful-wizard, ful-dialog and\n * ful-drawer: every activation of a section fires the section:requested family\n * on the host component (bubbling: the generic type, the #index type, and the\n * data-step name when present) and awaits the union of the answers, wherever\n * they were registered. The event's target is the component, whose local name\n * telling the family, e.target === e.currentTarget separating a host's own\n * sections from a nested component's, while detail.section stays the write\n * target. No listener is a plain pass-through, and the first-entry flag is not\n * even spent, so a listener attached later still sees the first activation. A\n * pending answer shows the loading chrome a frame late (answers that never\n * pend never flash) and declares the section aria-busy; a delivery superseded\n * by a newer activation of the same section owns no chrome; a rejection paints\n * the section's error chrome, replacing whatever a previous answer had\n * painted, and travels to the caller.\n */\nclass SectionRequests {\n #entered = new WeakSet();\n /** one generation of claims per section: the sections contend separately */\n #claims = new WeakMap();\n\n /**\n * @param {Element} host\n * @param {Element} section\n * @param {string|null} name\n * @param {number|null} index\n * @returns {Promise<any[]|undefined>} the union of the answers, or undefined when nobody listened\n */\n async request(host, section, name, index) {\n const first = !this.#entered.has(section);\n const detail = { name, section, index, first };\n const types = [\n 'section:requested',\n ...(index !== null && index !== undefined ? [`section:requested:#${index}`] : []),\n ...(name ? [`section:requested:${name}`] : []),\n ];\n const promises = [];\n for (const type of types) {\n const evt = /** @type {CustomEvent & { async?: { promises: Promise<any>[] } }} */ (\n new CustomEvent(type, { bubbles: true, detail })\n );\n host.dispatchEvent(evt);\n promises.push(...(evt.async?.promises ?? []));\n }\n if (promises.length === 0) {\n return undefined;\n }\n this.#entered.add(section);\n let claims = this.#claims.get(section);\n if (!claims) {\n claims = new Claims();\n this.#claims.set(section, claims);\n }\n const claim = claims.take();\n const owned = () => !claim.stale;\n section.querySelector(':scope > .ful-section-error')?.remove();\n const frame = requestAnimationFrame(() => {\n if (owned()) {\n section.toggleAttribute('loading', true);\n section.setAttribute('aria-busy', 'true');\n }\n });\n try {\n return await Promise.all(promises);\n } catch (cause) {\n if (owned()) {\n this.#paintError(section, cause);\n }\n throw cause;\n } finally {\n cancelAnimationFrame(frame);\n if (owned()) {\n section.toggleAttribute('loading', false);\n section.removeAttribute('aria-busy');\n }\n }\n }\n\n #paintError(section, cause) {\n section.querySelector(':scope > .ful-section-error')?.remove();\n const error = document.createElement('div');\n error.className = 'ful-section-error';\n error.setAttribute('role', 'alert');\n error.textContent = Failure.problemsText(cause);\n section.prepend(error);\n }\n}\n\nexport { SectionRequests };\n","/**\n * The dialog-target delegation, shared by the dialog and the drawer: any\n * element carrying dialog-target set to a dialog-bearing ful element's id\n * opens it, clones included. Wired once per document.\n */\nlet targetsWired = false;\nconst wireTargets = () => {\n if (targetsWired) {\n return;\n }\n targetsWired = true;\n document.addEventListener('click', (/** @type any */ e) => {\n const trigger = e.target.closest?.('[dialog-target]');\n if (!trigger) {\n return;\n }\n /** @type {any} */ (document.getElementById(trigger.getAttribute('dialog-target')))?.open?.();\n });\n};\n\nexport { wireTargets };\n","import { ParsedElement } from '../../ftl/index.mjs';\nimport { describable } from '../descriptions.mjs';\nimport { SectionRequests } from '../events/sections.mjs';\nimport { Anchors } from './anchors.mjs';\nimport { wireTargets } from './targets.mjs';\n\n/**\n * An info icon button toggling a popover with a short explanation.\n *\n * The marker is the page's `config.icon`, and the `icon` attribute names a\n * `ful-icon` for the tooltip that means something other than plain information:\n * a caveat, a warning, a setting. A name the library does not paint is the\n * page's own, declared as `ful-icon[name='...'] { mask-image: ... }`.\n *\n * `describes` is for the tooltip standing in a field: the note becomes part of\n * the accessible description of that field's control, so it is announced on\n * reaching the field rather than only on opening the marker, and the marker\n * leaves the tab order, so a form of hinted fields costs no extra keystrokes to\n * walk. The marker stays clickable, and stays a tab stop wherever the note was\n * not taken, a tooltip claiming `describes` outside a field among them: the\n * stop only goes where something else delivers the content.\n */\nclass Tooltip extends ParsedElement {\n static slots = true;\n static attributes = ['placement', 'icon', 'describes:presence'];\n static config = {\n icon: 'info-circle-fill',\n };\n static template = `\n <button type=\"button\" class=\"ful-tip\" data-ref=\"trigger\" data-tpl-aria-label=\"#l10n:t('info.tooltip')\"><ful-icon data-tpl-name=\"icon ?? config.icon\" aria-hidden=\"true\"></ful-icon></button>\n <ful-note popover data-ref=\"content\">{{{{ slots.default }}}}</ful-note>\n `;\n render({ slots }) {\n const fragment = this.template().withOverlay({ slots, icon: this.declared('icon') }).render();\n const trigger = fragment.querySelector('[data-ref=trigger]');\n const content = fragment.querySelector('[data-ref=content]');\n //placed here rather than by the anchor css: the note draws a callout that\n //has to point at the trigger wherever the viewport left room for the note,\n //which is a measurement the stylesheet cannot make for a pseudo-element\n Anchors.wire(trigger, content, { prefix: 'ful-tooltip', invoke: true, expanded: true, handPlace: true });\n //above the marker by default: a note opening downwards covers the control\n //the marker explains, the marker riding the field's label\n content.setAttribute('placement', this.declared('placement') ?? 'top');\n this.replaceChildren(fragment);\n if (this.declared('describes')) {\n Tooltip.#describe(this, trigger, content);\n }\n }\n /**\n * Offers the note to the field the tooltip stands in, and takes the trigger\n * out of the tab order only where the offer was accepted: a note nothing\n * carries is reachable by the keyboard through the marker alone, so\n * dropping the stop there would leave it reachable by nothing at all.\n *\n * The offer goes through the description protocol rather than naming a\n * field, the library's own arrow running from the forms to the disclosures.\n */\n static #describe(tooltip, trigger, content) {\n if (!describable(tooltip)?.describedBy(content)) {\n console.warn('a ful-tooltip declares describes but stands in nothing that takes a description', tooltip);\n return;\n }\n trigger.tabIndex = -1;\n }\n}\n\n/**\n * A modal dialog on the native platform, open()/ask() resolving with the\n * closer's data-result.\n *\n * The header carries a close button, as the drawer's does: Escape dismisses a\n * modal on its own, but nothing says so, and a dialog whose only exit is a key\n * you have to know about leaves a pointer with nowhere to go. It answers the way\n * Escape does, with null.\n *\n * `requires-answer` is for the dialog that must be answered: the close button is not\n * rendered and Escape is refused, so the only way out is a button that carries a\n * result. It has to be both, a close button withheld while Escape still worked\n * being decoration rather than a rule.\n *\n * The chrome is reachable by class as well as by tag, so a plain `<dialog\n * class=\"ful-dialog\">` written by a page gets the same look whatever its\n * structure: the tag form matches a direct child, and `ful-dialog-header`,\n * `ful-dialog-body` and `ful-dialog-footer` match at any depth, which is what a\n * dialog whose content is wrapped in a form needs.\n */\nclass Dialog extends ParsedElement {\n static attributes = ['header', 'requires-answer:presence'];\n static slots = true;\n static template = `\n <dialog data-ref=\"dialog\" class=\"ful-dialog\">\n <header data-tpl-if=\"header || !requiresAnswer\" class=\"ful-dialog-header\">\n <h2 data-tpl-if=\"header\">{{ header }}</h2>\n <button data-tpl-if=\"!requiresAnswer\" type=\"button\" data-ref=\"close\" data-tpl-aria-label=\"#l10n:t('dialog.close')\"><ful-icon name=\"x-lg\" aria-hidden=\"true\"></ful-icon></button>\n </header>\n <div data-ref=\"body\" class=\"ful-dialog-body\">{{{{ slots.default }}}}</div>\n <footer class=\"ful-dialog-footer\">\n <button type=\"button\" data-ref=\"acknowledge\" data-result=\"acknowledged\" data-tpl-if=\"!slots.buttons\" data-tpl-aria-label=\"#l10n:t('dialog.acknowledge')\">{{ #l10n:t('dialog.acknowledge') }}</button>\n {{{{ slots.buttons }}}}\n </footer>\n </dialog>\n `;\n #dialog;\n #body;\n #requests = new SectionRequests();\n #resolvers = [];\n render({ slots }) {\n const requiresAnswer = this.declared('requires-answer');\n const fragment = this.template()\n .withOverlay({ slots, header: this.declared('header') ?? '', requiresAnswer })\n .render();\n this.#dialog = fragment.querySelector('[data-ref=dialog]');\n this.#body = fragment.querySelector('[data-ref=body]');\n this.#dialog.addEventListener('close', () => {\n this.dispatchEvent(\n new CustomEvent('close', {\n detail: { result: this.#dialog.returnValue === '' ? null : this.#dialog.returnValue },\n }),\n );\n this.#settle();\n });\n this.#dialog.addEventListener('click', (/** @type any */ e) => {\n const result = e.target.closest('button[data-result]')?.dataset.result;\n if (result !== undefined) {\n this.#dialog.close(result);\n }\n });\n //dismissal, not an answer: the waiters are settled with null, as Escape does.\n //Optional because a subclass overriding the template owns what it renders\n fragment\n .querySelector('[data-ref=close]')\n ?.addEventListener('click', () => this.#dialog.close(''));\n if (requiresAnswer) {\n //the platform's own dismissal, refused where the dialog must be\n //answered: cancel fires for Escape and for a close request the\n //browser makes on its own, and preventing it leaves the dialog open\n this.#dialog.addEventListener('cancel', (/** @type any */ e) => e.preventDefault());\n }\n this.replaceChildren(fragment);\n wireTargets();\n }\n //answers every waiter with the dialog's own answer: null while still open\n //or closed without a result, which is also the unanswered answer a dialog\n //leaving the document owes its waiters instead of hanging them\n #settle() {\n const resolvers = this.#resolvers;\n this.#resolvers = [];\n for (const resolve of resolvers) {\n resolve(this.#dialog.returnValue === '' ? null : this.#dialog.returnValue);\n }\n }\n disconnectedCallback() {\n this.#settle();\n }\n open() {\n return this.ask();\n }\n ask() {\n if (!this.#dialog.open) {\n this.#dialog.returnValue = '';\n this.#dialog.showModal();\n this.#request();\n }\n return new Promise((resolve) => {\n this.#resolvers.push(resolve);\n });\n }\n #request() {\n this.#requests.request(this, this.#body, null, null)?.catch(() => undefined);\n }\n /**\n * Re-fires section:requested on the body, open or closed: the explicit\n * request for a body that wants refreshing. A failed refresh paints its\n * problems, nothing rejects: there is no caller to reject towards.\n */\n refresh() {\n return this.#requests.request(this, this.#body, null, null)?.then(undefined, () => undefined);\n }\n close(result) {\n this.#dialog.close(result ?? '');\n }\n}\n\nexport { Tooltip, Dialog };\n","import { ParsedElement } from '../../ftl/index.mjs';\nimport { Claims } from '../claims.mjs';\nimport { SectionRequests } from '../events/sections.mjs';\nimport { Failure } from '../../httpc/index.mjs';\nimport { wireTargets } from './targets.mjs';\n\n/**\n * A side panel drawer on the native dialog platform, update() owning its\n * open-deliver cycle.\n *\n * The `header` slot is content beside the title, before it: an icon, a badge, a\n * status. It sits outside the heading rather than in it because `update()` sets\n * the title through `textContent`, which would take anything nested there with\n * it.\n */\nclass Drawer extends ParsedElement {\n static attributes = ['title', 'placement'];\n static slots = true;\n static template = `\n <dialog data-ref=\"dialog\" class=\"ful-drawer\">\n <header>\n {{{{ slots.header }}}}\n <h2 data-ref=\"title\">{{ title }}</h2>\n <button type=\"button\" data-ref=\"close\" data-tpl-aria-label=\"#l10n:t('drawer.close')\"><ful-icon name=\"x-lg\" aria-hidden=\"true\"></ful-icon></button>\n </header>\n <section data-ref=\"loading\" hidden><ful-spinner class=\"centered\" role=\"status\"><span class=\"ful-sr-only\">{{ #l10n:t('spinner.loading') }}</span></ful-spinner></section>\n <section data-ref=\"error\" role=\"alert\" hidden></section>\n <section data-ref=\"content\">{{{{ slots.default }}}}</section>\n </dialog>\n `;\n #dialog;\n #title;\n #loading;\n #error;\n #content;\n #requests = new SectionRequests();\n #updates = new Claims();\n render({ slots }) {\n const fragment = this.template()\n .withOverlay({ slots, title: this.declared('title') ?? '' })\n .render();\n this.#dialog = fragment.querySelector('[data-ref=dialog]');\n this.#title = fragment.querySelector('[data-ref=title]');\n this.#loading = fragment.querySelector('[data-ref=loading]');\n this.#error = fragment.querySelector('[data-ref=error]');\n this.#content = fragment.querySelector('[data-ref=content]');\n const placement = this.declared('placement');\n if (placement) {\n this.#dialog.setAttribute('placement', placement);\n }\n fragment.querySelector('[data-ref=close]').addEventListener('click', () => this.close());\n this.#dialog.addEventListener('close', () => {\n this.dispatchEvent(new CustomEvent('close'));\n });\n this.replaceChildren(fragment);\n wireTargets();\n }\n get title() {\n return this.#title.textContent;\n }\n set title(v) {\n this.#title.textContent = v ?? '';\n }\n /**\n * Opens the drawer under the given title and waits for the callback: a\n * resolved value paints the content section (which is returned), a\n * rejection paints the problems and travels to the caller, and an update\n * superseded by a newer one paints nothing.\n */\n async update(title, cb) {\n //the claim detaches any update still in flight: its outcome belongs to\n //an abandoned opening and must neither be painted nor own the drawer\n const claim = this.#updates.take();\n this.title = title;\n this.#content.replaceChildren();\n this.#restChrome();\n this.#loading.removeAttribute('hidden');\n this.#content.setAttribute('hidden', '');\n //update owns its own open-answer-deliver cycle, so it shows the dialog\n //without going through open(): a user reopen during the wait is a\n //real open and goes through open()\n this.#show();\n try {\n const delivered = await cb();\n if (claim.stale) {\n return this.#content;\n }\n this.#content.replaceChildren(delivered);\n this.#loading.setAttribute('hidden', '');\n this.#content.removeAttribute('hidden');\n return this.#content;\n } catch (/** @type any */ e) {\n if (!claim.stale) {\n //revealed before it is filled, so the live region announces the\n //change rather than being revealed already holding it\n this.#error.removeAttribute('hidden');\n this.#error.textContent = Failure.problemsText(e);\n this.#loading.setAttribute('hidden', '');\n this.#content.setAttribute('hidden', '');\n }\n throw e;\n }\n }\n /**\n * Re-fires section:requested on the content, open or closed: the explicit\n * request for a body that wants refreshing. A failed refresh paints its\n * problems, nothing rejects: update() stays the rejecting call.\n */\n refresh() {\n return this.#requests.request(this, this.#content, null, null)?.then(undefined, () => undefined);\n }\n open() {\n if (!this.#show()) {\n return;\n }\n this.#restChrome();\n this.#requests.request(this, this.#content, null, null)?.catch(() => undefined);\n }\n close() {\n this.#dialog.close();\n }\n /** Shows the modal, answering whether this call is the one that opened it. */\n #show() {\n if (this.#dialog.open) {\n return false;\n }\n this.#dialog.showModal();\n return true;\n }\n #restChrome() {\n this.#error.replaceChildren();\n this.#error.setAttribute('hidden', '');\n this.#loading.setAttribute('hidden', '');\n this.#content.removeAttribute('hidden');\n }\n}\n\nexport { Drawer };\n","import { Localization, ParsedElement } from '../../ftl/index.mjs';\nimport { Failure } from '../../httpc/index.mjs';\n\nconst SEVERITIES = ['info', 'success', 'warning', 'error'];\n\n//the regions alive in the document: the show-toast listener is wired once and\n//forwards to each of them, so a re-hosted or second region never doubles a toast\nconst REGIONS = new Set();\nlet listenerWired = false;\n\n/** A transient feedback region: each show() stacks a toast that retires on its own timer. */\nclass Toasts extends ParsedElement {\n static attributes = ['timeout:number'];\n #timeout;\n connectedCallback() {\n super.connectedCallback();\n if (this.rendered) {\n REGIONS.add(this);\n }\n }\n disconnectedCallback() {\n REGIONS.delete(this);\n }\n render() {\n this.#timeout = this.declared('timeout') || 5000;\n this.setAttribute('role', 'region');\n //focusable only programmatically, so a retiring toast can hand its focus back\n this.setAttribute('tabindex', '-1');\n this.setAttribute('aria-label', Localization.of().t('toast.region'));\n if (!listenerWired) {\n listenerWired = true;\n document.addEventListener('show-toast', (/** @type any */ e) => {\n for (const region of REGIONS) {\n region.show(e.detail.message, e.detail);\n }\n });\n }\n REGIONS.add(this);\n }\n /**\n * Appends a toast carrying the message (a Failure shows its problems'\n * reasons, one per line), severity picking the theme and the announcement,\n * the toast retiring through its own timer or its dismiss button.\n * @param {any} message\n * @param {any} [options] severity and timeout\n * @returns {HTMLElement}\n */\n show(message, options = {}) {\n const severity = SEVERITIES.includes(options.severity) ? options.severity : 'info';\n const item = document.createElement('ful-toast');\n item.classList.add(severity);\n item.setAttribute('role', severity === 'error' ? 'alert' : 'status');\n const body = document.createElement('div');\n body.textContent = Failure.problemsText(message, `${message ?? ''}`);\n const dismiss = document.createElement('button');\n dismiss.type = 'button';\n dismiss.setAttribute('aria-label', Localization.of().t('toast.dismiss'));\n const icon = document.createElement('ful-icon');\n icon.setAttribute('name', 'x-lg');\n icon.setAttribute('aria-hidden', 'true');\n dismiss.append(icon);\n item.append(body, dismiss);\n item.addEventListener('animationend', () => {\n if (item.classList.contains('ful-toast-out')) {\n item.remove();\n }\n });\n const retire = () => {\n //the toast may hold the focus, on its own dismiss button: handing it\n //back to the region keeps the reader somewhere rather than on <body>\n if (item.contains(document.activeElement)) {\n /** @type HTMLElement */ (this).focus();\n }\n if (matchMedia('(prefers-reduced-motion: reduce)').matches) {\n item.remove();\n return;\n }\n item.classList.add('ful-toast-out');\n if (item.getAnimations().length === 0) {\n item.remove();\n }\n };\n dismiss.addEventListener('click', retire);\n this.append(item);\n setTimeout(retire, options.timeout ?? this.#timeout);\n return item;\n }\n}\n\nexport { Toasts };\n","import { Attributes, ParsedElement } from '../../ftl/index.mjs';\nimport { SectionRequests } from '../events/sections.mjs';\n\n/**\n * A tab panel: one visible panel at a time, announced through the tab pattern\n * (a tablist of tab buttons, each panel a tabpanel named by its tab). The tabs\n * are declared as <tab> elements in the tabs slot, the panels as the slotless\n * children, paired in order. Entering a panel fires the section:requested\n * family on it (generic and #index, panels being nameless) and awaits the\n * answers, so a panel can deliver itself asynchronously.\n */\nclass Tabs extends ParsedElement {\n static slots = true;\n static observed = ['active:number'];\n static template = `\n <ful-tablist role=\"tablist\">{{{{ slots.tabs }}}}</ful-tablist>\n {{{{ slots.default }}}}\n `;\n #tablist;\n #tabs = [];\n #panels = [];\n #requests = new SectionRequests();\n #active = 0;\n render({ slots }) {\n const fragment = this.template().withOverlay({ slots }).render();\n this.#tablist = fragment.querySelector('ful-tablist');\n const declared = [...this.#tablist.children];\n this.#panels = [...fragment.children].filter((el) => el !== this.#tablist);\n if (declared.length !== this.#panels.length) {\n console.warn(\n `ful-tabs: ${declared.length} tabs declared for ${this.#panels.length} panels, the surplus is left alone`,\n );\n }\n const count = Math.min(declared.length, this.#panels.length);\n this.#tabs = [];\n for (let i = 0; i !== count; ++i) {\n const panel = this.#panels[i];\n const tab = document.createElement('button');\n tab.type = 'button';\n tab.role = 'tab';\n tab.id = Attributes.uid('ful-tab');\n //an author-named panel keeps its name: the wiring adopts it\n if (!panel.id) {\n panel.id = Attributes.uid('ful-tabpanel');\n }\n tab.setAttribute('aria-controls', panel.id);\n panel.role = 'tabpanel';\n panel.setAttribute('aria-labelledby', tab.id);\n //the visible panel joins the tab order: keyboard and reader users\n //reach its content right after its tab, hidden ones stay out\n panel.tabIndex = 0;\n tab.append(...declared[i].childNodes);\n tab.addEventListener('click', () => {\n this.active = i;\n });\n declared[i].replaceWith(tab);\n this.#tabs.push(tab);\n }\n this.#tablist.addEventListener('keydown', (e) => {\n const current = this.#active;\n /** @type {number|null} */\n let target = null;\n if (e.key === 'ArrowRight') {\n target = (current + 1) % this.#tabs.length;\n } else if (e.key === 'ArrowLeft') {\n target = (current - 1 + this.#tabs.length) % this.#tabs.length;\n } else if (e.key === 'Home') {\n target = 0;\n } else if (e.key === 'End') {\n target = this.#tabs.length - 1;\n }\n if (target === null || target === current) {\n return;\n }\n e.preventDefault();\n this.active = target;\n this.#tabs[target].focus();\n });\n this.replaceChildren(fragment);\n }\n get active() {\n return this.#active;\n }\n /**\n * Re-fires the section:requested family on the panel (by index or the\n * panel element itself), whether active or not: the explicit request for a\n * content that wants refreshing. A failed refresh paints its problems,\n * nothing rejects: there is no caller to reject towards.\n */\n refresh(ref) {\n const index = ref instanceof Element ? this.#panels.indexOf(ref) : Number.isInteger(ref) ? ref : NaN;\n const panel = this.#panels[index];\n if (!panel) {\n console.warn(`ful-tabs: no panel answers to \"${ref}\"`);\n return undefined;\n }\n return this.#requests.request(this, panel, null, index)?.then(undefined, () => undefined);\n }\n set active(v) {\n const index = Math.min(Math.max(0, Number(v) || 0), Math.max(0, this.#tabs.length - 1));\n const previous = this.#active;\n for (const [i, tab] of this.#tabs.entries()) {\n tab.setAttribute('aria-selected', i === index ? 'true' : 'false');\n tab.tabIndex = i === index ? 0 : -1;\n this.#panels[i].hidden = i !== index;\n }\n this.#active = index;\n this.reflectTo('active', index);\n if (this.rendered && index !== previous) {\n this.dispatchEvent(new CustomEvent('change', { detail: { active: index, previous } }));\n }\n if (this.#panels.length > 0 && (index !== previous || !this.rendered)) {\n //the activation is the reader's own gesture: the chrome reports a\n //failed delivery, there is no caller to reject towards\n this.#requests.request(this, this.#panels[index], null, index)?.catch(() => undefined);\n }\n }\n}\n\nexport { Tabs };\n","import { Attributes, ParsedElement } from '../../ftl/index.mjs';\n\n/**\n * An accordion over native details/summary disclosures: the platform carries\n * the semantics, the keyboard and the toggling, the chrome paints the group.\n * With the exclusive claim the render assigns one shared name to every panel,\n * which is the platform's own exclusive grouping: opening one closes the others.\n */\nclass Accordion extends ParsedElement {\n static slots = true;\n static observed = ['exclusive:presence'];\n static template = `\n <ful-accordion-group>{{{{ slots.default }}}}</ful-accordion-group>\n `;\n #group;\n #exclusive = false;\n render({ slots }) {\n const fragment = this.template().withOverlay({ slots }).render();\n this.#group = fragment.querySelector('ful-accordion-group');\n this.replaceChildren(fragment);\n }\n get exclusive() {\n return this.#exclusive;\n }\n set exclusive(v) {\n this.#exclusive = v === true;\n this.reflectTo('exclusive', this.#exclusive);\n const name = this.#exclusive ? Attributes.uid('ful-accordion') : null;\n for (const details of this.#group.querySelectorAll(':scope > details')) {\n if (name === null) {\n details.removeAttribute('name');\n } else {\n details.setAttribute('name', name);\n }\n }\n }\n}\n\nexport { Accordion };\n","import { ParsedElement } from '../../ftl/index.mjs';\nimport { SectionRequests } from '../events/sections.mjs';\n\n/**\n * A wizard: a progress of steps over one-of-N sections, the homeinsurance\n * layout distilled. The steps are declared as <step> elements in the steps\n * slot, the sections as the slotless children, paired in order; each section\n * may carry a data-step name, which is what move() answers to. The current\n * step is the aria-current=step claim, carried in lockstep by the step and\n * its section: the chrome (including which section is shown) follows the\n * claim alone, so the markup state and the style can never disagree. The\n * progress chrome shows the current step alone by default; the progress\n * attribute picks another shape over the same claims (timeline, dots, none).\n * Entering a section\n * fires the section:requested family on it and awaits the answers, so a\n * section can deliver itself asynchronously; move() resolves when the entered\n * section is painted, and rejects when its delivery fails.\n */\nclass Wizard extends ParsedElement {\n static slots = true;\n static observed = ['progress'];\n static template = `\n <ful-steps><ol data-tpl-aria-label=\"#l10n:t('wizard.progress')\">{{{{ slots.steps }}}}</ol></ful-steps>\n {{{{ slots.default }}}}\n `;\n #steps = [];\n #sections = [];\n #requests = new SectionRequests();\n #index = 0;\n #progress;\n render({ slots }) {\n const fragment = this.template().withOverlay({ slots }).render();\n const list = fragment.querySelector('ful-steps ol');\n const declared = [...list.children];\n this.#sections = [...fragment.children].filter((el) => el.localName !== 'ful-steps');\n if (declared.length !== this.#sections.length) {\n console.warn(\n `ful-wizard: ${declared.length} steps declared for ${this.#sections.length} sections, the surplus is left alone`,\n );\n }\n const count = Math.min(declared.length, this.#sections.length);\n this.#steps = [];\n for (let i = 0; i !== count; ++i) {\n const li = document.createElement('li');\n li.append(...declared[i].childNodes);\n declared[i].replaceWith(li);\n this.#steps.push(li);\n //the section is the focus target of a move: the step that just\n //became current must receive it, the button that moved it having\n //left the document with its own section\n this.#sections[i].tabIndex = -1;\n }\n this.replaceChildren(fragment);\n if (count > 0) {\n //a section already carrying the claim keeps it: server-rendered state wins\n const claimed = this.#sections.findIndex((s) => s.getAttribute('aria-current') === 'step');\n this.#apply(claimed === -1 ? 0 : Math.min(claimed, count - 1));\n this.#enter(this.#index)?.catch(() => undefined);\n }\n }\n get index() {\n return this.#index;\n }\n get step() {\n return this.#sections[this.#index]?.getAttribute('data-step') ?? null;\n }\n get progress() {\n return this.#progress;\n }\n set progress(v) {\n this.#progress = v;\n this.reflectTo('progress', v);\n }\n next() {\n return this.#move(this.#index + 1);\n }\n prev() {\n return this.#move(this.#index - 1);\n }\n move(ref) {\n const index = this.#sections.findIndex((s) => s.getAttribute('data-step') === ref);\n if (index === -1) {\n console.warn(`ful-wizard: no section carries data-step=\"${ref}\"`);\n return undefined;\n }\n return this.#move(index);\n }\n /**\n * Re-fires the section:requested family on the named section (or the\n * section element itself), whether active or not: the explicit request for a\n * content that wants refreshing. A failed refresh paints its problems,\n * nothing rejects: move() stays the rejecting call.\n */\n refresh(ref) {\n const section =\n ref instanceof Element\n ? ref\n : typeof ref === 'string'\n ? this.#sections.find((s) => s.getAttribute('data-step') === ref)\n : undefined;\n const index = this.#sections.indexOf(section);\n if (index === -1) {\n console.warn(`ful-wizard: no section answers to \"${ref}\"`);\n return undefined;\n }\n return this.#enter(index)?.then(undefined, () => undefined);\n }\n #enter(index) {\n return this.#requests.request(\n this,\n this.#sections[index],\n this.#sections[index].getAttribute('data-step'),\n index,\n );\n }\n #move(index) {\n const clamped = Math.min(Math.max(0, index), Math.max(0, this.#steps.length - 1));\n if (clamped === this.#index) {\n return undefined;\n }\n this.#apply(clamped);\n //the moving control lived in the section that just hid: focus follows\n //the step, or the reader lands on the body knowing nothing happened\n this.#sections[this.#index].focus();\n if (this.rendered) {\n this.dispatchEvent(new CustomEvent('change', { detail: { index: this.#index, step: this.step } }));\n }\n return this.#enter(clamped);\n }\n #apply(index) {\n for (const [i, step] of this.#steps.entries()) {\n if (i === index) {\n step.setAttribute('aria-current', 'step');\n this.#sections[i].setAttribute('aria-current', 'step');\n } else {\n step.removeAttribute('aria-current');\n this.#sections[i].removeAttribute('aria-current');\n }\n }\n this.#index = index;\n }\n}\n\nexport { Wizard };\n","import { HttpClient } from '../httpc/index.mjs';\nimport { Localization } from '../ftl/index.mjs';\nimport { Checkbox } from './forms/checkbox.mjs';\nimport { LocalDate, Instant, InputLocalDate, InputLocalTime, InputInstant } from './forms/temporals.mjs';\nimport { BooleanFilter, InstantFilter, LocalDateFilter, NumberFilter, TextFilter } from './forms/filters.mjs';\nimport { FormLoader, Form } from './forms/form.mjs';\nimport { Input } from './forms/input.mjs';\nimport { InputFile } from './forms/files.mjs';\nimport { RadioGroup } from './forms/radio.mjs';\nimport { SelectLoader, Dropdown, Select } from './forms/select.mjs';\nimport { Tooltip, Dialog } from './disclosures/info.mjs';\nimport { Drawer } from './disclosures/drawer.mjs';\nimport { Toasts } from './disclosures/toast.mjs';\nimport { Tabs } from './navigation/tabs.mjs';\nimport { Accordion } from './disclosures/accordion.mjs';\nimport { Wizard } from './navigation/wizard.mjs';\nimport { TableLoader, Table, Pagination, SortButton } from './navigation/table.mjs';\nimport en from './l10n/en.mjs';\nimport it from './l10n/it.mjs';\nimport es from './l10n/es.mjs';\nimport fr from './l10n/fr.mjs';\n\nconst BUILTIN = { en, it, es, fr };\n\n/**\n * Registers everything ful provides on a registry: the elements, the loader\n * components, an http client, and the translations for the configured\n * language. A page calls `registry.plugin(new Plugin({…})).configure()` once.\n */\nclass Plugin {\n #language;\n #translations;\n #httpClient;\n\n /**\n * @param {{ language?: string, translations?: Record<string, any>, httpClient?: any }} [options]\n * `language` is fixed for the page: a full BCP-47 tag or a primary subtag,\n * defaulting to the browser's language. `translations` is a flat\n * active-language map applied over the built-in translations: reword built-in\n * keys ('pagination.showing', …) or add your own ('checkout.total', …).\n * `httpClient` is the client every ful component fetches through, registered\n * as the `http-client` component: where an unauthorized session goes is an\n * application decision, so a page that does not want the default's redirect\n * to '/' builds its own.\n */\n constructor(options = {}) {\n this.#language = options.language ?? navigator?.language ?? 'en';\n this.#translations = options.translations ?? {};\n this.#httpClient = options.httpClient ?? null;\n }\n\n configure(registry) {\n const httpClient =\n this.#httpClient ?? HttpClient.builder().withCsrfToken().withRedirectOnUnauthorized('/').build();\n //the fallback chain is baked here: en, the active language, the consumer's own strings\n const language = this.#language.split('-')[0];\n const l10n = { ...BUILTIN.en, ...BUILTIN[language], ...this.#translations };\n registry\n .defineModule('l10n', Localization)\n .defineComponent('http-client', httpClient)\n .defineElement('ful-tooltip', Tooltip)\n .defineElement('ful-dialog', Dialog)\n .defineElement('ful-drawer', Drawer)\n .defineElement('ful-toasts', Toasts)\n .defineElement('ful-tabs', Tabs)\n .defineElement('ful-accordion', Accordion)\n .defineElement('ful-wizard', Wizard)\n .defineElement('ful-form', Form)\n .defineElement('ful-checkbox', Checkbox)\n .defineElement('ful-input', Input)\n .defineElement('ful-input-file', InputFile)\n .defineElement('ful-local-date', LocalDate)\n .defineElement('ful-instant', Instant)\n .defineElement('ful-input-local-date', InputLocalDate)\n .defineElement('ful-input-local-time', InputLocalTime)\n .defineElement('ful-input-instant', InputInstant)\n .defineElement('ful-radio-group', RadioGroup)\n .defineElement('ful-table', Table)\n .defineElement('ful-pagination', Pagination)\n .defineElement('ful-sorter', SortButton)\n .defineElement('ful-filter-instant', InstantFilter)\n .defineElement('ful-filter-local-date', LocalDateFilter)\n .defineElement('ful-filter-number', NumberFilter)\n .defineElement('ful-filter-boolean', BooleanFilter)\n .defineElement('ful-filter-text', TextFilter)\n .defineElement('ful-select', Select)\n .defineElement('ful-dropdown', Dropdown)\n .defineComponent('loaders:select', SelectLoader)\n .defineComponent('loaders:form', FormLoader)\n .defineComponent('loaders:table', TableLoader)\n //the two names a template and the l10n facade resolve: the messages,\n //and the locale every formatter needs. The primary subtag is not a\n //third: it exists to pick the built-in bundle above, and publishing\n //it put a bare name nothing reads into the scope of every template\n .defineOverlay({\n l10n,\n locale: this.#language,\n });\n }\n}\n\nexport { Plugin };\n","export default {\n 'pagination.showing': 'Page {current} of {total}',\n 'pagination.navigation': 'Page navigation',\n 'pagination.previous': 'Previous',\n 'pagination.next': 'Next',\n 'pagination.reload': 'Reload',\n 'table.initial': 'Start searching to see results.',\n 'table.error': 'Error while loading data:',\n 'table.no-data': 'No elements found.',\n 'dropdown.empty': 'No results',\n 'select.remove': 'Remove',\n 'files.dropzone-label': 'Click or drop your files here',\n 'files.remove': 'Remove',\n 'files.unacceptable-file-type': 'Only files of type {types} are supported',\n 'files.max-file-size-exceeded': 'Maximum supported file size is {size}',\n 'files.max-total-size-exceeded': 'Maximum supported total file size is {size}',\n 'files.max-files-exceeded': { one: 'Maximum of {count} file exceeded', other: 'Maximum of {count} files exceeded' },\n 'filters.op.EQ': 'Equals',\n 'filters.op.NEQ': 'Not equal',\n 'filters.op.LT': 'Less than',\n 'filters.op.GT': 'Greater than',\n 'filters.op.LTE': 'At most',\n 'filters.op.GTE': 'At least',\n 'filters.op.BETWEEN': 'Between',\n 'filters.op.CONTAINS': 'Contains',\n 'filters.op.STARTS_WITH': 'Starts with',\n 'filters.op.ENDS_WITH': 'Ends with',\n 'filters.sensitivity.IGNORE_CASE': 'Ignore case',\n 'filters.sensitivity.CASE_SENSITIVE': 'Case sensitive',\n 'filters.boolean.any': 'Any',\n 'filters.boolean.true': 'Yes',\n 'filters.boolean.false': 'No',\n 'info.tooltip': 'More information',\n 'dialog.acknowledge': 'Got it',\n 'dialog.close': 'Close',\n 'drawer.close': 'Close',\n 'spinner.loading': 'Loading…',\n 'toast.region': 'Notifications',\n 'toast.dismiss': 'Dismiss',\n 'wizard.progress': 'Progress',\n};\n","export default {\n 'pagination.showing': 'Pagina {current} di {total}',\n 'pagination.navigation': 'Navigazione pagine',\n 'pagination.previous': 'Precedente',\n 'pagination.next': 'Successivo',\n 'pagination.reload': 'Ricarica',\n 'table.initial': 'Avvia la ricerca per visualizzare i risultati.',\n 'table.error': 'Errore nel caricamento dei dati:',\n 'table.no-data': 'Nessun elemento trovato.',\n 'dropdown.empty': 'Nessun risultato',\n 'select.remove': 'Rimuovi',\n 'files.dropzone-label': 'Clicca o trascina i file qui',\n 'files.remove': 'Rimuovi',\n 'files.unacceptable-file-type': 'Solo i file di tipo {types} sono supportati',\n 'files.max-file-size-exceeded': 'La dimensione massima di un file è di {size}',\n 'files.max-total-size-exceeded': 'La dimensione massima complessiva dei file è di {size}',\n 'files.max-files-exceeded': { other: 'Superato il numero massimo di {count} file' },\n 'filters.op.EQ': 'Uguale',\n 'filters.op.NEQ': 'Diverso',\n 'filters.op.LT': 'Minore',\n 'filters.op.GT': 'Maggiore',\n 'filters.op.LTE': 'Al massimo',\n 'filters.op.GTE': 'Almeno',\n 'filters.op.BETWEEN': 'Tra',\n 'filters.op.CONTAINS': 'Contiene',\n 'filters.op.STARTS_WITH': 'Inizia con',\n 'filters.op.ENDS_WITH': 'Termina con',\n 'filters.sensitivity.IGNORE_CASE': 'Ignora maiuscole',\n 'filters.sensitivity.CASE_SENSITIVE': 'Distingui maiuscole',\n 'filters.boolean.any': 'Qualsiasi',\n 'filters.boolean.true': 'Sì',\n 'filters.boolean.false': 'No',\n 'info.tooltip': 'Maggiori informazioni',\n 'dialog.acknowledge': 'Ho capito',\n 'dialog.close': 'Chiudi',\n 'drawer.close': 'Chiudi',\n 'spinner.loading': 'Caricamento…',\n 'toast.region': 'Notifiche',\n 'toast.dismiss': 'Chiudi',\n 'wizard.progress': 'Avanzamento',\n};\n","export default {\n 'pagination.showing': 'Página {current} de {total}',\n 'pagination.navigation': 'Navegación de páginas',\n 'pagination.previous': 'Anterior',\n 'pagination.next': 'Siguiente',\n 'pagination.reload': 'Recargar',\n 'table.initial': 'Inicia la búsqueda para ver los resultados.',\n 'table.error': 'Error al cargar los datos:',\n 'table.no-data': 'No se encontraron elementos.',\n 'dropdown.empty': 'Sin resultados',\n 'select.remove': 'Eliminar',\n 'files.dropzone-label': 'Haz clic o arrastra tus archivos aquí',\n 'files.remove': 'Eliminar',\n 'files.unacceptable-file-type': 'Solo se admiten archivos de tipo {types}',\n 'files.max-file-size-exceeded': 'El tamaño máximo de archivo admitido es {size}',\n 'files.max-total-size-exceeded': 'El tamaño total máximo admitido es {size}',\n 'files.max-files-exceeded': { other: 'Se ha superado el número máximo de {count} archivos' },\n 'filters.op.EQ': 'Igual',\n 'filters.op.NEQ': 'Distinto',\n 'filters.op.LT': 'Menor',\n 'filters.op.GT': 'Mayor',\n 'filters.op.LTE': 'Como máximo',\n 'filters.op.GTE': 'Al menos',\n 'filters.op.BETWEEN': 'Entre',\n 'filters.op.CONTAINS': 'Contiene',\n 'filters.op.STARTS_WITH': 'Empieza por',\n 'filters.op.ENDS_WITH': 'Termina por',\n 'filters.sensitivity.IGNORE_CASE': 'Ignorar mayúsculas',\n 'filters.sensitivity.CASE_SENSITIVE': 'Distinguir mayúsculas',\n 'filters.boolean.any': 'Cualquiera',\n 'filters.boolean.true': 'Sí',\n 'filters.boolean.false': 'No',\n 'info.tooltip': 'Más información',\n 'dialog.acknowledge': 'Entendido',\n 'dialog.close': 'Cerrar',\n 'drawer.close': 'Cerrar',\n 'spinner.loading': 'Cargando…',\n 'toast.region': 'Notificaciones',\n 'toast.dismiss': 'Cerrar',\n 'wizard.progress': 'Progreso',\n};\n","export default {\n 'pagination.showing': 'Page {current} sur {total}',\n 'pagination.navigation': 'Navigation des pages',\n 'pagination.previous': 'Précédent',\n 'pagination.next': 'Suivant',\n 'pagination.reload': 'Recharger',\n 'table.initial': 'Lancez la recherche pour voir les résultats.',\n 'table.error': 'Erreur lors du chargement des données :',\n 'table.no-data': 'Aucun élément trouvé.',\n 'dropdown.empty': 'Aucun résultat',\n 'select.remove': 'Retirer',\n 'files.dropzone-label': 'Cliquez ou déposez vos fichiers ici',\n 'files.remove': 'Retirer',\n 'files.unacceptable-file-type': 'Seuls les fichiers de type {types} sont pris en charge',\n 'files.max-file-size-exceeded': 'La taille maximale de fichier prise en charge est {size}',\n 'files.max-total-size-exceeded': 'La taille totale maximale prise en charge est {size}',\n 'files.max-files-exceeded': {\n one: 'Nombre maximal de {count} fichier dépassé',\n other: 'Nombre maximal de {count} fichiers dépassé',\n },\n 'filters.op.EQ': 'Égal',\n 'filters.op.NEQ': 'Différent',\n 'filters.op.LT': 'Inférieur',\n 'filters.op.GT': 'Supérieur',\n 'filters.op.LTE': 'Au plus',\n 'filters.op.GTE': 'Au moins',\n 'filters.op.BETWEEN': 'Entre',\n 'filters.op.CONTAINS': 'Contient',\n 'filters.op.STARTS_WITH': 'Commence par',\n 'filters.op.ENDS_WITH': 'Finit par',\n 'filters.sensitivity.IGNORE_CASE': 'Ignorer la casse',\n 'filters.sensitivity.CASE_SENSITIVE': 'Respecter la casse',\n 'filters.boolean.any': 'Indifférent',\n 'filters.boolean.true': 'Oui',\n 'filters.boolean.false': 'Non',\n 'info.tooltip': 'Plus d’informations',\n 'dialog.acknowledge': 'J’ai compris',\n 'dialog.close': 'Fermer',\n 'drawer.close': 'Fermer',\n 'spinner.loading': 'Chargement…',\n 'toast.region': 'Notifications',\n 'toast.dismiss': 'Fermer',\n 'wizard.progress': 'Progression',\n};\n"],"names":["storage","backing","remove","k","removeItem","load","got","getItem","JSON","parse","save","v","setItem","stringify","pop","decoded","versioned","store","key","revision","data","stored","LocalStorage","localStorage","SessionStorage","sessionStorage","VersionedLocalStorage","VersionedSessionStorage","AsyncEvents","fireAsync","el","evt","options","dispatchEvent","promises","async","mode","length","Promise","all","catch","Error","type","resolve","asyncOn","fn","listener","event","ae","promise","reject","withResolvers","push","e","addEventListener","asyncOff","removeEventListener","mixInto","classes","Object","assign","prototype","this","Claims","generation","take","hold","held","claims","stale","invalidate","describable","at","parentElement","Timing","sleep","ms","setTimeout","debounce","timeoutMs","func","immediate","tid","args","previousTimestamp","later","elapsed","performance","now","called","clearTimeout","undefined","throttle","leading","trailing","remaining","Bindings","flatten","obj","prefix","stops","keys","reduce","acc","pre","has","static","Set","providePath","result","path","value","split","map","test","FORBIDDEN","current","previous","i","ckey","pkey","Number","isInteger","Array","isArray","extract","getAttribute","checked","dataset","fulBindType","tagName","multiple","from","selectedOptions","o","submits","extractFrom","form","submitter","elements","hasAttribute","matches","mutate","raw","values","String","forEach","selected","includes","mutateIn","names","filter","n","flattenedKey","entries","querySelectorAll","CSS","escape","errors","es","scrollOnError","setAttribute","pinned","context","fieldErrors","globalErrors","setCustomValidity","replaceChildren","unmatched","parts","replace","slice","join","targets","input","reason","bannered","hel","removeAttribute","innerText","sort","a","b","getBoundingClientRect","y","focus","Field","ParsedElement","control","described","descriptions","errorId","fieldError","announces","also","constructor","super","internals","role","ROLE","mirrors","wire","fragment","error","label","freeze","readonly","preventDefault","id","Attributes","uid","describe","name","defaultPrevented","isComposing","target","submitsOnEnter","_requestSubmit","HTMLInputElement","describedBy","ids","set","setValidity","customError","candidates","requestSubmit","find","_notifyChange","extras","CustomEvent","bubbles","cancelable","detail","field","LABELABLE","_interactive","formResetCallback","unmarshal","disabled","d","reflectTo","toggleAttribute","readOnly","required","render","conf","built","_build","then","pieces","settle","RemoteJsonFormLoader","http","url","method","requestMapper","responseMapper","prepare","submit","request","json","fetch","transform","response","LocalFormLoader","FormLoader","create","component","declared","Form","document","createElement","forward","childNodes","stopPropagation","closest","stopImmediatePropagation","submitting","spinner","loader","se","sre","mapped","exception","Failure","problems","console","warn","reset","spinning","announce","defaultValue","hidden","textContent","trim","className","ref","append","Localization","of","t","spin","Math","max","querySelector","wd","vs","patternCache","BoundedCache","compiled","attr","pattern","getOrCompute","RegExp","warnedBoth","WeakSet","Input","_input","_type","slots","template","withOverlay","strip","keep","add","re","match","filterOf","before","after","start","selectionStart","caret","setSelectionRange","uppercase","uppercased","toUpperCase","trimmed","isNaN","placeholder","LocalDate","content","m","parsed","Date","getTime","date","locale","year","month","day","Instant","isoToLocal","hour","minute","second","hour12","iso","pad","padStart","getFullYear","getMonth","getDate","getHours","getMinutes","getSeconds","getMilliseconds","localToIso","local","toISOString","InputLocalDate","min","fromIsoOrOffset","step","formatLocalDate","getTimezoneOffset","exec","sign","offset","r","setHours","setDate","originalDay","setMonth","setFullYear","InputLocalTime","fromNowOrOffset","resolved","setMinutes","snapped","stepSeconds","seconds","floor","hh","mm","InputInstant","InputFile","list","files","dt","DataTransfer","file","items","accept","dropzone","warnings","group","warning","itemstemplate","Fragments","isBlank","Templates","fromFragment","idx","children","indexOf","f","click","dataTransfer","kind","getAsFile","update","ensureAcceptable","ensureFileSizes","ensureTotalSize","ensureFilesCount","renderTo","appendTo","WARNING_TIMEOUT","acceptable","toLowerCase","some","token","startsWith","endsWith","unacceptable","types","maxFiles","count","maxFileSize","oversized","size","bytes","maxTotalSize","totalsize","useItemList","itemList","useDropzone","open","Map","frame","reflowWired","clamp","low","high","place","popover","anchored","invoker","stretch","box","viewport","documentElement","vw","clientWidth","vh","clientHeight","style","removeProperty","computed","getComputedStyle","gap","parseFloat","marginTop","marginRight","marginBottom","marginLeft","right","bottom","margin","width","left","height","top","note","isNote","placement","cap","maxWidth","wide","here","setProperty","clientLeft","clientTop","reportCallout","reflow","isConnected","delete","schedule","requestAnimationFrame","Anchors","invoke","expanded","handPlace","anchor","anchorName","positionAnchor","newState","supports","property","unplace","window","RemoteLoader","prefetch","inFlight","configs","ensureFetched","exact","needle","reconfigureUrl","claim","revisionedData","finally","storageKey","fetchJson","PartialRemoteLoader","param","InMemoryLoader","SelectLoader","els","metadata","responseMapperFrom","_registry","evaluator","evaluateExpression","row","Dropdown","menu","empty","optionstemplate","shows","default","li","change","hide","firstElementChild","highlight","activated","scrollIntoView","block","behavior","matchMedia","acceptSelection","entry","index","picked","findIndex","get","hidePopover","shown","show","showPopover","moveOrShow","candidate","jump","first","lastElementChild","page","lis","offsetHeight","trunc","Select","ddmenu","warnedComma","assignments","editing","dload","abortdload","listbox","wireChrome","wireChips","wireInput","wireSelection","close","removeKeyAt","badge","Element","removeBadge","chipKeydown","code","selectionEnd","badges","select","relatedTarget","contains","comboboxKeydown","clear","coerceKey","changed","syncBadges","withLoader","reload","arrowKeydown","display","altKey","browse","next","selection","NaN","RadioGroup","fieldset","firstRadio","booleanType","radioEls","inputsAndLabels","fromChildNodes","radios","Checkbox","container","isSwitch","SortButton","order","sorter","orders","nextOrder","th","Pagination","prevIcon","nextIcon","reloadIcon","total","toCurrent","toTotal","maxRender","pageCount","hasPrev","hasNext","prev","enabled","curr","rendered","pages","_","focused","activeElement","back","TableSchemaParser","nodeOrFragment","schema","Nodes","queryChildren","headersTr","rowsTr","getAttributeNames","columns","queryChildrenAll","column","maybeTitleTag","titleNode","createTextNode","wrappedTitleNode","fulSorter","td","headersTemplate","inHeaders","inRows","withFragment","rowsTemplate","InMemoryTableLoader","pageRequest","sortRequest","filterRequest","rows","sorted","begin","end","l","RemoteTableLoader","filters","fromEntries","TableLoader","Table","searchIcon","body","loading","noAutoload","feedback","paginator","sorters","latestRequest","loadRequested","loads","pageSize","table","thead","Rendering","waitForChildren","maybeForm","s","pageResponse","problemsText","resetWithFilter","ceil","lastPage","ChoiceButton","narrow","vocabulary","narrowed","choice","button","glyphs","labelFor","interactive","onPick","allowed","claimed","wired","item","fill","sync","word","glyph","glyphSpan","wordSpan","GLYPHS","EQ","NEQ","LT","GT","LTE","GTE","BETWEEN","CONTAINS","STARTS_WITH","ENDS_WITH","COMPARE_OPERATORS","TEXT_OPERATORS","SENSITIVITIES","SENSITIVITY_GLYPHS","IGNORE_CASE","CASE_SENSITIVE","operatorLabel","op","sensitivityLabel","sensitivity","booleanValueLabel","CompareFilter","_operator","_container","_value1","_value2","_vocabulary","_syncBetween","operators","_showDefaultOperator","preferred","_defaultOperator","_showOperator","_serialize","_deserialize","_declaredOperators","_tuple","_applyTuple","operator","_choices","c","InstantFilter","LocalDateFilter","NumberFilter","TextFilter","_sensitivityButton","_sensitivity","_declaredSensitivities","sensitivities","tuple","BOOLEAN_VALUES","BOOLEAN_VALUE_GLYPHS","true","false","BooleanFilter","_value","valueButton","OPERATORS","DEFAULT_OPERATOR","SectionRequests","entered","WeakMap","host","section","owned","cause","paintError","cancelAnimationFrame","prepend","targetsWired","wireTargets","trigger","getElementById","Tooltip","icon","tooltip","tabIndex","Dialog","dialog","requests","resolvers","requiresAnswer","header","returnValue","disconnectedCallback","ask","showModal","refresh","Drawer","title","updates","cb","restChrome","delivered","SEVERITIES","REGIONS","listenerWired","Toasts","timeout","connectedCallback","region","message","severity","classList","dismiss","retire","getAnimations","Tabs","tablist","tabs","panels","active","panel","tab","replaceWith","Accordion","exclusive","details","Wizard","steps","sections","progress","localName","apply","enter","move","clamped","BUILTIN","en","one","other","it","fr","language","translations","httpClient","navigator","configure","registry","HttpClient","builder","withCsrfToken","withRedirectOnUnauthorized","build","l10n","defineModule","defineComponent","defineElement","defineOverlay"],"mappings":"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"}