@antadesign/anta 0.3.1 → 0.3.3

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 (98) hide show
  1. package/dist/anta_helpers.d.ts +111 -0
  2. package/dist/anta_helpers.js +90 -1
  3. package/dist/calendar-core.d.ts +126 -0
  4. package/dist/calendar-core.js +289 -0
  5. package/dist/components/Button.d.ts +9 -1
  6. package/dist/components/Button.js +12 -18
  7. package/dist/components/Calendar.d.ts +80 -0
  8. package/dist/components/Calendar.js +220 -0
  9. package/dist/components/Checkbox.d.ts +21 -15
  10. package/dist/components/Checkbox.js +17 -7
  11. package/dist/components/Expander.d.ts +7 -1
  12. package/dist/components/Expander.js +4 -2
  13. package/dist/components/Input.d.ts +16 -8
  14. package/dist/components/Input.js +19 -11
  15. package/dist/components/InputDate.d.ts +87 -0
  16. package/dist/components/InputDate.js +278 -0
  17. package/dist/components/InputDate.module.css +1 -0
  18. package/dist/components/Menu.d.ts +5 -1
  19. package/dist/components/Menu.js +6 -2
  20. package/dist/components/MenuItem.d.ts +48 -7
  21. package/dist/components/MenuItem.js +71 -7
  22. package/dist/components/MenuSeparator.d.ts +13 -2
  23. package/dist/components/MenuSeparator.js +12 -2
  24. package/dist/components/Progress.d.ts +4 -1
  25. package/dist/components/Progress.js +4 -3
  26. package/dist/components/RadioGroup.d.ts +17 -15
  27. package/dist/components/RadioGroup.js +8 -8
  28. package/dist/components/Select.d.ts +255 -0
  29. package/dist/components/Select.js +290 -0
  30. package/dist/components/Select.module.css +1 -0
  31. package/dist/components/Tab.d.ts +37 -0
  32. package/dist/components/Tab.js +5 -0
  33. package/dist/components/TabPanel.d.ts +22 -0
  34. package/dist/components/TabPanel.js +5 -0
  35. package/dist/components/Tabs.d.ts +129 -0
  36. package/dist/components/Tabs.js +176 -0
  37. package/dist/components/Tabs.module.css +1 -0
  38. package/dist/components/Tag.d.ts +10 -9
  39. package/dist/components/Tag.js +2 -2
  40. package/dist/components/Text.d.ts +6 -5
  41. package/dist/components/Title.d.ts +4 -2
  42. package/dist/components/Tooltip.d.ts +13 -1
  43. package/dist/components/Tooltip.js +9 -0
  44. package/dist/elements/a-button.css +1 -1
  45. package/dist/elements/a-calendar.css +1 -0
  46. package/dist/elements/a-calendar.d.ts +76 -0
  47. package/dist/elements/a-calendar.js +190 -0
  48. package/dist/elements/a-checkbox.css +1 -1
  49. package/dist/elements/a-checkbox.d.ts +1 -2
  50. package/dist/elements/a-checkbox.js +5 -5
  51. package/dist/elements/a-expander.css +1 -1
  52. package/dist/elements/a-expander.d.ts +16 -5
  53. package/dist/elements/a-expander.js +65 -9
  54. package/dist/elements/a-icon.shapes.css +1 -1
  55. package/dist/elements/a-icon.shapes.d.ts +6 -1
  56. package/dist/elements/a-icon.shapes.js +9 -0
  57. package/dist/elements/a-input.css +1 -1
  58. package/dist/elements/a-input.d.ts +6 -0
  59. package/dist/elements/a-input.js +28 -9
  60. package/dist/elements/a-menu-group.css +1 -1
  61. package/dist/elements/a-menu-item.css +1 -1
  62. package/dist/elements/a-menu-item.d.ts +14 -4
  63. package/dist/elements/a-menu-item.js +17 -0
  64. package/dist/elements/a-menu-separator.css +1 -1
  65. package/dist/elements/a-menu.css +1 -1
  66. package/dist/elements/a-menu.d.ts +51 -8
  67. package/dist/elements/a-menu.js +285 -42
  68. package/dist/elements/a-progress.css +1 -1
  69. package/dist/elements/a-radio-group.d.ts +1 -3
  70. package/dist/elements/a-radio-group.js +13 -13
  71. package/dist/elements/a-radio.css +1 -1
  72. package/dist/elements/a-radio.d.ts +3 -11
  73. package/dist/elements/a-radio.js +3 -34
  74. package/dist/elements/a-tab.css +1 -0
  75. package/dist/elements/a-tab.d.ts +6 -0
  76. package/dist/elements/a-tab.js +15 -0
  77. package/dist/elements/a-tabpanel.css +1 -0
  78. package/dist/elements/a-tabs.css +1 -0
  79. package/dist/elements/a-tabs.d.ts +28 -0
  80. package/dist/elements/a-tabs.js +157 -0
  81. package/dist/elements/a-tag.css +1 -1
  82. package/dist/elements/a-text.css +1 -1
  83. package/dist/elements/a-text.d.ts +14 -13
  84. package/dist/elements/a-text.js +53 -23
  85. package/dist/elements/a-title.css +1 -1
  86. package/dist/elements/a-tooltip.css +1 -1
  87. package/dist/elements/a-tooltip.d.ts +16 -8
  88. package/dist/elements/a-tooltip.js +62 -16
  89. package/dist/elements/index.d.ts +4 -0
  90. package/dist/elements/index.js +10 -0
  91. package/dist/general_types.d.ts +252 -30
  92. package/dist/index.d.ts +15 -1
  93. package/dist/index.js +43 -1
  94. package/dist/jsx-runtime.d.ts +20 -7
  95. package/dist/jsx-runtime.js +6 -0
  96. package/dist/reset.css +1 -1
  97. package/dist/tokens.css +1 -1
  98. package/package.json +4 -2
