@antadesign/anta 0.3.5 → 0.3.7

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.
Files changed (43) hide show
  1. package/dist/anta_helpers.d.ts +10 -0
  2. package/dist/anta_helpers.js +8 -0
  3. package/dist/components/Card.d.ts +86 -0
  4. package/dist/components/Card.js +72 -0
  5. package/dist/components/Dialog.d.ts +92 -0
  6. package/dist/components/Dialog.js +71 -0
  7. package/dist/components/Input.d.ts +3 -0
  8. package/dist/components/InputAutocomplete.d.ts +69 -0
  9. package/dist/components/InputAutocomplete.js +95 -0
  10. package/dist/components/InputDate.js +1 -2
  11. package/dist/components/Menu.d.ts +4 -1
  12. package/dist/components/Menu.js +2 -1
  13. package/dist/components/MenuItem.d.ts +9 -1
  14. package/dist/components/MenuItem.js +2 -1
  15. package/dist/components/Select.d.ts +5 -2
  16. package/dist/components/Select.js +11 -34
  17. package/dist/components/SelectFaceted.d.ts +7 -1
  18. package/dist/components/SelectFaceted.js +12 -11
  19. package/dist/components/select-options.d.ts +14 -0
  20. package/dist/components/select-options.js +31 -0
  21. package/dist/elements/a-card.css +211 -0
  22. package/dist/elements/a-card.d.ts +10 -0
  23. package/dist/elements/a-card.js +213 -0
  24. package/dist/elements/a-checkbox.css +1 -1
  25. package/dist/elements/a-dialog.css +1 -0
  26. package/dist/elements/a-dialog.d.ts +26 -0
  27. package/dist/elements/a-dialog.js +386 -0
  28. package/dist/elements/a-expander.js +2 -2
  29. package/dist/elements/a-input-time.js +2 -1
  30. package/dist/elements/a-input.d.ts +2 -0
  31. package/dist/elements/a-input.js +34 -1
  32. package/dist/elements/a-menu.d.ts +5 -2
  33. package/dist/elements/a-menu.js +52 -15
  34. package/dist/elements/a-radio.css +1 -1
  35. package/dist/elements/a-tooltip.d.ts +17 -0
  36. package/dist/elements/a-tooltip.js +28 -0
  37. package/dist/elements/index.d.ts +1 -0
  38. package/dist/elements/index.js +3 -0
  39. package/dist/general_types.d.ts +45 -0
  40. package/dist/index.d.ts +4 -0
  41. package/dist/index.js +4 -0
  42. package/dist/jsx-runtime.d.ts +2 -1
  43. package/package.json +1 -1
