@antadesign/anta 0.3.27 → 0.3.29

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 (162) hide show
  1. package/NOTICES.md +32 -1
  2. package/dist/anta_helpers.d.ts +25 -0
  3. package/dist/anta_helpers.js +28 -0
  4. package/dist/box-observation.d.ts +8 -0
  5. package/dist/box-observation.js +41 -0
  6. package/dist/box-types.d.ts +2 -0
  7. package/dist/bundle.css +1 -1
  8. package/dist/bundle.js +77 -46
  9. package/dist/components/Banner.js +2 -2
  10. package/dist/components/Box.d.ts +28 -12
  11. package/dist/components/Box.js +18 -11
  12. package/dist/components/Breadcrumbs.css +1 -1
  13. package/dist/components/Button.js +2 -2
  14. package/dist/components/Calendar.js +3 -5
  15. package/dist/components/Card.js +2 -2
  16. package/dist/components/Checkbox.d.ts +12 -13
  17. package/dist/components/Checkbox.js +5 -13
  18. package/dist/components/Expander.js +2 -2
  19. package/dist/components/Input.d.ts +8 -2
  20. package/dist/components/Input.js +6 -2
  21. package/dist/components/InputAutocomplete.js +3 -12
  22. package/dist/components/InputDate.css +1 -1
  23. package/dist/components/InputDate.js +2 -0
  24. package/dist/components/InputTime.js +2 -2
  25. package/dist/components/Loader.js +2 -1
  26. package/dist/components/Menu.d.ts +4 -4
  27. package/dist/components/Menu.js +1 -1
  28. package/dist/components/MenuItem.d.ts +7 -8
  29. package/dist/components/MenuItem.js +4 -4
  30. package/dist/components/Panel.d.ts +17 -0
  31. package/dist/components/Panel.js +22 -0
  32. package/dist/components/Progress.js +2 -2
  33. package/dist/components/RadioGroup.d.ts +14 -14
  34. package/dist/components/RadioGroup.js +7 -23
  35. package/dist/components/Select.d.ts +26 -21
  36. package/dist/components/Select.js +51 -38
  37. package/dist/components/SelectFaceted.d.ts +24 -11
  38. package/dist/components/SelectFaceted.js +65 -44
  39. package/dist/components/Slider.js +3 -3
  40. package/dist/components/Steps.css +1 -1
  41. package/dist/components/Switch.d.ts +10 -11
  42. package/dist/components/Switch.js +3 -11
  43. package/dist/components/TabPanel.d.ts +3 -8
  44. package/dist/components/TabPanel.js +2 -1
  45. package/dist/components/Tabs.d.ts +2 -2
  46. package/dist/components/Tabs.js +4 -3
  47. package/dist/components/Tag.d.ts +7 -9
  48. package/dist/components/Tag.js +2 -2
  49. package/dist/components/Text.js +2 -2
  50. package/dist/components/Title.js +2 -2
  51. package/dist/components/Tooltip.d.ts +1 -1
  52. package/dist/components/Tooltip.js +1 -1
  53. package/dist/components/select-parts.css +1 -1
  54. package/dist/elements/a-avatar.css +1 -1
  55. package/dist/elements/a-banner.css +1 -1
  56. package/dist/elements/a-box.css +1 -1
  57. package/dist/elements/a-box.d.ts +6 -6
  58. package/dist/elements/a-box.js +74 -23
  59. package/dist/elements/a-button.css +1 -1
  60. package/dist/elements/a-button.d.ts +16 -10
  61. package/dist/elements/a-button.js +64 -1
  62. package/dist/elements/a-calendar.css +1 -1
  63. package/dist/elements/a-capture.css +1 -1
  64. package/dist/elements/a-card.css +1 -1
  65. package/dist/elements/a-checkbox.css +1 -1
  66. package/dist/elements/a-checkbox.d.ts +3 -0
  67. package/dist/elements/a-checkbox.js +17 -1
  68. package/dist/elements/a-copy.css +1 -1
  69. package/dist/elements/a-dialog.css +1 -1
  70. package/dist/elements/a-expander.css +1 -1
  71. package/dist/elements/a-expander.js +1 -0
  72. package/dist/elements/a-icon.css +1 -1
  73. package/dist/elements/a-icon.shapes.css +1 -1
  74. package/dist/elements/a-input-time.css +1 -1
  75. package/dist/elements/a-input-time.d.ts +8 -0
  76. package/dist/elements/a-input-time.js +120 -15
  77. package/dist/elements/a-input.css +1 -1
  78. package/dist/elements/a-input.d.ts +27 -1
  79. package/dist/elements/a-input.js +180 -41
  80. package/dist/elements/a-loader.css +1 -1
  81. package/dist/elements/a-menu-group.css +1 -1
  82. package/dist/elements/a-menu-item.css +1 -1
  83. package/dist/elements/a-menu-item.js +1 -0
  84. package/dist/elements/a-menu-separator.css +1 -1
  85. package/dist/elements/a-menu.css +1 -1
  86. package/dist/elements/a-menu.d.ts +8 -13
  87. package/dist/elements/a-menu.js +146 -45
  88. package/dist/elements/a-panel.css +1 -0
  89. package/dist/elements/a-panel.d.ts +16 -0
  90. package/dist/elements/a-panel.js +153 -0
  91. package/dist/elements/a-progress.css +1 -1
  92. package/dist/elements/a-radio-group.css +1 -1
  93. package/dist/elements/a-radio.css +1 -1
  94. package/dist/elements/a-radio.d.ts +4 -0
  95. package/dist/elements/a-radio.js +18 -0
  96. package/dist/elements/a-slider.css +1 -1
  97. package/dist/elements/a-slider.d.ts +1 -0
  98. package/dist/elements/a-slider.js +3 -6
  99. package/dist/elements/a-switch.css +1 -1
  100. package/dist/elements/a-switch.d.ts +3 -0
  101. package/dist/elements/a-switch.js +17 -1
  102. package/dist/elements/a-tab.css +1 -1
  103. package/dist/elements/a-tabpanel.css +1 -1
  104. package/dist/elements/a-tabs.css +1 -1
  105. package/dist/elements/a-tag.css +1 -1
  106. package/dist/elements/a-text.css +1 -1
  107. package/dist/elements/a-text.js +1 -0
  108. package/dist/elements/a-title.css +1 -1
  109. package/dist/elements/a-toast.css +1 -1
  110. package/dist/elements/a-toaster.css +1 -1
  111. package/dist/elements/a-tooltip.css +1 -1
  112. package/dist/elements/a-tooltip.d.ts +3 -4
  113. package/dist/elements/a-tooltip.js +30 -8
  114. package/dist/elements/focus.d.ts +9 -0
  115. package/dist/elements/focus.js +41 -0
  116. package/dist/elements/index.d.ts +1 -0
  117. package/dist/elements/index.js +3 -0
  118. package/dist/elements/panel-focus.d.ts +10 -0
  119. package/dist/elements/panel-focus.js +86 -0
  120. package/dist/elements/shadow-aria.d.ts +10 -0
  121. package/dist/elements/shadow-aria.js +155 -0
  122. package/dist/general_types.d.ts +70 -42
  123. package/dist/generate-icons.mjs +3 -0
  124. package/dist/index.d.ts +5 -2
  125. package/dist/index.js +2 -0
  126. package/dist/jsx-runtime.d.ts +10 -1
  127. package/dist/reset.css +1 -1
  128. package/dist/theme-antithesis.css +1 -0
  129. package/dist/theme-antune.css +1 -0
  130. package/dist/tokens.css +1 -1
  131. package/docs/accessibility.md +4 -2
  132. package/docs/changelog.md +135 -0
  133. package/docs/colors.md +7 -7
  134. package/docs/comparison.md +2 -2
  135. package/docs/components/box.md +98 -34
  136. package/docs/components/breadcrumbs.md +75 -6
  137. package/docs/components/button.md +2 -2
  138. package/docs/components/capture.md +8 -8
  139. package/docs/components/checkbox.md +21 -16
  140. package/docs/components/input-autocomplete.md +6 -0
  141. package/docs/components/input-date.md +8 -2
  142. package/docs/components/input.md +99 -40
  143. package/docs/components/menu.md +5 -6
  144. package/docs/components/panel.md +189 -0
  145. package/docs/components/radio.md +16 -13
  146. package/docs/components/select-faceted.md +58 -2
  147. package/docs/components/select.md +72 -59
  148. package/docs/components/steps.md +4 -4
  149. package/docs/components/switch.md +16 -10
  150. package/docs/components/tabs.md +21 -8
  151. package/docs/components/tag.md +5 -3
  152. package/docs/components/tooltip.md +6 -4
  153. package/docs/index.md +1 -0
  154. package/docs/install-config.md +23 -12
  155. package/docs/normalization.md +6 -4
  156. package/docs/theming.md +95 -17
  157. package/package.json +8 -4
  158. package/dist/components/InputDate.module.css +0 -1
  159. package/dist/components/Select.module.css +0 -1
  160. package/dist/components/SelectFaceted.module.css +0 -1
  161. package/dist/search-index.json +0 -0
  162. package/dist/theme-anta.css +0 -1
