@antadesign/anta 0.3.28 → 0.3.30

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 (142) hide show
  1. package/NOTICES.md +32 -1
  2. package/dist/anta_helpers.d.ts +21 -0
  3. package/dist/anta_helpers.js +24 -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 +66 -29
  9. package/dist/components/Box.d.ts +28 -12
  10. package/dist/components/Box.js +18 -11
  11. package/dist/components/Breadcrumbs.css +1 -1
  12. package/dist/components/Breadcrumbs.d.ts +1 -1
  13. package/dist/components/Button.d.ts +3 -3
  14. package/dist/components/ButtonCopy.d.ts +1 -1
  15. package/dist/components/Calendar.js +3 -5
  16. package/dist/components/Checkbox.d.ts +2 -2
  17. package/dist/components/Input.d.ts +8 -2
  18. package/dist/components/Input.js +4 -0
  19. package/dist/components/InputAutocomplete.js +3 -12
  20. package/dist/components/InputDate.css +1 -1
  21. package/dist/components/InputDate.js +2 -0
  22. package/dist/components/Menu.d.ts +4 -4
  23. package/dist/components/Menu.js +1 -1
  24. package/dist/components/Panel.d.ts +17 -0
  25. package/dist/components/Panel.js +22 -0
  26. package/dist/components/RadioGroup.d.ts +2 -1
  27. package/dist/components/Select.d.ts +14 -14
  28. package/dist/components/Select.js +47 -35
  29. package/dist/components/SelectFaceted.d.ts +17 -6
  30. package/dist/components/SelectFaceted.js +61 -41
  31. package/dist/components/Steps.css +1 -1
  32. package/dist/components/Switch.d.ts +3 -3
  33. package/dist/components/TabPanel.d.ts +3 -8
  34. package/dist/components/TabPanel.js +2 -1
  35. package/dist/components/Tabs.d.ts +2 -2
  36. package/dist/components/Tabs.js +2 -1
  37. package/dist/components/Tooltip.d.ts +1 -1
  38. package/dist/components/Tooltip.js +1 -1
  39. package/dist/components/select-parts.css +1 -1
  40. package/dist/elements/a-avatar.css +1 -1
  41. package/dist/elements/a-banner.css +1 -1
  42. package/dist/elements/a-box.css +1 -1
  43. package/dist/elements/a-box.d.ts +6 -6
  44. package/dist/elements/a-box.js +76 -23
  45. package/dist/elements/a-button.css +1 -1
  46. package/dist/elements/a-button.d.ts +9 -1
  47. package/dist/elements/a-button.js +64 -1
  48. package/dist/elements/a-calendar.css +1 -1
  49. package/dist/elements/a-capture.css +1 -1
  50. package/dist/elements/a-card.css +1 -1
  51. package/dist/elements/a-checkbox.css +1 -1
  52. package/dist/elements/a-checkbox.d.ts +3 -0
  53. package/dist/elements/a-checkbox.js +17 -1
  54. package/dist/elements/a-copy.css +1 -1
  55. package/dist/elements/a-dialog.css +1 -1
  56. package/dist/elements/a-expander.css +1 -1
  57. package/dist/elements/a-icon.css +1 -1
  58. package/dist/elements/a-icon.shapes.css +1 -1
  59. package/dist/elements/a-icon.shapes.d.ts +1 -1
  60. package/dist/elements/a-input-time.css +1 -1
  61. package/dist/elements/a-input-time.d.ts +8 -0
  62. package/dist/elements/a-input-time.js +115 -8
  63. package/dist/elements/a-input.css +1 -1
  64. package/dist/elements/a-input.d.ts +27 -1
  65. package/dist/elements/a-input.js +176 -35
  66. package/dist/elements/a-loader.css +1 -1
  67. package/dist/elements/a-menu-group.css +1 -1
  68. package/dist/elements/a-menu-item.css +1 -1
  69. package/dist/elements/a-menu-item.js +1 -0
  70. package/dist/elements/a-menu-separator.css +1 -1
  71. package/dist/elements/a-menu.css +1 -1
  72. package/dist/elements/a-menu.d.ts +8 -13
  73. package/dist/elements/a-menu.js +146 -45
  74. package/dist/elements/a-panel.css +1 -0
  75. package/dist/elements/a-panel.d.ts +16 -0
  76. package/dist/elements/a-panel.js +153 -0
  77. package/dist/elements/a-progress.css +1 -1
  78. package/dist/elements/a-radio-group.css +1 -1
  79. package/dist/elements/a-radio.css +1 -1
  80. package/dist/elements/a-radio.d.ts +4 -0
  81. package/dist/elements/a-radio.js +18 -0
  82. package/dist/elements/a-slider.css +1 -1
  83. package/dist/elements/a-slider.d.ts +1 -0
  84. package/dist/elements/a-slider.js +3 -3
  85. package/dist/elements/a-switch.css +1 -1
  86. package/dist/elements/a-switch.d.ts +3 -0
  87. package/dist/elements/a-switch.js +17 -1
  88. package/dist/elements/a-tab.css +1 -1
  89. package/dist/elements/a-tabpanel.css +1 -1
  90. package/dist/elements/a-tabs.css +1 -1
  91. package/dist/elements/a-tag.css +1 -1
  92. package/dist/elements/a-text.css +1 -1
  93. package/dist/elements/a-title.css +1 -1
  94. package/dist/elements/a-toast.css +1 -1
  95. package/dist/elements/a-toaster.css +1 -1
  96. package/dist/elements/a-tooltip.css +1 -1
  97. package/dist/elements/a-tooltip.js +30 -7
  98. package/dist/elements/focus.d.ts +9 -0
  99. package/dist/elements/focus.js +41 -0
  100. package/dist/elements/index.d.ts +1 -0
  101. package/dist/elements/index.js +3 -0
  102. package/dist/elements/panel-focus.d.ts +10 -0
  103. package/dist/elements/panel-focus.js +86 -0
  104. package/dist/elements/shadow-aria.d.ts +10 -0
  105. package/dist/elements/shadow-aria.js +155 -0
  106. package/dist/general_types.d.ts +48 -19
  107. package/dist/generate-icons.mjs +3 -0
  108. package/dist/index.d.ts +4 -1
  109. package/dist/index.js +2 -0
  110. package/dist/jsx-runtime.d.ts +20 -1
  111. package/dist/jsx-runtime.js +12 -0
  112. package/dist/reset.css +1 -1
  113. package/dist/theme-antithesis.css +1 -1
  114. package/dist/theme-antune.css +1 -1
  115. package/dist/toaster.d.ts +1 -1
  116. package/dist/tokens.css +1 -1
  117. package/docs/accessibility.md +4 -2
  118. package/docs/changelog.md +89 -4
  119. package/docs/colors.md +6 -6
  120. package/docs/components/box.md +98 -34
  121. package/docs/components/breadcrumbs.md +33 -0
  122. package/docs/components/button.md +2 -2
  123. package/docs/components/capture.md +8 -8
  124. package/docs/components/checkbox.md +9 -4
  125. package/docs/components/input-autocomplete.md +6 -0
  126. package/docs/components/input-date.md +8 -2
  127. package/docs/components/input.md +99 -40
  128. package/docs/components/menu.md +3 -3
  129. package/docs/components/panel.md +189 -0
  130. package/docs/components/radio.md +4 -2
  131. package/docs/components/select-faceted.md +57 -2
  132. package/docs/components/select.md +63 -51
  133. package/docs/components/steps.md +4 -4
  134. package/docs/components/switch.md +12 -6
  135. package/docs/components/tabs.md +21 -8
  136. package/docs/components/tooltip.md +6 -4
  137. package/docs/index.md +2 -0
  138. package/docs/install-config.md +5 -4
  139. package/docs/normalization.md +3 -1
  140. package/docs/packages/plot.md +3771 -0
  141. package/docs/theming.md +1 -1
  142. package/package.json +16 -9
