@antadesign/anta 0.3.5 → 0.3.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/dist/anta_helpers.d.ts +10 -0
  2. package/dist/anta_helpers.js +8 -0
  3. package/dist/components/Card.d.ts +86 -0
  4. package/dist/components/Card.js +72 -0
  5. package/dist/components/Dialog.d.ts +92 -0
  6. package/dist/components/Dialog.js +71 -0
  7. package/dist/components/Input.d.ts +3 -0
  8. package/dist/components/InputAutocomplete.d.ts +69 -0
  9. package/dist/components/InputAutocomplete.js +95 -0
  10. package/dist/components/InputDate.js +1 -2
  11. package/dist/components/Menu.d.ts +4 -1
  12. package/dist/components/Menu.js +2 -1
  13. package/dist/components/MenuItem.d.ts +9 -1
  14. package/dist/components/MenuItem.js +2 -1
  15. package/dist/components/Select.d.ts +5 -2
  16. package/dist/components/Select.js +11 -34
  17. package/dist/components/SelectFaceted.d.ts +7 -1
  18. package/dist/components/SelectFaceted.js +12 -11
  19. package/dist/components/select-options.d.ts +14 -0
  20. package/dist/components/select-options.js +31 -0
  21. package/dist/elements/a-card.css +211 -0
  22. package/dist/elements/a-card.d.ts +10 -0
  23. package/dist/elements/a-card.js +213 -0
  24. package/dist/elements/a-checkbox.css +1 -1
  25. package/dist/elements/a-dialog.css +1 -0
  26. package/dist/elements/a-dialog.d.ts +26 -0
  27. package/dist/elements/a-dialog.js +386 -0
  28. package/dist/elements/a-expander.js +2 -2
  29. package/dist/elements/a-input-time.js +2 -1
  30. package/dist/elements/a-input.d.ts +2 -0
  31. package/dist/elements/a-input.js +34 -1
  32. package/dist/elements/a-menu.d.ts +5 -2
  33. package/dist/elements/a-menu.js +52 -15
  34. package/dist/elements/a-radio.css +1 -1
  35. package/dist/elements/a-tooltip.d.ts +17 -0
  36. package/dist/elements/a-tooltip.js +28 -0
  37. package/dist/elements/index.d.ts +1 -0
  38. package/dist/elements/index.js +3 -0
  39. package/dist/general_types.d.ts +45 -0
  40. package/dist/index.d.ts +4 -0
  41. package/dist/index.js +4 -0
  42. package/dist/jsx-runtime.d.ts +2 -1
  43. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- import { HTMLElementBase } from "../anta_helpers";
1
+ import { HTMLElementBase, parseOpenState } from "../anta_helpers";
2
2
  import "./a-expander.css";
3
3
  const ANIM_MS = 200;
