@aihu/primitives 0.1.4 → 0.1.5
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.
- package/README.md +7 -7
- package/dist/{button-Cha1gKlr.js → button-RgkdWi4q.js} +2 -2
- package/dist/{button-Cha1gKlr.js.map → button-RgkdWi4q.js.map} +1 -1
- package/dist/button.d.ts +1 -1
- package/dist/button.js +1 -1
- package/dist/checkbox.js +1 -1
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +11 -7
- package/dist/collection.js.map +1 -1
- package/dist/composed-tree-OMbp4NQn.js +297 -0
- package/dist/composed-tree-OMbp4NQn.js.map +1 -0
- package/dist/{dialog-VDL-W3Vy.js → dialog-BHtBlVHN.js} +12 -14
- package/dist/dialog-BHtBlVHN.js.map +1 -0
- package/dist/dialog.d.ts +1 -1
- package/dist/dialog.js +1 -1
- package/dist/{form-control-B_BO9j7_.js → form-control-CRF3PWcK.js} +12 -7
- package/dist/form-control-CRF3PWcK.js.map +1 -0
- package/dist/form-control.d.ts +1 -1
- package/dist/form-control.js +1 -1
- package/dist/{index-BvFa1Y-Z.d.ts → index-BODOUcDC.d.ts} +4 -2
- package/dist/{index-BvFa1Y-Z.d.ts.map → index-BODOUcDC.d.ts.map} +1 -1
- package/dist/{index-D7hJLfnb.d.ts → index-CyG_gCVH.d.ts} +6 -4
- package/dist/index-CyG_gCVH.d.ts.map +1 -0
- package/dist/{index-yPv3StRL.d.ts → index-Dgli1Q03.d.ts} +1 -1
- package/dist/{index-yPv3StRL.d.ts.map → index-Dgli1Q03.d.ts.map} +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +4 -4
- package/dist/input.d.ts +1 -1
- package/dist/input.js +1 -1
- package/dist/label.d.ts.map +1 -1
- package/dist/label.js +9 -7
- package/dist/label.js.map +1 -1
- package/dist/radio-group.js +1 -1
- package/dist/switch.js +1 -1
- package/dist/{text-control-BBX7s8Oe.js → text-control-CUbTuk5L.js} +2 -2
- package/dist/{text-control-BBX7s8Oe.js.map → text-control-CUbTuk5L.js.map} +1 -1
- package/dist/{text-control-Brv5fUEX.d.ts → text-control-wKoKU_--.d.ts} +1 -1
- package/dist/{text-control-Brv5fUEX.d.ts.map → text-control-wKoKU_--.d.ts.map} +1 -1
- package/dist/textarea.d.ts +1 -1
- package/dist/textarea.js +1 -1
- package/package.json +3 -3
- package/dist/dialog-VDL-W3Vy.js.map +0 -1
- package/dist/form-control-B_BO9j7_.js.map +0 -1
- package/dist/index-D7hJLfnb.d.ts.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"form-control-B_BO9j7_.js","names":[],"sources":["../src/form-control/hidden-input.ts","../src/form-control/index.ts"],"sourcesContent":["/**\n * `attachHiddenInput` — form-association substrate for custom form controls\n * (checkbox/switch/radio hosts). Mirrors a host's reactive state onto a\n * visually-hidden native `<input>` in the host's LIGHT DOM so the value rides\n * native `FormData` / form submission with zero re-implementation.\n *\n * The input only exists while BOTH conditions hold: the host is inside a\n * `<form>` (`host.closest('form')`) AND `name()` is non-null. When `name()`\n * becomes null the input is removed (reactively, inside the effect). The\n * inline visually-hidden styles are behavioral plumbing on a functional\n * element, not appearance — they do not violate the zero-CSS contract.\n *\n * The input is inserted as the host's NEXT SIBLING, not a child: hosts like\n * checkbox/switch carry an interactive ARIA role (`role=\"checkbox\"` etc.), and\n * a nested native form control would be an `aria-hidden`-not-withstanding\n * `nested-interactive` violation. Sibling placement keeps it in the same form\n * (so `FormData` is unchanged) while staying out of the host's subtree. When\n * the host has no parent yet (pre-insertion), it falls back to a child.\n */\n\nimport { effect, type Read } from '@aihu/signals'\n\nexport interface HiddenInputOptions {\n type: 'checkbox' | 'radio'\n name: Read<string | null>\n value: Read<string>\n checked: Read<boolean>\n required: Read<boolean>\n disabled: Read<boolean>\n}\n\n/**\n * Attach a visually-hidden native input to `host`, kept in sync with the\n * provided signals by a single effect. Returns a disposer that stops the\n * effect and removes the input.\n */\nexport function attachHiddenInput(host: HTMLElement, opts: HiddenInputOptions): () => void {\n let input: HTMLInputElement | null = null\n\n const remove = (): void => {\n input?.remove()\n input = null\n }\n\n const stop = effect(() => {\n // Read every signal unconditionally so the effect re-runs on any change\n // (including `name` flipping back from null).\n const name = opts.name()\n const value = opts.value()\n const checked = opts.checked()\n const required = opts.required()\n const disabled = opts.disabled()\n\n if (name === null || host.closest('form') === null) {\n remove()\n return\n }\n\n if (input === null) {\n input = document.createElement('input')\n input.type = opts.type\n input.setAttribute('aria-hidden', 'true')\n input.setAttribute('tabindex', '-1')\n // Visually hidden, but still form-associated. Behavior, not appearance.\n input.style.position = 'absolute'\n input.style.opacity = '0'\n input.style.pointerEvents = 'none'\n input.style.margin = '0'\n input.style.transform = 'translateX(-100%)'\n // Sibling-after-host (see header): avoids nested-interactive on roled\n // hosts. Fall back to a child if the host isn't inserted yet.\n if (host.parentNode !== null) host.after(input)\n else host.appendChild(input)\n }\n input.name = name\n input.value = value\n input.checked = checked\n input.required = required\n input.disabled = disabled\n })\n\n return () => {\n stop()\n remove()\n }\n}\n","/**\n * `<aihu-form-control>` — headless form-field coordinator. Owns the\n * disabled/required/invalid state for a field and wires the ARIA association\n * between a slotted control, its label, and its error/description text. Emits\n * NO CSS.\n *\n * Reflected attributes: `disabled`, `required`, `invalid` (boolean); `name`,\n * `control-id` (string).\n * Owned signals: `disabled`, `required`, `invalid`.\n * ARIA emitted onto the slotted control: `aria-required`, `aria-invalid`,\n * `aria-disabled`, `aria-describedby` (wired to a slotted `[data-fc-description]`\n * / `[data-fc-error]` element's id); a slotted `<label>` is associated via\n * `for`/`id`.\n * Context: provides `formControlContext` carrying\n * `{ disabled, required, invalid, controlId, describedById, labelId }` signals\n * so descendant pieces consume the shared state without prop-drilling.\n */\n\nimport { effect, type Read, signal } from '@aihu/signals'\nimport { createDomContext, provideContext } from '../dom-context.ts'\n\nexport { attachHiddenInput, type HiddenInputOptions } from './hidden-input.ts'\n\nexport interface FormControlContextValue {\n readonly disabled: Read<boolean>\n readonly required: Read<boolean>\n readonly invalid: Read<boolean>\n readonly controlId: Read<string>\n readonly describedById: Read<string | null>\n readonly labelId: Read<string | null>\n}\n\nexport const formControlContext = createDomContext<FormControlContextValue>('form-control')\n\nlet _idCounter = 0\nfunction nextId(): string {\n _idCounter += 1\n return `aihu-fc-${_idCounter}`\n}\n\nexport class AihuFormControl extends HTMLElement {\n static readonly observedAttributes = ['disabled', 'required', 'invalid', 'name', 'control-id']\n\n private readonly _disabled = signal(false)\n private readonly _required = signal(false)\n private readonly _invalid = signal(false)\n private readonly _controlId = signal('')\n private readonly _describedById = signal<string | null>(null)\n private readonly _labelId = signal<string | null>(null)\n\n private _disposers: Array<() => void> = []\n\n get disabled(): Read<boolean> {\n return this._disabled[0]\n }\n get required(): Read<boolean> {\n return this._required[0]\n }\n get invalid(): Read<boolean> {\n return this._invalid[0]\n }\n get controlId(): Read<string> {\n return this._controlId[0]\n }\n get labelId(): Read<string | null> {\n return this._labelId[0]\n }\n\n constructor() {\n super()\n provideContext(this, formControlContext, {\n disabled: this._disabled[0],\n required: this._required[0],\n invalid: this._invalid[0],\n controlId: this._controlId[0],\n describedById: this._describedById[0],\n labelId: this._labelId[0],\n })\n }\n\n connectedCallback(): void {\n // Stable control id (generated if not supplied).\n const supplied = this.getAttribute('control-id')\n this._controlId[1](supplied ?? nextId())\n\n this._syncBooleans()\n this._wireAssociations()\n\n // Reflect ARIA onto the slotted control reactively.\n this._disposers.push(\n effect(() => {\n const control = this._control()\n if (!control) return\n reflectAria(control, 'aria-disabled', this._disabled[0]())\n reflectAria(control, 'aria-required', this._required[0]())\n reflectAria(control, 'aria-invalid', this._invalid[0]())\n const describedBy = this._describedById[0]()\n if (describedBy) control.setAttribute('aria-describedby', describedBy)\n else control.removeAttribute('aria-describedby')\n }),\n )\n }\n\n disconnectedCallback(): void {\n for (const d of this._disposers) d()\n this._disposers = []\n }\n\n attributeChangedCallback(name: string, _old: string | null, value: string | null): void {\n switch (name) {\n case 'disabled':\n this._disabled[1](value !== null)\n break\n case 'required':\n this._required[1](value !== null)\n break\n case 'invalid':\n this._invalid[1](value !== null)\n break\n case 'control-id':\n if (value) this._controlId[1](value)\n break\n }\n }\n\n /** Re-derive `aria-describedby` from the slotted description/error pieces.\n * Call after a piece mounts/unmounts. */\n recomputeDescribedBy(): void {\n this._wireAssociations()\n }\n\n private _syncBooleans(): void {\n this._disabled[1](this.hasAttribute('disabled'))\n this._required[1](this.hasAttribute('required'))\n this._invalid[1](this.hasAttribute('invalid'))\n }\n\n /** The slotted control element (input/select/textarea/[data-fc-control]). */\n private _control(): HTMLElement | null {\n return this.querySelector<HTMLElement>(\n '[data-fc-control], input, select, textarea, [role=\"textbox\"]',\n )\n }\n\n private _wireAssociations(): void {\n const control = this._control()\n if (control) {\n if (!control.id) control.id = this._controlId[0]()\n else this._controlId[1](control.id)\n }\n\n // Associate a slotted label.\n const label = this.querySelector<HTMLElement>('label, [data-fc-label]')\n if (label && control) {\n if (label instanceof HTMLLabelElement) {\n label.htmlFor = control.id\n this._labelId[1](label.id || null)\n } else {\n // Non-native label ([data-fc-label]): `for` has no native semantics,\n // so associate via aria-labelledby pointing at the label's id.\n label.setAttribute('for', control.id)\n if (!label.id) label.id = nextId()\n control.setAttribute('aria-labelledby', label.id)\n this._labelId[1](label.id)\n }\n }\n\n // Collect description + error ids into aria-describedby.\n const described: string[] = []\n for (const el of this.querySelectorAll<HTMLElement>('[data-fc-description], [data-fc-error]')) {\n if (!el.id) el.id = nextId()\n described.push(el.id)\n }\n this._describedById[1](described.length ? described.join(' ') : null)\n }\n}\n\nfunction reflectAria(el: HTMLElement, attr: string, on: boolean): void {\n if (on) el.setAttribute(attr, 'true')\n else el.removeAttribute(attr)\n}\n\nlet _defined = false\n/** Register `<aihu-form-control>` (idempotent). */\nexport function defineFormControl(tag = 'aihu-form-control'): void {\n if (_defined || customElements.get(tag)) {\n _defined = true\n return\n }\n customElements.define(tag, AihuFormControl)\n _defined = true\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index-D7hJLfnb.d.ts","names":[],"sources":["../src/dialog/focus-trap.ts","../src/dialog/index.ts"],"mappings":";;;;;;;;AAYA;;UAAiB,SAAA;EACf,QAAA;EACA,UAAA;AAAA;AAAA,iBAcc,eAAA,CAAgB,SAAA,EAAW,OAAA,GAAU,SAAA;;;UCbpC,kBAAA;EAAA,SACN,IAAA,EAAM,IAAA;EAAA,SACN,KAAA,EAAO,IAAA;EAAA,SACP,SAAA,EAAW,IAAA;EAAA,SACX,OAAA,EAAS,IAAA;EAAA,SACT,aAAA,EAAe,IAAA;EACxB,UAAA,CAAW,EAAA;EACX,gBAAA,CAAiB,EAAA;EACjB,OAAA,CAAQ,IAAA;EACR,KAAA;EACA,MAAA;AAAA;AAAA,cAGW,aAAA,EAAa,UAAA,CAAA,kBAAA;AAAA,cAKb,cAAA,SAAuB,WAAA;EAAA,gBAClB,kBAAA;EAAA,iBAEC,KAAA;EAAA,iBACA,MAAA;EAAA,iBACA,UAAA;EAAA,iBACA,QAAA;EAAA,iBACA,cAAA;EAAA,QACT,UAAA;EAAA,QACA,IAAA;;MAmBJ,IAAA,CAAA,GAAQ,IAAA;EAIZ,OAAA,CAAQ,IAAA;EAOR,iBAAA,CAAA;EAUA,oBAAA,CAAA;EAKA,wBAAA,CAAyB,IAAA,UAAc,IAAA,iBAAqB,KAAA;AAAA;;uBAO/C,WAAA,SAAoB,WAAA;EAAA,UACvB,GAAA,EAAM,kBAAA;EAAA,UACN,SAAA,EAAW,KAAA;EAErB,iBAAA,CAAA;EAKA,oBAAA,CAAA;EAAA,UAKU,YAAA,CAAA;EAAA,mBAQS,SAAA,CAAA;AAAA;AAAA,cAGR,iBAAA,SAA0B,WAAA;EAAA,UAC3B,SAAA,CAAA;EAAA,iBAiBO,QAAA;AAAA;AAAA,cAKN,iBAAA,SAA0B,WAAA;EAAA,QAC7B,KAAA;EAAA,UAEE,SAAA,CAAA;EAmBD,oBAAA,CAAA;EAAA,QAMD,aAAA;EAAA,QAMA,eAAA;EAAA,iBAKS,UAAA;AAAA;AAAA,cAQN,kBAAA,SAA2B,WAAA;EAAA,UAC5B,SAAA,CAAA;EAAA,iBAKO,QAAA;AAAA;AAAA,cAON,eAAA,SAAwB,WAAA;EAAA,UACzB,SAAA,CAAA;EAAA,iBASO,QAAA;AAAA;AAAA,cAKN,eAAA,SAAwB,WAAA;EAAA,UACzB,SAAA,CAAA;AAAA;AAAA,cAMC,qBAAA,SAA8B,WAAA;EAAA,UAC/B,SAAA,CAAA;AAAA;;;;;;;;AAtIX;iBA+Je,YAAA,CAAa,MAAA"}
|