@@ -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%;
@@ -118,11 +119,13 @@ const SHADOW_STYLE = `
118
119
  padding-block: var(--_pad-block);
119
120
  overflow-y: auto;
120
121
  }
122
+ button { text-align: start; white-space: nowrap; overflow: hidden; cursor: pointer; }
123
+ button.placeholder { color: var(--input-placeholder); }
121
124
  :host([maxrows]:not([rows])) textarea {
122
125
  max-height: calc(var(--_lh) * var(--_maxrows) + var(--_pad-block) * 2);
123
126
  }
124
127
  input::placeholder, textarea::placeholder { color: var(--input-placeholder); opacity: 1; }
125
- input:disabled, textarea:disabled { cursor: not-allowed; }
128
+ input:disabled, textarea:disabled, button:disabled { cursor: not-allowed; }
126
129
  :host([readonly]:not([disabled])) .field,
127
130
  :host([readonly]:not([disabled])) input,
128
131
  :host([readonly]:not([disabled])) textarea { cursor: pointer; }
@@ -181,13 +184,17 @@ const SHADOW_STYLE = `
181
184
  line-height: calc(var(--_lh) - 2px);
182
185
  }
183
186
  `;
187
+ const READ_DELEGATED_ARIA = /* @__PURE__ */ Symbol("readDelegatedAria");
188
+ const WRITE_DELEGATED_ARIA = /* @__PURE__ */ Symbol("writeDelegatedAria");
184
189
  class AInputElement extends HTMLElementBase {
185
190
  static formAssociated = true;
186
191
  static observedAttributes = [
187
192
  ...FORWARDED,
193
+ ...SHADOW_ARIA_ATTRIBUTES,
188
194
  "value",
189
195
  "defaultvalue",
190
196
  "multiline",
197
+ "button",
191
198
  "rows",
192
199
  "maxrows",
193
200
  "status",
@@ -209,6 +216,18 @@ class AInputElement extends HTMLElementBase {
209
216
  // Set by formDisabledCallback when an ancestor <fieldset disabled> / disabled
210
217
  // form turns the field off (the host can't carry a [disabled] attribute itself).
211
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;
212
231
  constructor() {
213
232
  super();
214
233
  try {
@@ -261,14 +280,6 @@ class AInputElement extends HTMLElementBase {
261
280
  }
262
281
  connectedCallback() {
263
282
  trackFocusModality(this.doc);
264
- const type = this.getAttribute("type")?.toLowerCase();
265
- if (this.internals && type !== "number" && type !== "search") {
266
- this.internals.role = "textbox";
267
- } else if (this.internals && type === "number") {
268
- this.internals.role = "spinbutton";
269
- } else if (this.internals && type === "search") {
270
- this.internals.role = "searchbox";
271
- }
272
283
  if (Object.prototype.hasOwnProperty.call(this, "value")) {
273
284
  const v = this.value;
274
285
  delete this.value;
@@ -277,13 +288,34 @@ class AInputElement extends HTMLElementBase {
277
288
  if (!this.control) this.buildControl();
278
289
  this.ready = true;
279
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
+ }
280
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
+ }
281
311
  if (!this.ready && name !== "value" && name !== "defaultvalue") return;
282
- if (name === "multiline" || name === "rows" || name === "maxrows") {
312
+ if (name === "multiline" || name === "button" || name === "rows" || name === "maxrows") {
283
313
  if (!this.control) return;
284
314
  const needTextarea = this.hasAttribute("multiline") || this.hasAttribute("rows");
285
315
  const isTextarea = this.control instanceof HTMLTextAreaElement;
286
- 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);
287
319
  else if (this.control instanceof HTMLTextAreaElement) this.configureTextarea(this.control);
288
320
  return;
289
321
  }
@@ -303,22 +335,88 @@ class AInputElement extends HTMLElementBase {
303
335
  if (name === "defaultvalue") return;
304
336
  if (this.control) {
305
337
  this.forward(name, value);
338
+ this.syncButtonPresentation();
306
339
  this.updateValidity();
307
340
  }
308
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
+ }
309
403
  /** (Re)build the shadow control from the current attributes. */
310
404
  buildControl(initial) {
311
405
  const prev = this.control;
312
406
  const refocus = prev != null && this.shadowRoot?.activeElement === prev;
313
407
  let selStart = null;
314
408
  let selEnd = null;
315
- if (prev) try {
316
- selStart = prev.selectionStart;
317
- selEnd = prev.selectionEnd;
318
- } catch {
409
+ if (prev instanceof HTMLInputElement || prev instanceof HTMLTextAreaElement) {
410
+ try {
411
+ selStart = prev.selectionStart;
412
+ selEnd = prev.selectionEnd;
413
+ } catch {
414
+ }
319
415
  }
320
416
  const multiline = this.hasAttribute("multiline") || this.hasAttribute("rows");
321
- 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";
322
420
  next.setAttribute("part", "input");
323
421
  if (this.control) this.control.replaceWith(next);
324
422
  else this.leadingSlot.after(next);
@@ -329,23 +427,29 @@ class AInputElement extends HTMLElementBase {
329
427
  }
330
428
  this.syncDisabled();
331
429
  this.syncStatus();
430
+ for (const [name, value2] of this.delegatedAria) applyShadowAria(this, next, name, value2);
431
+ this.queueDelegatedAria();
332
432
  this.applyLabelAria();
333
433
  this.applyDescriptionAria();
434
+ this.applyPopupAria();
334
435
  if (multiline) this.configureTextarea(next);
335
436
  const value = initial ?? this.pendingValue ?? this.getAttribute("value") ?? this.getAttribute("defaultvalue") ?? "";
336
437
  next.value = value;
438
+ this.syncButtonPresentation();
337
439
  next.addEventListener("input", this.onInput);
338
440
  next.addEventListener("change", this.onChange);
339
441
  next.addEventListener("focus", this.onFocus);
340
442
  next.addEventListener("blur", this.onBlur);
341
443
  if (refocus) {
342
444
  next.focus();
343
- if (selStart != null) try {
344
- next.setSelectionRange(selStart, selEnd ?? selStart);
345
- } catch {
445
+ if (selStart != null && (next instanceof HTMLInputElement || next instanceof HTMLTextAreaElement)) {
446
+ try {
447
+ next.setSelectionRange(selStart, selEnd ?? selStart);
448
+ } catch {
449
+ }
346
450
  }
347
451
  }
348
- this.internals?.setFormValue(value);
452
+ this.syncFormValue(value);
349
453
  this.updateValidity();
350
454
  this.updateFilled();
351
455
  this.syncAutoHeight();
@@ -385,6 +489,7 @@ class AInputElement extends HTMLElementBase {
385
489
  forward(name, value) {
386
490
  const c = this.control;
387
491
  if (!c) return;
492
+ if (c instanceof HTMLButtonElement) return;
388
493
  if (c instanceof HTMLTextAreaElement && name === "type") return;
389
494
  if (BOOL_FORWARDED.has(name)) c.toggleAttribute(name, value != null);
390
495
  else if (value == null) c.removeAttribute(name);
@@ -393,6 +498,16 @@ class AInputElement extends HTMLElementBase {
393
498
  syncDisabled() {
394
499
  if (this.control) this.control.disabled = this.hasAttribute("disabled") || this.formDisabled;
395
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
+ }
396
511
  /** Reflect `status` into the control's `aria-invalid` and the `:state(invalid)`
397
512
  * custom state. Called on `status` change AND from buildControl — so a field
398
513
  * that mounts already `status="critical"` gets `:state(invalid)` on the FIRST
@@ -400,7 +515,8 @@ class AInputElement extends HTMLElementBase {
400
515
  * `ready` is false and the early-return skips it). */
401
516
  syncStatus() {
402
517
  const critical = this.getAttribute("status") === "critical";
403
- 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"));
404
520
  try {
405
521
  critical ? this.internals?.states?.add("invalid") : this.internals?.states?.delete("invalid");
406
522
  } catch {
@@ -408,7 +524,7 @@ class AInputElement extends HTMLElementBase {
408
524
  }
409
525
  onInput = (event) => {
410
526
  const v = this.control?.value ?? "";
411
- this.internals?.setFormValue(v);
527
+ this.syncFormValue(v);
412
528
  this.updateValidity();
413
529
  this.updateFilled();
414
530
  this.syncAutoHeight();
@@ -441,7 +557,7 @@ class AInputElement extends HTMLElementBase {
441
557
  applyLabelAria() {
442
558
  const c = this.control;
443
559
  if (!c) return;
444
- if (this.hasAttribute("aria-label") || this.hasAttribute("aria-labelledby")) return;
560
+ if (this.delegatedAria.has("aria-label") || this.delegatedAria.has("aria-labelledby")) return;
445
561
  const text = this.labelSlot.assignedNodes().map((n) => n.textContent ?? "").join(" ").trim();
446
562
  if (text) c.setAttribute("aria-label", text);
447
563
  else c.removeAttribute("aria-label");
@@ -452,11 +568,22 @@ class AInputElement extends HTMLElementBase {
452
568
  applyDescriptionAria() {
453
569
  const c = this.control;
454
570
  if (!c) return;
455
- if (this.hasAttribute("aria-description") || this.hasAttribute("aria-describedby")) return;
571
+ if (this.delegatedAria.has("aria-description") || this.delegatedAria.has("aria-describedby")) return;
456
572
  const text = this.hintSlot.assignedNodes().map((n) => n.textContent ?? "").join(" ").trim();
457
573
  if (text) c.setAttribute("aria-description", text);
458
574
  else c.removeAttribute("aria-description");
459
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
+ }
460
587
  updateFilled() {
461
588
  if (this.value) this.internals?.states?.add("filled");
462
589
  else this.internals?.states?.delete("filled");
@@ -479,7 +606,8 @@ class AInputElement extends HTMLElementBase {
479
606
  set value(v) {
480
607
  this.pendingValue = v;
481
608
  if (this.control && this.control.value !== v) this.control.value = v;
482
- this.internals?.setFormValue(v);
609
+ this.syncButtonPresentation();
610
+ this.syncFormValue(v);
483
611
  this.updateValidity();
484
612
  this.updateFilled();
485
613
  this.syncAutoHeight();
@@ -495,7 +623,8 @@ class AInputElement extends HTMLElementBase {
495
623
  clear() {
496
624
  if (!this.control) return;
497
625
  this.control.value = "";
498
- this.internals?.setFormValue("");
626
+ this.syncButtonPresentation();
627
+ this.syncFormValue("");
499
628
  this.updateValidity();
500
629
  this.updateFilled();
501
630
  this.syncAutoHeight();
@@ -543,6 +672,18 @@ class AInputElement extends HTMLElementBase {
543
672
  this.value = state ?? "";
544
673
  }
545
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
+ }
546
687
  function register_a_input() {
547
688
  if (typeof customElements === "undefined") return;
548
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-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}}
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: 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)}}
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