@@ -28,6 +28,7 @@ import './a-tooltip.css';
28
28
  * below) instead of selecting text or popping the system menu.
29
29
  */
30
30
  export declare class ATooltipElement extends HTMLElementBase {
31
+ #private;
31
32
  static observedAttributes: string[];
32
33
  /** Shadow-internal popover surface — the only thing we ever mutate. */
33
34
  private container;
@@ -60,14 +61,21 @@ export declare class ATooltipElement extends HTMLElementBase {
60
61
  * fed the latest cursor event, so it shows at the cursor and so moving back
61
62
  * onto an anchor after the tooltip was dismissed re-arms it. */
62
63
  private makeDebouncedShow;
63
- private get isInteractive();
64
- /** Pinned under the anchor (no cursor-following) the DEFAULT. Following the
65
- * cursor is opt-in via the `follow` attribute. `interactive` (you can't move
66
- * into a bubble that chases the cursor) and a touch long-press (a finger
67
- * can't track one) force pinned regardless of `follow`. */
68
- private get isPinned();
69
- private get prefersTop();
70
- private get delay();
64
+ /** The element whose overflow decides whether the tooltip shows: a
65
+ * `truncated-selector` resolved within the anchor wins; else the first of
66
+ * Anta's ellipsizing label parts inside the anchor; else the anchor itself
67
+ * (which may be the clipping box for a hand-authored target). */
68
+ private resolveTruncationTarget;
69
+ /** True when the resolved target overflows its box (horizontal ellipsis or
70
+ * vertical clamp). A 1px threshold absorbs sub-pixel rounding; a zero-size
71
+ * (hidden / detached) target counts as not truncated. Measured fresh on each
72
+ * show attempt, so late fonts / resizes self-correct with no observer. */
73
+ private isTargetTruncated;
74
+ /** True when there's nothing worth showing: no element children (so an
75
+ * icon/image-only bubble still counts as content) and no non-whitespace text
76
+ * (so formatting whitespace / an empty conditional doesn't open a blank bubble).
77
+ * Re-checked on every show(), so a tooltip populated later self-corrects. */
78
+ private isEmpty;
71
79
  private positionFrame?;
72
80
  private pendingPosition?;
73
81
  private schedulePosition;
@@ -1,4 +1,4 @@
1
- import { HTMLElementBase } from "../anta_helpers";
1
+ import { HTMLElementBase, anchorRect, isMenuOpen, isInsideOpenMenu } from "../anta_helpers";
2
2
  import { debounce } from "es-toolkit";
3
3
  import "./a-tooltip.css";
4
4
  const MARGIN = 4;
@@ -12,6 +12,7 @@ const PROX_NEAR = 10;
12
12
  const PROX_FAR = 100;
13
13
  const PROX_FADE_MS = 60;
14
14
  const ENTER_TOUCH_DELAY = 500;
15
+ const TRUNCATING_PARTS = "a-tab-label, a-button-label";
15
16
  const LEAVE_TOUCH_DELAY = 1500;
16
17
  const TOUCH_SLOP = 10;
17
18
  let currentOpen = null;
@@ -163,10 +164,10 @@ class ATooltipElement extends HTMLElementBase {
163
164
  this.bubble.setAttribute("part", "bubble");
164
165
  this.container.append(this.bubble);
165
166
  this.container.addEventListener("mouseenter", () => {
166
- if (this.isInteractive) this.cancelHide();
167
+ if (this.#isInteractive) this.cancelHide();
167
168
  });
168
169
  this.container.addEventListener("mouseleave", () => {
169
- if (this.isInteractive && this.shown) this.scheduleHide();
170
+ if (this.#isInteractive && this.shown) this.scheduleHide();
170
171
  });
171
172
  shadow.append(style, this.container);
172
173
  }
@@ -196,28 +197,68 @@ class ATooltipElement extends HTMLElementBase {
196
197
  * onto an anchor after the tooltip was dismissed re-arms it. */
197
198
  makeDebouncedShow() {
198
199
  this.debouncedShow?.cancel();
199
- this.debouncedShow = debounce((e) => this.show(e), this.delay);
200
+ this.debouncedShow = debounce((e) => this.show(e), this.#delay);
200
201
  }
201
- get isInteractive() {
202
+ get #isInteractive() {
202
203
  return this.hasAttribute("interactive");
203
204
  }
204
205
  /** Pinned under the anchor (no cursor-following) — the DEFAULT. Following the
205
206
  * cursor is opt-in via the `follow` attribute. `interactive` (you can't move
206
207
  * into a bubble that chases the cursor) and a touch long-press (a finger
207
208
  * can't track one) force pinned regardless of `follow`. */
208
- get isPinned() {
209
- if (this.isInteractive || this.touchOpen) return true;
209
+ get #isPinned() {
210
+ if (this.#isInteractive || this.touchOpen) return true;
210
211
  return !this.hasAttribute("follow");
211
212
  }
212
- get prefersTop() {
213
+ get #prefersTop() {
213
214
  return this.getAttribute("placement") === "top";
214
215
  }
215
- get delay() {
216
+ get #delay() {
216
217
  const attr = this.getAttribute("delay");
217
218
  if (attr == null) return DEFAULT_DELAY;
218
219
  const n = parseInt(attr, 10);
219
220
  return Number.isFinite(n) ? n : DEFAULT_DELAY;
220
221
  }
222
+ // --- truncated-only gating (UI-thread layout READS — no mutation) ---
223
+ /** When set, the tooltip only shows if its resolved target is actually
224
+ * truncated/clipped; a fitting label gets no tooltip. */
225
+ get #truncatedOnly() {
226
+ return this.hasAttribute("truncated-only");
227
+ }
228
+ /** The element whose overflow decides whether the tooltip shows: a
229
+ * `truncated-selector` resolved within the anchor wins; else the first of
230
+ * Anta's ellipsizing label parts inside the anchor; else the anchor itself
231
+ * (which may be the clipping box for a hand-authored target). */
232
+ resolveTruncationTarget() {
233
+ const anchor = this.anchor;
234
+ if (!anchor) return null;
235
+ const sel = this.getAttribute("truncated-selector");
236
+ if (sel) {
237
+ try {
238
+ const found = anchor.querySelector(sel);
239
+ if (found) return found;
240
+ } catch {
241
+ }
242
+ }
243
+ return anchor.querySelector(TRUNCATING_PARTS) ?? anchor;
244
+ }
245
+ /** True when the resolved target overflows its box (horizontal ellipsis or
246
+ * vertical clamp). A 1px threshold absorbs sub-pixel rounding; a zero-size
247
+ * (hidden / detached) target counts as not truncated. Measured fresh on each
248
+ * show attempt, so late fonts / resizes self-correct with no observer. */
249
+ isTargetTruncated() {
250
+ const t = this.resolveTruncationTarget();
251
+ if (!t) return false;
252
+ if (t.clientWidth === 0 && t.clientHeight === 0) return false;
253
+ return t.scrollWidth - t.clientWidth > 1 || t.scrollHeight - t.clientHeight > 1;
254
+ }
255
+ /** True when there's nothing worth showing: no element children (so an
256
+ * icon/image-only bubble still counts as content) and no non-whitespace text
257
+ * (so formatting whitespace / an empty conditional doesn't open a blank bubble).
258
+ * Re-checked on every show(), so a tooltip populated later self-corrects. */
259
+ isEmpty() {
260
+ return this.children.length === 0 && (this.textContent ?? "").trim() === "";
261
+ }
221
262
  // --- positioning (sets only the shadow container's own transform) ---
222
263
  // Single pending position frame: a burst of mousemoves within one frame
223
264
  // coalesces to ONE layout read + transform write, using the LATEST geometry
@@ -253,10 +294,10 @@ class ATooltipElement extends HTMLElementBase {
253
294
  positionToTarget = () => {
254
295
  this.schedulePosition(() => {
255
296
  if (!this.anchor || !this.shown) return;
256
- const a = this.anchor.getBoundingClientRect();
297
+ const a = anchorRect(this.anchor);
257
298
  const box = this.container.getBoundingClientRect();
258
299
  const { innerWidth: vw, innerHeight: vh } = this.view;
259
- const top = this.flipVertical(a.top - box.height - MARGIN, a.bottom + MARGIN, box.height, vh, this.prefersTop || this.touchOpen);
300
+ const top = this.flipVertical(a.top - box.height - MARGIN, a.bottom + MARGIN, box.height, vh, this.#prefersTop || this.touchOpen);
260
301
  this.place(a.left, top, box.width, vw);
261
302
  });
262
303
  };
@@ -265,12 +306,12 @@ class ATooltipElement extends HTMLElementBase {
265
306
  if (!this.shown && !this.fading) return;
266
307
  const box = this.container.getBoundingClientRect();
267
308
  const { innerWidth: vw, innerHeight: vh } = this.view;
268
- const top = this.flipVertical(e.clientY - box.height - MARGIN * 2, e.clientY + CURSOR_SIZE, box.height, vh, this.prefersTop);
309
+ const top = this.flipVertical(e.clientY - box.height - MARGIN * 2, e.clientY + CURSOR_SIZE, box.height, vh, this.#prefersTop);
269
310
  this.place(e.clientX - PADDING_X, top, box.width, vw);
270
311
  });
271
312
  };
272
313
  position(e) {
273
- if (!this.isPinned && e) this.positionToMouse(e);
314
+ if (!this.#isPinned && e) this.positionToMouse(e);
274
315
  else this.positionToTarget();
275
316
  }
276
317
  /** Opacity for the inner bubble from the cursor's distance to the anchor rect
@@ -278,7 +319,7 @@ class ATooltipElement extends HTMLElementBase {
278
319
  * Cursor-follow only — drives the "fade as you move away" behaviour. */
279
320
  proximityOpacity(e) {
280
321
  if (!this.anchor) return 1;
281
- const r = this.anchor.getBoundingClientRect();
322
+ const r = anchorRect(this.anchor);
282
323
  const dx = Math.max(r.left - e.clientX, 0, e.clientX - r.right);
283
324
  const dy = Math.max(r.top - e.clientY, 0, e.clientY - r.bottom);
284
325
  const dist = Math.hypot(dx, dy);
@@ -289,6 +330,9 @@ class ATooltipElement extends HTMLElementBase {
289
330
  // --- show / hide ---
290
331
  show = (e) => {
291
332
  if (!this.anchor) return;
333
+ if (isMenuOpen() && !isInsideOpenMenu(this.anchor)) return;
334
+ if (this.isEmpty()) return;
335
+ if (this.#truncatedOnly && !this.isTargetTruncated()) return;
292
336
  this.cancelHide();
293
337
  if (currentOpen && currentOpen !== this && this.anchor.contains(currentOpen.anchor)) {
294
338
  return;
@@ -365,7 +409,7 @@ class ATooltipElement extends HTMLElementBase {
365
409
  this.cleanup();
366
410
  return;
367
411
  }
368
- if (!(this.shown || this.fading) || this.isPinned) return;
412
+ if (!(this.shown || this.fading) || this.#isPinned) return;
369
413
  this.lastMouse = e;
370
414
  const o = this.proximityOpacity(e);
371
415
  if (o === 0) {
@@ -400,6 +444,8 @@ class ATooltipElement extends HTMLElementBase {
400
444
  /** Open now if another tooltip is hot (skip delay), else (re)arm the delayed
401
445
  * show with the latest cursor event. */
402
446
  trigger(e) {
447
+ if (this.isEmpty()) return;
448
+ if (this.#truncatedOnly && !this.isTargetTruncated()) return;
403
449
  if (isHot()) {
404
450
  this.debouncedShow?.cancel();
405
451
  this.show(e);
@@ -421,7 +467,7 @@ class ATooltipElement extends HTMLElementBase {
421
467
  if (e.pointerType !== "mouse") return;
422
468
  this.lastMouse = e;
423
469
  if (this.shown) {
424
- if (!this.isPinned) this.positionToMouse(e);
470
+ if (!this.#isPinned) this.positionToMouse(e);
425
471
  } else {
426
472
  this.trigger(e);
427
473
  }
@@ -21,11 +21,15 @@ export { ACheckboxElement, register_a_checkbox } from './a-checkbox';
21
21
  export { AExpanderElement, register_a_expander } from './a-expander';
22
22
  export { ATooltipElement, register_a_tooltip } from './a-tooltip';
23
23
  export { AInputElement, register_a_input } from './a-input';
24
+ export { ACalendarElement, register_a_calendar } from './a-calendar';
24
25
  export { ARadioElement, register_a_radio } from './a-radio';
25
26
  export { ARadioGroupElement, register_a_radio_group } from './a-radio-group';
26
27
  export { AMenuElement, register_a_menu } from './a-menu';
27
28
  export { AMenuItemElement, register_a_menu_item } from './a-menu-item';
28
29
  export { AMenuSeparatorElement, register_a_menu_separator } from './a-menu-separator';
29
30
  export { AMenuGroupElement, register_a_menu_group } from './a-menu-group';
31
+ export { ATabElement, register_a_tab } from './a-tab';
32
+ export { ATabsElement, register_a_tabs } from './a-tabs';
30
33
  import './a-title.css';
31
34
  import './a-tag.css';
35
+ import './a-tabpanel.css';
@@ -6,16 +6,21 @@ import { ACheckboxElement, register_a_checkbox } from "./a-checkbox";
6
6
  import { AExpanderElement, register_a_expander } from "./a-expander";
7
7
  import { ATooltipElement, register_a_tooltip } from "./a-tooltip";
8
8
  import { AInputElement, register_a_input } from "./a-input";
9
+ import { ACalendarElement, register_a_calendar } from "./a-calendar";
9
10
  import { ARadioElement, register_a_radio } from "./a-radio";
10
11
  import { ARadioGroupElement, register_a_radio_group } from "./a-radio-group";
11
12
  import { AMenuElement, register_a_menu } from "./a-menu";
12
13
  import { AMenuItemElement, register_a_menu_item } from "./a-menu-item";
13
14
  import { AMenuSeparatorElement, register_a_menu_separator } from "./a-menu-separator";
14
15
  import { AMenuGroupElement, register_a_menu_group } from "./a-menu-group";
16
+ import { ATabElement, register_a_tab } from "./a-tab";
17
+ import { ATabsElement, register_a_tabs } from "./a-tabs";
15
18
  import "./a-title.css";
16
19
  import "./a-tag.css";
20
+ import "./a-tabpanel.css";
17
21
  export {
18
22
  AButtonElement,
23
+ ACalendarElement,
19
24
  ACheckboxElement,
20
25
  AExpanderElement,
21
26
  AIconElement,
@@ -27,9 +32,12 @@ export {
27
32
  AProgressElement,
28
33
  ARadioElement,
29
34
  ARadioGroupElement,
35
+ ATabElement,
36
+ ATabsElement,
30
37
  ATextElement,
31
38
  ATooltipElement,
32
39
  register_a_button,
40
+ register_a_calendar,
33
41
  register_a_checkbox,
34
42
  register_a_expander,
35
43
  register_a_icon,
@@ -41,6 +49,8 @@ export {
41
49
  register_a_progress,
42
50
  register_a_radio,
43
51
  register_a_radio_group,
52
+ register_a_tab,
53
+ register_a_tabs,
44
54
  register_a_text,
45
55
  register_a_tooltip
46
56
  };