@@ -0,0 +1,213 @@
1
+ import { HTMLElementBase } from "../anta_helpers";
2
+ import "./a-card.css";
3
+ const SHADOW_STYLE = `
4
+ .container {
5
+ display: flex;
6
+ flex-direction: column;
7
+ box-sizing: border-box;
8
+ width: 100%;
9
+ height: 100%;
10
+ min-width: 0;
11
+ color: inherit;
12
+ text-decoration: none;
13
+ cursor: default;
14
+ border-radius: var(--card-radius, 8px);
15
+ -webkit-user-drag: none;
16
+ }
17
+ :host([media-position="bottom"]) .container { flex-direction: column-reverse; }
18
+ :host([media-position="left"]) .container { flex-direction: row; }
19
+ :host([media-position="right"]) .container { flex-direction: row-reverse; }
20
+
21
+ :host([href]) .container { user-select: none; }
22
+ :host([href]:not([loading])) .container { cursor: pointer; }
23
+
24
+ .container:focus-visible {
25
+ outline: none;
26
+ box-shadow: inset 0 0 0 1px transparent, inset 0 0 0 2px var(--focus-ring);
27
+ }
28
+
29
+ [part="media"] { display: none; }
30
+ [part="media"].has-content { display: block; }
31
+ :host([media-position="left"]) [part="media"].has-content,
32
+ :host([media-position="right"]) [part="media"].has-content { flex: none; }
33
+
34
+ .content {
35
+ display: flex;
36
+ flex-direction: column;
37
+ flex: 1 1 auto;
38
+ min-width: 0;
39
+ min-height: 0;
40
+ padding: var(--card-padding, 16px);
41
+ }
42
+
43
+ .header-row { display: none; }
44
+ .header-row.has-content {
45
+ display: flex;
46
+ align-items: flex-start;
47
+ gap: 8px;
48
+ }
49
+
50
+ slot[name="header"] { display: none; }
51
+ slot[name="header"].has-content {
52
+ display: block;
53
+ flex: 1 1 auto;
54
+ min-width: 0;
55
+ font-size: 17px;
56
+ line-height: 20px;
57
+ font-weight: 584.62;
58
+ letter-spacing: 0;
59
+ font-feature-settings: 'ss02', 'ss05', 'tnum';
60
+ color: var(--card-title, var(--text-1));
61
+ }
62
+
63
+ slot[name="actions"] { display: none; }
64
+ slot[name="actions"].has-content {
65
+ display: flex;
66
+ align-items: center;
67
+ gap: 4px;
68
+ flex: none;
69
+ }
70
+
71
+ slot[part="body"] {
72
+ display: block;
73
+ flex: 1 1 auto;
74
+ min-width: 0;
75
+ min-height: 0;
76
+ font-size: 15px;
77
+ line-height: 20px;
78
+ color: var(--card-text, var(--text-2));
79
+ }
80
+
81
+ slot[name="footer"] { display: none; }
82
+ slot[name="footer"].has-content {
83
+ display: flex;
84
+ align-items: center;
85
+ gap: 8px;
86
+ flex-wrap: wrap;
87
+ justify-content: flex-start;
88
+ padding-block-start: var(--card-padding, 16px);
89
+ }
90
+
91
+ :host([selected]) .container { box-shadow: inset 0 0 0 2px var(--card-selected-ring, var(--focus-ring)); }
92
+ :host([selected]) .container:focus-visible { box-shadow: inset 0 0 0 1px transparent, inset 0 0 0 2px var(--focus-ring); }
93
+
94
+ :host([loading]) .container { pointer-events: none; }
95
+ @media (prefers-reduced-motion: no-preference) {
96
+ :host([loading]) [part="content"] { animation: card-pulse 1.4s ease-in-out infinite; }
97
+ }
98
+ @keyframes card-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.55; } }
99
+ `;
100
+ class ACardElement extends HTMLElementBase {
101
+ static observedAttributes = ["href", "target", "rel", "ping", "loading", "aria-label"];
102
+ #container;
103
+ #mediaSlot;
104
+ #headerRow;
105
+ #headerSlot;
106
+ #actionsSlot;
107
+ #bodySlot;
108
+ #footerSlot;
109
+ constructor() {
110
+ super();
111
+ const shadow = this.attachShadow({ mode: "open" });
112
+ const style = document.createElement("style");
113
+ style.textContent = SHADOW_STYLE;
114
+ this.#container = document.createElement("a");
115
+ this.#container.className = "container";
116
+ this.#container.setAttribute("part", "container");
117
+ this.#mediaSlot = document.createElement("slot");
118
+ this.#mediaSlot.name = "media";
119
+ this.#mediaSlot.setAttribute("part", "media");
120
+ const content = document.createElement("div");
121
+ content.className = "content";
122
+ content.setAttribute("part", "content");
123
+ this.#headerRow = document.createElement("div");
124
+ this.#headerRow.className = "header-row";
125
+ this.#headerSlot = document.createElement("slot");
126
+ this.#headerSlot.name = "header";
127
+ this.#headerSlot.setAttribute("part", "header");
128
+ this.#actionsSlot = document.createElement("slot");
129
+ this.#actionsSlot.name = "actions";
130
+ this.#actionsSlot.setAttribute("part", "actions");
131
+ this.#bodySlot = document.createElement("slot");
132
+ this.#bodySlot.setAttribute("part", "body");
133
+ this.#footerSlot = document.createElement("slot");
134
+ this.#footerSlot.name = "footer";
135
+ this.#footerSlot.setAttribute("part", "footer");
136
+ this.#headerRow.append(this.#headerSlot, this.#actionsSlot);
137
+ content.append(this.#headerRow, this.#bodySlot, this.#footerSlot);
138
+ this.#container.append(this.#mediaSlot, content);
139
+ shadow.append(style, this.#container);
140
+ this.#mediaSlot.addEventListener("slotchange", () => this.#syncHasContent());
141
+ this.#footerSlot.addEventListener("slotchange", () => this.#syncHasContent());
142
+ this.#actionsSlot.addEventListener("slotchange", () => this.#syncHasContent());
143
+ this.#headerSlot.addEventListener("slotchange", () => {
144
+ this.#syncHasContent();
145
+ this.#syncName();
146
+ });
147
+ this.#bodySlot.addEventListener("slotchange", () => this.#syncName());
148
+ }
149
+ connectedCallback() {
150
+ this.#syncHasContent();
151
+ this.#syncLink();
152
+ }
153
+ attributeChangedCallback() {
154
+ this.#syncLink();
155
+ }
156
+ /** Toggle the per-zone `has-content` classes (empty zones reserve no box). */
157
+ #syncHasContent() {
158
+ const set = (el, has) => el.classList.toggle("has-content", has);
159
+ set(this.#mediaSlot, this.#mediaSlot.assignedNodes().length > 0);
160
+ set(this.#footerSlot, this.#footerSlot.assignedNodes().length > 0);
161
+ const header = this.#headerSlot.assignedNodes().length > 0;
162
+ const actions = this.#actionsSlot.assignedNodes().length > 0;
163
+ set(this.#headerSlot, header);
164
+ set(this.#actionsSlot, actions);
165
+ set(this.#headerRow, header || actions);
166
+ }
167
+ /** Mirror the link attributes onto the shadow anchor — but drop `href` while
168
+ * `loading` so a loading card can't navigate. Also reflects `aria-busy`. */
169
+ #syncLink() {
170
+ const href = this.getAttribute("href");
171
+ const loading = this.hasAttribute("loading");
172
+ if (href != null && !loading) {
173
+ this.#container.setAttribute("href", href);
174
+ for (const name of ["target", "rel", "ping"]) {
175
+ const v = this.getAttribute(name);
176
+ if (v != null) this.#container.setAttribute(name, v);
177
+ else this.#container.removeAttribute(name);
178
+ }
179
+ } else {
180
+ for (const name of ["href", "target", "rel", "ping"]) {
181
+ this.#container.removeAttribute(name);
182
+ }
183
+ }
184
+ if (loading) this.#container.setAttribute("aria-busy", "true");
185
+ else this.#container.removeAttribute("aria-busy");
186
+ this.#syncName();
187
+ }
188
+ /** Name the anchor (link mode only): explicit aria-label → header → body → href. */
189
+ #syncName() {
190
+ if (!this.#container.hasAttribute("href")) {
191
+ this.#container.removeAttribute("aria-label");
192
+ return;
193
+ }
194
+ const explicit = this.getAttribute("aria-label")?.trim();
195
+ const name = explicit || this.#slotText(this.#headerSlot) || this.#slotText(this.#bodySlot) || this.getAttribute("href") || "";
196
+ if (name) this.#container.setAttribute("aria-label", name);
197
+ else this.#container.removeAttribute("aria-label");
198
+ }
199
+ #slotText(slot) {
200
+ return slot.assignedNodes().map((n) => n.textContent ?? "").join(" ").replace(/\s+/g, " ").trim();
201
+ }
202
+ }
203
+ function register_a_card() {
204
+ if (typeof customElements === "undefined") return;
205
+ if (!customElements.get("a-card")) {
206
+ customElements.define("a-card", ACardElement);
207
+ }
208
+ }
209
+ register_a_card();
210
+ export {
211
+ ACardElement,
212
+ register_a_card
213
+ };
@@ -1 +1 @@
1
- @layer anta{a-checkbox{--checkbox-gap: 8px;--checkbox-box-size: 16px;--checkbox-bg: var(--bg-1);--checkbox-fill: #878089;--checkbox-fill-hover: #776e77;--checkbox-fill-active: #635b65;--checkbox-border-neutral: #d4ced4;--checkbox-border: var(--checkbox-border-neutral);--checkbox-border-hover: #c1b9c1;--checkbox-border-active: #9f99a1;--checkbox-icon: #f1eff1;--checkbox-icon-disabled: #c1b9c1;--checkbox-bg-disabled: color-mix(in oklch, #44374b 10%, transparent);--checkbox-border-disabled: color-mix(in oklch, #44374b 10%, transparent);--checkbox-mask-size: 12px;--checkbox-mask-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");--checkbox-mask-indeterminate: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14'/%3E%3C/svg%3E");--checkbox-label-color: var(--text-2);--checkbox-label-color-disabled: var(--text-4);--checkbox-hint-color: var(--text-3);--checkbox-label-fs: 15px;--checkbox-label-lh: 20px;--checkbox-hint-fs: 13px;--checkbox-hint-lh: 16px;display:inline-grid;grid-template-columns:auto 1fr;align-items:start;column-gap:var(--checkbox-gap);vertical-align:middle;cursor:pointer;user-select:none;-webkit-user-drag:none;outline:none;color:var(--checkbox-label-color);font-family:var(--sans-serif);font-size:var(--checkbox-label-fs);line-height:var(--checkbox-label-lh);font-feature-settings:"ss02","ss05","tnum";&:before{content:"";grid-column:1;grid-row:1 / -1;align-self:start;margin-block-start:calc((var(--checkbox-label-lh) - var(--checkbox-box-size)) / 2);box-sizing:border-box;inline-size:16px;block-size:16px;border-radius:4px;background:var(--checkbox-bg);border:1.5px solid var(--checkbox-border);transition:background-color .15s ease-out,border-color .15s ease-out}&[round]{--checkbox-round: attr(round type(<length>), 999px)}&[round]:before{border-radius:var(--checkbox-round, 999px)}&:after{content:"";grid-column:1;grid-row:1 / -1;align-self:start;margin-block-start:calc((var(--checkbox-label-lh) - var(--checkbox-box-size)) / 2);inline-size:16px;block-size:16px;background-color:transparent;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-position:center;mask-position:center;-webkit-mask-size:var(--checkbox-mask-size);mask-size:var(--checkbox-mask-size)}@media(hover:hover)and (pointer:fine){&:not(:disabled):hover:before{border-color:var(--checkbox-border-hover);transition:background-color 75ms ease-in,border-color 75ms ease-in}&:not(:disabled):hover:is(:state(checked),:state(indeterminate)):before{background:var(--checkbox-fill-hover);border-color:var(--checkbox-fill-hover)}}&:not(:disabled):active:before{border-color:var(--checkbox-border-active);transition:background-color 50ms linear,border-color 50ms linear}&:not(:disabled):active:is(:state(checked),:state(indeterminate)):before{background:var(--checkbox-fill-active);border-color:var(--checkbox-fill-active)}&:is(:state(checked),:state(indeterminate)){&:before{background:var(--checkbox-fill);border-color:var(--checkbox-fill)}&:after{background-color:var(--checkbox-icon)}}&:state(checked):after{-webkit-mask-image:var(--checkbox-mask-check);mask-image:var(--checkbox-mask-check)}&:state(indeterminate):after{-webkit-mask-image:var(--checkbox-mask-indeterminate);mask-image:var(--checkbox-mask-indeterminate)}&:focus-visible:before{outline:1px solid var(--focus-ring);outline-offset:1px}&:disabled{cursor:not-allowed;color:var(--checkbox-label-color-disabled);&:before{background:var(--checkbox-bg-disabled);border-color:var(--checkbox-border-disabled);transition:none}&:is(:state(checked),:state(indeterminate)):after{background-color:var(--checkbox-icon-disabled)}a-checkbox-hint{color:var(--checkbox-label-color-disabled)}}&[size=small]{--checkbox-gap: 6px;--checkbox-box-size: 14px;--checkbox-label-fs: 13px;--checkbox-label-lh: 16px;--checkbox-hint-fs: 12px;--checkbox-hint-lh: 14px;--checkbox-mask-size: 10px;&:before,&:after{inline-size:14px;block-size:14px}}&[size=large]{--checkbox-box-size: 18px;--checkbox-label-fs: 17px;--checkbox-label-lh: 22px;--checkbox-hint-fs: 15px;--checkbox-hint-lh: 19px;--checkbox-mask-size: 14px;&:before,&:after{inline-size:18px;block-size:18px}}}.dark a-checkbox{--checkbox-mask-size: 13px}.dark a-checkbox[size=small]{--checkbox-mask-size: 11px}.dark a-checkbox[size=large]{--checkbox-mask-size: 15px}a-checkbox-label,a-checkbox-hint{display:block;grid-column:2;min-width:0}a-checkbox-hint{color:var(--checkbox-hint-color);font-size:var(--checkbox-hint-fs);line-height:var(--checkbox-hint-lh);margin-block-start:2px}a-checkbox[tone=brand],a-checkbox[tone-selected=brand]{--checkbox-fill: #5f4bc3;--checkbox-fill-hover: #503cb4;--checkbox-fill-active: #483493}a-checkbox[tone=neutral],a-checkbox[tone-selected=neutral]{--checkbox-fill: #878089;--checkbox-fill-hover: #776e77;--checkbox-fill-active: #635b65}a-checkbox[tone=info],a-checkbox[tone-selected=info]{--checkbox-fill: #1f6eb2;--checkbox-fill-hover: #1a5b93;--checkbox-fill-active: #175082}a-checkbox[tone=success],a-checkbox[tone-selected=success]{--checkbox-fill: #2a7e43;--checkbox-fill-hover: #226737;--checkbox-fill-active: #1f5c31}a-checkbox[tone=warning],a-checkbox[tone-selected=warning]{--checkbox-fill: #c37416;--checkbox-fill-hover: #ae6613;--checkbox-fill-active: #995200}a-checkbox[tone=critical],a-checkbox[tone-selected=critical]{--checkbox-fill: #c9302c;--checkbox-fill-hover: #b02120;--checkbox-fill-active: #a01c1c}a-checkbox[tone=brand]{--checkbox-bg: #fcfcfe;--checkbox-border: #bcb1f1;--checkbox-border-hover: #9e8eeb;--checkbox-border-active: #9081df}a-checkbox[tone=info]{--checkbox-bg: #fbfcfe;--checkbox-border: #93c5ec;--checkbox-border-hover: #69ace5;--checkbox-border-active: #56a1e1}a-checkbox[tone=success]{--checkbox-bg: #f7fcf9;--checkbox-border: #88d7a0;--checkbox-border-hover: #5bc87b;--checkbox-border-active: #44c169}a-checkbox[tone=warning]{--checkbox-bg: #fefbf6;--checkbox-border: #edb25a;--checkbox-border-hover: #e09127;--checkbox-border-active: #d88118}a-checkbox[tone=critical]{--checkbox-bg: #fefbfb;--checkbox-border: #efa4a4;--checkbox-border-hover: #e87f7f;--checkbox-border-active: #e56c6c}a-checkbox[tone]:not([tone=""],[tone=neutral],[tone=brand],[tone=info],[tone=success],[tone=warning],[tone=critical]){--checkbox-bg: oklch(from var(--checkbox-tone-source) .99 calc(c*.03) h);--_checkbox-border-base: color-mix(in oklch, var(--checkbox-fill) 70%, var(--checkbox-border-neutral));--checkbox-border: oklch(from var(--_checkbox-border-base) calc(l + .17) c h);--checkbox-border-hover: oklch(from var(--_checkbox-border-base) calc(l + .1) c h);--checkbox-border-active: var(--_checkbox-border-base);.dark &{--checkbox-bg: oklch(from var(--checkbox-tone-source) .15 calc(c*.18) h);--checkbox-border: var(--_checkbox-border-base);--checkbox-border-hover: oklch(from var(--_checkbox-border-base) calc(l + .1) c h);--checkbox-border-active: oklch(from var(--_checkbox-border-base) calc(l + .17) c h)}}a-checkbox[tone]:not([tone=""],[tone=brand],[tone=neutral],[tone=info],[tone=success],[tone=warning],[tone=critical]){--checkbox-tone-source: attr(tone type(<color>), transparent)}a-checkbox[tone-selected]:not([tone-selected=""],[tone-selected=brand],[tone-selected=neutral],[tone-selected=info],[tone-selected=success],[tone-selected=warning],[tone-selected=critical]){--checkbox-tone-source: attr(tone-selected type(<color>), transparent)}a-checkbox[tone]:not([tone=""],[tone=brand],[tone=neutral],[tone=info],[tone=success],[tone=warning],[tone=critical]),a-checkbox[tone-selected]:not([tone-selected=""],[tone-selected=brand],[tone-selected=neutral],[tone-selected=info],[tone-selected=success],[tone-selected=warning],[tone-selected=critical]){--_tone-l-rest: .5;--_tone-l-hover: .45;--_tone-l-active: .4;--checkbox-fill: oklch(from var(--checkbox-tone-source) var(--_tone-l-rest) c h);--checkbox-fill-hover: oklch(from var(--checkbox-tone-source) var(--_tone-l-hover) c h);--checkbox-fill-active: oklch(from var(--checkbox-tone-source) var(--_tone-l-active) c h);.dark &{--_tone-l-rest: .45;--_tone-l-hover: .5;--_tone-l-active: .57}}.dark a-checkbox{--checkbox-border-neutral: #49424c;--checkbox-border-hover: #635b65;--checkbox-border-active: #776e77;--checkbox-fill: #49424c;--checkbox-fill-hover: #534c57;--checkbox-fill-active: #635b65;--checkbox-icon: #d4ced4;--checkbox-icon-disabled: #534c57;--checkbox-bg-disabled: color-mix(in oklch, #e4d1ef 10%, transparent);--checkbox-border-disabled: color-mix(in oklch, #e4d1ef 10%, transparent)}.dark a-checkbox[tone=brand],.dark a-checkbox[tone-selected=brand]{--checkbox-fill: #503cb4;--checkbox-fill-hover: #5f4bc3;--checkbox-fill-active: #7460d7}.dark a-checkbox[tone=neutral],.dark a-checkbox[tone-selected=neutral]{--checkbox-fill: #49424c;--checkbox-fill-hover: #534c57;--checkbox-fill-active: #635b65}.dark a-checkbox[tone=info],.dark a-checkbox[tone-selected=info]{--checkbox-fill: #1a5b93;--checkbox-fill-hover: #1f6eb2;--checkbox-fill-active: #2686d9}.dark a-checkbox[tone=success],.dark a-checkbox[tone-selected=success]{--checkbox-fill: #226737;--checkbox-fill-hover: #2a7e43;--checkbox-fill-active: #329550}.dark a-checkbox[tone=warning],.dark a-checkbox[tone-selected=warning]{--checkbox-fill: #7f410b;--checkbox-fill-hover: #995200;--checkbox-fill-active: #ae6613}.dark a-checkbox[tone=critical],.dark a-checkbox[tone-selected=critical]{--checkbox-fill: #b02120;--checkbox-fill-hover: #c9302c;--checkbox-fill-active: #de4545}.dark a-checkbox[tone=brand]{--checkbox-bg: #0b0916;--checkbox-border: #483493;--checkbox-border-hover: #5f4bc3;--checkbox-border-active: #7460d7}.dark a-checkbox[tone=info]{--checkbox-bg: #040d18;--checkbox-border: #175082;--checkbox-border-hover: #1f6eb2;--checkbox-border-active: #2686d9}.dark a-checkbox[tone=success]{--checkbox-bg: #041008;--checkbox-border: #1f5c31;--checkbox-border-hover: #2a7e43;--checkbox-border-active: #329550}.dark a-checkbox[tone=warning]{--checkbox-bg: #120a03;--checkbox-border: #6a3b0c;--checkbox-border-hover: #995200;--checkbox-border-active: #ae6613}.dark a-checkbox[tone=critical]{--checkbox-bg: #190405;--checkbox-border: #a01c1c;--checkbox-border-hover: #c9302c;--checkbox-border-active: #de4545}}
1
+ @layer anta{a-checkbox{--checkbox-gap: 8px;--checkbox-box-size: 16px;--checkbox-bg: var(--bg-1);--checkbox-fill: #878089;--checkbox-fill-hover: #776e77;--checkbox-fill-active: #635b65;--checkbox-border-neutral: #d4ced4;--checkbox-border: var(--checkbox-border-neutral);--checkbox-border-hover: #c1b9c1;--checkbox-border-active: #9f99a1;--checkbox-icon: #f6f4f6;--checkbox-icon-disabled: #c1b9c1;--checkbox-bg-disabled: color-mix(in oklch, #44374b 10%, transparent);--checkbox-border-disabled: color-mix(in oklch, #44374b 10%, transparent);--checkbox-mask-size: 12px;--checkbox-mask-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");--checkbox-mask-indeterminate: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14'/%3E%3C/svg%3E");--checkbox-label-color: var(--text-2);--checkbox-label-color-disabled: var(--text-4);--checkbox-hint-color: var(--text-3);--checkbox-label-fs: 15px;--checkbox-label-lh: 20px;--checkbox-hint-fs: 13px;--checkbox-hint-lh: 16px;display:inline-grid;grid-template-columns:auto 1fr;align-items:start;column-gap:var(--checkbox-gap);vertical-align:middle;cursor:pointer;user-select:none;-webkit-user-drag:none;outline:none;color:var(--checkbox-label-color);font-family:var(--sans-serif);font-size:var(--checkbox-label-fs);line-height:var(--checkbox-label-lh);font-feature-settings:"ss02","ss05","tnum";&:before{content:"";grid-column:1;grid-row:1 / -1;align-self:start;margin-block-start:calc((var(--checkbox-label-lh) - var(--checkbox-box-size)) / 2);box-sizing:border-box;inline-size:16px;block-size:16px;border-radius:4px;background:var(--checkbox-bg);border:1.5px solid var(--checkbox-border);transition:background-color .15s ease-out,border-color .15s ease-out}&[round]{--checkbox-round: attr(round type(<length>), 999px)}&[round]:before{border-radius:var(--checkbox-round, 999px)}&:after{content:"";grid-column:1;grid-row:1 / -1;align-self:start;margin-block-start:calc((var(--checkbox-label-lh) - var(--checkbox-box-size)) / 2);inline-size:16px;block-size:16px;background-color:transparent;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-position:center;mask-position:center;-webkit-mask-size:var(--checkbox-mask-size);mask-size:var(--checkbox-mask-size)}@media(hover:hover)and (pointer:fine){&:not(:disabled):hover:before{border-color:var(--checkbox-border-hover);transition:background-color 75ms ease-in,border-color 75ms ease-in}&:not(:disabled):hover:is(:state(checked),:state(indeterminate)):before{background:var(--checkbox-fill-hover);border-color:var(--checkbox-fill-hover)}}&:not(:disabled):active:before{border-color:var(--checkbox-border-active);transition:background-color 50ms linear,border-color 50ms linear}&:not(:disabled):active:is(:state(checked),:state(indeterminate)):before{background:var(--checkbox-fill-active);border-color:var(--checkbox-fill-active)}&:is(:state(checked),:state(indeterminate)){&:before{background:var(--checkbox-fill);border-color:var(--checkbox-fill)}&:after{background-color:var(--checkbox-icon)}}&:state(checked):after{-webkit-mask-image:var(--checkbox-mask-check);mask-image:var(--checkbox-mask-check)}&:state(indeterminate):after{-webkit-mask-image:var(--checkbox-mask-indeterminate);mask-image:var(--checkbox-mask-indeterminate)}&:focus-visible:before{outline:1px solid var(--focus-ring);outline-offset:1px}&:disabled{cursor:not-allowed;color:var(--checkbox-label-color-disabled);&:before{background:var(--checkbox-bg-disabled);border-color:var(--checkbox-border-disabled);transition:none}&:is(:state(checked),:state(indeterminate)):after{background-color:var(--checkbox-icon-disabled)}a-checkbox-hint{color:var(--checkbox-label-color-disabled)}}&[size=small]{--checkbox-gap: 6px;--checkbox-box-size: 14px;--checkbox-label-fs: 13px;--checkbox-label-lh: 16px;--checkbox-hint-fs: 12px;--checkbox-hint-lh: 14px;--checkbox-mask-size: 10px;&:before,&:after{inline-size:14px;block-size:14px}}&[size=large]{--checkbox-box-size: 18px;--checkbox-label-fs: 17px;--checkbox-label-lh: 22px;--checkbox-hint-fs: 15px;--checkbox-hint-lh: 19px;--checkbox-mask-size: 14px;&:before,&:after{inline-size:18px;block-size:18px}}}.dark a-checkbox{--checkbox-mask-size: 13px}.dark a-checkbox[size=small]{--checkbox-mask-size: 11px}.dark a-checkbox[size=large]{--checkbox-mask-size: 15px}a-checkbox-label,a-checkbox-hint{display:block;grid-column:2;min-width:0}a-checkbox-hint{color:var(--checkbox-hint-color);font-size:var(--checkbox-hint-fs);line-height:var(--checkbox-hint-lh);margin-block-start:2px}a-checkbox[tone=brand],a-checkbox[tone-selected=brand]{--checkbox-fill: #5f4bc3;--checkbox-fill-hover: #503cb4;--checkbox-fill-active: #483493}a-checkbox[tone=neutral],a-checkbox[tone-selected=neutral]{--checkbox-fill: #878089;--checkbox-fill-hover: #776e77;--checkbox-fill-active: #635b65}a-checkbox[tone=info],a-checkbox[tone-selected=info]{--checkbox-fill: #1f6eb2;--checkbox-fill-hover: #1a5b93;--checkbox-fill-active: #175082}a-checkbox[tone=success],a-checkbox[tone-selected=success]{--checkbox-fill: #2a7e43;--checkbox-fill-hover: #226737;--checkbox-fill-active: #1f5c31}a-checkbox[tone=warning],a-checkbox[tone-selected=warning]{--checkbox-fill: #c37416;--checkbox-fill-hover: #ae6613;--checkbox-fill-active: #995200}a-checkbox[tone=critical],a-checkbox[tone-selected=critical]{--checkbox-fill: #c9302c;--checkbox-fill-hover: #b02120;--checkbox-fill-active: #a01c1c}a-checkbox[tone=brand]{--checkbox-bg: #fcfcfe;--checkbox-border: #bcb1f1;--checkbox-border-hover: #9e8eeb;--checkbox-border-active: #9081df}a-checkbox[tone=info]{--checkbox-bg: #fbfcfe;--checkbox-border: #93c5ec;--checkbox-border-hover: #69ace5;--checkbox-border-active: #56a1e1}a-checkbox[tone=success]{--checkbox-bg: #f7fcf9;--checkbox-border: #88d7a0;--checkbox-border-hover: #5bc87b;--checkbox-border-active: #44c169}a-checkbox[tone=warning]{--checkbox-bg: #fefbf6;--checkbox-border: #edb25a;--checkbox-border-hover: #e09127;--checkbox-border-active: #d88118}a-checkbox[tone=critical]{--checkbox-bg: #fefbfb;--checkbox-border: #efa4a4;--checkbox-border-hover: #e87f7f;--checkbox-border-active: #e56c6c}a-checkbox[tone]:not([tone=""],[tone=neutral],[tone=brand],[tone=info],[tone=success],[tone=warning],[tone=critical]){--checkbox-bg: oklch(from var(--checkbox-tone-source) .99 calc(c*.03) h);--_checkbox-border-base: color-mix(in oklch, var(--checkbox-fill) 70%, var(--checkbox-border-neutral));--checkbox-border: oklch(from var(--_checkbox-border-base) calc(l + .17) c h);--checkbox-border-hover: oklch(from var(--_checkbox-border-base) calc(l + .1) c h);--checkbox-border-active: var(--_checkbox-border-base);.dark &{--checkbox-bg: oklch(from var(--checkbox-tone-source) .15 calc(c*.18) h);--checkbox-border: var(--_checkbox-border-base);--checkbox-border-hover: oklch(from var(--_checkbox-border-base) calc(l + .1) c h);--checkbox-border-active: oklch(from var(--_checkbox-border-base) calc(l + .17) c h)}}a-checkbox[tone]:not([tone=""],[tone=brand],[tone=neutral],[tone=info],[tone=success],[tone=warning],[tone=critical]){--checkbox-tone-source: attr(tone type(<color>), transparent)}a-checkbox[tone-selected]:not([tone-selected=""],[tone-selected=brand],[tone-selected=neutral],[tone-selected=info],[tone-selected=success],[tone-selected=warning],[tone-selected=critical]){--checkbox-tone-source: attr(tone-selected type(<color>), transparent)}a-checkbox[tone]:not([tone=""],[tone=brand],[tone=neutral],[tone=info],[tone=success],[tone=warning],[tone=critical]),a-checkbox[tone-selected]:not([tone-selected=""],[tone-selected=brand],[tone-selected=neutral],[tone-selected=info],[tone-selected=success],[tone-selected=warning],[tone-selected=critical]){--_tone-l-rest: .5;--_tone-l-hover: .45;--_tone-l-active: .4;--checkbox-fill: oklch(from var(--checkbox-tone-source) var(--_tone-l-rest) c h);--checkbox-fill-hover: oklch(from var(--checkbox-tone-source) var(--_tone-l-hover) c h);--checkbox-fill-active: oklch(from var(--checkbox-tone-source) var(--_tone-l-active) c h);.dark &{--_tone-l-rest: .45;--_tone-l-hover: .5;--_tone-l-active: .57}}.dark a-checkbox{--checkbox-border-neutral: #49424c;--checkbox-border-hover: #635b65;--checkbox-border-active: #776e77;--checkbox-fill: #49424c;--checkbox-fill-hover: #534c57;--checkbox-fill-active: #635b65;--checkbox-icon: #ece9ec;--checkbox-icon-disabled: #534c57;--checkbox-bg-disabled: color-mix(in oklch, #e4d1ef 10%, transparent);--checkbox-border-disabled: color-mix(in oklch, #e4d1ef 10%, transparent)}.dark a-checkbox[tone=brand],.dark a-checkbox[tone-selected=brand]{--checkbox-fill: #503cb4;--checkbox-fill-hover: #5f4bc3;--checkbox-fill-active: #7460d7}.dark a-checkbox[tone=neutral],.dark a-checkbox[tone-selected=neutral]{--checkbox-fill: #49424c;--checkbox-fill-hover: #534c57;--checkbox-fill-active: #635b65}.dark a-checkbox[tone=info],.dark a-checkbox[tone-selected=info]{--checkbox-fill: #1a5b93;--checkbox-fill-hover: #1f6eb2;--checkbox-fill-active: #2686d9}.dark a-checkbox[tone=success],.dark a-checkbox[tone-selected=success]{--checkbox-fill: #226737;--checkbox-fill-hover: #2a7e43;--checkbox-fill-active: #329550}.dark a-checkbox[tone=warning],.dark a-checkbox[tone-selected=warning]{--checkbox-fill: #7f410b;--checkbox-fill-hover: #995200;--checkbox-fill-active: #ae6613}.dark a-checkbox[tone=critical],.dark a-checkbox[tone-selected=critical]{--checkbox-fill: #b02120;--checkbox-fill-hover: #c9302c;--checkbox-fill-active: #de4545}.dark a-checkbox[tone=brand]{--checkbox-bg: #0b0916;--checkbox-border: #483493;--checkbox-border-hover: #5f4bc3;--checkbox-border-active: #7460d7}.dark a-checkbox[tone=info]{--checkbox-bg: #040d18;--checkbox-border: #175082;--checkbox-border-hover: #1f6eb2;--checkbox-border-active: #2686d9}.dark a-checkbox[tone=success]{--checkbox-bg: #041008;--checkbox-border: #1f5c31;--checkbox-border-hover: #2a7e43;--checkbox-border-active: #329550}.dark a-checkbox[tone=warning]{--checkbox-bg: #120a03;--checkbox-border: #6a3b0c;--checkbox-border-hover: #995200;--checkbox-border-active: #ae6613}.dark a-checkbox[tone=critical]{--checkbox-bg: #190405;--checkbox-border: #a01c1c;--checkbox-border-hover: #c9302c;--checkbox-border-active: #de4545}}
@@ -0,0 +1 @@
1
+ @layer anta{a-dialog{--dialog-bg: var(--bg-1);--dialog-text: var(--text-2);--dialog-border: color-mix(in oklch, black 9%, transparent);--dialog-radius: 10px;--dialog-shadow: inset 0 0 0 1px var(--dialog-border), 0 1px 3px color-mix(in oklch, black 10%, transparent), 0 12px 32px color-mix(in oklch, black 22%, transparent), 0 28px 64px color-mix(in oklch, black 14%, transparent);--dialog-overlay: color-mix(in oklch, black 42%, transparent);display:contents}a-dialog[round]{--dialog-round: attr(round type(<length>), var(--dialog-radius, 10px))}a-dialog:not(:defined){display:none}.dark a-dialog{--dialog-border: color-mix(in oklch, white 14%, transparent);--dialog-shadow: inset 0 0 0 1px var(--dialog-border), 0 1px 3px color-mix(in oklch, black 40%, transparent), 0 12px 32px color-mix(in oklch, black 55%, transparent), 0 28px 64px color-mix(in oklch, black 40%, transparent);--dialog-overlay: color-mix(in oklch, black 62%, transparent)}}
@@ -0,0 +1,26 @@
1
+ import { HTMLElementBase } from '../anta_helpers';
2
+ import './a-dialog.css';
3
+ export declare class ADialogElement extends HTMLElementBase {
4
+ #private;
5
+ static observedAttributes: string[];
6
+ private dialog;
7
+ private headerSlot;
8
+ private footerSlot;
9
+ private closeSlot;
10
+ constructor();
11
+ connectedCallback(): void;
12
+ disconnectedCallback(): void;
13
+ attributeChangedCallback(name: string): void;
14
+ /** Public imperative API — mirrors `<dialog>`. `show()` requests open,
15
+ * `close()` requests close; both honor the state contract. */
16
+ show(): void;
17
+ close(): void;
18
+ get open(): boolean;
19
+ /** Announce a requested OPEN (cancelable, before applying), then — uncontrolled
20
+ * and un-vetoed — apply it. Controlled: never self-apply. */
21
+ requestOpen(): void;
22
+ /** Announce a requested CLOSE (cancelable, before applying), then — uncontrolled
23
+ * and un-vetoed — apply it. Controlled: never self-apply. */
24
+ requestClose(): void;
25
+ }
26
+ export declare function register_a_dialog(): void;
@@ -0,0 +1,386 @@
1
+ import { HTMLElementBase, parseOpenState } from "../anta_helpers";
2
+ import "./a-dialog.css";
3
+ const CLOSE_TRIGGER = "closerequest";
4
+ const ANIM_MS = 200;
5
+ const SHADOW_STYLE = `
6
+ :host { display: contents; }
7
+
8
+ dialog {
9
+ --_dur: ${ANIM_MS}ms;
10
+ --_r: var(--dialog-round, var(--dialog-radius, 10px));
11
+
12
+ position: fixed;
13
+ box-sizing: border-box;
14
+ padding: 0;
15
+ border: none;
16
+ max-width: calc(100vw - 2 * var(--dialog-margin, 32px));
17
+ max-height: calc(100dvh - 2 * var(--dialog-margin, 32px));
18
+ width: var(--dialog-width, 480px);
19
+ height: var(--dialog-height, fit-content);
20
+ overflow: visible;
21
+ color: var(--dialog-text, inherit);
22
+ background: var(--dialog-bg, #fff);
23
+ border-radius: var(--_r);
24
+ box-shadow: var(--dialog-shadow, inset 0 0 0 1px color-mix(in oklch, black 8%, transparent), 0 10px 38px color-mix(in oklch, black 28%, transparent));
25
+
26
+ flex-direction: column;
27
+ }
28
+
29
+ dialog[open] {
30
+ display: flex;
31
+ }
32
+
33
+ dialog:focus, dialog:focus-visible { outline: none; }
34
+
35
+ dialog::backdrop {
36
+ background: var(--dialog-overlay, color-mix(in oklch, black 40%, transparent));
37
+ }
38
+
39
+ :host { --_enter-from: scale(0.97); }
40
+ :host([position="left"]) { --_enter-from: translateX(-100%); }
41
+ :host([position="right"]) { --_enter-from: translateX(100%); }
42
+ :host([position="top"]) { --_enter-from: translateY(-100%); }
43
+ :host([position="bottom"]) { --_enter-from: translateY(100%); }
44
+
45
+ @media (prefers-reduced-motion: no-preference) {
46
+ dialog {
47
+ opacity: 0;
48
+ transform: var(--_enter-from);
49
+ transition:
50
+ opacity var(--_dur) ease,
51
+ transform var(--_dur) ease,
52
+ overlay var(--_dur) ease allow-discrete,
53
+ display var(--_dur) ease allow-discrete;
54
+ }
55
+ dialog[open] {
56
+ opacity: 1;
57
+ transform: none;
58
+ }
59
+ @starting-style {
60
+ dialog[open] { opacity: 0; transform: var(--_enter-from); }
61
+ }
62
+
63
+ dialog::backdrop {
64
+ background: transparent;
65
+ transition:
66
+ background var(--_dur) ease,
67
+ overlay var(--_dur) ease allow-discrete,
68
+ display var(--_dur) ease allow-discrete;
69
+ }
70
+ dialog[open]::backdrop { background: var(--dialog-overlay, color-mix(in oklch, black 40%, transparent)); }
71
+ @starting-style {
72
+ dialog[open]::backdrop { background: transparent; }
73
+ }
74
+ }
75
+
76
+ :host([position="left"]) dialog,
77
+ :host([position="right"]) dialog {
78
+ width: var(--dialog-width, 380px);
79
+ max-width: calc(100vw - var(--dialog-margin, 32px));
80
+ height: 100dvh;
81
+ max-height: 100dvh;
82
+ border-radius: 0;
83
+ }
84
+ :host([position="left"]) dialog { margin: 0 auto 0 0; }
85
+ :host([position="right"]) dialog { margin: 0 0 0 auto; }
86
+
87
+ :host([position="top"]) dialog,
88
+ :host([position="bottom"]) dialog {
89
+ width: 100vw;
90
+ max-width: 100vw;
91
+ height: var(--dialog-height, fit-content);
92
+ max-height: calc(100dvh - var(--dialog-margin, 32px));
93
+ border-radius: 0;
94
+ }
95
+ :host([position="top"]) dialog { margin: 0 auto auto auto; }
96
+ :host([position="bottom"]) dialog { margin: auto auto 0 auto; }
97
+
98
+ :host([position="fullscreen"]) dialog {
99
+ width: 100vw;
100
+ max-width: 100vw;
101
+ height: 100dvh;
102
+ max-height: 100dvh;
103
+ margin: 0;
104
+ border-radius: 0;
105
+ }
106
+
107
+ :host([round]) dialog { border-radius: var(--_r); }
108
+ :host([round="top"]) dialog { border-radius: var(--_r) var(--_r) 0 0; }
109
+ :host([round="bottom"]) dialog { border-radius: 0 0 var(--_r) var(--_r); }
110
+ :host([round="left"]) dialog { border-radius: var(--_r) 0 0 var(--_r); }
111
+ :host([round="right"]) dialog { border-radius: 0 var(--_r) var(--_r) 0; }
112
+
113
+ slot[name="header"] {
114
+ display: none;
115
+ flex: 0 0 auto;
116
+ padding: var(--dialog-header-padding, 18px 20px 8px);
117
+ font-size: 17px;
118
+ font-weight: 560;
119
+ line-height: 24px;
120
+ }
121
+ slot[name="header"].has-content { display: block; }
122
+ dialog.has-close slot[name="header"] { padding-inline-end: 52px; }
123
+
124
+ slot[part="body"] {
125
+ display: block;
126
+ flex: 1 1 auto;
127
+ min-height: 0;
128
+ overflow: auto;
129
+ padding: var(--dialog-body-padding, 8px 20px 12px);
130
+ }
131
+ /* With a close button but no header, the body is the top zone, so it takes the
132
+ \u2715 clearance instead of the header (which is display:none when empty). */
133
+ dialog.has-close slot[name="header"]:not(.has-content) ~ slot[part="body"] {
134
+ padding-inline-end: 52px;
135
+ }
136
+
137
+ slot[name="footer"] {
138
+ display: none;
139
+ flex: 0 0 auto;
140
+ padding: var(--dialog-footer-padding, 8px 20px 18px);
141
+ }
142
+ slot[name="footer"].has-content {
143
+ display: flex;
144
+ gap: 8px;
145
+ justify-content: flex-end;
146
+ align-items: center;
147
+ flex-wrap: wrap;
148
+ }
149
+
150
+ slot[name="close"] { display: none; }
151
+ slot[name="close"].has-content {
152
+ display: block;
153
+ position: absolute;
154
+ inset-block-start: 10px;
155
+ inset-inline-end: 10px;
156
+ z-index: 1;
157
+ }
158
+ `;
159
+ class ADialogElement extends HTMLElementBase {
160
+ static observedAttributes = ["state", "name"];
161
+ dialog;
162
+ headerSlot;
163
+ footerSlot;
164
+ closeSlot;
165
+ // Counts `dialog.close()` calls WE initiate whose async `close` event is still
166
+ // pending, and is decremented as each arrives. The native `close` event fires
167
+ // from a queued task, so a synchronous guard can't span it, and a boolean
168
+ // can't span a BURST (two re-parents in one tick queue two closes; the first
169
+ // event would clear the flag and the second would be misread as out-of-band).
170
+ // The counter lets the `close` handler tell our own closes (ignore) from an
171
+ // out-of-band one (`<form method="dialog">`, a consumer calling the shadow
172
+ // dialog's close(), bfcache), which it must reconcile.
173
+ #programmaticCloses = 0;
174
+ // The intended (uncontrolled) open state, held in JS so it survives a
175
+ // disconnect → reconnect (a DOM move / re-parent). disconnectedCallback
176
+ // force-closes the native dialog to free the top layer, but must not lose
177
+ // whether the user had it open — otherwise a re-parented open dialog would
178
+ // vanish (trigger-opened) or a re-parented closed one would pop back (a stale
179
+ // `default-state="open"` re-seeding). Only ever reflects genuine open/close
180
+ // intent, never the disconnect teardown.
181
+ #wantOpen = false;
182
+ // default-state is read ONCE (the first connect), never again — re-seeding on
183
+ // every connect would reopen a dialog the user has since closed.
184
+ #seeded = false;
185
+ // Whether the current pointer press began on the backdrop (the dialog element
186
+ // itself), so a press-inside → release-on-backdrop drag (text selection) is
187
+ // NOT read as a backdrop dismiss.
188
+ #pressedBackdrop = false;
189
+ // The document click listener wired for the `name`-trigger convenience, kept so
190
+ // it can be torn down (and re-wired when `name` / controlled-ness changes).
191
+ #triggerListener;
192
+ constructor() {
193
+ super();
194
+ const shadow = this.attachShadow({ mode: "open" });
195
+ const style = document.createElement("style");
196
+ style.textContent = SHADOW_STYLE;
197
+ this.dialog = document.createElement("dialog");
198
+ this.dialog.setAttribute("part", "dialog");
199
+ this.dialog.tabIndex = -1;
200
+ this.closeSlot = document.createElement("slot");
201
+ this.closeSlot.name = "close";
202
+ this.closeSlot.setAttribute("part", "close");
203
+ this.headerSlot = document.createElement("slot");
204
+ this.headerSlot.name = "header";
205
+ this.headerSlot.setAttribute("part", "header");
206
+ const bodySlot = document.createElement("slot");
207
+ bodySlot.setAttribute("part", "body");
208
+ this.footerSlot = document.createElement("slot");
209
+ this.footerSlot.name = "footer";
210
+ this.footerSlot.setAttribute("part", "footer");
211
+ for (const slot of [this.headerSlot, this.footerSlot, this.closeSlot]) {
212
+ slot.addEventListener("slotchange", () => {
213
+ const has = slot.assignedNodes().length > 0;
214
+ slot.classList.toggle("has-content", has);
215
+ if (slot === this.closeSlot) this.dialog.classList.toggle("has-close", has);
216
+ });
217
+ }
218
+ this.headerSlot.addEventListener("slotchange", () => this.#syncAccessibleName());
219
+ this.dialog.append(this.headerSlot, bodySlot, this.footerSlot, this.closeSlot);
220
+ shadow.append(style, this.dialog);
221
+ this.dialog.addEventListener("cancel", (e) => {
222
+ e.preventDefault();
223
+ if (!this.#persistent) this.requestClose();
224
+ });
225
+ this.dialog.addEventListener("pointerdown", (e) => {
226
+ this.#pressedBackdrop = e.target === this.dialog;
227
+ });
228
+ this.dialog.addEventListener("click", (e) => {
229
+ if (this.#persistent) return;
230
+ if (this.#pressedBackdrop && e.target === this.dialog) this.requestClose();
231
+ });
232
+ this.dialog.addEventListener("close", () => {
233
+ if (this.#programmaticCloses > 0) {
234
+ this.#programmaticCloses--;
235
+ return;
236
+ }
237
+ if (this.#controlled) this.#reflect(parseOpenState(this.getAttribute("state")));
238
+ else this.#wantOpen = false;
239
+ });
240
+ this.addEventListener(CLOSE_TRIGGER, () => this.requestClose());
241
+ }
242
+ connectedCallback() {
243
+ if (this.#controlled) {
244
+ this.#reflect(parseOpenState(this.getAttribute("state")));
245
+ } else {
246
+ if (!this.#seeded) {
247
+ if (parseOpenState(this.getAttribute("default-state")) === "open") this.#wantOpen = true;
248
+ this.#seeded = true;
249
+ }
250
+ if (this.#wantOpen) this.#open();
251
+ }
252
+ this.#syncTriggerListener();
253
+ this.#syncAccessibleName();
254
+ }
255
+ disconnectedCallback() {
256
+ this.#teardownTriggerListener();
257
+ if (this.dialog.open) {
258
+ this.#programmaticCloses++;
259
+ this.dialog.close();
260
+ }
261
+ }
262
+ attributeChangedCallback(name) {
263
+ if (name === "state") {
264
+ if (this.#controlled) this.#reflect(parseOpenState(this.getAttribute("state")));
265
+ this.#syncTriggerListener();
266
+ } else if (name === "name") {
267
+ this.#syncTriggerListener();
268
+ }
269
+ }
270
+ /** Controlled mode: the `state` attribute is present and owns the open state. */
271
+ get #controlled() {
272
+ return this.hasAttribute("state");
273
+ }
274
+ /** Light-dismiss (Esc + backdrop) disabled — the dialog closes only via
275
+ * explicit controls (close button / programmatic). */
276
+ get #persistent() {
277
+ return this.hasAttribute("persistent");
278
+ }
279
+ /** The currently *applied* open state (read from the native dialog — the
280
+ * source of truth for what's painted). */
281
+ get #current() {
282
+ return this.dialog.open ? "open" : "closed";
283
+ }
284
+ /** Public imperative API — mirrors `<dialog>`. `show()` requests open,
285
+ * `close()` requests close; both honor the state contract. */
286
+ show() {
287
+ this.requestOpen();
288
+ }
289
+ close() {
290
+ this.requestClose();
291
+ }
292
+ get open() {
293
+ return this.dialog.open;
294
+ }
295
+ /** Announce a requested OPEN (cancelable, before applying), then — uncontrolled
296
+ * and un-vetoed — apply it. Controlled: never self-apply. */
297
+ requestOpen() {
298
+ if (this.#current === "open") return;
299
+ const ok = this.#announce("open");
300
+ if (this.#controlled) return;
301
+ if (ok) this.#open();
302
+ }
303
+ /** Announce a requested CLOSE (cancelable, before applying), then — uncontrolled
304
+ * and un-vetoed — apply it. Controlled: never self-apply. */
305
+ requestClose() {
306
+ if (this.#current === "closed") return;
307
+ const ok = this.#announce("closed");
308
+ if (this.#controlled) return;
309
+ if (ok) this.#close();
310
+ }
311
+ /** Dispatch the cancelable `statechange` for a requested transition. Returns
312
+ * false if a handler vetoed it. */
313
+ #announce(next) {
314
+ return this.dispatchEvent(
315
+ new CustomEvent("statechange", {
316
+ cancelable: true,
317
+ detail: { next, prev: this.#current }
318
+ })
319
+ );
320
+ }
321
+ /** Reflect a controlled `state` onto the native dialog (idempotent). No
322
+ * `statechange` — this is the consumer's own command, not a user gesture. */
323
+ #reflect(state) {
324
+ if (state === "open") this.#open();
325
+ else this.#close();
326
+ }
327
+ /** Raw open: show the modal dialog. Records the open intent (survives a
328
+ * disconnect). Guarded against a not-connected / already-open native element
329
+ * (both throw / no-op). */
330
+ #open() {
331
+ this.#wantOpen = true;
332
+ if (this.dialog.open || !this.isConnected) return;
333
+ this.dialog.showModal();
334
+ if (!this.querySelector("[autofocus]")) this.dialog.focus();
335
+ }
336
+ /** Raw close. Records the closed intent and counts the pending `close` event as
337
+ * ours so the listener doesn't reconcile it. (The disconnect teardown closes
338
+ * the native dialog directly, NOT through here, to preserve `#wantOpen`.) */
339
+ #close() {
340
+ this.#wantOpen = false;
341
+ if (!this.dialog.open) return;
342
+ this.#programmaticCloses++;
343
+ this.dialog.close();
344
+ }
345
+ /** Publish the header text as the shadow dialog's accessible name (a-input's
346
+ * label-mirror pattern). Shadow-internal — not a host / light-DOM write. */
347
+ #syncAccessibleName() {
348
+ const text = this.headerSlot.assignedNodes().map((n) => n.textContent ?? "").join(" ").trim();
349
+ if (text) this.dialog.setAttribute("aria-label", text);
350
+ else this.dialog.removeAttribute("aria-label");
351
+ }
352
+ // --- `name`-trigger convenience (uncontrolled only) ---
353
+ #syncTriggerListener() {
354
+ const wanted = !this.#controlled && !!this.getAttribute("name");
355
+ if (wanted && !this.#triggerListener) this.#wireTriggerListener();
356
+ else if (!wanted && this.#triggerListener) this.#teardownTriggerListener();
357
+ }
358
+ #wireTriggerListener() {
359
+ this.#triggerListener = (e) => {
360
+ const name = this.getAttribute("name");
361
+ if (!name) return;
362
+ const t = e.target;
363
+ if (!(t instanceof Element)) return;
364
+ if (t.closest(`[data-dialog-open="${CSS.escape(name)}"]`)) this.requestOpen();
365
+ else if (t.closest(`[data-dialog-close="${CSS.escape(name)}"]`)) this.requestClose();
366
+ };
367
+ this.doc.addEventListener("click", this.#triggerListener);
368
+ }
369
+ #teardownTriggerListener() {
370
+ if (this.#triggerListener) {
371
+ this.doc.removeEventListener("click", this.#triggerListener);
372
+ this.#triggerListener = void 0;
373
+ }
374
+ }
375
+ }
376
+ function register_a_dialog() {
377
+ if (typeof customElements === "undefined") return;
378
+ if (!customElements.get("a-dialog")) {
379
+ customElements.define("a-dialog", ADialogElement);
380
+ }
381
+ }
382
+ register_a_dialog();
383
+ export {
384
+ ADialogElement,
385
+ register_a_dialog
386
+ };