4
4
  const SUMMARY_TYPE_SCALE = {
@@ -139,7 +139,7 @@ const SHADOW_STYLE = `
139
139
  transition-behavior: allow-discrete;
140
140
  }
141
141
  `;
142
- const parseState = (v) => v === "open" ? "open" : "closed";
142
+ const parseState = parseOpenState;
143
143
  class AExpanderElement extends HTMLElementBase {
144
144
  static observedAttributes = ["state", "disabled", "round"];
145
145
  summary;
@@ -94,6 +94,7 @@ const SHADOW_STYLE = `
94
94
  padding-inline: 1px;
95
95
  border-radius: 2px;
96
96
  text-align: center;
97
+ white-space: nowrap;
97
98
  outline: none;
98
99
  cursor: default;
99
100
  font-variant-numeric: tabular-nums;
@@ -102,7 +103,7 @@ const SHADOW_STYLE = `
102
103
  .seg[inputmode="numeric"] {
103
104
  /* Fixed to two tabular digits so the box never reflows: neither the narrower
104
105
  placeholder dashes nor a mid-entry single digit changes the field width. */
105
- width: calc(2ch + 2px);
106
+ width: calc(2ch + 4px);
106
107
  }
107
108
  .seg:focus {
108
109
  background: var(--input-time-seg-focus-bg);
@@ -45,6 +45,8 @@ export declare class AInputElement extends HTMLElementBase {
45
45
  private syncStatus;
46
46
  private onInput;
47
47
  private onChange;
48
+ private onFocus;
49
+ private onBlur;
48
50
  private onLabelSlotChange;
49
51
  private applyLabelAria;
50
52
  private onHintSlotChange;
@@ -22,6 +22,18 @@ const FORWARDED = [
22
22
  "aria-label"
23
23
  ];
24
24
  const BOOL_FORWARDED = /* @__PURE__ */ new Set(["readonly", "required"]);
25
+ let focusFromKeyboard = false;
26
+ const modalityDocs = /* @__PURE__ */ new WeakSet();
27
+ function trackFocusModality(doc) {
28
+ if (modalityDocs.has(doc)) return;
29
+ modalityDocs.add(doc);
30
+ doc.addEventListener("keydown", () => {
31
+ focusFromKeyboard = true;
32
+ }, true);
33
+ doc.addEventListener("pointerdown", () => {
34
+ focusFromKeyboard = false;
35
+ }, true);
36
+ }
25
37
  const CLEAR_TRIGGER = "clearrequest";
26
38
  const CLEAR_CLICK_EVENT = "clearclick";
27
39
  const CLEAR_INPUT_EVENT = "clearinput";
@@ -72,7 +84,8 @@ const SHADOW_STYLE = `
72
84
  @media (hover: hover) and (pointer: fine) {
73
85
  :host(:not(:disabled)) .field:hover { --_bc: var(--input-border-hover); }
74
86
  }
75
- .field:has(input:focus, textarea:focus) {
87
+ :host(:not([readonly])) .field:has(input:focus, textarea:focus),
88
+ :host([readonly]:state(kb-focus)) .field {
76
89
  --_bc: var(--input-border-hover);
77
90
  outline: 1px solid var(--focus-ring);
78
91
  outline-offset: 1px;
@@ -269,6 +282,7 @@ class AInputElement extends HTMLElementBase {
269
282
  return this.field.getBoundingClientRect();
270
283
  }
271
284
  connectedCallback() {
285
+ trackFocusModality(this.doc);
272
286
  if (Object.prototype.hasOwnProperty.call(this, "value")) {
273
287
  const v = this.value;
274
288
  delete this.value;
@@ -336,6 +350,8 @@ class AInputElement extends HTMLElementBase {
336
350
  next.value = value;
337
351
  next.addEventListener("input", this.onInput);
338
352
  next.addEventListener("change", this.onChange);
353
+ next.addEventListener("focus", this.onFocus);
354
+ next.addEventListener("blur", this.onBlur);
339
355
  if (refocus) {
340
356
  next.focus();
341
357
  if (selStart != null) try {
@@ -415,6 +431,23 @@ class AInputElement extends HTMLElementBase {
415
431
  onChange = () => {
416
432
  this.dispatchEvent(new Event("change", { bubbles: true }));
417
433
  };
434
+ // Stamp the off-DOM `:state(kb-focus)` when this focus arrived via the keyboard
435
+ // (see `trackFocusModality`), so the read-only field's ring can draw for keyboard
436
+ // focus but not a mouse click — the one distinction Chromium's `:focus-visible`
437
+ // won't make for an <input>. Editable fields ignore the state (ring on `:focus`).
438
+ onFocus = () => {
439
+ try {
440
+ if (focusFromKeyboard) this.internals?.states.add("kb-focus");
441
+ else this.internals?.states.delete("kb-focus");
442
+ } catch {
443
+ }
444
+ };
445
+ onBlur = () => {
446
+ try {
447
+ this.internals?.states.delete("kb-focus");
448
+ } catch {
449
+ }
450
+ };
418
451
  onLabelSlotChange = () => {
419
452
  this.labelBox.classList.toggle("has-label", this.labelSlot.assignedNodes().length > 0);
420
453
  this.applyLabelAria();
@@ -110,8 +110,11 @@ export declare class AMenuElement extends HTMLElementBase {
110
110
  * the seat target — the cursor lands on the first real option — but they stay
111
111
  * arrow-reachable. */
112
112
  private resetActive;
113
- /** Combobox arrow / Home / End / Enter handling; returns true if it consumed the
114
- * key (so `handleKey` stops). Any other key falls through to the input (typing). */
113
+ /** Combobox arrow / PageUp / PageDown / Enter handling; returns true if it
114
+ * consumed the key (so `handleKey` stops). Home / End are deliberately NOT
115
+ * handled: focus is in a text field, so they must reach it for caret movement
116
+ * (line start/end); PageUp / PageDown jump the option list to first / last
117
+ * instead. Any other key falls through to the input (typing). */
115
118
  private handleComboKey;
116
119
  /** Public imperative API. Routes through the same intent path as the
117
120
  * triggers, so it emits `statechange` and respects controlled mode. */
@@ -7,6 +7,8 @@ const SUBMENU_OPEN_DELAY = 130;
7
7
  const SUBMENU_CLOSE_DELAY = 130;
8
8
  const TYPEAHEAD_RESET = 500;
9
9
  const ANCHOR_VISIBLE_RATIO = 0.5;
10
+ const SELF_ACTIVATING = 'a-button, button, a[href], input[type="button"], input[type="submit"], input[type="reset"], [role="button"]';
11
+ const EDITABLE_FIELD = "input:not([readonly]), textarea:not([readonly]), a-input:not([readonly]), a-input-time:not([readonly])";
10
12
  const openStack = [];
11
13
  let docBound = false;
12
14
  let boundDoc = null;
@@ -451,11 +453,22 @@ class AMenuElement extends HTMLElementBase {
451
453
  el.style.setProperty("--fade-bottom", bottom ? "14px" : "0px");
452
454
  }
453
455
  /* ------------------------------ combobox mode ------------------------------ */
454
- /** The filter field slotted into THIS menu (never a submenu's), or null. Its
456
+ /** Combobox-anchor mode: the trigger anchor ITSELF is the filter field (it
457
+ * carries `[data-menu-search]`), as in `InputAutocomplete` where an editable
458
+ * `<a-input>` is the always-visible field the menu hangs under. null for the
459
+ * normal case — `Select`/`SelectFaceted` slot the field as a child, so their
460
+ * anchor never carries the marker and this stays inert for them. */
461
+ get #comboAnchor() {
462
+ const a = this.triggerAnchor;
463
+ return a?.matches("[data-menu-search]") ? a : null;
464
+ }
465
+ /** The filter field of THIS menu, or null. A slotted child (never a submenu's)
466
+ * wins; else the anchor when it's the field (combobox-anchor mode). Its
455
467
  * presence switches the menu to the combobox keyboard. */
456
468
  get #searchField() {
457
469
  const el = this.querySelector("[data-menu-search]");
458
- return el && el.closest("a-menu") === this ? el : null;
470
+ if (el && el.closest("a-menu") === this) return el;
471
+ return this.#comboAnchor;
459
472
  }
460
473
  /** Move the combobox cursor. Sets the item's `active` **property** (off-DOM
461
474
  * `:state(active)`, no attribute churn) for the highlight, and REPORTS the
@@ -481,11 +494,15 @@ class AMenuElement extends HTMLElementBase {
481
494
  resetActive() {
482
495
  const q = this.#searchField?.value;
483
496
  if (!q || !q.trim()) return this.setActive(null);
497
+ if (this.#comboAnchor) return this.setActive(null);
484
498
  const items = this.focusableItems();
485
499
  this.setActive(items.find((it) => !it.hasAttribute("data-menu-skip-active")) ?? items[0] ?? null);
486
500
  }
487
- /** Combobox arrow / Home / End / Enter handling; returns true if it consumed the
488
- * key (so `handleKey` stops). Any other key falls through to the input (typing). */
501
+ /** Combobox arrow / PageUp / PageDown / Enter handling; returns true if it
502
+ * consumed the key (so `handleKey` stops). Home / End are deliberately NOT
503
+ * handled: focus is in a text field, so they must reach it for caret movement
504
+ * (line start/end); PageUp / PageDown jump the option list to first / last
505
+ * instead. Any other key falls through to the input (typing). */
489
506
  handleComboKey(e) {
490
507
  const items = this.focusableItems();
491
508
  const idx = this.activeItem ? items.indexOf(this.activeItem) : -1;
@@ -498,11 +515,11 @@ class AMenuElement extends HTMLElementBase {
498
515
  e.preventDefault();
499
516
  this.setActive(items[idx <= 0 ? items.length - 1 : idx - 1] ?? null);
500
517
  return true;
501
- case "Home":
518
+ case "PageUp":
502
519
  e.preventDefault();
503
520
  this.setActive(items[0] ?? null);
504
521
  return true;
505
- case "End":
522
+ case "PageDown":
506
523
  e.preventDefault();
507
524
  this.setActive(items[items.length - 1] ?? null);
508
525
  return true;
@@ -848,6 +865,10 @@ class AMenuElement extends HTMLElementBase {
848
865
  return;
849
866
  }
850
867
  if (e.key === "Tab") {
868
+ if (this.#comboAnchor) {
869
+ this.requestClose(e);
870
+ return;
871
+ }
851
872
  const f = this.focusables();
852
873
  if (!f.length) return;
853
874
  e.preventDefault();
@@ -928,6 +949,12 @@ class AMenuElement extends HTMLElementBase {
928
949
  return ((label ?? it).textContent ?? "").trim().toLowerCase();
929
950
  }
930
951
  /* ====================== trigger listener wiring ====================== */
952
+ /** Pointer coord for a keyboard-opened `coord` menu: the trigger's own rect
953
+ * (a DOM read, not a mutation) instead of the 0,0 a keyboard event reports. */
954
+ #anchorCoord(anchor) {
955
+ const r = anchorRect(anchor);
956
+ return [r.left, r.bottom];
957
+ }
931
958
  setupListeners() {
932
959
  if (this.listening) return;
933
960
  const anchor = this.triggerAnchor;
@@ -969,24 +996,34 @@ class AMenuElement extends HTMLElementBase {
969
996
  anchor.removeEventListener("contextmenu", onContext);
970
997
  this.listening = false;
971
998
  };
999
+ } else if (this.#comboAnchor) {
1000
+ this.teardown = () => {
1001
+ this.listening = false;
1002
+ };
1003
+ this.listening = true;
1004
+ return;
972
1005
  } else {
973
1006
  const onClick = (e) => {
974
1007
  const viaKeyboard = e.detail === 0;
975
- let coord;
976
- if (this.#isCoord) {
977
- if (viaKeyboard) {
978
- const r = anchorRect(anchor);
979
- coord = [r.left, r.bottom];
980
- } else {
981
- coord = [e.clientX, e.clientY];
982
- }
983
- }
1008
+ const coord = this.#isCoord ? viaKeyboard ? this.#anchorCoord(anchor) : [e.clientX, e.clientY] : void 0;
984
1009
  if (this._shown) this.requestClose(e);
985
1010
  else this.requestOpen({ coord, viaKeyboard, originEvent: e });
986
1011
  };
1012
+ const onKey = (e) => {
1013
+ if (this._shown) return;
1014
+ if (anchor.matches(SELF_ACTIVATING) || anchor.hasAttribute("disabled")) return;
1015
+ const editable = anchor.matches(EDITABLE_FIELD);
1016
+ const opens = e.key === "ArrowDown" || e.key === "ArrowUp" || !editable && (e.key === "Enter" || e.key === " ");
1017
+ if (!opens) return;
1018
+ e.preventDefault();
1019
+ const coord = this.#isCoord ? this.#anchorCoord(anchor) : void 0;
1020
+ this.requestOpen({ coord, viaKeyboard: true, originEvent: e });
1021
+ };
987
1022
  anchor.addEventListener("click", onClick);
1023
+ anchor.addEventListener("keydown", onKey);
988
1024
  this.teardown = () => {
989
1025
  anchor.removeEventListener("click", onClick);
1026
+ anchor.removeEventListener("keydown", onKey);
990
1027
  this.listening = false;
991
1028
  };
992
1029
  }
@@ -1 +1 @@
1
- @layer anta{a-radio{--radio-control-size: 16px;--radio-border-width: 1.5px;--radio-dot-size: 6px;--_radio-dot-adjust: 0px;--radio-gap: 8px;--radio-bg: var(--bg-1);--radio-fill: #878089;--radio-fill-hover: #776e77;--radio-fill-active: #635b65;--radio-border-neutral: #d4ced4;--radio-border: var(--radio-border-neutral);--radio-border-hover: #c1b9c1;--radio-border-active: #9f99a1;--radio-dot: #f1eff1;--radio-dot-disabled: #c1b9c1;--radio-bg-disabled: color-mix(in oklch, #44374b 10%, transparent);--radio-border-disabled: color-mix(in oklch, #44374b 10%, transparent);--radio-label-color: var(--text-2);--radio-label-color-disabled: var(--text-4);--radio-hint-color: var(--text-3);--radio-label-fs: 15px;--radio-label-lh: 20px;--radio-hint-fs: 14px;--radio-hint-lh: 17px;display:inline-grid;grid-template-columns:auto 1fr;align-items:start;column-gap:var(--radio-gap);cursor:pointer;user-select:none;-webkit-user-drag:none;vertical-align:middle;outline:none;color:var(--radio-label-color);font-family:var(--sans-serif);font-size:var(--radio-label-fs);line-height:var(--radio-label-lh);font-feature-settings:"ss02","ss05","tnum";&:before{content:"";grid-column:1;grid-row:1 / -1;align-self:start;margin-block-start:calc((var(--radio-label-lh) - var(--radio-control-size)) / 2);box-sizing:border-box;inline-size:var(--radio-control-size);block-size:var(--radio-control-size);border-radius:50%;background:var(--radio-bg);border:var(--radio-border-width) solid var(--radio-border);transition:background-color .15s ease-out,border-color .15s ease-out}&:after{content:"";grid-column:1;grid-row:1 / -1;align-self:start;justify-self:center;margin-block-start:calc((var(--radio-label-lh) - (var(--radio-dot-size) - var(--_radio-dot-adjust))) / 2);inline-size:calc(var(--radio-dot-size) - var(--_radio-dot-adjust));block-size:calc(var(--radio-dot-size) - var(--_radio-dot-adjust));border-radius:50%;background:var(--radio-dot);transform:scale(0);transition:transform .12s ease-out;pointer-events:none}@media(hover:hover)and (pointer:fine){&:not([disabled]):hover:before{border-color:var(--radio-border-hover);transition:background-color 75ms ease-in,border-color 75ms ease-in}&:not([disabled]):hover:state(selected):before{background:var(--radio-fill-hover);border-color:var(--radio-fill-hover)}}&:not([disabled]):active:before{border-color:var(--radio-border-active);transition:background-color 50ms linear,border-color 50ms linear}&:not([disabled]):active:state(selected):before{background:var(--radio-fill-active);border-color:var(--radio-fill-active)}&:state(selected){&:before{background:var(--radio-fill);border-color:var(--radio-fill)}&:after{transform:scale(1)}}&:focus-visible:before{outline:1px solid var(--focus-ring);outline-offset:1px}&[disabled]{cursor:not-allowed;color:var(--radio-label-color-disabled);&:before{background:var(--radio-bg-disabled);border-color:var(--radio-border-disabled);transition:none}&:state(selected):after{background:var(--radio-dot-disabled)}a-radio-hint{color:var(--radio-label-color-disabled)}}&[size=small]{--radio-control-size: 14px;--radio-dot-size: 5px;--radio-gap: 6px;--radio-label-fs: 13px;--radio-label-lh: 16px;--radio-hint-fs: 12px;--radio-hint-lh: 14px}&[size=large]{--radio-control-size: 18px;--radio-dot-size: 7px;--radio-label-fs: 17px;--radio-label-lh: 22px;--radio-hint-fs: 16px;--radio-hint-lh: 21px}}a-radio-label,a-radio-hint{display:block;grid-column:2;min-width:0}a-radio-hint{color:var(--radio-hint-color);font-size:var(--radio-hint-fs);line-height:var(--radio-hint-lh);margin-block-start:2px}a-radio-group:focus-visible a-radio:state(selected):before{outline:1px solid var(--focus-ring);outline-offset:1px}a-radio[tone=brand],a-radio[tone-selected=brand],a-radio-group[tone=brand] a-radio:not([tone]),a-radio-group[tone-selected=brand] a-radio:not([tone-selected]){--radio-fill: #5f4bc3;--radio-fill-hover: #503cb4;--radio-fill-active: #483493}a-radio[tone=neutral],a-radio[tone-selected=neutral],a-radio-group[tone=neutral] a-radio:not([tone]),a-radio-group[tone-selected=neutral] a-radio:not([tone-selected]){--radio-fill: #878089;--radio-fill-hover: #776e77;--radio-fill-active: #635b65}a-radio[tone=info],a-radio[tone-selected=info],a-radio-group[tone=info] a-radio:not([tone]),a-radio-group[tone-selected=info] a-radio:not([tone-selected]){--radio-fill: #1f6eb2;--radio-fill-hover: #1a5b93;--radio-fill-active: #175082}a-radio[tone=success],a-radio[tone-selected=success],a-radio-group[tone=success] a-radio:not([tone]),a-radio-group[tone-selected=success] a-radio:not([tone-selected]){--radio-fill: #2a7e43;--radio-fill-hover: #226737;--radio-fill-active: #1f5c31}a-radio[tone=warning],a-radio[tone-selected=warning],a-radio-group[tone=warning] a-radio:not([tone]),a-radio-group[tone-selected=warning] a-radio:not([tone-selected]){--radio-fill: #c37416;--radio-fill-hover: #ae6613;--radio-fill-active: #995200}a-radio[tone=critical],a-radio[tone-selected=critical],a-radio-group[tone=critical] a-radio:not([tone]),a-radio-group[tone-selected=critical] a-radio:not([tone-selected]){--radio-fill: #c9302c;--radio-fill-hover: #b02120;--radio-fill-active: #a01c1c}a-radio[tone=brand],a-radio-group[tone=brand] a-radio:not([tone]){--radio-bg: #fcfcfe;--radio-border: #bcb1f1;--radio-border-hover: #9e8eeb;--radio-border-active: #9081df}a-radio[tone=info],a-radio-group[tone=info] a-radio:not([tone]){--radio-bg: #fbfcfe;--radio-border: #93c5ec;--radio-border-hover: #69ace5;--radio-border-active: #56a1e1}a-radio[tone=success],a-radio-group[tone=success] a-radio:not([tone]){--radio-bg: #f7fcf9;--radio-border: #88d7a0;--radio-border-hover: #5bc87b;--radio-border-active: #44c169}a-radio[tone=warning],a-radio-group[tone=warning] a-radio:not([tone]){--radio-bg: #fefbf6;--radio-border: #edb25a;--radio-border-hover: #e09127;--radio-border-active: #d88118}a-radio[tone=critical],a-radio-group[tone=critical] a-radio:not([tone]){--radio-bg: #fefbfb;--radio-border: #efa4a4;--radio-border-hover: #e87f7f;--radio-border-active: #e56c6c}a-radio[tone]:not([tone=""],[tone=neutral],[tone=brand],[tone=info],[tone=success],[tone=warning],[tone=critical]),a-radio-group[tone]:not([tone=""],[tone=neutral],[tone=brand],[tone=info],[tone=success],[tone=warning],[tone=critical]) a-radio:not([tone]){--radio-bg: oklch(from var(--radio-tone-source) .99 calc(c*.03) h);--_radio-border-base: color-mix(in oklch, var(--radio-fill) 70%, var(--radio-border-neutral));--radio-border: oklch(from var(--_radio-border-base) calc(l + .17) c h);--radio-border-hover: oklch(from var(--_radio-border-base) calc(l + .1) c h);--radio-border-active: var(--_radio-border-base);.dark &{--radio-bg: oklch(from var(--radio-tone-source) .15 calc(c*.18) h);--radio-border: var(--_radio-border-base);--radio-border-hover: oklch(from var(--_radio-border-base) calc(l + .1) c h);--radio-border-active: oklch(from var(--_radio-border-base) calc(l + .17) c h)}}a-radio[tone]:not([tone=""],[tone=brand],[tone=neutral],[tone=info],[tone=success],[tone=warning],[tone=critical]){--radio-tone-source: attr(tone type(<color>), transparent)}a-radio[tone-selected]:not([tone-selected=""],[tone-selected=brand],[tone-selected=neutral],[tone-selected=info],[tone-selected=success],[tone-selected=warning],[tone-selected=critical]){--radio-tone-source: attr(tone-selected type(<color>), transparent)}a-radio[tone]:not([tone=""],[tone=brand],[tone=neutral],[tone=info],[tone=success],[tone=warning],[tone=critical]),a-radio[tone-selected]:not([tone-selected=""],[tone-selected=brand],[tone-selected=neutral],[tone-selected=info],[tone-selected=success],[tone-selected=warning],[tone-selected=critical]),a-radio-group[tone]:not([tone=""],[tone=brand],[tone=neutral],[tone=info],[tone=success],[tone=warning],[tone=critical]) a-radio:not([tone]),a-radio-group[tone-selected]:not([tone-selected=""],[tone-selected=brand],[tone-selected=neutral],[tone-selected=info],[tone-selected=success],[tone-selected=warning],[tone-selected=critical]) a-radio:not([tone-selected]){--_tone-l-rest: .5;--_tone-l-hover: .45;--_tone-l-active: .4;--radio-fill: oklch(from var(--radio-tone-source) var(--_tone-l-rest) c h);--radio-fill-hover: oklch(from var(--radio-tone-source) var(--_tone-l-hover) c h);--radio-fill-active: oklch(from var(--radio-tone-source) var(--_tone-l-active) c h);.dark &{--_tone-l-rest: .45;--_tone-l-hover: .5;--_tone-l-active: .57}}.dark a-radio{--_radio-dot-adjust: 1px;&:after{box-shadow:0 0 1px 1px color-mix(in oklch,black 40%,transparent)}--radio-border-neutral: #49424c;--radio-border-hover: #635b65;--radio-border-active: #776e77;--radio-fill: #49424c;--radio-fill-hover: #534c57;--radio-fill-active: #635b65;--radio-dot: #d4ced4;--radio-dot-disabled: #534c57;--radio-bg-disabled: color-mix(in oklch, #e4d1ef 10%, transparent);--radio-border-disabled: color-mix(in oklch, #e4d1ef 10%, transparent)}.dark a-radio[tone=brand],.dark a-radio[tone-selected=brand],.dark a-radio-group[tone=brand] a-radio:not([tone]),.dark a-radio-group[tone-selected=brand] a-radio:not([tone-selected]){--radio-fill: #503cb4;--radio-fill-hover: #5f4bc3;--radio-fill-active: #7460d7}.dark a-radio[tone=neutral],.dark a-radio[tone-selected=neutral],.dark a-radio-group[tone=neutral] a-radio:not([tone]),.dark a-radio-group[tone-selected=neutral] a-radio:not([tone-selected]){--radio-fill: #49424c;--radio-fill-hover: #534c57;--radio-fill-active: #635b65}.dark a-radio[tone=info],.dark a-radio[tone-selected=info],.dark a-radio-group[tone=info] a-radio:not([tone]),.dark a-radio-group[tone-selected=info] a-radio:not([tone-selected]){--radio-fill: #1a5b93;--radio-fill-hover: #1f6eb2;--radio-fill-active: #2686d9}.dark a-radio[tone=success],.dark a-radio[tone-selected=success],.dark a-radio-group[tone=success] a-radio:not([tone]),.dark a-radio-group[tone-selected=success] a-radio:not([tone-selected]){--radio-fill: #226737;--radio-fill-hover: #2a7e43;--radio-fill-active: #329550}.dark a-radio[tone=warning],.dark a-radio[tone-selected=warning],.dark a-radio-group[tone=warning] a-radio:not([tone]),.dark a-radio-group[tone-selected=warning] a-radio:not([tone-selected]){--radio-fill: #7f410b;--radio-fill-hover: #995200;--radio-fill-active: #ae6613}.dark a-radio[tone=critical],.dark a-radio[tone-selected=critical],.dark a-radio-group[tone=critical] a-radio:not([tone]),.dark a-radio-group[tone-selected=critical] a-radio:not([tone-selected]){--radio-fill: #b02120;--radio-fill-hover: #c9302c;--radio-fill-active: #de4545}.dark a-radio[tone=brand],.dark a-radio-group[tone=brand] a-radio:not([tone]){--radio-bg: #0b0916;--radio-border: #483493;--radio-border-hover: #5f4bc3;--radio-border-active: #7460d7}.dark a-radio[tone=info],.dark a-radio-group[tone=info] a-radio:not([tone]){--radio-bg: #040d18;--radio-border: #175082;--radio-border-hover: #1f6eb2;--radio-border-active: #2686d9}.dark a-radio[tone=success],.dark a-radio-group[tone=success] a-radio:not([tone]){--radio-bg: #041008;--radio-border: #1f5c31;--radio-border-hover: #2a7e43;--radio-border-active: #329550}.dark a-radio[tone=warning],.dark a-radio-group[tone=warning] a-radio:not([tone]){--radio-bg: #120a03;--radio-border: #6a3b0c;--radio-border-hover: #995200;--radio-border-active: #ae6613}.dark a-radio[tone=critical],.dark a-radio-group[tone=critical] a-radio:not([tone]){--radio-bg: #190405;--radio-border: #a01c1c;--radio-border-hover: #c9302c;--radio-border-active: #de4545}}
1
+ @layer anta{a-radio{--radio-control-size: 16px;--radio-border-width: 1.5px;--radio-dot-size: 6px;--_radio-dot-adjust: 0px;--radio-gap: 8px;--radio-bg: var(--bg-1);--radio-fill: #878089;--radio-fill-hover: #776e77;--radio-fill-active: #635b65;--radio-border-neutral: #d4ced4;--radio-border: var(--radio-border-neutral);--radio-border-hover: #c1b9c1;--radio-border-active: #9f99a1;--radio-dot: #f6f4f6;--radio-dot-disabled: #c1b9c1;--radio-bg-disabled: color-mix(in oklch, #44374b 10%, transparent);--radio-border-disabled: color-mix(in oklch, #44374b 10%, transparent);--radio-label-color: var(--text-2);--radio-label-color-disabled: var(--text-4);--radio-hint-color: var(--text-3);--radio-label-fs: 15px;--radio-label-lh: 20px;--radio-hint-fs: 14px;--radio-hint-lh: 17px;display:inline-grid;grid-template-columns:auto 1fr;align-items:start;column-gap:var(--radio-gap);cursor:pointer;user-select:none;-webkit-user-drag:none;vertical-align:middle;outline:none;color:var(--radio-label-color);font-family:var(--sans-serif);font-size:var(--radio-label-fs);line-height:var(--radio-label-lh);font-feature-settings:"ss02","ss05","tnum";&:before{content:"";grid-column:1;grid-row:1 / -1;align-self:start;margin-block-start:calc((var(--radio-label-lh) - var(--radio-control-size)) / 2);box-sizing:border-box;inline-size:var(--radio-control-size);block-size:var(--radio-control-size);border-radius:50%;background:var(--radio-bg);border:var(--radio-border-width) solid var(--radio-border);transition:background-color .15s ease-out,border-color .15s ease-out}&:after{content:"";grid-column:1;grid-row:1 / -1;align-self:start;justify-self:center;margin-block-start:calc((var(--radio-label-lh) - (var(--radio-dot-size) - var(--_radio-dot-adjust))) / 2);inline-size:calc(var(--radio-dot-size) - var(--_radio-dot-adjust));block-size:calc(var(--radio-dot-size) - var(--_radio-dot-adjust));border-radius:50%;background:var(--radio-dot);transform:scale(0);transition:transform .12s ease-out;pointer-events:none}@media(hover:hover)and (pointer:fine){&:not([disabled]):hover:before{border-color:var(--radio-border-hover);transition:background-color 75ms ease-in,border-color 75ms ease-in}&:not([disabled]):hover:state(selected):before{background:var(--radio-fill-hover);border-color:var(--radio-fill-hover)}}&:not([disabled]):active:before{border-color:var(--radio-border-active);transition:background-color 50ms linear,border-color 50ms linear}&:not([disabled]):active:state(selected):before{background:var(--radio-fill-active);border-color:var(--radio-fill-active)}&:state(selected){&:before{background:var(--radio-fill);border-color:var(--radio-fill)}&:after{transform:scale(1)}}&:focus-visible:before{outline:1px solid var(--focus-ring);outline-offset:1px}&[disabled]{cursor:not-allowed;color:var(--radio-label-color-disabled);&:before{background:var(--radio-bg-disabled);border-color:var(--radio-border-disabled);transition:none}&:state(selected):after{background:var(--radio-dot-disabled)}a-radio-hint{color:var(--radio-label-color-disabled)}}&[size=small]{--radio-control-size: 14px;--radio-dot-size: 5px;--radio-gap: 6px;--radio-label-fs: 13px;--radio-label-lh: 16px;--radio-hint-fs: 12px;--radio-hint-lh: 14px}&[size=large]{--radio-control-size: 18px;--radio-dot-size: 7px;--radio-label-fs: 17px;--radio-label-lh: 22px;--radio-hint-fs: 16px;--radio-hint-lh: 21px}}a-radio-label,a-radio-hint{display:block;grid-column:2;min-width:0}a-radio-hint{color:var(--radio-hint-color);font-size:var(--radio-hint-fs);line-height:var(--radio-hint-lh);margin-block-start:2px}a-radio-group:focus-visible a-radio:state(selected):before{outline:1px solid var(--focus-ring);outline-offset:1px}a-radio[tone=brand],a-radio[tone-selected=brand],a-radio-group[tone=brand] a-radio:not([tone]),a-radio-group[tone-selected=brand] a-radio:not([tone-selected]){--radio-fill: #5f4bc3;--radio-fill-hover: #503cb4;--radio-fill-active: #483493}a-radio[tone=neutral],a-radio[tone-selected=neutral],a-radio-group[tone=neutral] a-radio:not([tone]),a-radio-group[tone-selected=neutral] a-radio:not([tone-selected]){--radio-fill: #878089;--radio-fill-hover: #776e77;--radio-fill-active: #635b65}a-radio[tone=info],a-radio[tone-selected=info],a-radio-group[tone=info] a-radio:not([tone]),a-radio-group[tone-selected=info] a-radio:not([tone-selected]){--radio-fill: #1f6eb2;--radio-fill-hover: #1a5b93;--radio-fill-active: #175082}a-radio[tone=success],a-radio[tone-selected=success],a-radio-group[tone=success] a-radio:not([tone]),a-radio-group[tone-selected=success] a-radio:not([tone-selected]){--radio-fill: #2a7e43;--radio-fill-hover: #226737;--radio-fill-active: #1f5c31}a-radio[tone=warning],a-radio[tone-selected=warning],a-radio-group[tone=warning] a-radio:not([tone]),a-radio-group[tone-selected=warning] a-radio:not([tone-selected]){--radio-fill: #c37416;--radio-fill-hover: #ae6613;--radio-fill-active: #995200}a-radio[tone=critical],a-radio[tone-selected=critical],a-radio-group[tone=critical] a-radio:not([tone]),a-radio-group[tone-selected=critical] a-radio:not([tone-selected]){--radio-fill: #c9302c;--radio-fill-hover: #b02120;--radio-fill-active: #a01c1c}a-radio[tone=brand],a-radio-group[tone=brand] a-radio:not([tone]){--radio-bg: #fcfcfe;--radio-border: #bcb1f1;--radio-border-hover: #9e8eeb;--radio-border-active: #9081df}a-radio[tone=info],a-radio-group[tone=info] a-radio:not([tone]){--radio-bg: #fbfcfe;--radio-border: #93c5ec;--radio-border-hover: #69ace5;--radio-border-active: #56a1e1}a-radio[tone=success],a-radio-group[tone=success] a-radio:not([tone]){--radio-bg: #f7fcf9;--radio-border: #88d7a0;--radio-border-hover: #5bc87b;--radio-border-active: #44c169}a-radio[tone=warning],a-radio-group[tone=warning] a-radio:not([tone]){--radio-bg: #fefbf6;--radio-border: #edb25a;--radio-border-hover: #e09127;--radio-border-active: #d88118}a-radio[tone=critical],a-radio-group[tone=critical] a-radio:not([tone]){--radio-bg: #fefbfb;--radio-border: #efa4a4;--radio-border-hover: #e87f7f;--radio-border-active: #e56c6c}a-radio[tone]:not([tone=""],[tone=neutral],[tone=brand],[tone=info],[tone=success],[tone=warning],[tone=critical]),a-radio-group[tone]:not([tone=""],[tone=neutral],[tone=brand],[tone=info],[tone=success],[tone=warning],[tone=critical]) a-radio:not([tone]){--radio-bg: oklch(from var(--radio-tone-source) .99 calc(c*.03) h);--_radio-border-base: color-mix(in oklch, var(--radio-fill) 70%, var(--radio-border-neutral));--radio-border: oklch(from var(--_radio-border-base) calc(l + .17) c h);--radio-border-hover: oklch(from var(--_radio-border-base) calc(l + .1) c h);--radio-border-active: var(--_radio-border-base);.dark &{--radio-bg: oklch(from var(--radio-tone-source) .15 calc(c*.18) h);--radio-border: var(--_radio-border-base);--radio-border-hover: oklch(from var(--_radio-border-base) calc(l + .1) c h);--radio-border-active: oklch(from var(--_radio-border-base) calc(l + .17) c h)}}a-radio[tone]:not([tone=""],[tone=brand],[tone=neutral],[tone=info],[tone=success],[tone=warning],[tone=critical]){--radio-tone-source: attr(tone type(<color>), transparent)}a-radio[tone-selected]:not([tone-selected=""],[tone-selected=brand],[tone-selected=neutral],[tone-selected=info],[tone-selected=success],[tone-selected=warning],[tone-selected=critical]){--radio-tone-source: attr(tone-selected type(<color>), transparent)}a-radio[tone]:not([tone=""],[tone=brand],[tone=neutral],[tone=info],[tone=success],[tone=warning],[tone=critical]),a-radio[tone-selected]:not([tone-selected=""],[tone-selected=brand],[tone-selected=neutral],[tone-selected=info],[tone-selected=success],[tone-selected=warning],[tone-selected=critical]),a-radio-group[tone]:not([tone=""],[tone=brand],[tone=neutral],[tone=info],[tone=success],[tone=warning],[tone=critical]) a-radio:not([tone]),a-radio-group[tone-selected]:not([tone-selected=""],[tone-selected=brand],[tone-selected=neutral],[tone-selected=info],[tone-selected=success],[tone-selected=warning],[tone-selected=critical]) a-radio:not([tone-selected]){--_tone-l-rest: .5;--_tone-l-hover: .45;--_tone-l-active: .4;--radio-fill: oklch(from var(--radio-tone-source) var(--_tone-l-rest) c h);--radio-fill-hover: oklch(from var(--radio-tone-source) var(--_tone-l-hover) c h);--radio-fill-active: oklch(from var(--radio-tone-source) var(--_tone-l-active) c h);.dark &{--_tone-l-rest: .45;--_tone-l-hover: .5;--_tone-l-active: .57}}.dark a-radio{--_radio-dot-adjust: 1px;&:after{box-shadow:0 0 1px 1px color-mix(in oklch,black 40%,transparent)}--radio-border-neutral: #49424c;--radio-border-hover: #635b65;--radio-border-active: #776e77;--radio-fill: #49424c;--radio-fill-hover: #534c57;--radio-fill-active: #635b65;--radio-dot: #ece9ec;--radio-dot-disabled: #534c57;--radio-bg-disabled: color-mix(in oklch, #e4d1ef 10%, transparent);--radio-border-disabled: color-mix(in oklch, #e4d1ef 10%, transparent)}.dark a-radio[tone=brand],.dark a-radio[tone-selected=brand],.dark a-radio-group[tone=brand] a-radio:not([tone]),.dark a-radio-group[tone-selected=brand] a-radio:not([tone-selected]){--radio-fill: #503cb4;--radio-fill-hover: #5f4bc3;--radio-fill-active: #7460d7}.dark a-radio[tone=neutral],.dark a-radio[tone-selected=neutral],.dark a-radio-group[tone=neutral] a-radio:not([tone]),.dark a-radio-group[tone-selected=neutral] a-radio:not([tone-selected]){--radio-fill: #49424c;--radio-fill-hover: #534c57;--radio-fill-active: #635b65}.dark a-radio[tone=info],.dark a-radio[tone-selected=info],.dark a-radio-group[tone=info] a-radio:not([tone]),.dark a-radio-group[tone-selected=info] a-radio:not([tone-selected]){--radio-fill: #1a5b93;--radio-fill-hover: #1f6eb2;--radio-fill-active: #2686d9}.dark a-radio[tone=success],.dark a-radio[tone-selected=success],.dark a-radio-group[tone=success] a-radio:not([tone]),.dark a-radio-group[tone-selected=success] a-radio:not([tone-selected]){--radio-fill: #226737;--radio-fill-hover: #2a7e43;--radio-fill-active: #329550}.dark a-radio[tone=warning],.dark a-radio[tone-selected=warning],.dark a-radio-group[tone=warning] a-radio:not([tone]),.dark a-radio-group[tone-selected=warning] a-radio:not([tone-selected]){--radio-fill: #7f410b;--radio-fill-hover: #995200;--radio-fill-active: #ae6613}.dark a-radio[tone=critical],.dark a-radio[tone-selected=critical],.dark a-radio-group[tone=critical] a-radio:not([tone]),.dark a-radio-group[tone-selected=critical] a-radio:not([tone-selected]){--radio-fill: #b02120;--radio-fill-hover: #c9302c;--radio-fill-active: #de4545}.dark a-radio[tone=brand],.dark a-radio-group[tone=brand] a-radio:not([tone]){--radio-bg: #0b0916;--radio-border: #483493;--radio-border-hover: #5f4bc3;--radio-border-active: #7460d7}.dark a-radio[tone=info],.dark a-radio-group[tone=info] a-radio:not([tone]){--radio-bg: #040d18;--radio-border: #175082;--radio-border-hover: #1f6eb2;--radio-border-active: #2686d9}.dark a-radio[tone=success],.dark a-radio-group[tone=success] a-radio:not([tone]){--radio-bg: #041008;--radio-border: #1f5c31;--radio-border-hover: #2a7e43;--radio-border-active: #329550}.dark a-radio[tone=warning],.dark a-radio-group[tone=warning] a-radio:not([tone]){--radio-bg: #120a03;--radio-border: #6a3b0c;--radio-border-hover: #995200;--radio-border-active: #ae6613}.dark a-radio[tone=critical],.dark a-radio-group[tone=critical] a-radio:not([tone]){--radio-bg: #190405;--radio-border: #a01c1c;--radio-border-hover: #c9302c;--radio-border-active: #de4545}}
@@ -52,6 +52,9 @@ export declare class ATooltipElement extends HTMLElementBase {
52
52
  private fading;
53
53
  private fadeTimer?;
54
54
  private docMoveBound;
55
+ /** Active only while shown: re-runs the empty gate when the slotted content
56
+ * changes under a live bubble. See observeContent(). */
57
+ private contentObserver?;
55
58
  constructor();
56
59
  connectedCallback(): void;
57
60
  disconnectedCallback(): void;
@@ -76,6 +79,20 @@ export declare class ATooltipElement extends HTMLElementBase {
76
79
  * (so formatting whitespace / an empty conditional doesn't open a blank bubble).
77
80
  * Re-checked on every show(), so a tooltip populated later self-corrects. */
78
81
  private isEmpty;
82
+ /** While shown, watch the slotted content so a bubble whose content is
83
+ * cleared out from under it — a reactive re-render dropping the text /
84
+ * children under one persistent anchor — self-hides. The mirror of
85
+ * isEmpty()'s "populated later self-corrects": the show-time gate can't fire
86
+ * again on its own once open, so this drives the reverse.
87
+ *
88
+ * A MutationObserver, not `slotchange`, because reactive renderers update
89
+ * text in place — React sets an existing text node's nodeValue rather than
90
+ * replacing the node — which changes no assigned-node set and so fires no
91
+ * `slotchange`; childList + characterData + subtree catches both that and
92
+ * node removal. Observing our own light-DOM children is a READ (like the
93
+ * truncation measurements), so it stays within the no-host-mutation rule.
94
+ * Runs only while shown — attached here, disconnected by hide() / cleanup(). */
95
+ private observeContent;
79
96
  private positionFrame?;
80
97
  private pendingPosition?;
81
98
  private schedulePosition;
@@ -85,6 +85,9 @@ class ATooltipElement extends HTMLElementBase {
85
85
  fading = false;
86
86
  fadeTimer;
87
87
  docMoveBound = false;
88
+ /** Active only while shown: re-runs the empty gate when the slotted content
89
+ * changes under a live bubble. See observeContent(). */
90
+ contentObserver;
88
91
  constructor() {
89
92
  super();
90
93
  const shadow = this.attachShadow({ mode: "open" });
@@ -259,6 +262,28 @@ class ATooltipElement extends HTMLElementBase {
259
262
  isEmpty() {
260
263
  return this.children.length === 0 && (this.textContent ?? "").trim() === "";
261
264
  }
265
+ /** While shown, watch the slotted content so a bubble whose content is
266
+ * cleared out from under it — a reactive re-render dropping the text /
267
+ * children under one persistent anchor — self-hides. The mirror of
268
+ * isEmpty()'s "populated later self-corrects": the show-time gate can't fire
269
+ * again on its own once open, so this drives the reverse.
270
+ *
271
+ * A MutationObserver, not `slotchange`, because reactive renderers update
272
+ * text in place — React sets an existing text node's nodeValue rather than
273
+ * replacing the node — which changes no assigned-node set and so fires no
274
+ * `slotchange`; childList + characterData + subtree catches both that and
275
+ * node removal. Observing our own light-DOM children is a READ (like the
276
+ * truncation measurements), so it stays within the no-host-mutation rule.
277
+ * Runs only while shown — attached here, disconnected by hide() / cleanup(). */
278
+ observeContent() {
279
+ if (typeof MutationObserver === "undefined") return;
280
+ if (!this.contentObserver) {
281
+ this.contentObserver = new MutationObserver(() => {
282
+ if (this.shown && this.isEmpty()) this.hide();
283
+ });
284
+ }
285
+ this.contentObserver.observe(this, { childList: true, characterData: true, subtree: true });
286
+ }
262
287
  // --- positioning (sets only the shadow container's own transform) ---
263
288
  // Single pending position frame: a burst of mousemoves within one frame
264
289
  // coalesces to ONE layout read + transform write, using the LATEST geometry
@@ -353,6 +378,7 @@ class ATooltipElement extends HTMLElementBase {
353
378
  this.doc.addEventListener("mousemove", this.onDocMove);
354
379
  this.docMoveBound = true;
355
380
  }
381
+ this.observeContent();
356
382
  }
357
383
  this.position(e);
358
384
  };
@@ -361,6 +387,7 @@ class ATooltipElement extends HTMLElementBase {
361
387
  if (!this.shown) return;
362
388
  this.shown = false;
363
389
  this.touchOpen = false;
390
+ this.contentObserver?.disconnect();
364
391
  this.container.hidePopover();
365
392
  this.fading = true;
366
393
  if (this.fadeTimer !== void 0) clearTimeout(this.fadeTimer);
@@ -391,6 +418,7 @@ class ATooltipElement extends HTMLElementBase {
391
418
  * calls it. */
392
419
  cleanup() {
393
420
  this.cancelHide();
421
+ this.contentObserver?.disconnect();
394
422
  if (this.shown) {
395
423
  this.shown = false;
396
424
  this.touchOpen = false;
@@ -32,5 +32,6 @@ export { AMenuGroupElement, register_a_menu_group } from './a-menu-group';
32
32
  export { ATabElement, register_a_tab } from './a-tab';
33
33
  export { ATabsElement, register_a_tabs } from './a-tabs';
34
34
  export { ATabPanelElement, register_a_tabpanel } from './a-tabpanel';
35
+ export { ADialogElement, register_a_dialog } from './a-dialog';
35
36
  import './a-title.css';
36
37
  import './a-tag.css';
@@ -17,12 +17,14 @@ import { AMenuGroupElement, register_a_menu_group } from "./a-menu-group";
17
17
  import { ATabElement, register_a_tab } from "./a-tab";
18
18
  import { ATabsElement, register_a_tabs } from "./a-tabs";
19
19
  import { ATabPanelElement, register_a_tabpanel } from "./a-tabpanel";
20
+ import { ADialogElement, register_a_dialog } from "./a-dialog";
20
21
  import "./a-title.css";
21
22
  import "./a-tag.css";
22
23
  export {
23
24
  AButtonElement,
24
25
  ACalendarElement,
25
26
  ACheckboxElement,
27
+ ADialogElement,
26
28
  AExpanderElement,
27
29
  AIconElement,
28
30
  AInputElement,
@@ -42,6 +44,7 @@ export {
42
44
  register_a_button,
43
45
  register_a_calendar,
44
46
  register_a_checkbox,
47
+ register_a_dialog,
45
48
  register_a_expander,
46
49
  register_a_icon,
47
50
  register_a_input,
@@ -291,6 +291,51 @@ export interface AExpanderAttributes extends BaseAttributes {
291
291
  prev: 'open' | 'closed';
292
292
  }>) => void;
293
293
  }
294
+ /**
295
+ * Attributes for the `<a-dialog>` custom element — a modal dialog / edge drawer
296
+ * built on a native `<dialog>` in shadow DOM (top layer, focus trap, backdrop,
297
+ * Esc from the platform). Slots (light-DOM children): `header`, `footer`,
298
+ * `close` (the close button), and the default slot for the body. The element
299
+ * exposes `::part(dialog | header | body | footer | close)`. Low-level
300
+ * attributes; for the typed JSX wrapper use `Dialog` from `@antadesign/anta`.
301
+ */
302
+ export interface ADialogAttributes extends BaseAttributes {
303
+ /** Controlled open state (`'open'` / `'closed'`). Present → controlled: the
304
+ * attribute is the source of truth, user dismiss only dispatches the
305
+ * cancelable `statechange` event, and the consumer answers by updating it.
306
+ * Absent → uncontrolled (use `default-state`). See STATEFUL-COMPONENTS.md. */
307
+ state?: 'open' | 'closed';
308
+ /** Initial open state for the uncontrolled mode (`'open'` / `'closed'`); read
309
+ * once when the element connects. */
310
+ 'default-state'?: 'open' | 'closed';
311
+ /** Placement. `center` (default, omit) is a centered modal; `left` / `right` /
312
+ * `top` / `bottom` turn it into an edge drawer; `fullscreen` fills the whole
313
+ * viewport (no edge gap, no radius). */
314
+ position?: 'center' | 'left' | 'right' | 'top' | 'bottom' | 'fullscreen';
315
+ /** Corner radius. A side keyword (`top` / `right` / `bottom` / `left`) rounds
316
+ * only that edge's two corners at `--dialog-radius`; a length (`round="20px"`)
317
+ * or full `border-radius` shorthand rounds all corners at that value; bare
318
+ * `round` rounds all corners at `--dialog-radius`. Omit for the position
319
+ * default (center rounded, drawers / fullscreen square). */
320
+ round?: boolean | number | 'top' | 'right' | 'bottom' | 'left' | (string & {});
321
+ /** Disable light dismiss — Esc + backdrop click no longer close the dialog (it
322
+ * closes only via the close button or programmatically). For alert / confirm
323
+ * dialogs. Presence-based (`''` on, omit off). */
324
+ persistent?: boolean | '';
325
+ /** Uncontrolled trigger name. Any element with `data-dialog-open="{name}"`
326
+ * opens this dialog and `data-dialog-close="{name}"` closes it, via a document
327
+ * click listener. Ignored in controlled mode. */
328
+ name?: string;
329
+ /** Fires before the open state changes — the element dispatches a `cancelable`
330
+ * `statechange` `CustomEvent` whose `detail` is `{ next, prev }` in the
331
+ * `'open'|'closed'` vocabulary. Uncontrolled, `preventDefault()` vetoes the
332
+ * transition. All-lowercase so both renderers bind it (React 19 keeps the case
333
+ * after `on`; Preact lowercases). */
334
+ onstatechange?: (e: CustomEvent<{
335
+ next: 'open' | 'closed';
336
+ prev: 'open' | 'closed';
337
+ }>) => void;
338
+ }
294
339
  /**
295
340
  * Attributes for the `<a-icon>` custom element. `shape` is typed as
296
341
  * `IconShape` (`keyof IconShapes`); the `IconShapes` interface is
package/dist/index.d.ts CHANGED
@@ -51,6 +51,8 @@ export { InputDate } from './components/InputDate';
51
51
  export type { InputDateProps, InputDateChangeAttrs } from './components/InputDate';
52
52
  export { InputTime } from './components/InputTime';
53
53
  export type { InputTimeProps, InputTimeChangeAttrs } from './components/InputTime';
54
+ export { InputAutocomplete } from './components/InputAutocomplete';
55
+ export type { InputAutocompleteProps } from './components/InputAutocomplete';
54
56
  export { buildMonth, getWeekdays, firstDayOfWeek, clampDate, isOutOfRange, parseISODate, parseDateInput, formatDateInput, dateFormatPattern, parseTimeInput, parseDateTimeInput, formatDateTimeInput, dateTimeFormatPattern, usesHour12, } from './calendar-core';
55
57
  export type { CalendarDay, CalendarWeekday, CalendarMonth, BuildMonthOptions, ParseDateOptions, } from './calendar-core';
56
58
  export { RadioGroup } from './components/RadioGroup';
@@ -63,6 +65,8 @@ export { Tabs } from './components/Tabs';
63
65
  export type { TabsProps, TabOption, TabsChangeAttrs } from './components/Tabs';
64
66
  export { TabPanel } from './components/TabPanel';
65
67
  export type { TabPanelProps } from './components/TabPanel';
68
+ export { Dialog } from './components/Dialog';
69
+ export type { DialogProps } from './components/Dialog';
66
70
  export type { BaseProps, BaseAttributes } from './general_types';
67
71
  export { configure } from './jsx-runtime';
68
72
  export type { AntaIntrinsicElements } from './jsx-runtime';
package/dist/index.js CHANGED
@@ -16,6 +16,7 @@ import { Input } from "./components/Input";
16
16
  import { Calendar } from "./components/Calendar";
17
17
  import { InputDate } from "./components/InputDate";
18
18
  import { InputTime } from "./components/InputTime";
19
+ import { InputAutocomplete } from "./components/InputAutocomplete";
19
20
  import {
20
21
  buildMonth,
21
22
  getWeekdays,
@@ -37,16 +38,19 @@ import { Select, optionsWithSelection } from "./components/Select";
37
38
  import { SelectFaceted } from "./components/SelectFaceted";
38
39
  import { Tabs } from "./components/Tabs";
39
40
  import { TabPanel } from "./components/TabPanel";
41
+ import { Dialog } from "./components/Dialog";
40
42
  import { configure } from "./jsx-runtime";
41
43
  export {
42
44
  Button,
43
45
  Calendar,
44
46
  Checkbox,
47
+ Dialog,
45
48
  Expander,
46
49
  ICON_SHAPES,
47
50
  ICON_SYNONYMS,
48
51
  Icon,
49
52
  Input,
53
+ InputAutocomplete,
50
54
  InputDate,
51
55
  InputTime,
52
56
  Menu,
@@ -41,7 +41,7 @@ export declare function useMemo<T>(factory: () => T, deps: unknown[]): T;
41
41
  export declare function jsx(type: ComponentType, props: Record<string, unknown> | null, key?: string | number): unknown;
42
42
  export declare function jsxs(type: ComponentType, props: Record<string, unknown> | null, key?: string | number): unknown;
43
43
  export { _Fragment as Fragment };
44
- import type { AProgressAttributes, ATextAttributes, ATitleAttributes, ATagAttributes, AExpanderAttributes, AIconAttributes, AButtonAttributes, ACheckboxAttributes, ATooltipAttributes, AInputAttributes, AInputTimeAttributes, ACalendarAttributes, ARadioAttributes, ARadioGroupAttributes, AMenuAttributes, AMenuItemAttributes, AMenuGroupAttributes, ATabsAttributes, ATabAttributes, ATabpanelAttributes, BaseAttributes } from './general_types';
44
+ import type { AProgressAttributes, ATextAttributes, ATitleAttributes, ATagAttributes, AExpanderAttributes, AIconAttributes, AButtonAttributes, ACheckboxAttributes, ATooltipAttributes, AInputAttributes, AInputTimeAttributes, ACalendarAttributes, ARadioAttributes, ARadioGroupAttributes, AMenuAttributes, AMenuItemAttributes, AMenuGroupAttributes, ATabsAttributes, ATabAttributes, ATabpanelAttributes, ADialogAttributes, BaseAttributes } from './general_types';
45
45
  export declare namespace JSX {
46
46
  interface IntrinsicElements extends React.JSX.IntrinsicElements, AntaIntrinsicElements {
47
47
  }
@@ -91,4 +91,5 @@ export interface AntaIntrinsicElements {
91
91
  'a-tab': ATabAttributes;
92
92
  'a-tab-label': BaseAttributes;
93
93
  'a-tabpanel': ATabpanelAttributes;
94
+ 'a-dialog': ADialogAttributes;
94
95
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@antadesign/anta",
3
- "version": "0.3.5",
3
+ "version": "0.3.7",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",