@@ -1,4 +1,10 @@
1
- import { HTMLElementBase } from "../anta_helpers";
1
+ import { HTMLElementBase, SYNC_POPUP_ARIA } from "../anta_helpers";
2
+ import {
3
+ applyShadowAria,
4
+ ariaAttributeProperty,
5
+ SHADOW_ARIA_ATTRIBUTES,
6
+ SHADOW_ARIA_ATTRIBUTE_SET
7
+ } from "./shadow-aria";
2
8
  import "./a-input.css";
3
9
  const FORWARDED = [
4
10
  "placeholder",
@@ -14,12 +20,7 @@ const FORWARDED = [
14
20
  "required",
15
21
  "min",
16
22
  "max",
17
- "step",
18
- // `aria-label` on the host names the internal control (the actual textbox);
19
- // without forwarding it, a bare `<a-input aria-label>` leaves the control
20
- // unnamed. `applyLabelAria` already defers to a host `aria-label` over the
21
- // label-slot text, so the two don't fight.
22
- "aria-label"
23
+ "step"
23
24
  ];
24
25
  const BOOL_FORWARDED = /* @__PURE__ */ new Set(["readonly", "required"]);
25
26
  let focusFromKeyboard = false;
@@ -83,7 +84,7 @@ const SHADOW_STYLE = `
83
84
  @media (hover: hover) and (pointer: fine) {
84
85
  :host(:not(:disabled)) .field:hover { --_bw: 1px; }
85
86
  }
86
- :host(:not([readonly])) .field:has(input:focus, textarea:focus),
87
+ :host(:not([readonly])) .field:has(input:focus, textarea:focus, button:focus-visible),
87
88
  :host([readonly]:state(kb-focus)) .field {
88
89
  --_bw: 1px;
89
90
  outline: 1px solid var(--focus-ring);
@@ -91,7 +92,7 @@ const SHADOW_STYLE = `
91
92
  }
92
93
  @media (forced-colors: active) { .field { border: 1px solid ButtonBorder; } }
93
94
 
