@aihu/primitives 0.0.12 → 0.1.1
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 +14 -7
- package/dist/{button-C-8c-A17.js → button-Cha1gKlr.js} +2 -2
- package/dist/{button-C-8c-A17.js.map → button-Cha1gKlr.js.map} +1 -1
- package/dist/button.d.ts +1 -1
- package/dist/button.js +1 -1
- package/dist/checkbox.d.ts +45 -0
- package/dist/checkbox.d.ts.map +1 -0
- package/dist/checkbox.js +190 -0
- package/dist/checkbox.js.map +1 -0
- package/dist/{dialog-y7MHc6vf.js → dialog-VDL-W3Vy.js} +17 -7
- package/dist/{dialog-y7MHc6vf.js.map → dialog-VDL-W3Vy.js.map} +1 -1
- package/dist/dialog.d.ts +1 -1
- package/dist/dialog.js +1 -1
- package/dist/form-control-B_BO9j7_.js +223 -0
- package/dist/form-control-B_BO9j7_.js.map +1 -0
- package/dist/form-control.d.ts +2 -41
- package/dist/form-control.js +2 -145
- package/dist/index-BvFa1Y-Z.d.ts +60 -0
- package/dist/index-BvFa1Y-Z.d.ts.map +1 -0
- package/dist/{index-D9kf9rVU.d.ts → index-D7hJLfnb.d.ts} +10 -3
- package/dist/{index-D9kf9rVU.d.ts.map → index-D7hJLfnb.d.ts.map} +1 -1
- package/dist/{index-DPD4L6Nj.d.ts → index-yPv3StRL.d.ts} +1 -1
- package/dist/{index-DPD4L6Nj.d.ts.map → index-yPv3StRL.d.ts.map} +1 -1
- package/dist/index.d.ts +12 -4
- package/dist/index.js +12 -4
- package/dist/input.d.ts +13 -0
- package/dist/input.d.ts.map +1 -0
- package/dist/input.js +42 -0
- package/dist/input.js.map +1 -0
- package/dist/label.d.ts +24 -0
- package/dist/label.d.ts.map +1 -0
- package/dist/label.js +136 -0
- package/dist/label.js.map +1 -0
- package/dist/radio-group.d.ts +82 -0
- package/dist/radio-group.d.ts.map +1 -0
- package/dist/radio-group.js +298 -0
- package/dist/radio-group.js.map +1 -0
- package/dist/roving-focus.d.ts +4 -2
- package/dist/roving-focus.d.ts.map +1 -1
- package/dist/roving-focus.js +5 -3
- package/dist/roving-focus.js.map +1 -1
- package/dist/separator.d.ts +25 -0
- package/dist/separator.d.ts.map +1 -0
- package/dist/separator.js +85 -0
- package/dist/separator.js.map +1 -0
- package/dist/switch.d.ts +44 -0
- package/dist/switch.d.ts.map +1 -0
- package/dist/switch.js +176 -0
- package/dist/switch.js.map +1 -0
- package/dist/text-control-BBX7s8Oe.js +181 -0
- package/dist/text-control-BBX7s8Oe.js.map +1 -0
- package/dist/text-control-Brv5fUEX.d.ts +38 -0
- package/dist/text-control-Brv5fUEX.d.ts.map +1 -0
- package/dist/textarea.d.ts +13 -0
- package/dist/textarea.d.ts.map +1 -0
- package/dist/textarea.js +38 -0
- package/dist/textarea.js.map +1 -0
- package/dist/tooltip.d.ts +8 -2
- package/dist/tooltip.d.ts.map +1 -1
- package/dist/tooltip.js +15 -6
- package/dist/tooltip.js.map +1 -1
- package/package.json +33 -2
- package/dist/form-control.d.ts.map +0 -1
- package/dist/form-control.js.map +0 -1
package/README.md
CHANGED
|
@@ -48,7 +48,7 @@ npm install @aihu/primitives
|
|
|
48
48
|
bun add @aihu/primitives
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
-
<sub><i>Auto-generated against `@aihu/primitives@0.
|
|
51
|
+
<sub><i>Auto-generated against `@aihu/primitives@0.1.1`.</i></sub>
|
|
52
52
|
|
|
53
53
|
<!-- END_AUTOGEN: install -->
|
|
54
54
|
|
|
@@ -59,12 +59,12 @@ bun add @aihu/primitives
|
|
|
59
59
|
|
|
60
60
|
| | |
|
|
61
61
|
|---|---|
|
|
62
|
-
| **Version** | `0.
|
|
62
|
+
| **Version** | `0.1.1` |
|
|
63
63
|
| **Tier** | E — Held private (unmapped tier) |
|
|
64
64
|
| **Published files** | 3 entries |
|
|
65
65
|
| **License** | MIT |
|
|
66
66
|
|
|
67
|
-
<sub><i>Auto-generated against `@aihu/primitives@0.
|
|
67
|
+
<sub><i>Auto-generated against `@aihu/primitives@0.1.1`.</i></sub>
|
|
68
68
|
|
|
69
69
|
<!-- END_AUTOGEN: stats -->
|
|
70
70
|
|
|
@@ -85,8 +85,15 @@ bun add @aihu/primitives
|
|
|
85
85
|
| `./dialog` | `./dist/dialog.js` | `—` |
|
|
86
86
|
| `./tooltip` | `./dist/tooltip.js` | `—` |
|
|
87
87
|
| `./button` | `./dist/button.js` | `—` |
|
|
88
|
+
| `./separator` | `./dist/separator.js` | `—` |
|
|
89
|
+
| `./label` | `./dist/label.js` | `—` |
|
|
90
|
+
| `./input` | `./dist/input.js` | `—` |
|
|
91
|
+
| `./textarea` | `./dist/textarea.js` | `—` |
|
|
92
|
+
| `./checkbox` | `./dist/checkbox.js` | `—` |
|
|
93
|
+
| `./switch` | `./dist/switch.js` | `—` |
|
|
94
|
+
| `./radio-group` | `./dist/radio-group.js` | `—` |
|
|
88
95
|
|
|
89
|
-
<sub><i>Auto-generated against `@aihu/primitives@0.
|
|
96
|
+
<sub><i>Auto-generated against `@aihu/primitives@0.1.1`.</i></sub>
|
|
90
97
|
|
|
91
98
|
<!-- END_AUTOGEN: exports -->
|
|
92
99
|
|
|
@@ -101,7 +108,7 @@ bun add @aihu/primitives
|
|
|
101
108
|
- `@aihu/arbor` — `workspace:*`
|
|
102
109
|
- `@aihu/css-engine` — `workspace:*`
|
|
103
110
|
|
|
104
|
-
<sub><i>Auto-generated against `@aihu/primitives@0.
|
|
111
|
+
<sub><i>Auto-generated against `@aihu/primitives@0.1.1`.</i></sub>
|
|
105
112
|
|
|
106
113
|
<!-- END_AUTOGEN: deps -->
|
|
107
114
|
|
|
@@ -113,7 +120,7 @@ bun add @aihu/primitives
|
|
|
113
120
|
- [Aihu framework root](../../README.md)
|
|
114
121
|
- [v1.1 roadmap](../../docs/roadmap/SUMMARY.md)
|
|
115
122
|
|
|
116
|
-
<sub><i>Auto-generated against `@aihu/primitives@0.
|
|
123
|
+
<sub><i>Auto-generated against `@aihu/primitives@0.1.1`.</i></sub>
|
|
117
124
|
|
|
118
125
|
<!-- END_AUTOGEN: see-also -->
|
|
119
126
|
|
|
@@ -124,6 +131,6 @@ bun add @aihu/primitives
|
|
|
124
131
|
|
|
125
132
|
MIT — see [LICENSE](../../LICENSE).
|
|
126
133
|
|
|
127
|
-
<sub><i>Auto-generated against `@aihu/primitives@0.
|
|
134
|
+
<sub><i>Auto-generated against `@aihu/primitives@0.1.1`.</i></sub>
|
|
128
135
|
|
|
129
136
|
<!-- END_AUTOGEN: license -->
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { injectValue } from "./dom-context.js";
|
|
2
|
-
import { formControlContext } from "./form-control.js";
|
|
2
|
+
import { r as formControlContext } from "./form-control-B_BO9j7_.js";
|
|
3
3
|
import { effect, signal } from "@aihu/signals";
|
|
4
4
|
//#region src/button/button.ts
|
|
5
5
|
/**
|
|
@@ -123,4 +123,4 @@ function defineButton(tag) {
|
|
|
123
123
|
//#endregion
|
|
124
124
|
export { defineButton as n, AihuButton as t };
|
|
125
125
|
|
|
126
|
-
//# sourceMappingURL=button-
|
|
126
|
+
//# sourceMappingURL=button-Cha1gKlr.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"button-
|
|
1
|
+
{"version":3,"file":"button-Cha1gKlr.js","names":[],"sources":["../src/button/button.ts"],"sourcesContent":["/**\n * `AihuButton` — headless button base class (WAI-ARIA APG Button). Consumers\n * (or Plan 5 recipes) extend it; it is NOT a registered tag in this package.\n * Use `defineButton(tag)` to register a concrete element for tests/consumers.\n *\n * Behavior:\n * - If the host is NOT a native `<button>`, sets `role=\"button\"` +\n * `tabindex=\"0\"` and handles Enter / Space to fire a synthetic `click`\n * (the APG Button keyboard contract). A native `<button>` defers to native\n * semantics.\n * - `aria-pressed` reflects the `pressed` toggle state.\n * - `aria-disabled` + suppressed activation when `disabled`.\n * - Inherits `disabled` from a `FormControlContext` ancestor (Task 5) so a\n * button inside a disabled `form-control` is disabled too.\n * - `data-state` reflects `pressed` / `disabled`. Emits NO CSS.\n */\n\nimport { effect, type Read, signal } from '@aihu/signals'\nimport { injectValue } from '../dom-context.ts'\nimport { formControlContext } from '../form-control/index.ts'\n\nexport type ButtonType = 'button' | 'submit' | 'reset'\n\nexport class AihuButton extends HTMLElement {\n static readonly observedAttributes = ['disabled', 'pressed', 'type']\n\n private readonly _disabled = signal(false)\n private readonly _pressed = signal<boolean | null>(null)\n private _inheritedDisabled: Read<boolean> | null = null\n private _disposers: Array<() => void> = []\n\n /** True when this is a toggle button (the `pressed` attribute is present). */\n private _isToggle = false\n\n get disabled(): Read<boolean> {\n return this._disabled[0]\n }\n get pressed(): Read<boolean | null> {\n return this._pressed[0]\n }\n\n private get _isNativeButton(): boolean {\n return this.tagName === 'BUTTON'\n }\n\n connectedCallback(): void {\n this._isToggle = this.hasAttribute('pressed')\n this._syncFromAttrs()\n\n if (!this._isNativeButton) {\n if (!this.hasAttribute('role')) this.setAttribute('role', 'button')\n if (!this.hasAttribute('tabindex')) this.setAttribute('tabindex', '0')\n this.addEventListener('keydown', this._onKeydown)\n }\n // Suppress activation when disabled (capture so it beats consumer handlers).\n this.addEventListener('click', this._onClickCapture, true)\n\n // Inherit disabled from a FormControlContext ancestor, if any.\n try {\n this._inheritedDisabled = injectValue(this, formControlContext).disabled\n } catch {\n this._inheritedDisabled = null\n }\n\n this._disposers.push(\n effect(() => {\n const disabled = this._effectiveDisabled()\n if (disabled) this.setAttribute('aria-disabled', 'true')\n else this.removeAttribute('aria-disabled')\n\n if (this._isToggle) {\n this.setAttribute('aria-pressed', String(this._pressed[0]() === true))\n }\n this.setAttribute('data-state', this._stateString(disabled))\n }),\n )\n }\n\n disconnectedCallback(): void {\n this.removeEventListener('keydown', this._onKeydown)\n this.removeEventListener('click', this._onClickCapture, true)\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 'pressed':\n this._isToggle = value !== null ? true : this._isToggle\n this._pressed[1](value !== null)\n break\n }\n }\n\n /** Toggle a toggle-button's pressed state. */\n toggle(): void {\n if (!this._isToggle) return\n this._pressed[1](!(this._pressed[0]() === true))\n }\n\n private _effectiveDisabled(): boolean {\n if (this._disabled[0]()) return true\n return this._inheritedDisabled ? this._inheritedDisabled() : false\n }\n\n private _stateString(disabled: boolean): string {\n if (disabled) return 'disabled'\n if (this._isToggle) return this._pressed[0]() === true ? 'on' : 'off'\n return 'idle'\n }\n\n private readonly _onKeydown = (ev: KeyboardEvent): void => {\n if (this._effectiveDisabled()) return\n if (ev.key === 'Enter' || ev.key === ' ' || ev.key === 'Spacebar') {\n ev.preventDefault()\n this.click()\n }\n }\n\n private readonly _onClickCapture = (ev: Event): void => {\n if (this._effectiveDisabled()) {\n ev.preventDefault()\n ev.stopImmediatePropagation()\n return\n }\n if (this._isToggle) this.toggle()\n }\n\n private _syncFromAttrs(): void {\n this._disabled[1](this.hasAttribute('disabled'))\n if (this._isToggle) this._pressed[1](this.getAttribute('pressed') !== 'false')\n }\n}\n\n/** Register a concrete button tag backed by `AihuButton` (idempotent). */\nexport function defineButton(tag: string): typeof AihuButton {\n if (!customElements.get(tag)) {\n // A fresh subclass per tag so multiple tags can be registered.\n class TaggedButton extends AihuButton {}\n customElements.define(tag, TaggedButton)\n }\n return AihuButton\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAuBA,IAAa,aAAb,cAAgC,YAAY;CAC1C,OAAgB,qBAAqB;EAAC;EAAY;EAAW;EAAO;CAEpE,YAA6B,OAAO,MAAM;CAC1C,WAA4B,OAAuB,KAAK;CACxD,qBAAmD;CACnD,aAAwC,EAAE;;CAG1C,YAAoB;CAEpB,IAAI,WAA0B;EAC5B,OAAO,KAAK,UAAU;;CAExB,IAAI,UAAgC;EAClC,OAAO,KAAK,SAAS;;CAGvB,IAAY,kBAA2B;EACrC,OAAO,KAAK,YAAY;;CAG1B,oBAA0B;EACxB,KAAK,YAAY,KAAK,aAAa,UAAU;EAC7C,KAAK,gBAAgB;EAErB,IAAI,CAAC,KAAK,iBAAiB;GACzB,IAAI,CAAC,KAAK,aAAa,OAAO,EAAE,KAAK,aAAa,QAAQ,SAAS;GACnE,IAAI,CAAC,KAAK,aAAa,WAAW,EAAE,KAAK,aAAa,YAAY,IAAI;GACtE,KAAK,iBAAiB,WAAW,KAAK,WAAW;;EAGnD,KAAK,iBAAiB,SAAS,KAAK,iBAAiB,KAAK;EAG1D,IAAI;GACF,KAAK,qBAAqB,YAAY,MAAM,mBAAmB,CAAC;UAC1D;GACN,KAAK,qBAAqB;;EAG5B,KAAK,WAAW,KACd,aAAa;GACX,MAAM,WAAW,KAAK,oBAAoB;GAC1C,IAAI,UAAU,KAAK,aAAa,iBAAiB,OAAO;QACnD,KAAK,gBAAgB,gBAAgB;GAE1C,IAAI,KAAK,WACP,KAAK,aAAa,gBAAgB,OAAO,KAAK,SAAS,IAAI,KAAK,KAAK,CAAC;GAExE,KAAK,aAAa,cAAc,KAAK,aAAa,SAAS,CAAC;IAC5D,CACH;;CAGH,uBAA6B;EAC3B,KAAK,oBAAoB,WAAW,KAAK,WAAW;EACpD,KAAK,oBAAoB,SAAS,KAAK,iBAAiB,KAAK;EAC7D,KAAK,MAAM,KAAK,KAAK,YAAY,GAAG;EACpC,KAAK,aAAa,EAAE;;CAGtB,yBAAyB,MAAc,MAAqB,OAA4B;EACtF,QAAQ,MAAR;GACE,KAAK;IACH,KAAK,UAAU,GAAG,UAAU,KAAK;IACjC;GACF,KAAK;IACH,KAAK,YAAY,UAAU,OAAO,OAAO,KAAK;IAC9C,KAAK,SAAS,GAAG,UAAU,KAAK;IAChC;;;;CAKN,SAAe;EACb,IAAI,CAAC,KAAK,WAAW;EACrB,KAAK,SAAS,GAAG,EAAE,KAAK,SAAS,IAAI,KAAK,MAAM;;CAGlD,qBAAsC;EACpC,IAAI,KAAK,UAAU,IAAI,EAAE,OAAO;EAChC,OAAO,KAAK,qBAAqB,KAAK,oBAAoB,GAAG;;CAG/D,aAAqB,UAA2B;EAC9C,IAAI,UAAU,OAAO;EACrB,IAAI,KAAK,WAAW,OAAO,KAAK,SAAS,IAAI,KAAK,OAAO,OAAO;EAChE,OAAO;;CAGT,cAA+B,OAA4B;EACzD,IAAI,KAAK,oBAAoB,EAAE;EAC/B,IAAI,GAAG,QAAQ,WAAW,GAAG,QAAQ,OAAO,GAAG,QAAQ,YAAY;GACjE,GAAG,gBAAgB;GACnB,KAAK,OAAO;;;CAIhB,mBAAoC,OAAoB;EACtD,IAAI,KAAK,oBAAoB,EAAE;GAC7B,GAAG,gBAAgB;GACnB,GAAG,0BAA0B;GAC7B;;EAEF,IAAI,KAAK,WAAW,KAAK,QAAQ;;CAGnC,iBAA+B;EAC7B,KAAK,UAAU,GAAG,KAAK,aAAa,WAAW,CAAC;EAChD,IAAI,KAAK,WAAW,KAAK,SAAS,GAAG,KAAK,aAAa,UAAU,KAAK,QAAQ;;;;AAKlF,SAAgB,aAAa,KAAgC;CAC3D,IAAI,CAAC,eAAe,IAAI,IAAI,EAAE;EAE5B,MAAM,qBAAqB,WAAW;EACtC,eAAe,OAAO,KAAK,aAAa;;CAE1C,OAAO"}
|
package/dist/button.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as ButtonType, r as defineButton, t as AihuButton } from "./index-
|
|
1
|
+
import { n as ButtonType, r as defineButton, t as AihuButton } from "./index-yPv3StRL.js";
|
|
2
2
|
export { AihuButton, ButtonType, defineButton };
|
package/dist/button.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as defineButton, t as AihuButton } from "./button-
|
|
1
|
+
import { n as defineButton, t as AihuButton } from "./button-Cha1gKlr.js";
|
|
2
2
|
export { AihuButton, defineButton };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { DomContext } from "./dom-context.js";
|
|
2
|
+
import { Read } from "@aihu/signals";
|
|
3
|
+
|
|
4
|
+
//#region src/checkbox/index.d.ts
|
|
5
|
+
type CheckboxState = 'checked' | 'unchecked' | 'indeterminate';
|
|
6
|
+
interface CheckboxContextValue {
|
|
7
|
+
readonly state: Read<CheckboxState>;
|
|
8
|
+
readonly disabled: Read<boolean>;
|
|
9
|
+
}
|
|
10
|
+
declare const checkboxContext: DomContext<CheckboxContextValue>;
|
|
11
|
+
declare class AihuCheckboxRoot extends HTMLElement {
|
|
12
|
+
static readonly observedAttributes: string[];
|
|
13
|
+
private readonly _state;
|
|
14
|
+
private readonly _disabled;
|
|
15
|
+
private readonly _required;
|
|
16
|
+
private readonly _name;
|
|
17
|
+
private readonly _value;
|
|
18
|
+
private _fc;
|
|
19
|
+
private _disposers;
|
|
20
|
+
private _defaultSeeded;
|
|
21
|
+
constructor();
|
|
22
|
+
get state(): Read<CheckboxState>;
|
|
23
|
+
/** Programmatic write: signal + reflected `checked` attribute (two-way,
|
|
24
|
+
* dialog open-attr pattern). Does NOT emit `checked-change`. */
|
|
25
|
+
setChecked(next: boolean | 'mixed'): void;
|
|
26
|
+
connectedCallback(): void;
|
|
27
|
+
disconnectedCallback(): void;
|
|
28
|
+
attributeChangedCallback(name: string, _old: string | null, value: string | null): void;
|
|
29
|
+
private _effectiveDisabled;
|
|
30
|
+
private _effectiveRequired;
|
|
31
|
+
private _syncFromAttrs;
|
|
32
|
+
private readonly _onKeydown;
|
|
33
|
+
private readonly _onClickCapture;
|
|
34
|
+
}
|
|
35
|
+
/** Presentational styling hook: mirrors the root's state, hidden from AT. */
|
|
36
|
+
declare class AihuCheckboxIndicator extends HTMLElement {
|
|
37
|
+
private _disposers;
|
|
38
|
+
connectedCallback(): void;
|
|
39
|
+
disconnectedCallback(): void;
|
|
40
|
+
}
|
|
41
|
+
/** Register all checkbox custom elements (idempotent). */
|
|
42
|
+
declare function defineCheckbox(): void;
|
|
43
|
+
//#endregion
|
|
44
|
+
export { AihuCheckboxIndicator, AihuCheckboxRoot, CheckboxContextValue, CheckboxState, checkboxContext, defineCheckbox };
|
|
45
|
+
//# sourceMappingURL=checkbox.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkbox.d.ts","names":[],"sources":["../src/checkbox/index.ts"],"mappings":";;;;KAyBY,aAAA;AAAA,UAEK,oBAAA;EAAA,SACN,KAAA,EAAO,IAAA,CAAK,aAAA;EAAA,SACZ,QAAA,EAAU,IAAA;AAAA;AAAA,cAGR,eAAA,EAAe,UAAA,CAAA,oBAAA;AAAA,cAUf,gBAAA,SAAyB,WAAA;EAAA,gBACpB,kBAAA;EAAA,iBASC,MAAA;EAAA,iBACA,SAAA;EAAA,iBACA,SAAA;EAAA,iBACA,KAAA;EAAA,iBACA,MAAA;EAAA,QACT,GAAA;EAAA,QACA,UAAA;EAAA,QACA,cAAA;;MAUJ,KAAA,CAAA,GAAS,IAAA,CAAK,aAAA;EA3B6B;;EAiC/C,UAAA,CAAW,IAAA;EAQX,iBAAA,CAAA;EAoDA,oBAAA,CAAA;EAOA,wBAAA,CAAyB,IAAA,UAAc,IAAA,iBAAqB,KAAA;EAAA,QAqBpD,kBAAA;EAAA,QAKA,kBAAA;EAAA,QAKA,cAAA;EAAA,iBAOS,UAAA;EAAA,iBAaA,eAAA;AAAA;;cAoBN,qBAAA,SAA8B,WAAA;EAAA,QACjC,UAAA;EAER,iBAAA,CAAA;EAYA,oBAAA,CAAA;AAAA;;iBAac,cAAA,CAAA"}
|
package/dist/checkbox.js
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { createDomContext, injectValue, provideContext } from "./dom-context.js";
|
|
2
|
+
import { i as attachHiddenInput, r as formControlContext } from "./form-control-B_BO9j7_.js";
|
|
3
|
+
import { effect, signal } from "@aihu/signals";
|
|
4
|
+
//#region src/checkbox/index.ts
|
|
5
|
+
/**
|
|
6
|
+
* Headless checkbox — `<aihu-checkbox-root>` (state owner) + presentational
|
|
7
|
+
* `<aihu-checkbox-indicator>`. Implements the WAI-ARIA APG **Checkbox**
|
|
8
|
+
* pattern (tri-state): `role="checkbox"`, `aria-checked="true" | "false" |
|
|
9
|
+
* "mixed"`, Space toggles, Enter does NOT activate (APG/Radix). Emits NO CSS —
|
|
10
|
+
* each piece reflects `data-state="checked" | "unchecked" | "indeterminate"`
|
|
11
|
+
* (+ `data-disabled` presence) for the consumer to style.
|
|
12
|
+
*
|
|
13
|
+
* Form participation rides `attachHiddenInput` (a visually-hidden native
|
|
14
|
+
* checkbox in the host's light DOM): the value submits only when fully
|
|
15
|
+
* checked — indeterminate submits as UNCHECKED (native parity).
|
|
16
|
+
*
|
|
17
|
+
* `checked-change` (detail `{ checked: boolean | 'mixed' }`, bubbles,
|
|
18
|
+
* composed) is dispatched on USER-driven toggles only (clicks/keys), matching
|
|
19
|
+
* the dialog precedent — programmatic attribute writes do not emit.
|
|
20
|
+
*/
|
|
21
|
+
const checkboxContext = createDomContext("checkbox");
|
|
22
|
+
/** `checked` attribute grammar: absent=unchecked, "mixed"=indeterminate,
|
|
23
|
+
* any other value (including empty)=checked. */
|
|
24
|
+
function parseChecked(value) {
|
|
25
|
+
if (value === null) return "unchecked";
|
|
26
|
+
if (value === "mixed") return "indeterminate";
|
|
27
|
+
return "checked";
|
|
28
|
+
}
|
|
29
|
+
var AihuCheckboxRoot = class extends HTMLElement {
|
|
30
|
+
static observedAttributes = [
|
|
31
|
+
"checked",
|
|
32
|
+
"default-checked",
|
|
33
|
+
"disabled",
|
|
34
|
+
"required",
|
|
35
|
+
"name",
|
|
36
|
+
"value"
|
|
37
|
+
];
|
|
38
|
+
_state = signal("unchecked");
|
|
39
|
+
_disabled = signal(false);
|
|
40
|
+
_required = signal(false);
|
|
41
|
+
_name = signal(null);
|
|
42
|
+
_value = signal("on");
|
|
43
|
+
_fc = null;
|
|
44
|
+
_disposers = [];
|
|
45
|
+
_defaultSeeded = false;
|
|
46
|
+
constructor() {
|
|
47
|
+
super();
|
|
48
|
+
provideContext(this, checkboxContext, {
|
|
49
|
+
state: this._state[0],
|
|
50
|
+
disabled: () => this._effectiveDisabled()
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
get state() {
|
|
54
|
+
return this._state[0];
|
|
55
|
+
}
|
|
56
|
+
/** Programmatic write: signal + reflected `checked` attribute (two-way,
|
|
57
|
+
* dialog open-attr pattern). Does NOT emit `checked-change`. */
|
|
58
|
+
setChecked(next) {
|
|
59
|
+
const state = next === "mixed" ? "indeterminate" : next ? "checked" : "unchecked";
|
|
60
|
+
if (state === this._state[0]()) return;
|
|
61
|
+
this._state[1](state);
|
|
62
|
+
if (state === "unchecked") this.removeAttribute("checked");
|
|
63
|
+
else this.setAttribute("checked", state === "indeterminate" ? "mixed" : "");
|
|
64
|
+
}
|
|
65
|
+
connectedCallback() {
|
|
66
|
+
if (this.hasAttribute("checked")) this._state[1](parseChecked(this.getAttribute("checked")));
|
|
67
|
+
else if (!this._defaultSeeded && this.hasAttribute("default-checked")) this._state[1](parseChecked(this.getAttribute("default-checked")));
|
|
68
|
+
this._defaultSeeded = true;
|
|
69
|
+
this._syncFromAttrs();
|
|
70
|
+
if (!this.hasAttribute("role")) this.setAttribute("role", "checkbox");
|
|
71
|
+
if (!this.hasAttribute("tabindex")) this.setAttribute("tabindex", "0");
|
|
72
|
+
this.setAttribute("data-fc-control", "");
|
|
73
|
+
this.addEventListener("keydown", this._onKeydown);
|
|
74
|
+
this.addEventListener("click", this._onClickCapture, true);
|
|
75
|
+
try {
|
|
76
|
+
this._fc = injectValue(this, formControlContext);
|
|
77
|
+
} catch {
|
|
78
|
+
this._fc = null;
|
|
79
|
+
}
|
|
80
|
+
this._disposers.push(effect(() => {
|
|
81
|
+
const state = this._state[0]();
|
|
82
|
+
this.setAttribute("aria-checked", state === "checked" ? "true" : state === "indeterminate" ? "mixed" : "false");
|
|
83
|
+
if (this._effectiveRequired()) this.setAttribute("aria-required", "true");
|
|
84
|
+
else this.removeAttribute("aria-required");
|
|
85
|
+
this.setAttribute("data-state", state);
|
|
86
|
+
if (this._effectiveDisabled()) this.setAttribute("data-disabled", "");
|
|
87
|
+
else this.removeAttribute("data-disabled");
|
|
88
|
+
}), attachHiddenInput(this, {
|
|
89
|
+
type: "checkbox",
|
|
90
|
+
name: this._name[0],
|
|
91
|
+
value: this._value[0],
|
|
92
|
+
checked: () => this._state[0]() === "checked",
|
|
93
|
+
required: () => this._effectiveRequired(),
|
|
94
|
+
disabled: () => this._effectiveDisabled()
|
|
95
|
+
}));
|
|
96
|
+
}
|
|
97
|
+
disconnectedCallback() {
|
|
98
|
+
this.removeEventListener("keydown", this._onKeydown);
|
|
99
|
+
this.removeEventListener("click", this._onClickCapture, true);
|
|
100
|
+
for (const d of this._disposers) d();
|
|
101
|
+
this._disposers = [];
|
|
102
|
+
}
|
|
103
|
+
attributeChangedCallback(name, _old, value) {
|
|
104
|
+
switch (name) {
|
|
105
|
+
case "checked":
|
|
106
|
+
this._state[1](parseChecked(value));
|
|
107
|
+
break;
|
|
108
|
+
case "disabled":
|
|
109
|
+
this._disabled[1](value !== null);
|
|
110
|
+
break;
|
|
111
|
+
case "required":
|
|
112
|
+
this._required[1](value !== null);
|
|
113
|
+
break;
|
|
114
|
+
case "name":
|
|
115
|
+
this._name[1](value);
|
|
116
|
+
break;
|
|
117
|
+
case "value":
|
|
118
|
+
this._value[1](value ?? "on");
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
_effectiveDisabled() {
|
|
123
|
+
if (this._disabled[0]()) return true;
|
|
124
|
+
return this._fc ? this._fc.disabled() : false;
|
|
125
|
+
}
|
|
126
|
+
_effectiveRequired() {
|
|
127
|
+
if (this._required[0]()) return true;
|
|
128
|
+
return this._fc ? this._fc.required() : false;
|
|
129
|
+
}
|
|
130
|
+
_syncFromAttrs() {
|
|
131
|
+
this._disabled[1](this.hasAttribute("disabled"));
|
|
132
|
+
this._required[1](this.hasAttribute("required"));
|
|
133
|
+
this._name[1](this.getAttribute("name"));
|
|
134
|
+
this._value[1](this.getAttribute("value") ?? "on");
|
|
135
|
+
}
|
|
136
|
+
_onKeydown = (ev) => {
|
|
137
|
+
if (ev.key === "Enter") {
|
|
138
|
+
ev.preventDefault();
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
if (ev.key === " " || ev.key === "Spacebar") {
|
|
142
|
+
ev.preventDefault();
|
|
143
|
+
if (this._effectiveDisabled()) return;
|
|
144
|
+
this.click();
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
_onClickCapture = (ev) => {
|
|
148
|
+
if (this._effectiveDisabled()) {
|
|
149
|
+
ev.preventDefault();
|
|
150
|
+
ev.stopImmediatePropagation();
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
const next = this._state[0]() !== "checked";
|
|
154
|
+
this.setChecked(next);
|
|
155
|
+
this.dispatchEvent(new CustomEvent("checked-change", {
|
|
156
|
+
detail: { checked: next },
|
|
157
|
+
bubbles: true,
|
|
158
|
+
composed: true
|
|
159
|
+
}));
|
|
160
|
+
};
|
|
161
|
+
};
|
|
162
|
+
/** Presentational styling hook: mirrors the root's state, hidden from AT. */
|
|
163
|
+
var AihuCheckboxIndicator = class extends HTMLElement {
|
|
164
|
+
_disposers = [];
|
|
165
|
+
connectedCallback() {
|
|
166
|
+
const ctx = injectValue(this, checkboxContext);
|
|
167
|
+
this.setAttribute("aria-hidden", "true");
|
|
168
|
+
this._disposers.push(effect(() => {
|
|
169
|
+
this.setAttribute("data-state", ctx.state());
|
|
170
|
+
if (ctx.disabled()) this.setAttribute("data-disabled", "");
|
|
171
|
+
else this.removeAttribute("data-disabled");
|
|
172
|
+
}));
|
|
173
|
+
}
|
|
174
|
+
disconnectedCallback() {
|
|
175
|
+
for (const d of this._disposers) d();
|
|
176
|
+
this._disposers = [];
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
const REGISTRY = [["aihu-checkbox-root", AihuCheckboxRoot], ["aihu-checkbox-indicator", AihuCheckboxIndicator]];
|
|
180
|
+
let _defined = false;
|
|
181
|
+
/** Register all checkbox custom elements (idempotent). */
|
|
182
|
+
function defineCheckbox() {
|
|
183
|
+
if (_defined) return;
|
|
184
|
+
for (const [tag, ctor] of REGISTRY) if (!customElements.get(tag)) customElements.define(tag, ctor);
|
|
185
|
+
_defined = true;
|
|
186
|
+
}
|
|
187
|
+
//#endregion
|
|
188
|
+
export { AihuCheckboxIndicator, AihuCheckboxRoot, checkboxContext, defineCheckbox };
|
|
189
|
+
|
|
190
|
+
//# sourceMappingURL=checkbox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkbox.js","names":[],"sources":["../src/checkbox/index.ts"],"sourcesContent":["/**\n * Headless checkbox — `<aihu-checkbox-root>` (state owner) + presentational\n * `<aihu-checkbox-indicator>`. Implements the WAI-ARIA APG **Checkbox**\n * pattern (tri-state): `role=\"checkbox\"`, `aria-checked=\"true\" | \"false\" |\n * \"mixed\"`, Space toggles, Enter does NOT activate (APG/Radix). Emits NO CSS —\n * each piece reflects `data-state=\"checked\" | \"unchecked\" | \"indeterminate\"`\n * (+ `data-disabled` presence) for the consumer to style.\n *\n * Form participation rides `attachHiddenInput` (a visually-hidden native\n * checkbox in the host's light DOM): the value submits only when fully\n * checked — indeterminate submits as UNCHECKED (native parity).\n *\n * `checked-change` (detail `{ checked: boolean | 'mixed' }`, bubbles,\n * composed) is dispatched on USER-driven toggles only (clicks/keys), matching\n * the dialog precedent — programmatic attribute writes do not emit.\n */\n\nimport { effect, type Read, signal } from '@aihu/signals'\nimport { createDomContext, injectValue, provideContext } from '../dom-context.ts'\nimport {\n attachHiddenInput,\n type FormControlContextValue,\n formControlContext,\n} from '../form-control/index.ts'\n\nexport type CheckboxState = 'checked' | 'unchecked' | 'indeterminate'\n\nexport interface CheckboxContextValue {\n readonly state: Read<CheckboxState>\n readonly disabled: Read<boolean>\n}\n\nexport const checkboxContext = createDomContext<CheckboxContextValue>('checkbox')\n\n/** `checked` attribute grammar: absent=unchecked, \"mixed\"=indeterminate,\n * any other value (including empty)=checked. */\nfunction parseChecked(value: string | null): CheckboxState {\n if (value === null) return 'unchecked'\n if (value === 'mixed') return 'indeterminate'\n return 'checked'\n}\n\nexport class AihuCheckboxRoot extends HTMLElement {\n static readonly observedAttributes = [\n 'checked',\n 'default-checked',\n 'disabled',\n 'required',\n 'name',\n 'value',\n ]\n\n private readonly _state = signal<CheckboxState>('unchecked')\n private readonly _disabled = signal(false)\n private readonly _required = signal(false)\n private readonly _name = signal<string | null>(null)\n private readonly _value = signal('on')\n private _fc: FormControlContextValue | null = null\n private _disposers: Array<() => void> = []\n private _defaultSeeded = false\n\n constructor() {\n super()\n provideContext(this, checkboxContext, {\n state: this._state[0],\n disabled: () => this._effectiveDisabled(),\n })\n }\n\n get state(): Read<CheckboxState> {\n return this._state[0]\n }\n\n /** Programmatic write: signal + reflected `checked` attribute (two-way,\n * dialog open-attr pattern). Does NOT emit `checked-change`. */\n setChecked(next: boolean | 'mixed'): void {\n const state: CheckboxState = next === 'mixed' ? 'indeterminate' : next ? 'checked' : 'unchecked'\n if (state === this._state[0]()) return\n this._state[1](state)\n if (state === 'unchecked') this.removeAttribute('checked')\n else this.setAttribute('checked', state === 'indeterminate' ? 'mixed' : '')\n }\n\n connectedCallback(): void {\n // Initial state: the `checked` attribute wins; otherwise `default-checked`\n // seeds ONCE (signal only — never reflected).\n if (this.hasAttribute('checked')) {\n this._state[1](parseChecked(this.getAttribute('checked')))\n } else if (!this._defaultSeeded && this.hasAttribute('default-checked')) {\n this._state[1](parseChecked(this.getAttribute('default-checked')))\n }\n this._defaultSeeded = true\n this._syncFromAttrs()\n\n if (!this.hasAttribute('role')) this.setAttribute('role', 'checkbox')\n if (!this.hasAttribute('tabindex')) this.setAttribute('tabindex', '0')\n // Discoverable by an ancestor <aihu-form-control> ([data-fc-control] is\n // first in its control selector, so the HOST wins over the hidden input).\n this.setAttribute('data-fc-control', '')\n\n this.addEventListener('keydown', this._onKeydown)\n // Capture so disabled suppression beats consumer handlers (button precedent).\n this.addEventListener('click', this._onClickCapture, true)\n\n try {\n this._fc = injectValue(this, formControlContext)\n } catch {\n this._fc = null\n }\n\n this._disposers.push(\n effect(() => {\n const state = this._state[0]()\n this.setAttribute(\n 'aria-checked',\n state === 'checked' ? 'true' : state === 'indeterminate' ? 'mixed' : 'false',\n )\n if (this._effectiveRequired()) this.setAttribute('aria-required', 'true')\n else this.removeAttribute('aria-required')\n this.setAttribute('data-state', state)\n if (this._effectiveDisabled()) this.setAttribute('data-disabled', '')\n else this.removeAttribute('data-disabled')\n }),\n attachHiddenInput(this, {\n type: 'checkbox',\n name: this._name[0],\n value: this._value[0],\n // Indeterminate submits as unchecked (native parity).\n checked: () => this._state[0]() === 'checked',\n required: () => this._effectiveRequired(),\n disabled: () => this._effectiveDisabled(),\n }),\n )\n }\n\n disconnectedCallback(): void {\n this.removeEventListener('keydown', this._onKeydown)\n this.removeEventListener('click', this._onClickCapture, true)\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 'checked':\n this._state[1](parseChecked(value))\n break\n case 'disabled':\n this._disabled[1](value !== null)\n break\n case 'required':\n this._required[1](value !== null)\n break\n case 'name':\n this._name[1](value)\n break\n case 'value':\n this._value[1](value ?? 'on')\n break\n // 'default-checked' is read once on connect — never reactive.\n }\n }\n\n private _effectiveDisabled(): boolean {\n if (this._disabled[0]()) return true\n return this._fc ? this._fc.disabled() : false\n }\n\n private _effectiveRequired(): boolean {\n if (this._required[0]()) return true\n return this._fc ? this._fc.required() : false\n }\n\n private _syncFromAttrs(): void {\n this._disabled[1](this.hasAttribute('disabled'))\n this._required[1](this.hasAttribute('required'))\n this._name[1](this.getAttribute('name'))\n this._value[1](this.getAttribute('value') ?? 'on')\n }\n\n private readonly _onKeydown = (ev: KeyboardEvent): void => {\n if (ev.key === 'Enter') {\n // APG/Radix: Enter does NOT activate a checkbox.\n ev.preventDefault()\n return\n }\n if (ev.key === ' ' || ev.key === 'Spacebar') {\n ev.preventDefault() // stop page scroll\n if (this._effectiveDisabled()) return\n this.click()\n }\n }\n\n private readonly _onClickCapture = (ev: Event): void => {\n if (this._effectiveDisabled()) {\n ev.preventDefault()\n ev.stopImmediatePropagation()\n return\n }\n // User-driven toggle: 'mixed' activates to CHECKED (Radix rule).\n const next = this._state[0]() !== 'checked'\n this.setChecked(next)\n this.dispatchEvent(\n new CustomEvent<{ checked: boolean | 'mixed' }>('checked-change', {\n detail: { checked: next },\n bubbles: true,\n composed: true,\n }),\n )\n }\n}\n\n/** Presentational styling hook: mirrors the root's state, hidden from AT. */\nexport class AihuCheckboxIndicator extends HTMLElement {\n private _disposers: Array<() => void> = []\n\n connectedCallback(): void {\n const ctx = injectValue(this, checkboxContext)\n this.setAttribute('aria-hidden', 'true')\n this._disposers.push(\n effect(() => {\n this.setAttribute('data-state', ctx.state())\n if (ctx.disabled()) this.setAttribute('data-disabled', '')\n else this.removeAttribute('data-disabled')\n }),\n )\n }\n\n disconnectedCallback(): void {\n for (const d of this._disposers) d()\n this._disposers = []\n }\n}\n\nconst REGISTRY: Array<[string, CustomElementConstructor]> = [\n ['aihu-checkbox-root', AihuCheckboxRoot],\n ['aihu-checkbox-indicator', AihuCheckboxIndicator],\n]\n\nlet _defined = false\n/** Register all checkbox custom elements (idempotent). */\nexport function defineCheckbox(): void {\n if (_defined) return\n for (const [tag, ctor] of REGISTRY) {\n if (!customElements.get(tag)) customElements.define(tag, ctor)\n }\n _defined = true\n}\n"],"mappings":"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"}
|
|
@@ -240,14 +240,24 @@ const REGISTRY = [
|
|
|
240
240
|
["aihu-dialog-title", AihuDialogTitle],
|
|
241
241
|
["aihu-dialog-description", AihuDialogDescription]
|
|
242
242
|
];
|
|
243
|
-
|
|
244
|
-
/**
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
243
|
+
const _definedPrefixes = /* @__PURE__ */ new Set();
|
|
244
|
+
/**
|
|
245
|
+
* Register all dialog custom elements under `<prefix>-dialog-*` (idempotent
|
|
246
|
+
* per prefix). Non-default prefixes register a fresh trivial subclass per
|
|
247
|
+
* piece — a constructor can only be `customElements.define`d once, so the
|
|
248
|
+
* original classes stay reserved for the default tags. Demos/stories use a
|
|
249
|
+
* non-`aihu` prefix so styled recipes own the `aihu-dialog-*` namespace
|
|
250
|
+
* (spec §9.4).
|
|
251
|
+
*/
|
|
252
|
+
function defineDialog(prefix = "aihu") {
|
|
253
|
+
if (_definedPrefixes.has(prefix)) return;
|
|
254
|
+
for (const [tag, ctor] of REGISTRY) {
|
|
255
|
+
const name = prefix === "aihu" ? tag : tag.replace(/^aihu-/, `${prefix}-`);
|
|
256
|
+
if (!customElements.get(name)) customElements.define(name, prefix === "aihu" ? ctor : class extends ctor {});
|
|
257
|
+
}
|
|
258
|
+
_definedPrefixes.add(prefix);
|
|
249
259
|
}
|
|
250
260
|
//#endregion
|
|
251
261
|
export { AihuDialogRoot as a, defineDialog as c, AihuDialogDescription as i, dialogContext as l, AihuDialogClose as n, AihuDialogTitle as o, AihuDialogContent as r, AihuDialogTrigger as s, AihuDialogBackdrop as t, createFocusTrap as u };
|
|
252
262
|
|
|
253
|
-
//# sourceMappingURL=dialog-
|
|
263
|
+
//# sourceMappingURL=dialog-VDL-W3Vy.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dialog-y7MHc6vf.js","names":[],"sources":["../src/dialog/focus-trap.ts","../src/dialog/index.ts"],"sourcesContent":["/**\n * `createFocusTrap` — a tiny native-DOM focus trap (no library). Queries the\n * focusable descendants of a container, wraps Tab at the edges, moves focus to\n * the first focusable (or the container) on activate, and restores focus to the\n * previously-active element on deactivate. Used by `dialog-content`.\n */\n\nconst FOCUSABLE =\n 'a[href], area[href], button:not([disabled]), input:not([disabled]):not([type=\"hidden\"]), ' +\n 'select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"]), ' +\n '[contenteditable=\"true\"], audio[controls], video[controls], details>summary:first-of-type'\n\nexport interface FocusTrap {\n activate(): void\n deactivate(): void\n}\n\nfunction focusables(container: Element): HTMLElement[] {\n return Array.from(container.querySelectorAll<HTMLElement>(FOCUSABLE)).filter(\n (el) => el.offsetParent !== null || el === document.activeElement || isInJsdom(el),\n )\n}\n\n/** jsdom does not lay out, so `offsetParent` is always null — treat all as visible there. */\nfunction isInJsdom(_el: HTMLElement): boolean {\n return typeof navigator !== 'undefined' && navigator.userAgent.includes('jsdom')\n}\n\nexport function createFocusTrap(container: Element): FocusTrap {\n let previouslyFocused: HTMLElement | null = null\n let active = false\n\n const onKeydown = (ev: KeyboardEvent): void => {\n if (!active || ev.key !== 'Tab') return\n const items = focusables(container)\n const first = items[0]\n const last = items[items.length - 1]\n if (!first || !last) {\n ev.preventDefault()\n return\n }\n const current = (container.getRootNode() as Document | ShadowRoot).activeElement as HTMLElement\n\n if (ev.shiftKey && (current === first || !container.contains(current))) {\n ev.preventDefault()\n last.focus()\n } else if (!ev.shiftKey && (current === last || !container.contains(current))) {\n ev.preventDefault()\n first.focus()\n }\n }\n\n return {\n activate(): void {\n if (active) return\n active = true\n previouslyFocused = document.activeElement as HTMLElement | null\n const items = focusables(container)\n const target = items[0] ?? (container as HTMLElement)\n // Ensure the container itself is focusable as a fallback.\n if (!items.length && !(container as HTMLElement).hasAttribute('tabindex')) {\n ;(container as HTMLElement).setAttribute('tabindex', '-1')\n }\n target.focus()\n document.addEventListener('keydown', onKeydown, true)\n },\n deactivate(): void {\n if (!active) return\n active = false\n document.removeEventListener('keydown', onKeydown, true)\n // Return focus to whatever opened the trap.\n previouslyFocused?.focus?.()\n previouslyFocused = null\n },\n }\n}\n","/**\n * Headless dialog — `<aihu-dialog-root>` (state owner) + pieces\n * `<aihu-dialog-trigger>`, `<aihu-dialog-content>`, `<aihu-dialog-backdrop>`,\n * `<aihu-dialog-close>`, `<aihu-dialog-title>`, `<aihu-dialog-description>`.\n * Implements the WAI-ARIA APG **Dialog (Modal)** pattern: focus-trap +\n * return-focus, Escape-to-close, `role=dialog` / `aria-modal` /\n * `aria-labelledby` / `aria-describedby`, trigger `aria-haspopup` /\n * `aria-expanded` / `aria-controls`. Emits NO CSS — every piece reflects\n * `data-state=\"open\"|\"closed\"` for the consumer to style.\n */\n\nimport { effect, type Read, signal } from '@aihu/signals'\nimport { createDomContext, injectValue, provideContext } from '../dom-context.ts'\nimport { createFocusTrap, type FocusTrap } from './focus-trap.ts'\n\nexport interface DialogContextValue {\n readonly open: Read<boolean>\n readonly modal: Read<boolean>\n readonly contentId: Read<string>\n readonly titleId: Read<string | null>\n readonly descriptionId: Read<string | null>\n setTitleId(id: string): void\n setDescriptionId(id: string): void\n setOpen(next: boolean): void\n close(): void\n toggle(): void\n}\n\nexport const dialogContext = createDomContext<DialogContextValue>('dialog')\n\nlet _idSeq = 0\nconst uid = (p: string): string => `aihu-${p}-${(_idSeq += 1)}`\n\nexport class AihuDialogRoot extends HTMLElement {\n static readonly observedAttributes = ['open', 'modal']\n\n private readonly _open = signal(false)\n private readonly _modal = signal(true)\n private readonly _contentId = signal(uid('dialog'))\n private readonly _titleId = signal<string | null>(null)\n private readonly _descriptionId = signal<string | null>(null)\n private _disposers: Array<() => void> = []\n private _ctx: DialogContextValue\n\n constructor() {\n super()\n this._ctx = {\n open: this._open[0],\n modal: this._modal[0],\n contentId: this._contentId[0],\n titleId: this._titleId[0],\n descriptionId: this._descriptionId[0],\n setTitleId: (id) => this._titleId[1](id),\n setDescriptionId: (id) => this._descriptionId[1](id),\n setOpen: (next) => this.setOpen(next),\n close: () => this.setOpen(false),\n toggle: () => this.setOpen(!this._open[0]()),\n }\n provideContext(this, dialogContext, this._ctx)\n }\n\n get open(): Read<boolean> {\n return this._open[0]\n }\n\n setOpen(next: boolean): void {\n if (next === this._open[0]()) return\n this._open[1](next)\n if (next) this.setAttribute('open', '')\n else this.removeAttribute('open')\n }\n\n connectedCallback(): void {\n if (this.hasAttribute('modal')) this._modal[1](this.getAttribute('modal') !== 'false')\n this._open[1](this.hasAttribute('open'))\n this._disposers.push(\n effect(() => {\n this.setAttribute('data-state', this._open[0]() ? 'open' : 'closed')\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 if (name === 'open') this._open[1](value !== null)\n if (name === 'modal') this._modal[1](value !== 'false')\n }\n}\n\n/** Base for pieces that inject the dialog context lazily on connect. */\nabstract class DialogPiece extends HTMLElement {\n protected ctx!: DialogContextValue\n protected disposers: Array<() => void> = []\n\n connectedCallback(): void {\n this.ctx = injectValue(this, dialogContext)\n this.onConnect()\n }\n\n disconnectedCallback(): void {\n for (const d of this.disposers) d()\n this.disposers = []\n }\n\n protected reflectState(): void {\n this.disposers.push(\n effect(() => {\n this.setAttribute('data-state', this.ctx.open() ? 'open' : 'closed')\n }),\n )\n }\n\n protected abstract onConnect(): void\n}\n\nexport class AihuDialogTrigger extends DialogPiece {\n protected onConnect(): void {\n if (this.tagName !== 'BUTTON') {\n if (!this.hasAttribute('role')) this.setAttribute('role', 'button')\n if (!this.hasAttribute('tabindex')) this.setAttribute('tabindex', '0')\n }\n this.setAttribute('aria-haspopup', 'dialog')\n this.addEventListener('click', this._onClick)\n this.disposers.push(\n effect(() => {\n const open = this.ctx.open()\n this.setAttribute('aria-expanded', String(open))\n this.setAttribute('aria-controls', this.ctx.contentId())\n }),\n )\n this.reflectState()\n }\n\n private readonly _onClick = (): void => {\n this.ctx.toggle()\n }\n}\n\nexport class AihuDialogContent extends DialogPiece {\n private _trap: FocusTrap | null = null\n\n protected onConnect(): void {\n this.setAttribute('role', this.getAttribute('role') ?? 'dialog')\n this.addEventListener('keydown', this._onKeydown)\n this.disposers.push(\n effect(() => {\n const open = this.ctx.open()\n this.id = this.ctx.contentId()\n if (this.ctx.modal()) this.setAttribute('aria-modal', 'true')\n const titleId = this.ctx.titleId()\n if (titleId) this.setAttribute('aria-labelledby', titleId)\n const descId = this.ctx.descriptionId()\n if (descId) this.setAttribute('aria-describedby', descId)\n this.setAttribute('data-state', open ? 'open' : 'closed')\n if (open) this._activateTrap()\n else this._deactivateTrap()\n }),\n )\n }\n\n override disconnectedCallback(): void {\n this._deactivateTrap()\n this.removeEventListener('keydown', this._onKeydown)\n super.disconnectedCallback()\n }\n\n private _activateTrap(): void {\n if (this._trap) return\n this._trap = createFocusTrap(this)\n this._trap.activate()\n }\n\n private _deactivateTrap(): void {\n this._trap?.deactivate()\n this._trap = null\n }\n\n private readonly _onKeydown = (ev: KeyboardEvent): void => {\n if (ev.key === 'Escape' && this.getAttribute('data-dismissable-escape') !== 'false') {\n ev.stopPropagation()\n this.ctx.close()\n }\n }\n}\n\nexport class AihuDialogBackdrop extends DialogPiece {\n protected onConnect(): void {\n this.addEventListener('click', this._onClick)\n this.reflectState()\n }\n\n private readonly _onClick = (): void => {\n if (this.ctx.modal() && this.getAttribute('data-dismissable-outside') !== 'false') {\n this.ctx.close()\n }\n }\n}\n\nexport class AihuDialogClose extends DialogPiece {\n protected onConnect(): void {\n if (this.tagName !== 'BUTTON') {\n if (!this.hasAttribute('role')) this.setAttribute('role', 'button')\n if (!this.hasAttribute('tabindex')) this.setAttribute('tabindex', '0')\n }\n this.addEventListener('click', this._onClick)\n this.reflectState()\n }\n\n private readonly _onClick = (): void => {\n this.ctx.close()\n }\n}\n\nexport class AihuDialogTitle extends DialogPiece {\n protected onConnect(): void {\n if (!this.id) this.id = uid('dialog-title')\n this.ctx.setTitleId(this.id)\n }\n}\n\nexport class AihuDialogDescription extends DialogPiece {\n protected onConnect(): void {\n if (!this.id) this.id = uid('dialog-desc')\n this.ctx.setDescriptionId(this.id)\n }\n}\n\nconst REGISTRY: Array<[string, CustomElementConstructor]> = [\n ['aihu-dialog-root', AihuDialogRoot],\n ['aihu-dialog-trigger', AihuDialogTrigger],\n ['aihu-dialog-content', AihuDialogContent],\n ['aihu-dialog-backdrop', AihuDialogBackdrop],\n ['aihu-dialog-close', AihuDialogClose],\n ['aihu-dialog-title', AihuDialogTitle],\n ['aihu-dialog-description', AihuDialogDescription],\n]\n\nlet _defined = false\n/** Register all dialog custom elements (idempotent). */\nexport function defineDialog(): void {\n if (_defined) return\n for (const [tag, ctor] of REGISTRY) {\n if (!customElements.get(tag)) customElements.define(tag, ctor)\n }\n _defined = true\n}\n\nexport { createFocusTrap, type FocusTrap } from './focus-trap.ts'\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"dialog-VDL-W3Vy.js","names":[],"sources":["../src/dialog/focus-trap.ts","../src/dialog/index.ts"],"sourcesContent":["/**\n * `createFocusTrap` — a tiny native-DOM focus trap (no library). Queries the\n * focusable descendants of a container, wraps Tab at the edges, moves focus to\n * the first focusable (or the container) on activate, and restores focus to the\n * previously-active element on deactivate. Used by `dialog-content`.\n */\n\nconst FOCUSABLE =\n 'a[href], area[href], button:not([disabled]), input:not([disabled]):not([type=\"hidden\"]), ' +\n 'select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"]), ' +\n '[contenteditable=\"true\"], audio[controls], video[controls], details>summary:first-of-type'\n\nexport interface FocusTrap {\n activate(): void\n deactivate(): void\n}\n\nfunction focusables(container: Element): HTMLElement[] {\n return Array.from(container.querySelectorAll<HTMLElement>(FOCUSABLE)).filter(\n (el) => el.offsetParent !== null || el === document.activeElement || isInJsdom(el),\n )\n}\n\n/** jsdom does not lay out, so `offsetParent` is always null — treat all as visible there. */\nfunction isInJsdom(_el: HTMLElement): boolean {\n return typeof navigator !== 'undefined' && navigator.userAgent.includes('jsdom')\n}\n\nexport function createFocusTrap(container: Element): FocusTrap {\n let previouslyFocused: HTMLElement | null = null\n let active = false\n\n const onKeydown = (ev: KeyboardEvent): void => {\n if (!active || ev.key !== 'Tab') return\n const items = focusables(container)\n const first = items[0]\n const last = items[items.length - 1]\n if (!first || !last) {\n ev.preventDefault()\n return\n }\n const current = (container.getRootNode() as Document | ShadowRoot).activeElement as HTMLElement\n\n if (ev.shiftKey && (current === first || !container.contains(current))) {\n ev.preventDefault()\n last.focus()\n } else if (!ev.shiftKey && (current === last || !container.contains(current))) {\n ev.preventDefault()\n first.focus()\n }\n }\n\n return {\n activate(): void {\n if (active) return\n active = true\n previouslyFocused = document.activeElement as HTMLElement | null\n const items = focusables(container)\n const target = items[0] ?? (container as HTMLElement)\n // Ensure the container itself is focusable as a fallback.\n if (!items.length && !(container as HTMLElement).hasAttribute('tabindex')) {\n ;(container as HTMLElement).setAttribute('tabindex', '-1')\n }\n target.focus()\n document.addEventListener('keydown', onKeydown, true)\n },\n deactivate(): void {\n if (!active) return\n active = false\n document.removeEventListener('keydown', onKeydown, true)\n // Return focus to whatever opened the trap.\n previouslyFocused?.focus?.()\n previouslyFocused = null\n },\n }\n}\n","/**\n * Headless dialog — `<aihu-dialog-root>` (state owner) + pieces\n * `<aihu-dialog-trigger>`, `<aihu-dialog-content>`, `<aihu-dialog-backdrop>`,\n * `<aihu-dialog-close>`, `<aihu-dialog-title>`, `<aihu-dialog-description>`.\n * Implements the WAI-ARIA APG **Dialog (Modal)** pattern: focus-trap +\n * return-focus, Escape-to-close, `role=dialog` / `aria-modal` /\n * `aria-labelledby` / `aria-describedby`, trigger `aria-haspopup` /\n * `aria-expanded` / `aria-controls`. Emits NO CSS — every piece reflects\n * `data-state=\"open\"|\"closed\"` for the consumer to style.\n */\n\nimport { effect, type Read, signal } from '@aihu/signals'\nimport { createDomContext, injectValue, provideContext } from '../dom-context.ts'\nimport { createFocusTrap, type FocusTrap } from './focus-trap.ts'\n\nexport interface DialogContextValue {\n readonly open: Read<boolean>\n readonly modal: Read<boolean>\n readonly contentId: Read<string>\n readonly titleId: Read<string | null>\n readonly descriptionId: Read<string | null>\n setTitleId(id: string): void\n setDescriptionId(id: string): void\n setOpen(next: boolean): void\n close(): void\n toggle(): void\n}\n\nexport const dialogContext = createDomContext<DialogContextValue>('dialog')\n\nlet _idSeq = 0\nconst uid = (p: string): string => `aihu-${p}-${(_idSeq += 1)}`\n\nexport class AihuDialogRoot extends HTMLElement {\n static readonly observedAttributes = ['open', 'modal']\n\n private readonly _open = signal(false)\n private readonly _modal = signal(true)\n private readonly _contentId = signal(uid('dialog'))\n private readonly _titleId = signal<string | null>(null)\n private readonly _descriptionId = signal<string | null>(null)\n private _disposers: Array<() => void> = []\n private _ctx: DialogContextValue\n\n constructor() {\n super()\n this._ctx = {\n open: this._open[0],\n modal: this._modal[0],\n contentId: this._contentId[0],\n titleId: this._titleId[0],\n descriptionId: this._descriptionId[0],\n setTitleId: (id) => this._titleId[1](id),\n setDescriptionId: (id) => this._descriptionId[1](id),\n setOpen: (next) => this.setOpen(next),\n close: () => this.setOpen(false),\n toggle: () => this.setOpen(!this._open[0]()),\n }\n provideContext(this, dialogContext, this._ctx)\n }\n\n get open(): Read<boolean> {\n return this._open[0]\n }\n\n setOpen(next: boolean): void {\n if (next === this._open[0]()) return\n this._open[1](next)\n if (next) this.setAttribute('open', '')\n else this.removeAttribute('open')\n }\n\n connectedCallback(): void {\n if (this.hasAttribute('modal')) this._modal[1](this.getAttribute('modal') !== 'false')\n this._open[1](this.hasAttribute('open'))\n this._disposers.push(\n effect(() => {\n this.setAttribute('data-state', this._open[0]() ? 'open' : 'closed')\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 if (name === 'open') this._open[1](value !== null)\n if (name === 'modal') this._modal[1](value !== 'false')\n }\n}\n\n/** Base for pieces that inject the dialog context lazily on connect. */\nabstract class DialogPiece extends HTMLElement {\n protected ctx!: DialogContextValue\n protected disposers: Array<() => void> = []\n\n connectedCallback(): void {\n this.ctx = injectValue(this, dialogContext)\n this.onConnect()\n }\n\n disconnectedCallback(): void {\n for (const d of this.disposers) d()\n this.disposers = []\n }\n\n protected reflectState(): void {\n this.disposers.push(\n effect(() => {\n this.setAttribute('data-state', this.ctx.open() ? 'open' : 'closed')\n }),\n )\n }\n\n protected abstract onConnect(): void\n}\n\nexport class AihuDialogTrigger extends DialogPiece {\n protected onConnect(): void {\n if (this.tagName !== 'BUTTON') {\n if (!this.hasAttribute('role')) this.setAttribute('role', 'button')\n if (!this.hasAttribute('tabindex')) this.setAttribute('tabindex', '0')\n }\n this.setAttribute('aria-haspopup', 'dialog')\n this.addEventListener('click', this._onClick)\n this.disposers.push(\n effect(() => {\n const open = this.ctx.open()\n this.setAttribute('aria-expanded', String(open))\n this.setAttribute('aria-controls', this.ctx.contentId())\n }),\n )\n this.reflectState()\n }\n\n private readonly _onClick = (): void => {\n this.ctx.toggle()\n }\n}\n\nexport class AihuDialogContent extends DialogPiece {\n private _trap: FocusTrap | null = null\n\n protected onConnect(): void {\n this.setAttribute('role', this.getAttribute('role') ?? 'dialog')\n this.addEventListener('keydown', this._onKeydown)\n this.disposers.push(\n effect(() => {\n const open = this.ctx.open()\n this.id = this.ctx.contentId()\n if (this.ctx.modal()) this.setAttribute('aria-modal', 'true')\n const titleId = this.ctx.titleId()\n if (titleId) this.setAttribute('aria-labelledby', titleId)\n const descId = this.ctx.descriptionId()\n if (descId) this.setAttribute('aria-describedby', descId)\n this.setAttribute('data-state', open ? 'open' : 'closed')\n if (open) this._activateTrap()\n else this._deactivateTrap()\n }),\n )\n }\n\n override disconnectedCallback(): void {\n this._deactivateTrap()\n this.removeEventListener('keydown', this._onKeydown)\n super.disconnectedCallback()\n }\n\n private _activateTrap(): void {\n if (this._trap) return\n this._trap = createFocusTrap(this)\n this._trap.activate()\n }\n\n private _deactivateTrap(): void {\n this._trap?.deactivate()\n this._trap = null\n }\n\n private readonly _onKeydown = (ev: KeyboardEvent): void => {\n if (ev.key === 'Escape' && this.getAttribute('data-dismissable-escape') !== 'false') {\n ev.stopPropagation()\n this.ctx.close()\n }\n }\n}\n\nexport class AihuDialogBackdrop extends DialogPiece {\n protected onConnect(): void {\n this.addEventListener('click', this._onClick)\n this.reflectState()\n }\n\n private readonly _onClick = (): void => {\n if (this.ctx.modal() && this.getAttribute('data-dismissable-outside') !== 'false') {\n this.ctx.close()\n }\n }\n}\n\nexport class AihuDialogClose extends DialogPiece {\n protected onConnect(): void {\n if (this.tagName !== 'BUTTON') {\n if (!this.hasAttribute('role')) this.setAttribute('role', 'button')\n if (!this.hasAttribute('tabindex')) this.setAttribute('tabindex', '0')\n }\n this.addEventListener('click', this._onClick)\n this.reflectState()\n }\n\n private readonly _onClick = (): void => {\n this.ctx.close()\n }\n}\n\nexport class AihuDialogTitle extends DialogPiece {\n protected onConnect(): void {\n if (!this.id) this.id = uid('dialog-title')\n this.ctx.setTitleId(this.id)\n }\n}\n\nexport class AihuDialogDescription extends DialogPiece {\n protected onConnect(): void {\n if (!this.id) this.id = uid('dialog-desc')\n this.ctx.setDescriptionId(this.id)\n }\n}\n\nconst REGISTRY: Array<[string, CustomElementConstructor]> = [\n ['aihu-dialog-root', AihuDialogRoot],\n ['aihu-dialog-trigger', AihuDialogTrigger],\n ['aihu-dialog-content', AihuDialogContent],\n ['aihu-dialog-backdrop', AihuDialogBackdrop],\n ['aihu-dialog-close', AihuDialogClose],\n ['aihu-dialog-title', AihuDialogTitle],\n ['aihu-dialog-description', AihuDialogDescription],\n]\n\nconst _definedPrefixes = new Set<string>()\n/**\n * Register all dialog custom elements under `<prefix>-dialog-*` (idempotent\n * per prefix). Non-default prefixes register a fresh trivial subclass per\n * piece — a constructor can only be `customElements.define`d once, so the\n * original classes stay reserved for the default tags. Demos/stories use a\n * non-`aihu` prefix so styled recipes own the `aihu-dialog-*` namespace\n * (spec §9.4).\n */\nexport function defineDialog(prefix = 'aihu'): void {\n if (_definedPrefixes.has(prefix)) return\n for (const [tag, ctor] of REGISTRY) {\n const name = prefix === 'aihu' ? tag : tag.replace(/^aihu-/, `${prefix}-`)\n if (!customElements.get(name)) {\n customElements.define(name, prefix === 'aihu' ? ctor : class extends ctor {})\n }\n }\n _definedPrefixes.add(prefix)\n}\n\nexport { createFocusTrap, type FocusTrap } from './focus-trap.ts'\n"],"mappings":";;;;;;;;;AAOA,MAAM,YACJ;AASF,SAAS,WAAW,WAAmC;CACrD,OAAO,MAAM,KAAK,UAAU,iBAA8B,UAAU,CAAC,CAAC,QACnE,OAAO,GAAG,iBAAiB,QAAQ,OAAO,SAAS,iBAAiB,UAAU,GAAG,CACnF;;;AAIH,SAAS,UAAU,KAA2B;CAC5C,OAAO,OAAO,cAAc,eAAe,UAAU,UAAU,SAAS,QAAQ;;AAGlF,SAAgB,gBAAgB,WAA+B;CAC7D,IAAI,oBAAwC;CAC5C,IAAI,SAAS;CAEb,MAAM,aAAa,OAA4B;EAC7C,IAAI,CAAC,UAAU,GAAG,QAAQ,OAAO;EACjC,MAAM,QAAQ,WAAW,UAAU;EACnC,MAAM,QAAQ,MAAM;EACpB,MAAM,OAAO,MAAM,MAAM,SAAS;EAClC,IAAI,CAAC,SAAS,CAAC,MAAM;GACnB,GAAG,gBAAgB;GACnB;;EAEF,MAAM,UAAW,UAAU,aAAa,CAA2B;EAEnE,IAAI,GAAG,aAAa,YAAY,SAAS,CAAC,UAAU,SAAS,QAAQ,GAAG;GACtE,GAAG,gBAAgB;GACnB,KAAK,OAAO;SACP,IAAI,CAAC,GAAG,aAAa,YAAY,QAAQ,CAAC,UAAU,SAAS,QAAQ,GAAG;GAC7E,GAAG,gBAAgB;GACnB,MAAM,OAAO;;;CAIjB,OAAO;EACL,WAAiB;GACf,IAAI,QAAQ;GACZ,SAAS;GACT,oBAAoB,SAAS;GAC7B,MAAM,QAAQ,WAAW,UAAU;GACnC,MAAM,SAAS,MAAM,MAAO;GAE5B,IAAI,CAAC,MAAM,UAAU,CAAE,UAA0B,aAAa,WAAW,EACtE,UAA2B,aAAa,YAAY,KAAK;GAE5D,OAAO,OAAO;GACd,SAAS,iBAAiB,WAAW,WAAW,KAAK;;EAEvD,aAAmB;GACjB,IAAI,CAAC,QAAQ;GACb,SAAS;GACT,SAAS,oBAAoB,WAAW,WAAW,KAAK;GAExD,mBAAmB,SAAS;GAC5B,oBAAoB;;EAEvB;;;;;;;;;;;;;;AC9CH,MAAa,gBAAgB,iBAAqC,SAAS;AAE3E,IAAI,SAAS;AACb,MAAM,OAAO,MAAsB,QAAQ,EAAE,GAAI,UAAU;AAE3D,IAAa,iBAAb,cAAoC,YAAY;CAC9C,OAAgB,qBAAqB,CAAC,QAAQ,QAAQ;CAEtD,QAAyB,OAAO,MAAM;CACtC,SAA0B,OAAO,KAAK;CACtC,aAA8B,OAAO,IAAI,SAAS,CAAC;CACnD,WAA4B,OAAsB,KAAK;CACvD,iBAAkC,OAAsB,KAAK;CAC7D,aAAwC,EAAE;CAC1C;CAEA,cAAc;EACZ,OAAO;EACP,KAAK,OAAO;GACV,MAAM,KAAK,MAAM;GACjB,OAAO,KAAK,OAAO;GACnB,WAAW,KAAK,WAAW;GAC3B,SAAS,KAAK,SAAS;GACvB,eAAe,KAAK,eAAe;GACnC,aAAa,OAAO,KAAK,SAAS,GAAG,GAAG;GACxC,mBAAmB,OAAO,KAAK,eAAe,GAAG,GAAG;GACpD,UAAU,SAAS,KAAK,QAAQ,KAAK;GACrC,aAAa,KAAK,QAAQ,MAAM;GAChC,cAAc,KAAK,QAAQ,CAAC,KAAK,MAAM,IAAI,CAAC;GAC7C;EACD,eAAe,MAAM,eAAe,KAAK,KAAK;;CAGhD,IAAI,OAAsB;EACxB,OAAO,KAAK,MAAM;;CAGpB,QAAQ,MAAqB;EAC3B,IAAI,SAAS,KAAK,MAAM,IAAI,EAAE;EAC9B,KAAK,MAAM,GAAG,KAAK;EACnB,IAAI,MAAM,KAAK,aAAa,QAAQ,GAAG;OAClC,KAAK,gBAAgB,OAAO;;CAGnC,oBAA0B;EACxB,IAAI,KAAK,aAAa,QAAQ,EAAE,KAAK,OAAO,GAAG,KAAK,aAAa,QAAQ,KAAK,QAAQ;EACtF,KAAK,MAAM,GAAG,KAAK,aAAa,OAAO,CAAC;EACxC,KAAK,WAAW,KACd,aAAa;GACX,KAAK,aAAa,cAAc,KAAK,MAAM,IAAI,GAAG,SAAS,SAAS;IACpE,CACH;;CAGH,uBAA6B;EAC3B,KAAK,MAAM,KAAK,KAAK,YAAY,GAAG;EACpC,KAAK,aAAa,EAAE;;CAGtB,yBAAyB,MAAc,MAAqB,OAA4B;EACtF,IAAI,SAAS,QAAQ,KAAK,MAAM,GAAG,UAAU,KAAK;EAClD,IAAI,SAAS,SAAS,KAAK,OAAO,GAAG,UAAU,QAAQ;;;;AAK3D,IAAe,cAAf,cAAmC,YAAY;CAC7C;CACA,YAAyC,EAAE;CAE3C,oBAA0B;EACxB,KAAK,MAAM,YAAY,MAAM,cAAc;EAC3C,KAAK,WAAW;;CAGlB,uBAA6B;EAC3B,KAAK,MAAM,KAAK,KAAK,WAAW,GAAG;EACnC,KAAK,YAAY,EAAE;;CAGrB,eAA+B;EAC7B,KAAK,UAAU,KACb,aAAa;GACX,KAAK,aAAa,cAAc,KAAK,IAAI,MAAM,GAAG,SAAS,SAAS;IACpE,CACH;;;AAML,IAAa,oBAAb,cAAuC,YAAY;CACjD,YAA4B;EAC1B,IAAI,KAAK,YAAY,UAAU;GAC7B,IAAI,CAAC,KAAK,aAAa,OAAO,EAAE,KAAK,aAAa,QAAQ,SAAS;GACnE,IAAI,CAAC,KAAK,aAAa,WAAW,EAAE,KAAK,aAAa,YAAY,IAAI;;EAExE,KAAK,aAAa,iBAAiB,SAAS;EAC5C,KAAK,iBAAiB,SAAS,KAAK,SAAS;EAC7C,KAAK,UAAU,KACb,aAAa;GACX,MAAM,OAAO,KAAK,IAAI,MAAM;GAC5B,KAAK,aAAa,iBAAiB,OAAO,KAAK,CAAC;GAChD,KAAK,aAAa,iBAAiB,KAAK,IAAI,WAAW,CAAC;IACxD,CACH;EACD,KAAK,cAAc;;CAGrB,iBAAwC;EACtC,KAAK,IAAI,QAAQ;;;AAIrB,IAAa,oBAAb,cAAuC,YAAY;CACjD,QAAkC;CAElC,YAA4B;EAC1B,KAAK,aAAa,QAAQ,KAAK,aAAa,OAAO,IAAI,SAAS;EAChE,KAAK,iBAAiB,WAAW,KAAK,WAAW;EACjD,KAAK,UAAU,KACb,aAAa;GACX,MAAM,OAAO,KAAK,IAAI,MAAM;GAC5B,KAAK,KAAK,KAAK,IAAI,WAAW;GAC9B,IAAI,KAAK,IAAI,OAAO,EAAE,KAAK,aAAa,cAAc,OAAO;GAC7D,MAAM,UAAU,KAAK,IAAI,SAAS;GAClC,IAAI,SAAS,KAAK,aAAa,mBAAmB,QAAQ;GAC1D,MAAM,SAAS,KAAK,IAAI,eAAe;GACvC,IAAI,QAAQ,KAAK,aAAa,oBAAoB,OAAO;GACzD,KAAK,aAAa,cAAc,OAAO,SAAS,SAAS;GACzD,IAAI,MAAM,KAAK,eAAe;QACzB,KAAK,iBAAiB;IAC3B,CACH;;CAGH,uBAAsC;EACpC,KAAK,iBAAiB;EACtB,KAAK,oBAAoB,WAAW,KAAK,WAAW;EACpD,MAAM,sBAAsB;;CAG9B,gBAA8B;EAC5B,IAAI,KAAK,OAAO;EAChB,KAAK,QAAQ,gBAAgB,KAAK;EAClC,KAAK,MAAM,UAAU;;CAGvB,kBAAgC;EAC9B,KAAK,OAAO,YAAY;EACxB,KAAK,QAAQ;;CAGf,cAA+B,OAA4B;EACzD,IAAI,GAAG,QAAQ,YAAY,KAAK,aAAa,0BAA0B,KAAK,SAAS;GACnF,GAAG,iBAAiB;GACpB,KAAK,IAAI,OAAO;;;;AAKtB,IAAa,qBAAb,cAAwC,YAAY;CAClD,YAA4B;EAC1B,KAAK,iBAAiB,SAAS,KAAK,SAAS;EAC7C,KAAK,cAAc;;CAGrB,iBAAwC;EACtC,IAAI,KAAK,IAAI,OAAO,IAAI,KAAK,aAAa,2BAA2B,KAAK,SACxE,KAAK,IAAI,OAAO;;;AAKtB,IAAa,kBAAb,cAAqC,YAAY;CAC/C,YAA4B;EAC1B,IAAI,KAAK,YAAY,UAAU;GAC7B,IAAI,CAAC,KAAK,aAAa,OAAO,EAAE,KAAK,aAAa,QAAQ,SAAS;GACnE,IAAI,CAAC,KAAK,aAAa,WAAW,EAAE,KAAK,aAAa,YAAY,IAAI;;EAExE,KAAK,iBAAiB,SAAS,KAAK,SAAS;EAC7C,KAAK,cAAc;;CAGrB,iBAAwC;EACtC,KAAK,IAAI,OAAO;;;AAIpB,IAAa,kBAAb,cAAqC,YAAY;CAC/C,YAA4B;EAC1B,IAAI,CAAC,KAAK,IAAI,KAAK,KAAK,IAAI,eAAe;EAC3C,KAAK,IAAI,WAAW,KAAK,GAAG;;;AAIhC,IAAa,wBAAb,cAA2C,YAAY;CACrD,YAA4B;EAC1B,IAAI,CAAC,KAAK,IAAI,KAAK,KAAK,IAAI,cAAc;EAC1C,KAAK,IAAI,iBAAiB,KAAK,GAAG;;;AAItC,MAAM,WAAsD;CAC1D,CAAC,oBAAoB,eAAe;CACpC,CAAC,uBAAuB,kBAAkB;CAC1C,CAAC,uBAAuB,kBAAkB;CAC1C,CAAC,wBAAwB,mBAAmB;CAC5C,CAAC,qBAAqB,gBAAgB;CACtC,CAAC,qBAAqB,gBAAgB;CACtC,CAAC,2BAA2B,sBAAsB;CACnD;AAED,MAAM,mCAAmB,IAAI,KAAa;;;;;;;;;AAS1C,SAAgB,aAAa,SAAS,QAAc;CAClD,IAAI,iBAAiB,IAAI,OAAO,EAAE;CAClC,KAAK,MAAM,CAAC,KAAK,SAAS,UAAU;EAClC,MAAM,OAAO,WAAW,SAAS,MAAM,IAAI,QAAQ,UAAU,GAAG,OAAO,GAAG;EAC1E,IAAI,CAAC,eAAe,IAAI,KAAK,EAC3B,eAAe,OAAO,MAAM,WAAW,SAAS,OAAO,cAAc,KAAK,GAAG;;CAGjF,iBAAiB,IAAI,OAAO"}
|
package/dist/dialog.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as AihuDialogRoot, c as DialogContextValue, d as FocusTrap, f as createFocusTrap, i as AihuDialogDescription, l as defineDialog, n as AihuDialogClose, o as AihuDialogTitle, r as AihuDialogContent, s as AihuDialogTrigger, t as AihuDialogBackdrop, u as dialogContext } from "./index-
|
|
1
|
+
import { a as AihuDialogRoot, c as DialogContextValue, d as FocusTrap, f as createFocusTrap, i as AihuDialogDescription, l as defineDialog, n as AihuDialogClose, o as AihuDialogTitle, r as AihuDialogContent, s as AihuDialogTrigger, t as AihuDialogBackdrop, u as dialogContext } from "./index-D7hJLfnb.js";
|
|
2
2
|
export { AihuDialogBackdrop, AihuDialogClose, AihuDialogContent, AihuDialogDescription, AihuDialogRoot, AihuDialogTitle, AihuDialogTrigger, DialogContextValue, FocusTrap, createFocusTrap, defineDialog, dialogContext };
|
package/dist/dialog.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as AihuDialogRoot, c as defineDialog, i as AihuDialogDescription, l as dialogContext, n as AihuDialogClose, o as AihuDialogTitle, r as AihuDialogContent, s as AihuDialogTrigger, t as AihuDialogBackdrop, u as createFocusTrap } from "./dialog-
|
|
1
|
+
import { a as AihuDialogRoot, c as defineDialog, i as AihuDialogDescription, l as dialogContext, n as AihuDialogClose, o as AihuDialogTitle, r as AihuDialogContent, s as AihuDialogTrigger, t as AihuDialogBackdrop, u as createFocusTrap } from "./dialog-VDL-W3Vy.js";
|
|
2
2
|
export { AihuDialogBackdrop, AihuDialogClose, AihuDialogContent, AihuDialogDescription, AihuDialogRoot, AihuDialogTitle, AihuDialogTrigger, createFocusTrap, defineDialog, dialogContext };
|