94
- input, textarea {
95
+ input, textarea, button {
95
96
  flex: 1 1 auto;
96
97
  min-width: 0;
97
98
  width: 100%;
@@ -104,27 +105,27 @@ const SHADOW_STYLE = `
104
105
  outline: none;
105
106
  color: var(--input-text);
106
107
  font-family: var(--sans-serif);
107
- font-feature-settings: 'ss02', 'ss05', 'tnum';
108
- font-variation-settings: 'wdth' 100, 'slnt' 0, 'ital' 0;
108
+ font-stretch: normal;
109
+ font-style: normal;
110
+ font-variation-settings: inherit;
109
111
  font-size: var(--_fs);
110
112
  line-height: var(--_lh);
111
113
  font-weight: 400;
112
114
  -webkit-appearance: none;
113
115
  appearance: none;
114
116
  }
115
- @media (pointer: coarse) {
116
- input:focus, textarea:focus { font-size: max(16px, var(--_fs)); }
117
- }
118
117
  textarea {
119
118
  resize: none;
120
119
  padding-block: var(--_pad-block);
121
120
  overflow-y: auto;
122
121
  }
122
+ button { text-align: start; white-space: nowrap; overflow: hidden; cursor: pointer; }
123
+ button.placeholder { color: var(--input-placeholder); }
123
124
  :host([maxrows]:not([rows])) textarea {
124
125
  max-height: calc(var(--_lh) * var(--_maxrows) + var(--_pad-block) * 2);
125
126
  }
126
127
  input::placeholder, textarea::placeholder { color: var(--input-placeholder); opacity: 1; }
127
- input:disabled, textarea:disabled { cursor: not-allowed; }
128
+ input:disabled, textarea:disabled, button:disabled { cursor: not-allowed; }
128
129
  :host([readonly]:not([disabled])) .field,
129
130
  :host([readonly]:not([disabled])) input,
130
131
  :host([readonly]:not([disabled])) textarea { cursor: pointer; }
@@ -142,7 +143,7 @@ const SHADOW_STYLE = `
142
143
  color: var(--input-adornment);
143
144
  font-size: var(--_fs);
144
145
  line-height: var(--_lh);
145
- font-variation-settings: "wdth" 88, "slnt" 0, "ital" 0;
146
+ font-stretch: var(--_input-adornment-font-stretch, normal);
146
147
  }
147
148
  :host([dim-actions]) slot[name="leading"],
148
149
  :host([dim-actions]) slot[name="trailing"],
@@ -183,13 +184,17 @@ const SHADOW_STYLE = `
183
184
  line-height: calc(var(--_lh) - 2px);
184
185
  }
185
186
  `;
187
+ const READ_DELEGATED_ARIA = Symbol("readDelegatedAria");
188
+ const WRITE_DELEGATED_ARIA = Symbol("writeDelegatedAria");
186
189
  class AInputElement extends HTMLElementBase {
187
190
  static formAssociated = true;
188
191
  static observedAttributes = [
189
192
  ...FORWARDED,
193
+ ...SHADOW_ARIA_ATTRIBUTES,
190
194
  "value",
191
195
  "defaultvalue",
192
196
  "multiline",
197
+ "button",
193
198
  "rows",
194
199
  "maxrows",
195
200
  "status",
@@ -211,6 +216,18 @@ class AInputElement extends HTMLElementBase {
211
216
  // Set by formDisabledCallback when an ancestor <fieldset disabled> / disabled
212
217
  // form turns the field off (the host can't carry a [disabled] attribute itself).
213
218
  formDisabled = false;
219
+ // Standard role/aria attributes are consumed from the neutral host and
220
+ // applied to the native shadow control. The values live off-DOM so the host
221
+ // does not become a second control in the accessibility tree.
222
+ delegatedAria = /* @__PURE__ */ new Map();
223
+ consumingAria = /* @__PURE__ */ new Set();
224
+ ariaApplyQueued = false;
225
+ // Direct element relationships supplied by an adjacent a-menu. These avoid
226
+ // renderer-local IDs and apply only when the consumer has not authored the
227
+ // corresponding ARIA relationship explicitly.
228
+ popupAriaSource;
229
+ popupControls = null;
230
+ popupActiveDescendant = null;
214
231
  constructor() {
215
232
  super();
216
233
  try {
@@ -263,14 +280,6 @@ class AInputElement extends HTMLElementBase {
263
280
  }
264
281
  connectedCallback() {
265
282
  trackFocusModality(this.doc);
266
- const type = this.getAttribute("type")?.toLowerCase();
267
- if (this.internals && type !== "number" && type !== "search") {
268
- this.internals.role = "textbox";
269
- } else if (this.internals && type === "number") {
270
- this.internals.role = "spinbutton";
271
- } else if (this.internals && type === "search") {
272
- this.internals.role = "searchbox";
273
- }
274
283
  if (Object.prototype.hasOwnProperty.call(this, "value")) {
275
284
  const v = this.value;
276
285
  delete this.value;
@@ -279,13 +288,34 @@ class AInputElement extends HTMLElementBase {
279
288
  if (!this.control) this.buildControl();
280
289
  this.ready = true;
281
290
  }
291
+ [SYNC_POPUP_ARIA](relations) {
292
+ if (relations.clear) {
293
+ if (this.popupAriaSource !== relations.source) return;
294
+ this.popupAriaSource = void 0;
295
+ this.popupControls = null;
296
+ this.popupActiveDescendant = null;
297
+ } else {
298
+ this.popupAriaSource = relations.source;
299
+ if ("controls" in relations) this.popupControls = relations.controls ?? null;
300
+ if ("activeDescendant" in relations)
301
+ this.popupActiveDescendant = relations.activeDescendant ?? null;
302
+ }
303
+ this.applyPopupAria();
304
+ }
282
305
  attributeChangedCallback(name, _old, value) {
306
+ if (SHADOW_ARIA_ATTRIBUTE_SET.has(name)) {
307
+ if (this.consumingAria.has(name)) return;
308
+ this.consumeAria(name, value);
309
+ return;
310
+ }
283
311
  if (!this.ready && name !== "value" && name !== "defaultvalue") return;
284
- if (name === "multiline" || name === "rows" || name === "maxrows") {
312
+ if (name === "multiline" || name === "button" || name === "rows" || name === "maxrows") {
285
313
  if (!this.control) return;
286
314
  const needTextarea = this.hasAttribute("multiline") || this.hasAttribute("rows");
287
315
  const isTextarea = this.control instanceof HTMLTextAreaElement;
288
- if (needTextarea !== isTextarea) this.buildControl(this.value);
316
+ const needButton = !needTextarea && this.hasAttribute("button");
317
+ const isButton = this.control instanceof HTMLButtonElement;
318
+ if (needTextarea !== isTextarea || needButton !== isButton) this.buildControl(this.value);
289
319
  else if (this.control instanceof HTMLTextAreaElement) this.configureTextarea(this.control);
290
320
  return;
291
321
  }
@@ -305,22 +335,88 @@ class AInputElement extends HTMLElementBase {
305
335
  if (name === "defaultvalue") return;
306
336
  if (this.control) {
307
337
  this.forward(name, value);
338
+ this.syncButtonPresentation();
308
339
  this.updateValidity();
309
340
  }
310
341
  }
342
+ /** Standard ARIA is the raw custom-element API, but its semantic target is the
343
+ * native shadow field. Consume it synchronously so the host never remains a
344
+ * duplicate control after upgrade. */
345
+ consumeAria(name, value) {
346
+ if (value == null) this.delegatedAria.delete(name);
347
+ else this.delegatedAria.set(name, value);
348
+ if (this.hasAttribute(name)) {
349
+ this.consumingAria.add(name);
350
+ super.removeAttribute(name);
351
+ this.consumingAria.delete(name);
352
+ }
353
+ this.applyDelegatedAria(name);
354
+ this.queueDelegatedAria();
355
+ }
356
+ /** React/Preact may remove a prop after Anta has already consumed its host
357
+ * attribute. Catch that no-op DOM removal so the shadow control still updates. */
358
+ removeAttribute(name) {
359
+ if (SHADOW_ARIA_ATTRIBUTE_SET.has(name) && !this.consumingAria.has(name) && !this.hasAttribute(name)) {
360
+ const ariaName = name;
361
+ if (this.delegatedAria.delete(ariaName)) {
362
+ this.applyDelegatedAria(ariaName);
363
+ this.queueDelegatedAria();
364
+ }
365
+ return;
366
+ }
367
+ super.removeAttribute(name);
368
+ }
369
+ toggleAttribute(name, force) {
370
+ if (SHADOW_ARIA_ATTRIBUTE_SET.has(name)) {
371
+ const ariaName = name;
372
+ const next = force ?? !this.delegatedAria.has(ariaName);
373
+ this.consumeAria(ariaName, next ? "" : null);
374
+ return next;
375
+ }
376
+ return super.toggleAttribute(name, force);
377
+ }
378
+ [READ_DELEGATED_ARIA](name) {
379
+ return this.delegatedAria.get(name) ?? null;
380
+ }
381
+ [WRITE_DELEGATED_ARIA](name, value) {
382
+ this.consumeAria(name, value == null ? null : String(value));
383
+ }
384
+ applyDelegatedAria(name) {
385
+ const control = this.control;
386
+ if (!control) return;
387
+ applyShadowAria(this, control, name, this.delegatedAria.get(name) ?? null);
388
+ if (name === "aria-label" || name === "aria-labelledby") this.applyLabelAria();
389
+ if (name === "aria-description" || name === "aria-describedby") this.applyDescriptionAria();
390
+ if (name === "aria-invalid" && !this.delegatedAria.has(name)) this.syncStatus();
391
+ if (name === "aria-controls" || name === "aria-activedescendant") this.applyPopupAria();
392
+ }
393
+ queueDelegatedAria() {
394
+ if (this.ariaApplyQueued) return;
395
+ this.ariaApplyQueued = true;
396
+ queueMicrotask(() => {
397
+ this.ariaApplyQueued = false;
398
+ const control = this.control;
399
+ if (!control) return;
400
+ for (const [name, value] of this.delegatedAria) applyShadowAria(this, control, name, value);
401
+ });
402
+ }
311
403
  /** (Re)build the shadow control from the current attributes. */
312
404
  buildControl(initial) {
313
405
  const prev = this.control;
314
406
  const refocus = prev != null && this.shadowRoot?.activeElement === prev;
315
407
  let selStart = null;
316
408
  let selEnd = null;
317
- if (prev) try {
318
- selStart = prev.selectionStart;
319
- selEnd = prev.selectionEnd;
320
- } catch {
409
+ if (prev instanceof HTMLInputElement || prev instanceof HTMLTextAreaElement) {
410
+ try {
411
+ selStart = prev.selectionStart;
412
+ selEnd = prev.selectionEnd;
413
+ } catch {
414
+ }
321
415
  }
322
416
  const multiline = this.hasAttribute("multiline") || this.hasAttribute("rows");
323
- const next = document.createElement(multiline ? "textarea" : "input");
417
+ const button = !multiline && this.hasAttribute("button");
418
+ const next = document.createElement(button ? "button" : multiline ? "textarea" : "input");
419
+ if (next instanceof HTMLButtonElement) next.type = "button";
324
420
  next.setAttribute("part", "input");
325
421
  if (this.control) this.control.replaceWith(next);
326
422
  else this.leadingSlot.after(next);
@@ -331,23 +427,29 @@ class AInputElement extends HTMLElementBase {
331
427
  }
332
428
  this.syncDisabled();
333
429
  this.syncStatus();
430
+ for (const [name, value2] of this.delegatedAria) applyShadowAria(this, next, name, value2);
431
+ this.queueDelegatedAria();
334
432
  this.applyLabelAria();
335
433
  this.applyDescriptionAria();
434
+ this.applyPopupAria();
336
435
  if (multiline) this.configureTextarea(next);
337
436
  const value = initial ?? this.pendingValue ?? this.getAttribute("value") ?? this.getAttribute("defaultvalue") ?? "";
338
437
  next.value = value;
438
+ this.syncButtonPresentation();
339
439
  next.addEventListener("input", this.onInput);
340
440
  next.addEventListener("change", this.onChange);
341
441
  next.addEventListener("focus", this.onFocus);
342
442
  next.addEventListener("blur", this.onBlur);
343
443
  if (refocus) {
344
444
  next.focus();
345
- if (selStart != null) try {
346
- next.setSelectionRange(selStart, selEnd ?? selStart);
347
- } catch {
445
+ if (selStart != null && (next instanceof HTMLInputElement || next instanceof HTMLTextAreaElement)) {
446
+ try {
447
+ next.setSelectionRange(selStart, selEnd ?? selStart);
448
+ } catch {
449
+ }
348
450
  }
349
451
  }
350
- this.internals?.setFormValue(value);
452
+ this.syncFormValue(value);
351
453
  this.updateValidity();
352
454
  this.updateFilled();
353
455
  this.syncAutoHeight();
@@ -387,6 +489,7 @@ class AInputElement extends HTMLElementBase {
387
489
  forward(name, value) {
388
490
  const c = this.control;
389
491
  if (!c) return;
492
+ if (c instanceof HTMLButtonElement) return;
390
493
  if (c instanceof HTMLTextAreaElement && name === "type") return;
391
494
  if (BOOL_FORWARDED.has(name)) c.toggleAttribute(name, value != null);
392
495
  else if (value == null) c.removeAttribute(name);
@@ -395,6 +498,16 @@ class AInputElement extends HTMLElementBase {
395
498
  syncDisabled() {
396
499
  if (this.control) this.control.disabled = this.hasAttribute("disabled") || this.formDisabled;
397
500
  }
501
+ syncButtonPresentation() {
502
+ const button = this.control;
503
+ if (!(button instanceof HTMLButtonElement)) return;
504
+ const value = button.value;
505
+ button.textContent = value || this.getAttribute("placeholder") || "";
506
+ button.classList.toggle("placeholder", !value);
507
+ }
508
+ syncFormValue(value) {
509
+ this.internals?.setFormValue(this.control instanceof HTMLButtonElement ? null : value);
510
+ }
398
511
  /** Reflect `status` into the control's `aria-invalid` and the `:state(invalid)`
399
512
  * custom state. Called on `status` change AND from buildControl — so a field
400
513
  * that mounts already `status="critical"` gets `:state(invalid)` on the FIRST
@@ -402,7 +515,8 @@ class AInputElement extends HTMLElementBase {
402
515
  * `ready` is false and the early-return skips it). */
403
516
  syncStatus() {
404
517
  const critical = this.getAttribute("status") === "critical";
405
- this.control?.setAttribute("aria-invalid", critical ? "true" : "false");
518
+ const explicit = this.delegatedAria.get("aria-invalid");
519
+ this.control?.setAttribute("aria-invalid", explicit ?? (critical ? "true" : "false"));
406
520
  try {
407
521
  critical ? this.internals?.states?.add("invalid") : this.internals?.states?.delete("invalid");
408
522
  } catch {
@@ -410,7 +524,7 @@ class AInputElement extends HTMLElementBase {
410
524
  }
411
525
  onInput = (event) => {
412
526
  const v = this.control?.value ?? "";
413
- this.internals?.setFormValue(v);
527
+ this.syncFormValue(v);
414
528
  this.updateValidity();
415
529
  this.updateFilled();
416
530
  this.syncAutoHeight();
@@ -443,7 +557,7 @@ class AInputElement extends HTMLElementBase {
443
557
  applyLabelAria() {
444
558
  const c = this.control;
445
559
  if (!c) return;
446
- if (this.hasAttribute("aria-label") || this.hasAttribute("aria-labelledby")) return;
560
+ if (this.delegatedAria.has("aria-label") || this.delegatedAria.has("aria-labelledby")) return;
447
561
  const text = this.labelSlot.assignedNodes().map((n) => n.textContent ?? "").join(" ").trim();
448
562
  if (text) c.setAttribute("aria-label", text);
449
563
  else c.removeAttribute("aria-label");
@@ -454,11 +568,22 @@ class AInputElement extends HTMLElementBase {
454
568
  applyDescriptionAria() {
455
569
  const c = this.control;
456
570
  if (!c) return;
457
- if (this.hasAttribute("aria-description") || this.hasAttribute("aria-describedby")) return;
571
+ if (this.delegatedAria.has("aria-description") || this.delegatedAria.has("aria-describedby")) return;
458
572
  const text = this.hintSlot.assignedNodes().map((n) => n.textContent ?? "").join(" ").trim();
459
573
  if (text) c.setAttribute("aria-description", text);
460
574
  else c.removeAttribute("aria-description");
461
575
  }
576
+ applyPopupAria() {
577
+ const control = this.control;
578
+ if (!control) return;
579
+ try {
580
+ if (!this.delegatedAria.has("aria-controls") && "ariaControlsElements" in control)
581
+ control.ariaControlsElements = this.popupControls ? [this.popupControls] : null;
582
+ if (!this.delegatedAria.has("aria-activedescendant") && "ariaActiveDescendantElement" in control)
583
+ control.ariaActiveDescendantElement = this.popupActiveDescendant;
584
+ } catch {
585
+ }
586
+ }
462
587
  updateFilled() {
463
588
  if (this.value) this.internals?.states?.add("filled");
464
589
  else this.internals?.states?.delete("filled");
@@ -481,7 +606,8 @@ class AInputElement extends HTMLElementBase {
481
606
  set value(v) {
482
607
  this.pendingValue = v;
483
608
  if (this.control && this.control.value !== v) this.control.value = v;
484
- this.internals?.setFormValue(v);
609
+ this.syncButtonPresentation();
610
+ this.syncFormValue(v);
485
611
  this.updateValidity();
486
612
  this.updateFilled();
487
613
  this.syncAutoHeight();
@@ -497,7 +623,8 @@ class AInputElement extends HTMLElementBase {
497
623
  clear() {
498
624
  if (!this.control) return;
499
625
  this.control.value = "";
500
- this.internals?.setFormValue("");
626
+ this.syncButtonPresentation();
627
+ this.syncFormValue("");
501
628
  this.updateValidity();
502
629
  this.updateFilled();
503
630
  this.syncAutoHeight();
@@ -545,6 +672,18 @@ class AInputElement extends HTMLElementBase {
545
672
  this.value = state ?? "";
546
673
  }
547
674
  }
675
+ for (const name of SHADOW_ARIA_ATTRIBUTES) {
676
+ Object.defineProperty(AInputElement.prototype, ariaAttributeProperty(name), {
677
+ configurable: true,
678
+ enumerable: true,
679
+ get() {
680
+ return this[READ_DELEGATED_ARIA](name);
681
+ },
682
+ set(value) {
683
+ this[WRITE_DELEGATED_ARIA](name, value);
684
+ }
685
+ });
686
+ }
548
687
  function register_a_input() {
549
688
  if (typeof customElements === "undefined") return;
550
689
  if (!customElements.get("a-input")) {
@@ -1 +1 @@
1
- @layer anta.components{a-loader{color:var(--text-3)}@media not (forced-colors:active){a-loader[tone=brand]{color:var(--text-2-brand)}a-loader[tone=info]{color:var(--text-2-info)}a-loader[tone=success]{color:var(--text-2-success)}a-loader[tone=warning]{color:var(--text-2-warning)}a-loader[tone=critical]{color:var(--text-2-critical)}}:where(a-loader,a-icon[shape=loader]){display:inline-block;inline-size:var(--loader-size, var(--icon-size, 16px));block-size:var(--loader-size, var(--icon-size, 16px));flex:none;vertical-align:middle;border-radius:50%;animation:loader-spin var(--loader-speed, .75s) linear infinite;animation-delay:-9999s}a-loader{background:conic-gradient(from 0deg,color-mix(in oklch,currentColor 6%,transparent),color-mix(in oklch,currentColor 70%,transparent))}a-icon[shape=loader]{-webkit-mask-image:conic-gradient(from 0deg,color-mix(in oklch,#000 6%,transparent),color-mix(in oklch,#000 70%,transparent));mask-image:conic-gradient(from 0deg,color-mix(in oklch,#000 6%,transparent),color-mix(in oklch,#000 75%,transparent))}a-loader[value]{background:conic-gradient(from 0deg,color-mix(in oklch,currentColor 60%,transparent) 0,color-mix(in oklch,currentColor 75%,transparent) var(--loader-value, 0%),color-mix(in oklch,currentColor 6%,transparent) var(--loader-value, 0%) 100%);animation:none}@keyframes loader-spin{to{transform:rotate(1turn)}}@media(forced-colors:active){a-loader{forced-color-adjust:none;color:CanvasText}}}
1
+ @layer base,anta,components,utilities;@layer anta.reset,anta.components,anta.theme;@layer anta.components{a-loader{color:var(--text-3)}@media not (forced-colors:active){a-loader[tone=brand]{color:var(--text-2-brand)}a-loader[tone=info]{color:var(--text-2-info)}a-loader[tone=success]{color:var(--text-2-success)}a-loader[tone=warning]{color:var(--text-2-warning)}a-loader[tone=critical]{color:var(--text-2-critical)}}:where(a-loader,a-icon[shape=loader]){display:inline-block;inline-size:var(--loader-size, var(--icon-size, 16px));block-size:var(--loader-size, var(--icon-size, 16px));flex:none;vertical-align:middle;border-radius:50%;animation:loader-spin var(--loader-speed, .75s) linear infinite;animation-delay:-9999s}a-loader{background:conic-gradient(from 0deg,color-mix(in oklch,currentColor 6%,transparent),color-mix(in oklch,currentColor 70%,transparent))}a-icon[shape=loader]{-webkit-mask-image:conic-gradient(from 0deg,color-mix(in oklch,#000 6%,transparent),color-mix(in oklch,#000 70%,transparent));mask-image:conic-gradient(from 0deg,color-mix(in oklch,#000 6%,transparent),color-mix(in oklch,#000 75%,transparent))}a-loader[value]{background:conic-gradient(from 0deg,color-mix(in oklch,currentColor 60%,transparent) 0,color-mix(in oklch,currentColor 75%,transparent) var(--loader-value, 0%),color-mix(in oklch,currentColor 6%,transparent) var(--loader-value, 0%) 100%);animation:none}@keyframes loader-spin{to{transform:rotate(1turn)}}@media(forced-colors:active){a-loader{forced-color-adjust:none;color:CanvasText}}}
@@ -1 +1 @@
1
- @layer anta.components{a-menu-group:not(:defined){display:none}a-menu-group{display:flex;flex-direction:column;gap:1px}a-menu-group-label{display:block;padding:6px 8px 2px;color:var(--text-5);font-size:.75em;font-weight:600;letter-spacing:.06em;text-transform:uppercase;user-select:none}}
1
+ @layer base,anta,components,utilities;@layer anta.reset,anta.components,anta.theme;@layer anta.components{a-menu-group:not(:defined){display:none}a-menu-group{display:flex;flex-direction:column;gap:1px}a-menu-group-label{display:block;padding:6px 8px 2px;color:var(--text-5);font-size:.75em;font-weight:600;letter-spacing:.03em;text-transform:uppercase;user-select:none}}
@@ -1 +1 @@
1
- @layer anta.components{a-menu-item:not(:defined){display:none}a[data-anta-menu-item]{text-decoration:none}a-menu-item,a[data-anta-menu-item]{--menu-item-color: var(--text-2);--menu-item-icon-color: var(--text-3);--menu-item-hint-color: var(--text-3);--menu-item-hover: 5%;--menu-item-active: 8%;--menu-item-selected: 8%;--menu-item-timing-in: 60ms ease-in-out;--menu-item-timing-out: .28s ease-out;--menu-item-padding-x: 8px;--menu-item-padding-y: 6px;display:flex;flex-shrink:0;align-items:center;gap:.6ch;box-sizing:border-box;width:100%;min-height:28px;padding-block:var(--menu-item-padding-y);padding-inline:var(--menu-item-padding-x);border-radius:var(--radius-sm, 4px);color:var(--menu-item-color);background:transparent;transition:background-color var(--menu-item-timing-out);font:inherit;font-size:14px;line-height:16px;text-align:left;white-space:nowrap;cursor:pointer;user-select:none;outline:none}a-menu[round] a-menu-item,a-menu[round] a[data-anta-menu-item]{border-radius:999px}a-menu-item:hover,a-menu-item:focus-visible,a[data-anta-menu-item]:hover,a[data-anta-menu-item]:focus-visible,a-menu-item:has(>a-menu:state(open)),a-menu-item:state(active){background:color-mix(in oklch,currentColor var(--menu-item-hover),transparent);transition:background-color var(--menu-item-timing-in)}a-menu-item:active,a[data-anta-menu-item]:active{background:color-mix(in oklch,currentColor var(--menu-item-active),transparent);transition:none}a-menu-item[selected],a[data-anta-menu-item][aria-current=true]{background:color-mix(in oklch,currentColor var(--menu-item-selected),transparent)}a-menu-item:focus-visible,a[data-anta-menu-item]:focus-visible{outline:1px solid var(--focus-ring);outline-offset:1px}a-menu-item>a-menu-item-label,a-menu-item>a-menu-item-text,a[data-anta-menu-item]>a-menu-item-label,a[data-anta-menu-item]>a-menu-item-text{flex:1 1 auto;min-width:0}a-menu-item>a-menu-item-text,a[data-anta-menu-item]>a-menu-item-text{display:flex;flex-direction:column}a-menu-item:has(>a-menu-item-text),a[data-anta-menu-item]:has(>a-menu-item-text){align-items:flex-start}a-menu-item-label{display:block;min-width:0;overflow:hidden;text-overflow:ellipsis}a-menu-item-hint{display:block;min-width:0;overflow:hidden;text-overflow:ellipsis;margin-block-start:1px;color:var(--menu-item-hint-color);font-size:12px;line-height:15px}a-menu-item>a-icon,a[data-anta-menu-item]>a-icon{flex:none;--icon-size: 16px;color:var(--menu-item-icon-color)}a-menu-item>a-checkbox,a-menu-item>a-radio{flex:none;--checkbox-gap: 0;--radio-gap: 0;pointer-events:none}a-menu-item>a-checkbox:before,a-menu-item>a-checkbox:after,a-menu-item>a-radio:before{margin-block-start:0}a-menu-item>a-radio:after{margin-block-start:calc((var(--radio-control-size) - (var(--radio-dot-size) - var(--_radio-dot-adjust))) / 2)}a-menu-item:has(>:is(a-icon,a-checkbox,a-radio,[data-indicator]):first-child:not(:only-child)),a[data-anta-menu-item]:has(>:is(a-icon,[data-indicator]):first-child:not(:only-child)){padding-inline-start:var(--menu-item-padding-y)}a-menu-item:not([submenu]):has(>a-icon:last-child:not(:only-child)),a[data-anta-menu-item]:has(>a-icon:last-child:not(:only-child)){padding-inline-end:max(0px,var(--menu-item-padding-x) - 2px)}a-menu-item>kbd,a[data-anta-menu-item]>kbd{flex:none;margin-left:auto;padding-left:12px;color:var(--text-5);font:inherit;font-size:1em;letter-spacing:.1ch;white-space:nowrap}a-menu-item[submenu]>a-icon:last-of-type{margin-left:auto}a-menu-item[submenu]>a-icon:last-of-type,a-menu-item>a-icon:last-child:not(:only-child),a[data-anta-menu-item]>a-icon:last-child:not(:only-child){position:relative;inset-inline-end:-2px}a-menu-item[tone=brand],a-menu-item[tone=info],a-menu-item[tone=success],a-menu-item[tone=warning],a-menu-item[tone=critical],a[data-anta-menu-item][tone=brand],a[data-anta-menu-item][tone=info],a[data-anta-menu-item][tone=success],a[data-anta-menu-item][tone=warning],a[data-anta-menu-item][tone=critical]{--menu-item-icon-color: var(--menu-item-color)}a-menu-item[tone=brand],a[data-anta-menu-item][tone=brand]{--menu-item-color: var(--text-2-brand);--menu-item-hint-color: var(--text-3-brand)}a-menu-item[tone=info],a[data-anta-menu-item][tone=info]{--menu-item-color: var(--text-2-info);--menu-item-hint-color: var(--text-3-info)}a-menu-item[tone=success],a[data-anta-menu-item][tone=success]{--menu-item-color: var(--text-2-success);--menu-item-hint-color: var(--text-3-success)}a-menu-item[tone=warning],a[data-anta-menu-item][tone=warning]{--menu-item-color: var(--text-2-warning);--menu-item-hint-color: var(--text-3-warning)}a-menu-item[tone=critical],a[data-anta-menu-item][tone=critical]{--menu-item-color: var(--text-2-critical);--menu-item-hint-color: var(--text-3-critical)}a-menu-item[tone]:not([tone=""],[tone=brand],[tone=neutral],[tone=info],[tone=success],[tone=warning],[tone=critical]),a[data-anta-menu-item][tone]:not([tone=""],[tone=brand],[tone=neutral],[tone=info],[tone=success],[tone=warning],[tone=critical]){--menu-item-tone-source: var(--text-2);--menu-item-color: oklch(from var(--menu-item-tone-source) .45 c h);--menu-item-icon-color: var(--menu-item-color);--menu-item-hint-color: oklch(from var(--menu-item-tone-source) .45 c h / .8);.dark &{--menu-item-color: oklch(from var(--menu-item-tone-source) .78 c h);--menu-item-hint-color: oklch(from var(--menu-item-tone-source) .78 c h / .8)}@supports (color: attr(probe type(<color>),red)){--menu-item-tone-source: attr(tone type(<color>), var(--text-2))}}a-menu-item[disabled],a[data-anta-menu-item][aria-disabled=true]{--menu-item-color: var(--text-5);--menu-item-icon-color: var(--text-5);--menu-item-hint-color: var(--text-5);cursor:default;pointer-events:none}.dark a-menu-item,.dark a[data-anta-menu-item]{--menu-item-hover: 10%;--menu-item-active: 14%;--menu-item-selected: 14%}}
1
+ @layer base,anta,components,utilities;@layer anta.reset,anta.components,anta.theme;@layer anta.components{a-menu-item:not(:defined){display:none}a[data-anta-menu-item]{text-decoration:none}a-menu-item,a[data-anta-menu-item]{--menu-item-color: var(--text-2);--menu-item-icon-color: var(--text-3);--menu-item-hint-color: var(--text-3);--menu-item-hover-bg: light-dark( color-mix(in oklch, currentColor 5%, transparent), color-mix(in oklch, currentColor 10%, transparent) );--menu-item-active-bg: light-dark( color-mix(in oklch, currentColor 8%, transparent), color-mix(in oklch, currentColor 14%, transparent) );--menu-item-selected-bg: var(--menu-item-active-bg);--menu-item-timing-in: 60ms ease-in-out;--menu-item-timing-out: .28s ease-out;--menu-item-padding-x: 8px;--menu-item-padding-y: 6px;display:flex;flex-shrink:0;align-items:center;gap:.6ch;box-sizing:border-box;width:100%;min-height:28px;padding-block:var(--menu-item-padding-y);padding-inline:var(--menu-item-padding-x);border-radius:var(--radius-sm, 4px);color:var(--menu-item-color);background:transparent;transition:background-color var(--menu-item-timing-out);font:inherit;font-variation-settings:inherit;font-size:14px;line-height:16px;text-align:left;white-space:nowrap;cursor:pointer;user-select:none;outline:none}a-menu[round] a-menu-item,a-menu[round] a[data-anta-menu-item]{border-radius:999px}a-menu-item:hover,a-menu-item:focus-visible,a[data-anta-menu-item]:hover,a[data-anta-menu-item]:focus-visible,a-menu-item:has(>a-menu:state(open)),a-menu-item:state(active){background:var(--menu-item-hover-bg);transition:background-color var(--menu-item-timing-in)}a-menu-item:active,a[data-anta-menu-item]:active{background:var(--menu-item-active-bg);transition:none}a-menu-item[selected],a[data-anta-menu-item][aria-current=true]{background:var(--menu-item-selected-bg)}a-menu-item:focus-visible,a[data-anta-menu-item]:focus-visible{outline:1px solid var(--focus-ring);outline-offset:1px}a-menu-item>a-menu-item-label,a-menu-item>a-menu-item-text,a[data-anta-menu-item]>a-menu-item-label,a[data-anta-menu-item]>a-menu-item-text{flex:1 1 auto;min-width:0}a-menu-item>a-menu-item-text,a[data-anta-menu-item]>a-menu-item-text{display:flex;flex-direction:column}a-menu-item:has(>a-menu-item-text),a[data-anta-menu-item]:has(>a-menu-item-text){align-items:flex-start}a-menu-item-label{display:block;min-width:0;overflow:hidden;text-overflow:ellipsis}a-menu-item-hint{display:block;min-width:0;overflow:hidden;text-overflow:ellipsis;margin-block-start:1px;color:var(--menu-item-hint-color);font-size:12px;line-height:15px}a-menu-item>a-icon,a[data-anta-menu-item]>a-icon{flex:none;--icon-size: 16px;color:var(--menu-item-icon-color)}a-menu-item>a-checkbox,a-menu-item>a-radio{flex:none;--checkbox-gap: 0;--radio-gap: 0;pointer-events:none}a-menu-item>a-checkbox:before,a-menu-item>a-checkbox:after,a-menu-item>a-radio:before{margin-block-start:0}a-menu-item>a-radio:after{margin-block-start:calc((var(--radio-control-size) - (var(--radio-dot-size) - var(--_radio-dot-adjust))) / 2)}a-menu-item:has(>:is(a-icon,a-checkbox,a-radio,[data-indicator]):first-child:not(:only-child)),a[data-anta-menu-item]:has(>:is(a-icon,[data-indicator]):first-child:not(:only-child)){padding-inline-start:var(--menu-item-padding-y)}a-menu-item:not([submenu]):has(>a-icon:last-child:not(:only-child)),a[data-anta-menu-item]:has(>a-icon:last-child:not(:only-child)){padding-inline-end:max(0px,var(--menu-item-padding-x) - 2px)}a-menu-item>kbd,a[data-anta-menu-item]>kbd{flex:none;margin-left:auto;padding-left:12px;color:var(--text-5);font:inherit;font-variation-settings:inherit;font-size:1em;letter-spacing:.1ch;white-space:nowrap}a-menu-item[submenu]>a-icon:last-of-type{margin-left:auto}a-menu-item[submenu]>a-icon:last-of-type,a-menu-item>a-icon:last-child:not(:only-child),a[data-anta-menu-item]>a-icon:last-child:not(:only-child){position:relative;inset-inline-end:-2px}a-menu-item[tone=brand],a-menu-item[tone=info],a-menu-item[tone=success],a-menu-item[tone=warning],a-menu-item[tone=critical],a[data-anta-menu-item][tone=brand],a[data-anta-menu-item][tone=info],a[data-anta-menu-item][tone=success],a[data-anta-menu-item][tone=warning],a[data-anta-menu-item][tone=critical]{--menu-item-icon-color: var(--menu-item-color)}a-menu-item[tone=brand],a[data-anta-menu-item][tone=brand]{--menu-item-color: var(--text-2-brand);--menu-item-hint-color: var(--text-3-brand)}a-menu-item[tone=info],a[data-anta-menu-item][tone=info]{--menu-item-color: var(--text-2-info);--menu-item-hint-color: var(--text-3-info)}a-menu-item[tone=success],a[data-anta-menu-item][tone=success]{--menu-item-color: var(--text-2-success);--menu-item-hint-color: var(--text-3-success)}a-menu-item[tone=warning],a[data-anta-menu-item][tone=warning]{--menu-item-color: var(--text-2-warning);--menu-item-hint-color: var(--text-3-warning)}a-menu-item[tone=critical],a[data-anta-menu-item][tone=critical]{--menu-item-color: var(--text-2-critical);--menu-item-hint-color: var(--text-3-critical)}a-menu-item[tone]:not([tone=""],[tone=brand],[tone=neutral],[tone=info],[tone=success],[tone=warning],[tone=critical]),a[data-anta-menu-item][tone]:not([tone=""],[tone=brand],[tone=neutral],[tone=info],[tone=success],[tone=warning],[tone=critical]){--menu-item-tone-source: var(--text-2);--menu-item-color: light-dark( oklch(from var(--menu-item-tone-source) .45 c h), oklch(from var(--menu-item-tone-source) .78 c h) );--menu-item-icon-color: var(--menu-item-color);--menu-item-hint-color: light-dark( oklch(from var(--menu-item-tone-source) .45 c h / .8), oklch(from var(--menu-item-tone-source) .78 c h / .8) );@supports (color: attr(probe type(<color>),red)){--menu-item-tone-source: attr(tone type(<color>), var(--text-2))}}a-menu-item[disabled],a[data-anta-menu-item][aria-disabled=true]{--menu-item-color: var(--text-5);--menu-item-icon-color: var(--text-5);--menu-item-hint-color: var(--text-5);cursor:default;pointer-events:none}}
@@ -15,6 +15,7 @@ class AMenuItemElement extends HTMLElementBase {
15
15
  if (!this.internals) return;
16
16
  if (on) this.internals?.states?.add("active");
17
17
  else this.internals?.states?.delete("active");
18
+ this.internals.ariaSelected = this.getAttribute("role") === "option" ? on ? "true" : "false" : null;
18
19
  }
19
20
  get active() {
20
21
  return this.internals?.states?.has("active") ?? false;
@@ -1 +1 @@
1
- @layer anta.components{a-menu-separator:not(:defined){display:none}a-menu-separator{--menu-separator-label-size: 13px;display:block;flex-shrink:0;height:1px;margin:2px 4px;background:var(--border-5)}a-menu-separator:not(:empty){height:auto;margin:0;padding:6px 8px;background:none;color:var(--text-3);font-size:var(--menu-separator-label-size);line-height:1.3;user-select:none}}
1
+ @layer base,anta,components,utilities;@layer anta.reset,anta.components,anta.theme;@layer anta.components{a-menu-separator:not(:defined){display:none}a-menu-separator{--menu-separator-label-size: 13px;display:block;flex-shrink:0;height:1px;margin:2px 4px;background:var(--border-5)}a-menu-separator:not(:empty){height:auto;margin:0;padding:6px 8px;background:none;color:var(--text-3);font-size:var(--menu-separator-label-size);line-height:1.3;user-select:none}}
@@ -1 +1 @@
1
- @layer anta.components{a-menu:not(:defined){display:none}a-menu{--menu-bg: color-mix(in oklch, var(--bg-1) 90%, transparent);--menu-radius: var(--radius-md, 8px);--menu-border: 1px solid var(--border-3);--menu-shadow: 0 2px 6px color-mix(in oklch, var(--text-1) 8%, transparent), 0 8px 24px color-mix(in oklch, var(--text-1) 10%, transparent);--menu-padding: 4px;--menu-min-width: 88px;--menu-backdrop-filter: blur(20px);--menu-width-duration: .16s}@media(prefers-reduced-motion:reduce){a-menu{--menu-width-duration: 0}}a-menu[round]{--menu-radius: 20px;@supports (border-radius: attr(probe type(<length>),1px)){--menu-radius: attr(round type(<length>), 20px)}}.dark a-menu{--menu-bg: color-mix(in oklch, var(--bg-1) 78%, transparent);--menu-shadow: 0 2px 8px color-mix(in oklch, black 50%, transparent), 0 12px 32px color-mix(in oklch, black 40%, transparent), inset 0 0 0 1px color-mix(in oklch, white 8%, transparent)}}
1
+ @layer base,anta,components,utilities;@layer anta.reset,anta.components,anta.theme;@layer anta.components{a-menu:not(:defined){display:none}a-menu{--menu-bg: light-dark( color-mix(in oklch, var(--bg-1) 90%, transparent), color-mix(in oklch, var(--bg-1) 78%, transparent) );--menu-radius: var(--radius-md, 8px);--menu-border: 1px solid var(--border-3);--menu-shadow: 0 2px 6px color-mix(in oklch, var(--text-1) 8%, transparent), 0 8px 24px color-mix(in oklch, var(--text-1) 10%, transparent);--menu-padding: 4px;--menu-min-width: 88px;--menu-backdrop-filter: blur(20px);--menu-width-duration: .16s}@media(prefers-reduced-motion:reduce){a-menu{--menu-width-duration: 0}}a-menu[round]{--menu-radius: 20px;@supports (border-radius: attr(probe type(<length>),1px)){--menu-radius: attr(round type(<length>), 20px)}}.dark a-menu{--menu-shadow: 0 2px 8px color-mix(in oklch, black 50%, transparent), 0 12px 32px color-mix(in oklch, black 40%, transparent), inset 0 0 0 1px color-mix(in oklch, white 8%, transparent)}}
@@ -42,6 +42,7 @@ export declare class AMenuElement extends HTMLElementBase {
42
42
  private typeTimer?;
43
43
  private activeItem;
44
44
  private comboObserver?;
45
+ private accessibilityObserver?;
45
46
  private _flippedTop;
46
47
  private _flippedSide;
47
48
  constructor();
@@ -73,9 +74,7 @@ export declare class AMenuElement extends HTMLElementBase {
73
74
  * `.focus()` on one silently fails). `getClientRects` is the fallback where
74
75
  * `checkVisibility` isn't available. */
75
76
  private isVisible;
76
- /** The subset of `focusables()` that are menu items (drives arrow / Home /
77
- * End / type-ahead navigation). Same visibility / disabled / ownership
78
- * filter — just narrowed to `a-menu-item`. */
77
+ /** Custom menu rows that support the combobox cursor and selection state. */
79
78
  private focusableItems;
80
79
  /** The rows the arrow keys / Home / End / initial-focus step between:
81
80
  * `focusableItems()` PLUS native-anchor link items (`<a data-anta-menu-item>`),
@@ -83,10 +82,7 @@ export declare class AMenuElement extends HTMLElementBase {
83
82
  * custom-element-only because the combobox cursor (`setActive`) and selection
84
83
  * seating are `a-menu-item` affordances a plain link doesn't carry. */
85
84
  private navigableItems;
86
- /** Every tabbable element belonging to THIS menu (items + nested controls
87
- * like inputs / sliders / buttons), in DOM order, visible and enabled —
88
- * used to trap Tab within the open menu. Submenu contents are excluded
89
- * (their nearest `a-menu` is the submenu). */
85
+ /** Tab stops in rendered order, excluding controls owned by nested menus. */
90
86
  private focusables;
91
87
  /** On open, seat initial focus like a native `<select>` / macOS menu: a menu
92
88
  * carrying a current value opens *at* that value, not at the top. Brings the
@@ -107,10 +103,9 @@ export declare class AMenuElement extends HTMLElementBase {
107
103
  * `.scroll` mask reads; runs on scroll and after every (re)position.
108
104
  * Shadow-internal only. */
109
105
  private updateScrollFade;
110
- /** Move the combobox cursor. Sets the item's `active` **property** (off-DOM
111
- * `:state(active)`, no attribute churn) for the highlight, and REPORTS the
112
- * active id via the `activedescendant` event so the reactive layer can set
113
- * `aria-activedescendant` on the light-DOM field. `null` clears the cursor. */
106
+ /** Move the combobox cursor. Sets the item's `active` property for its
107
+ * off-DOM highlight/selected state, associates it directly with an Anta
108
+ * Input, and reports it for raw/custom observers. `null` clears the cursor. */
114
109
  private setActive;
115
110
  /** Re-seat the cursor on the first option — but only once the filter has input.
116
111
  * An empty filter (e.g. right after opening) shows NO active row, so the first
@@ -168,8 +163,8 @@ export declare class AMenuElement extends HTMLElementBase {
168
163
  * mutates deep in its subtree, not this menu's direct children, so it won't
169
164
  * spuriously reset the cursor. */
170
165
  private startComboObserver;
171
- /** Apply CLOSE to the DOM (no event). Closes this menu and everything stacked
172
- * above it (its submenus). */
166
+ /** Apply CLOSE without notifying this menu's owner. Notify nested menus so
167
+ * their controlled state follows the closing parent. */
173
168
  private hide;
174
169
  /** Shadow-only show: open the popover and position it. `instant` positions
175
170
  * synchronously (no rAF), so a menu opening over an already-visible one is