@antadesign/anta 0.3.33 → 0.3.35

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 (205) hide show
  1. package/LICENSE.md +14 -1
  2. package/README.md +9 -0
  3. package/dist/anta_helpers.d.ts +46 -30
  4. package/dist/anta_helpers.js +66 -25
  5. package/dist/bundle.css +1 -1
  6. package/dist/bundle.js +2 -1353
  7. package/dist/components/Banner.d.ts +25 -40
  8. package/dist/components/Banner.js +15 -17
  9. package/dist/components/Breadcrumbs.d.ts +0 -1
  10. package/dist/components/Breadcrumbs.js +0 -1
  11. package/dist/components/Button.d.ts +2 -3
  12. package/dist/components/Button.js +1 -0
  13. package/dist/components/ButtonCopy.js +3 -2
  14. package/dist/components/Calendar.js +13 -13
  15. package/dist/components/Card.d.ts +9 -17
  16. package/dist/components/Card.js +50 -46
  17. package/dist/components/Dialog.d.ts +1 -0
  18. package/dist/components/Dialog.js +16 -10
  19. package/dist/components/Expander.d.ts +6 -21
  20. package/dist/components/Expander.js +24 -23
  21. package/dist/components/Icon.d.ts +8 -14
  22. package/dist/components/Input.d.ts +77 -96
  23. package/dist/components/Input.js +23 -27
  24. package/dist/components/InputAutocomplete.d.ts +29 -10
  25. package/dist/components/InputAutocomplete.js +25 -8
  26. package/dist/components/InputDate.d.ts +0 -1
  27. package/dist/components/InputDate.js +2 -3
  28. package/dist/components/InputTime.d.ts +10 -4
  29. package/dist/components/InputTime.js +20 -16
  30. package/dist/components/Loader.d.ts +2 -2
  31. package/dist/components/Menu.d.ts +5 -4
  32. package/dist/components/Menu.js +13 -8
  33. package/dist/components/MenuItem.js +1 -14
  34. package/dist/components/MenuItemCopy.js +2 -2
  35. package/dist/components/Panel.d.ts +3 -1
  36. package/dist/components/Panel.js +17 -11
  37. package/dist/components/Progress.d.ts +21 -23
  38. package/dist/components/Progress.js +13 -9
  39. package/dist/components/RadioGroup.js +6 -8
  40. package/dist/components/{select-parts.css → Select.css} +1 -1
  41. package/dist/components/Select.d.ts +53 -36
  42. package/dist/components/Select.js +53 -98
  43. package/dist/components/SelectFaceted.d.ts +7 -4
  44. package/dist/components/SelectFaceted.js +21 -10
  45. package/dist/components/Slider.d.ts +28 -11
  46. package/dist/components/Slider.js +20 -20
  47. package/dist/components/Steps.css +1 -1
  48. package/dist/components/Steps.d.ts +0 -1
  49. package/dist/components/Steps.js +1 -12
  50. package/dist/components/Tabs.d.ts +17 -20
  51. package/dist/components/Tabs.js +7 -9
  52. package/dist/components/Text.d.ts +55 -36
  53. package/dist/components/Text.js +35 -22
  54. package/dist/components/Title.d.ts +19 -27
  55. package/dist/components/Title.js +2 -1
  56. package/dist/components/Toaster.js +9 -2
  57. package/dist/components/Tooltip.d.ts +10 -15
  58. package/dist/components/copy-props.d.ts +14 -3
  59. package/dist/components/copy-props.js +14 -3
  60. package/dist/components/select-tree.d.ts +24 -0
  61. package/dist/components/select-tree.js +35 -0
  62. package/dist/element-base.d.ts +10 -0
  63. package/dist/element-base.js +15 -0
  64. package/dist/elements/a-avatar.css +1 -1
  65. package/dist/elements/a-avatar.js +2 -28
  66. package/dist/elements/a-banner.css +1 -1
  67. package/dist/elements/a-banner.d.ts +4 -1
  68. package/dist/elements/a-banner.js +22 -112
  69. package/dist/elements/a-breadcrumbs.d.ts +1 -0
  70. package/dist/elements/a-breadcrumbs.js +1 -0
  71. package/dist/elements/a-button.css +1 -1
  72. package/dist/elements/a-button.d.ts +10 -7
  73. package/dist/elements/a-button.js +18 -1
  74. package/dist/elements/a-calendar.d.ts +14 -13
  75. package/dist/elements/a-calendar.js +29 -24
  76. package/dist/elements/a-card.css +1 -1
  77. package/dist/elements/a-card.d.ts +0 -9
  78. package/dist/elements/a-card.js +0 -184
  79. package/dist/elements/a-checkbox.css +1 -1
  80. package/dist/elements/a-copy.css +1 -1
  81. package/dist/elements/a-copy.d.ts +1 -5
  82. package/dist/elements/a-copy.js +129 -108
  83. package/dist/elements/a-dialog.css +1 -1
  84. package/dist/elements/a-dialog.d.ts +1 -1
  85. package/dist/elements/a-dialog.js +68 -194
  86. package/dist/elements/a-expander.css +1 -1
  87. package/dist/elements/a-expander.d.ts +4 -30
  88. package/dist/elements/a-expander.js +85 -344
  89. package/dist/elements/a-icon.d.ts +5 -23
  90. package/dist/elements/a-icon.js +1 -2
  91. package/dist/elements/a-input-date.d.ts +1 -0
  92. package/dist/elements/a-input-date.js +1 -0
  93. package/dist/elements/a-input-time.css +1 -1
  94. package/dist/elements/a-input-time.d.ts +2 -1
  95. package/dist/elements/a-input-time.js +101 -168
  96. package/dist/elements/a-input.css +1 -1
  97. package/dist/elements/a-input.d.ts +10 -8
  98. package/dist/elements/a-input.js +155 -230
  99. package/dist/elements/a-loader.d.ts +5 -8
  100. package/dist/elements/a-loader.js +1 -2
  101. package/dist/elements/a-menu-item.css +1 -1
  102. package/dist/elements/a-menu-item.d.ts +5 -3
  103. package/dist/elements/a-menu-item.js +5 -1
  104. package/dist/elements/a-menu.css +1 -1
  105. package/dist/elements/a-menu.d.ts +5 -7
  106. package/dist/elements/a-menu.js +383 -299
  107. package/dist/elements/a-panel.css +1 -1
  108. package/dist/elements/a-panel.js +19 -37
  109. package/dist/elements/a-progress.css +1 -1
  110. package/dist/elements/a-progress.d.ts +0 -22
  111. package/dist/elements/a-progress.js +0 -100
  112. package/dist/elements/a-radio-group.d.ts +1 -1
  113. package/dist/elements/a-radio-group.js +6 -4
  114. package/dist/elements/a-select-faceted.d.ts +1 -0
  115. package/dist/elements/a-select-faceted.js +1 -0
  116. package/dist/elements/a-select.d.ts +1 -0
  117. package/dist/elements/a-select.js +1 -0
  118. package/dist/elements/a-slider.css +1 -1
  119. package/dist/elements/a-slider.d.ts +11 -3
  120. package/dist/elements/a-slider.js +244 -242
  121. package/dist/elements/a-steps.d.ts +1 -0
  122. package/dist/elements/a-steps.js +1 -0
  123. package/dist/elements/a-switch.css +1 -1
  124. package/dist/elements/a-tab.css +1 -1
  125. package/dist/elements/a-tabpanel.d.ts +2 -2
  126. package/dist/elements/a-tabpanel.js +13 -3
  127. package/dist/elements/a-tabs.css +1 -1
  128. package/dist/elements/a-tabs.d.ts +1 -1
  129. package/dist/elements/a-tabs.js +6 -4
  130. package/dist/elements/a-tag.css +1 -1
  131. package/dist/elements/a-tag.d.ts +1 -0
  132. package/dist/elements/a-tag.js +1 -0
  133. package/dist/elements/a-text.css +1 -1
  134. package/dist/elements/a-text.d.ts +6 -43
  135. package/dist/elements/a-text.js +110 -193
  136. package/dist/elements/a-title.css +1 -1
  137. package/dist/elements/a-title.d.ts +1 -0
  138. package/dist/elements/a-title.js +1 -0
  139. package/dist/elements/a-toast.css +1 -1
  140. package/dist/elements/a-toast.d.ts +10 -45
  141. package/dist/elements/a-toast.js +80 -66
  142. package/dist/elements/a-toaster.css +1 -1
  143. package/dist/elements/a-toaster.js +9 -44
  144. package/dist/elements/a-tooltip.css +1 -1
  145. package/dist/elements/a-tooltip.d.ts +1 -1
  146. package/dist/elements/a-tooltip.js +142 -136
  147. package/dist/elements/copy-behavior.d.ts +1 -1
  148. package/dist/elements/copy-behavior.js +21 -21
  149. package/dist/elements/index.d.ts +9 -3
  150. package/dist/elements/index.js +6 -6
  151. package/dist/elements/input-focus-modality.d.ts +15 -0
  152. package/dist/elements/input-focus-modality.js +44 -0
  153. package/dist/elements/input-trailing-actions.d.ts +5 -0
  154. package/dist/elements/input-trailing-actions.js +38 -0
  155. package/dist/elements/shadow-aria.d.ts +2 -0
  156. package/dist/elements/shadow-aria.js +2 -1
  157. package/dist/elements/value-input.d.ts +3 -0
  158. package/dist/elements/value-input.js +12 -0
  159. package/dist/general_types.d.ts +103 -96
  160. package/dist/index.d.ts +1 -1
  161. package/dist/input-events.d.ts +4 -0
  162. package/dist/input-events.js +15 -0
  163. package/dist/jsx-runtime.d.ts +70 -23
  164. package/dist/jsx-runtime.js +26 -19
  165. package/dist/native-event-props.d.ts +2 -0
  166. package/dist/native-event-props.js +10 -0
  167. package/dist/reset.css +1 -1
  168. package/dist/theme-antithesis.css +10 -1
  169. package/dist/theme-antune.css +1 -1
  170. package/docs/accessibility.md +17 -3
  171. package/docs/changelog.md +384 -2
  172. package/docs/comparison.md +2 -2
  173. package/docs/components/avatar.md +5 -0
  174. package/docs/components/banner.md +117 -187
  175. package/docs/components/breadcrumbs.md +9 -6
  176. package/docs/components/button.md +22 -0
  177. package/docs/components/card.md +74 -28
  178. package/docs/components/checkbox.md +9 -10
  179. package/docs/components/dialog.md +83 -32
  180. package/docs/components/expander.md +198 -435
  181. package/docs/components/icon.md +11 -17
  182. package/docs/components/input-autocomplete.md +152 -52
  183. package/docs/components/input-date.md +175 -148
  184. package/docs/components/input-time.md +81 -38
  185. package/docs/components/input.md +343 -349
  186. package/docs/components/loader.md +2 -1
  187. package/docs/components/menu.md +35 -6
  188. package/docs/components/panel.md +18 -0
  189. package/docs/components/progress.md +83 -49
  190. package/docs/components/radio.md +39 -43
  191. package/docs/components/select-faceted.md +54 -7
  192. package/docs/components/select.md +390 -386
  193. package/docs/components/slider.md +136 -19
  194. package/docs/components/steps.md +6 -3
  195. package/docs/components/switch.md +8 -9
  196. package/docs/components/tabs.md +110 -104
  197. package/docs/components/text.md +110 -86
  198. package/docs/components/title.md +47 -33
  199. package/docs/components/toaster.md +242 -84
  200. package/docs/components/tooltip.md +204 -113
  201. package/docs/install-config.md +461 -96
  202. package/docs/packages/plot.md +228 -143
  203. package/docs/theming.md +29 -13
  204. package/package.json +43 -4
  205. package/theme-antithesis-license.md +66 -0
@@ -1,20 +1,17 @@
1
1
  import { jsx, jsxs } from "@antadesign/anta/jsx-runtime";
2
- import { neutralToneAttr, toneStyle, roundStyle, roundAttr, lengthStyle, cssLength } from "../anta_helpers";
2
+ import { useNativeEventProps } from "../native-event-props";
3
+ import { valueAttributes, unwrapNativeEvent, neutralToneAttr, toneStyle, roundStyle, roundAttr, lengthStyle, cssLength } from "../anta_helpers";
3
4
  const number = (value, fallback) => Number.isFinite(value) ? value : fallback;
4
- const isStringish = (node) => typeof node === "string" || typeof node === "number";
5
5
  const bounds = (min, max) => {
6
6
  const low = number(min, 0);
7
7
  return { min: low, max: Math.max(low, number(max, 100)) };
8
8
  };
9
9
  const attrsOf = (event) => {
10
- const element = event?.target ?? {};
11
- return {
12
- value: element.value,
13
- min: Number(element.getAttribute?.("min") ?? 0),
14
- max: Number(element.getAttribute?.("max") ?? 100),
15
- step: Number(element.getAttribute?.("step") ?? 1),
16
- name: element.getAttribute?.("name") ?? void 0
17
- };
10
+ const native = unwrapNativeEvent(event);
11
+ if (native.target && native.currentTarget && native.target !== native.currentTarget) return;
12
+ const attrs = native.detail;
13
+ if (!attrs || typeof attrs.min !== "number" || typeof attrs.max !== "number" || typeof attrs.step !== "number") return;
14
+ return { ...attrs, value: Array.isArray(attrs.value) ? [...attrs.value] : attrs.value };
18
15
  };
19
16
  const Slider = ({
20
17
  label,
@@ -42,6 +39,9 @@ const Slider = ({
42
39
  onChange,
43
40
  onValueChange,
44
41
  onValueCommit,
42
+ onKeyDown,
43
+ onPointerDown,
44
+ onPointerMove,
45
45
  className,
46
46
  style,
47
47
  children,
@@ -67,8 +67,9 @@ const Slider = ({
67
67
  const step = number(stepProp, 1) > 0 ? number(stepProp, 1) : 1;
68
68
  const explicitAriaLabel = rest["aria-label"];
69
69
  const ariaLabel = (typeof explicitAriaLabel === "string" ? explicitAriaLabel : void 0) ?? (typeof label === "string" || typeof label === "number" ? String(label) : void 0);
70
- const range = Array.isArray(value) || Array.isArray(defaultValue);
71
- const serializeValue = (input) => Array.isArray(input) ? `${input[0]} ${input[1]}` : typeof input === "number" ? input : void 0;
70
+ const controlled = value != null;
71
+ const range = Array.isArray(controlled ? value : defaultValue);
72
+ const serializeValue = (input) => Array.isArray(input) ? `${input[0]} ${input[1]}` : typeof input === "number" ? String(input) : void 0;
72
73
  const resolvedValueDisplay = valueDisplay === "inline" && label == null ? "end" : valueDisplay;
73
74
  const markerPosition = (marker) => {
74
75
  if (marker.value <= min) return "0%";
@@ -85,25 +86,25 @@ const Slider = ({
85
86
  const handleInput = onInput || onValueChange ? (event) => {
86
87
  const attrs = attrsOf(event);
87
88
  onInput?.(event);
88
- onValueChange?.(event, attrs);
89
+ if (attrs) onValueChange?.(event, attrs);
89
90
  } : void 0;
90
91
  const handleChange = onChange || onValueCommit ? (event) => {
91
92
  const attrs = attrsOf(event);
92
93
  onChange?.(event);
93
- onValueCommit?.(event, attrs);
94
+ if (attrs) onValueCommit?.(event, attrs);
94
95
  } : void 0;
96
+ const events = useNativeEventProps({ oninput: handleInput, onchange: handleChange, onkeydown: onKeyDown, onpointerdown: onPointerDown, onpointermove: onPointerMove });
95
97
  return /* @__PURE__ */ jsxs(
96
98
  "a-slider",
97
99
  {
98
- value: serializeValue(value),
99
- defaultvalue: serializeValue(defaultValue),
100
+ ...valueAttributes(serializeValue(value), serializeValue(defaultValue)),
100
101
  min,
101
102
  max,
102
103
  step,
103
104
  name,
104
105
  disabled: disabled ? "" : void 0,
105
106
  tone: neutralToneAttr(tone),
106
- "thumb-tone": neutralToneAttr(thumbTone),
107
+ "thumb-tone": thumbTone || void 0,
107
108
  size: size && size !== "medium" ? size : void 0,
108
109
  "track-size": trackSizeValue,
109
110
  "thumb-size": thumbSizeValue,
@@ -117,13 +118,12 @@ const Slider = ({
117
118
  role: range ? "group" : "slider",
118
119
  "aria-label": ariaLabel,
119
120
  tabIndex: disabled || range ? -1 : tabIndex ?? 0,
120
- oninput: handleInput,
121
- onchange: handleChange,
121
+ ...events,
122
122
  class: className,
123
123
  style: computedStyle,
124
124
  ...rest,
125
125
  children: [
126
- label != null && (isStringish(label) ? /* @__PURE__ */ jsx("span", { slot: "label", children: label }) : /* @__PURE__ */ jsx("span", { slot: "label", style: { display: "contents" }, children: label })),
126
+ label != null && /* @__PURE__ */ jsx("span", { slot: "label", children: label }),
127
127
  markers?.map((marker, index) => {
128
128
  const alignment = markerAlignment(marker);
129
129
  return /* @__PURE__ */ jsx(
@@ -1 +1 @@
1
- @layer base,anta,components,utilities;@layer anta.reset,anta.components,anta.theme;@layer anta.components{a-steps{--steps-marker-size: 28px;--steps-icon-size: 16px;--steps-marker-border-width: 1.5px;--steps-marker-rest-border: var(--border-4);--steps-item-gap: 6px;--steps-gap: 4px;--steps-connector-color: var(--border-3);--steps-connector-width: 1px;--steps-complete-connector-color: var(--border-2);--steps-tab-padding-x: 9px;--steps-tab-padding-block: 0px;--steps-hint-leading: 16px;display:flex;flex-direction:column;width:100%;min-width:0}a-steps:has(>a-tabs[size=small]){--steps-marker-size: 24px;--steps-icon-size: 14px;--steps-tab-padding-x: 7px;--steps-hint-leading: 14px}a-steps:has(>a-tabs[size=large]){--steps-marker-size: 32px;--steps-icon-size: 18px;--steps-tab-padding-x: 13px;--steps-hint-leading: 20px}a-tabs[data-steps]{--steps-marker-active-border: var(--border-1);--steps-primary-marker-fg: #ffffff;--tabs-gap: 0px;align-items:center;width:fit-content;align-self:flex-start;overflow-x:auto;scrollbar-width:thin}a-tabs[data-steps][fill]{width:100%;align-self:stretch;justify-content:space-between}a-tabs[data-steps]>a-tab[tone=brand]{--steps-marker-active-border: var(--border-1-brand)}a-tabs[data-steps]>a-tab[tone=info]{--steps-marker-active-border: var(--border-1-info)}a-tabs[data-steps]>a-tab[tone=success]{--steps-marker-active-border: var(--border-1-success)}a-tabs[data-steps]>a-tab[tone=warning]{--steps-marker-active-border: var(--border-1-warning)}a-tabs[data-steps]>a-tab[tone=critical]{--steps-marker-active-border: var(--border-1-critical)}a-tabs[data-steps]>a-tab[tone=neutral]{--steps-marker-active-border: var(--border-1)}a-tabs[data-steps]>a-tab[tone]:not([tone=""],[tone=neutral]){--steps-primary-marker-bg: light-dark( oklch(from var(--tabs-tone-source) .5 .17 h), oklch(from var(--tabs-tone-source) .4 .16 h) )}a-tabs[data-steps]:not([priority=secondary],[priority=tertiary]){--steps-marker-border-width: 2px;--steps-marker-rest-border: var(--border-3);--steps-connector-color: var(--border-3);--steps-connector-width: 2px}a-tabs[data-steps][priority=tertiary]{--steps-marker-size: calc(var(--steps-icon-size) + 4px);--steps-marker-border-width: 0px}a-steps>a-tabs[data-steps]{background:transparent;border-radius:0;box-shadow:none}a-tabs[data-steps]>a-tab{--steps-complete-connector-color: var(--tab-selected-border);--steps-primary-marker-bg: light-dark( oklch(from var(--tabs-tone-source) .5 .02 h), oklch(from var(--tabs-tone-source) .4 .015 h) );--steps-primary-completed-marker-bg: color-mix( in oklch, var(--steps-primary-marker-bg) 80%, transparent );position:relative;flex:1 1 0;min-width:0;max-width:max-content;padding-block:0;justify-content:flex-start;gap:var(--steps-item-gap);transition:color var(--tab-timing),background-color var(--tab-timing),box-shadow var(--tab-timing)}a-steps[data-orientation=vertical]:has(>a-tabs[data-steps]>a-tab:state(selected)[tone=brand]){--steps-complete-connector-color: var(--border-2-brand)}a-steps[data-orientation=vertical]:has(>a-tabs[data-steps]>a-tab:state(selected)[tone=info]){--steps-complete-connector-color: var(--border-2-info)}a-steps[data-orientation=vertical]:has(>a-tabs[data-steps]>a-tab:state(selected)[tone=success]){--steps-complete-connector-color: var(--border-2-success)}a-steps[data-orientation=vertical]:has(>a-tabs[data-steps]>a-tab:state(selected)[tone=warning]){--steps-complete-connector-color: var(--border-2-warning)}a-steps[data-orientation=vertical]:has(>a-tabs[data-steps]>a-tab:state(selected)[tone=critical]){--steps-complete-connector-color: var(--border-2-critical)}a-tabs[data-steps]:not([orientation=vertical])>a-tab:first-child{padding-inline-start:0}a-steps>a-tabs[data-steps][fill]>a-tab:not(:last-child){flex:1 1 0;max-width:none}a-steps>a-tabs[data-steps][fill]>a-tab:last-child{flex:0 1 auto;max-width:max-content}a-steps>a-tabs[data-steps]>a-tab:state(selected){--tab-bg: transparent;box-shadow:none}a-steps>a-tabs[data-steps][priority=tertiary]>a-tab:after{border:0}a-step-desc{display:inline-flex;flex:0 1 auto;flex-direction:column;min-width:0;max-width:100%}a-step-desc>a-tab-label{display:block;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:500}a-step-hint{display:block;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--tab-rest-tone, var(--text-3));font-size:calc(1em - 2px);font-weight:400;line-height:var(--steps-hint-leading)}a-step-marker{display:inline-flex;flex:none;align-items:center;justify-content:center;width:var(--steps-marker-size);height:var(--steps-marker-size);box-sizing:border-box;color:var(--text-4);border:var(--steps-marker-border-width) solid var(--steps-marker-rest-border);border-radius:999px;transition:color var(--tab-timing),background-color var(--tab-timing),border-color var(--tab-timing)}a-tabs[data-steps] a-step-marker :is(a-icon,a-loader){--icon-size: var(--steps-icon-size)}a-tabs[data-steps]>a-tab[tone]{--tab-secondary-bg: light-dark( oklch(from var(--tabs-tone-source) .55 .008 h / .03), oklch(from var(--tabs-tone-source) .8 .008 h / .08) )}a-tabs[data-steps]>a-tab[tone]:not([tone=""],[tone=neutral]){--tab-secondary-bg: light-dark( oklch(from var(--tabs-tone-source) .55 .14 h / .03), oklch(from var(--tabs-tone-source) .8 .12 h / .08) )}a-tabs[data-steps]>a-tab[tone] a-step-marker{color:var(--tab-selected-text)}a-tabs[data-steps]>a-tab:is(:state(selected),[data-step-state=completed]) a-step-marker{border-color:var(--steps-marker-active-border)}a-tabs[data-steps]>a-tab[data-step-state=error]:not(:state(selected)):not([disabled]) a-step-marker{border-color:var(--border-2-critical)}a-tabs[data-steps]:is([priority=secondary],[priority=tertiary])>a-tab[tone]:not([tone=""],[tone=neutral]) a-step-marker{color:var(--tab-fg)}a-tabs[data-steps][priority=secondary] a-tab:state(selected):not([disabled]) a-step-marker{color:var(--tab-selected-text);background-color:var(--tab-secondary-bg);border-color:var(--steps-marker-active-border)}a-tabs[data-steps]:not([priority=secondary],[priority=tertiary]) a-tab:state(selected):not([disabled]) a-step-marker{color:var(--steps-primary-marker-fg);background-color:var(--steps-primary-marker-bg);border-color:var(--steps-primary-marker-bg)}a-tabs[data-steps]:not([priority=secondary],[priority=tertiary]) a-tab[data-step-state=completed]:not(:state(selected)):not([disabled]) a-step-marker{color:var(--steps-primary-marker-fg);background-color:var(--steps-primary-completed-marker-bg);border-color:transparent}a-tabs[data-steps][priority=tertiary] a-tab:state(selected):not([disabled]) a-step-marker{color:var(--tab-selected-text);background-color:transparent;border-color:transparent}a-tabs[data-steps] a-step-marker>a-loader{transition:color var(--tab-timing)}a-tabs[data-steps]:is([priority=secondary],[priority=tertiary]) a-step-marker>a-loader:not([tone=neutral]){color:inherit}a-tabs[data-steps] a-tab:state(selected):not([disabled]) a-step-marker>a-loader{color:inherit}a-tabs[data-steps]:not([orientation=vertical])>a-tab:not(:last-child):before{content:"";order:3;flex:1 1 auto;align-self:center;min-width:calc(var(--steps-marker-size) / 2);height:var(--steps-connector-width);margin-inline-start:calc(1ch - var(--steps-item-gap));margin-inline-end:calc(1ch - 2 * var(--steps-tab-padding-x));background:var(--steps-connector-color);pointer-events:none}a-tabs[data-steps]:not([orientation=vertical])>a-tab[data-step-state=completed]:not(:last-child):before{background:var(--steps-complete-connector-color)}a-tabs[data-steps] a-tab[disabled]{--tab-fg: var(--text-5);opacity:1}a-tabs[data-steps] a-tab[disabled] a-step-marker,a-tabs[data-steps] a-tab[disabled] a-step-marker>a-loader{color:var(--text-5)}a-tabs[data-steps] a-tab[disabled] a-step-hint{color:var(--text-5)}a-steps[data-orientation=vertical]{--steps-content-indent: calc( var(--steps-marker-size) + var(--steps-item-gap) );--steps-vertical-gap: calc(var(--steps-gap) + 4px);display:grid;grid-template-columns:minmax(0,1fr);row-gap:var(--steps-vertical-gap)}a-steps[data-orientation=vertical]>a-tabs[orientation=vertical]{display:contents}a-steps[data-orientation=vertical]>a-tabs[orientation=vertical]>a-tab{flex:none;min-width:0;grid-column:1;width:max-content;max-width:100%;padding-inline-start:0}a-steps[data-orientation=vertical] a-tab:not(:last-child):before{content:"";position:absolute;inset-block-start:calc(var(--steps-tab-padding-block) + var(--steps-marker-size));inset-inline-start:calc(var(--steps-marker-size) / 2 - var(--steps-connector-width) / 2);inset-inline-end:auto;width:var(--steps-connector-width);height:calc(100% - var(--steps-marker-size) + var(--steps-vertical-gap));background:var(--steps-connector-color);transform:none;pointer-events:none}a-steps[data-orientation=vertical]>a-tabpanel{grid-column:1;grid-row:var(--steps-panel-row);width:calc(100% - var(--steps-content-indent));margin-inline-start:var(--steps-content-indent)}a-steps[data-orientation=vertical]:has(>a-tabpanel):has(>a-tabs[orientation=vertical]>a-tab:state(selected):not(:last-child)):after{content:"";grid-column:1;grid-row:var(--steps-panel-row);align-self:stretch;justify-self:start;width:var(--steps-connector-width);min-height:var(--steps-marker-size);margin-inline-start:calc(var(--steps-marker-size) / 2 - var(--steps-connector-width) / 2);margin-block-end:calc(-1 * var(--steps-vertical-gap));background:var(--steps-connector-color);pointer-events:none;z-index:1}a-steps[data-orientation=vertical]>a-tabs[data-steps]>a-tab[data-step-state=completed]:not(:last-child):before{background:var(--steps-complete-connector-color)}a-steps[data-orientation=vertical]:has(>a-tabpanel):has(>a-tabs[data-steps][orientation=vertical]>a-tab[data-step-state=completed]:state(selected):not(:last-child)):after{background:var(--steps-complete-connector-color)}@media(forced-colors:active){a-tabs[data-steps][priority=secondary] a-tab:state(selected){background-color:transparent;border:0;box-shadow:none}a-step-marker{color:CanvasText;background-color:Canvas;border-color:CanvasText}a-tabs[data-steps] a-tab:state(selected):not([disabled]) a-step-marker{border-color:Highlight}}}
1
+ @layer base,anta,components,utilities;@layer anta.reset,anta.components,anta.theme;@layer anta.components{a-steps{--steps-marker-size: 28px;--steps-icon-size: 16px;--steps-marker-border-width: 1.5px;--steps-marker-rest-border: var(--border-4);--steps-item-gap: 6px;--steps-gap: 4px;--steps-connector-color: var(--border-3);--steps-connector-width: 1px;--steps-complete-connector-color: var(--border-2);--steps-tab-padding-x: 9px;--steps-tab-padding-block: 0px;--steps-hint-leading: 16px;display:flex;flex-direction:column;width:100%;min-width:0}a-steps:has(>a-tabs[size=small]){--steps-marker-size: 24px;--steps-icon-size: 14px;--steps-tab-padding-x: 7px;--steps-hint-leading: 14px}a-steps:has(>a-tabs[size=large]){--steps-marker-size: 32px;--steps-icon-size: 18px;--steps-tab-padding-x: 13px;--steps-hint-leading: 20px}a-tabs[data-steps]{--steps-marker-active-border: var(--border-1);--steps-primary-marker-fg: #ffffff;--tabs-gap: 0px;align-items:center;width:fit-content;align-self:flex-start;overflow-x:auto;scrollbar-width:thin}a-tabs[data-steps][fill]{width:100%;align-self:stretch;justify-content:space-between}a-tabs[data-steps]>a-tab[tone=brand]{--steps-marker-active-border: var(--border-1-brand)}a-tabs[data-steps]>a-tab[tone=info]{--steps-marker-active-border: var(--border-1-info)}a-tabs[data-steps]>a-tab[tone=success]{--steps-marker-active-border: var(--border-1-success)}a-tabs[data-steps]>a-tab[tone=warning]{--steps-marker-active-border: var(--border-1-warning)}a-tabs[data-steps]>a-tab[tone=critical]{--steps-marker-active-border: var(--border-1-critical)}a-tabs[data-steps]>a-tab[tone=neutral]{--steps-marker-active-border: var(--border-1)}a-tabs[data-steps]>a-tab[tone]:not([tone=""],[tone=neutral]){--steps-primary-marker-bg: light-dark( oklch(from var(--tabs-tone-source) .5 .17 h), oklch(from var(--tabs-tone-source) .4 .16 h) )}a-tabs[data-steps]:not([priority=secondary],[priority=tertiary]){--steps-marker-border-width: 2px;--steps-marker-rest-border: var(--border-3);--steps-connector-color: var(--border-3);--steps-connector-width: 2px}a-tabs[data-steps][priority=tertiary]{--steps-marker-size: calc(var(--steps-icon-size) + 4px);--steps-marker-border-width: 0px}a-steps>a-tabs[data-steps]{background:transparent;border-radius:0;box-shadow:none}a-tabs[data-steps]>a-tab{--steps-complete-connector-color: var(--tab-selected-border);--steps-primary-marker-bg: light-dark( oklch(from var(--tabs-tone-source) .5 .02 h), oklch(from var(--tabs-tone-source) .4 .015 h) );--steps-primary-completed-marker-bg: color-mix( in oklch, var(--steps-primary-marker-bg) 80%, transparent );position:relative;flex:1 1 0;min-width:0;max-width:max-content;padding-block:0;justify-content:flex-start;gap:var(--steps-item-gap);transition:color var(--tab-timing),background-color var(--tab-timing),box-shadow var(--tab-timing)}a-steps[data-orientation=vertical]:has(>a-tabs[data-steps]>a-tab:state(selected)[tone=brand]){--steps-complete-connector-color: var(--border-2-brand)}a-steps[data-orientation=vertical]:has(>a-tabs[data-steps]>a-tab:state(selected)[tone=info]){--steps-complete-connector-color: var(--border-2-info)}a-steps[data-orientation=vertical]:has(>a-tabs[data-steps]>a-tab:state(selected)[tone=success]){--steps-complete-connector-color: var(--border-2-success)}a-steps[data-orientation=vertical]:has(>a-tabs[data-steps]>a-tab:state(selected)[tone=warning]){--steps-complete-connector-color: var(--border-2-warning)}a-steps[data-orientation=vertical]:has(>a-tabs[data-steps]>a-tab:state(selected)[tone=critical]){--steps-complete-connector-color: var(--border-2-critical)}a-tabs[data-steps]:not([orientation=vertical])>a-tab:first-child{padding-inline-start:0}a-steps>a-tabs[data-steps][fill]>a-tab:not(:last-child){flex:1 1 0;max-width:none}a-steps>a-tabs[data-steps][fill]>a-tab:last-child{flex:0 1 auto;max-width:max-content}a-steps>a-tabs[data-steps]>a-tab:state(selected){--tab-bg: transparent;box-shadow:none}a-steps>a-tabs[data-steps][priority=tertiary]>a-tab:after{border:0}a-step-desc{display:inline-flex;flex:0 1 auto;flex-direction:column;min-width:0;max-width:100%}a-step-desc>a-tab-label{display:block;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:500}a-step-hint{display:block;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--tab-rest-tone, var(--text-3));font-size:calc(1em - 2px);font-weight:400;line-height:var(--steps-hint-leading)}a-step-marker{display:inline-flex;flex:none;align-items:center;justify-content:center;width:var(--steps-marker-size);height:var(--steps-marker-size);box-sizing:border-box;color:var(--text-4);border:var(--steps-marker-border-width) solid var(--steps-marker-rest-border);border-radius:999px;transition:color var(--tab-timing),background-color var(--tab-timing),border-color var(--tab-timing)}a-tabs[data-steps] a-step-marker :is(a-icon,a-loader){--icon-size: var(--steps-icon-size)}a-tabs[data-steps]>a-tab[tone]{--tab-secondary-bg: light-dark( oklch(from var(--tabs-tone-source) .55 .008 h / .03), oklch(from var(--tabs-tone-source) .8 .008 h / .08) )}a-tabs[data-steps]>a-tab[tone]:not([tone=""],[tone=neutral]){--tab-secondary-bg: light-dark( oklch(from var(--tabs-tone-source) .55 .14 h / .03), oklch(from var(--tabs-tone-source) .8 .12 h / .08) )}a-tabs[data-steps]>a-tab[tone] a-step-marker{color:var(--tab-selected-text)}a-tabs[data-steps]>a-tab:is(:state(selected),[data-step-state=completed]) a-step-marker{border-color:var(--steps-marker-active-border)}a-tabs[data-steps]>a-tab[data-step-state=error]:not(:state(selected)):not([disabled]) a-step-marker{border-color:var(--border-2-critical)}a-tabs[data-steps]:is([priority=secondary],[priority=tertiary])>a-tab[tone]:not([tone=""],[tone=neutral]) a-step-marker{color:var(--tab-fg)}a-tabs[data-steps][priority=secondary] a-tab:state(selected):not([disabled]) a-step-marker{color:var(--tab-selected-text);background-color:var(--tab-secondary-bg);border-color:var(--steps-marker-active-border)}a-tabs[data-steps]:not([priority=secondary],[priority=tertiary]) a-tab:state(selected):not([disabled]) a-step-marker{color:var(--steps-primary-marker-fg);background-color:var(--steps-primary-marker-bg);border-color:var(--steps-primary-marker-bg)}a-tabs[data-steps]:not([priority=secondary],[priority=tertiary]) a-tab[data-step-state=completed]:not(:state(selected)):not([disabled]) a-step-marker{color:var(--steps-primary-marker-fg);background-color:var(--steps-primary-completed-marker-bg);border-color:transparent}a-tabs[data-steps][priority=tertiary] a-tab:state(selected):not([disabled]) a-step-marker{color:var(--tab-selected-text);background-color:transparent;border-color:transparent}a-tabs[data-steps] a-step-marker>a-loader{transition:color var(--tab-timing)}a-tabs[data-steps]:is([priority=secondary],[priority=tertiary]) a-step-marker>a-loader:not([tone=neutral]){color:inherit}a-tabs[data-steps] a-tab:state(selected):not([disabled]) a-step-marker>a-loader{color:inherit}a-tabs[data-steps]:not([orientation=vertical])>a-tab:not(:last-child):before{content:"";order:3;flex:1 1 auto;align-self:center;min-width:calc(var(--steps-marker-size) / 2);height:var(--steps-connector-width);margin-inline-start:calc(1ch - var(--steps-item-gap));margin-inline-end:calc(1ch - 2 * var(--steps-tab-padding-x));background:var(--steps-connector-color);pointer-events:none}a-tabs[data-steps]:not([orientation=vertical])>a-tab[data-step-state=completed]:not(:last-child):before{background:var(--steps-complete-connector-color)}a-tabs[data-steps] a-tab[disabled]{--tab-fg: var(--text-5);opacity:1}a-tabs[data-steps] a-tab[disabled] a-step-marker,a-tabs[data-steps] a-tab[disabled] a-step-marker>a-loader{color:var(--text-5)}a-tabs[data-steps] a-tab[disabled] a-step-hint{color:var(--text-5)}a-steps[data-orientation=vertical]{--steps-content-indent: calc( var(--steps-marker-size) + var(--steps-item-gap) );--steps-vertical-gap: calc(var(--steps-gap) + 4px);display:grid;grid-template-columns:minmax(0,1fr);row-gap:var(--steps-vertical-gap)}a-steps[data-orientation=vertical]>a-tabs[orientation=vertical]{display:contents}a-steps[data-orientation=vertical]>a-tabs[orientation=vertical]>a-tab{flex:none;min-width:0;grid-column:1;width:max-content;max-width:100%;padding-inline-start:0}a-steps[data-orientation=vertical] a-tab:not(:last-child):before{content:"";position:absolute;inset-block-start:calc(var(--steps-tab-padding-block) + var(--steps-marker-size));inset-inline-start:calc(var(--steps-marker-size) / 2 - var(--steps-connector-width) / 2);inset-inline-end:auto;width:var(--steps-connector-width);height:calc(100% - var(--steps-marker-size) + var(--steps-vertical-gap));background:var(--steps-connector-color);transform:none;pointer-events:none}a-steps[data-orientation=vertical]>a-tabs[orientation=vertical]>a-tab:state(selected)~a-tab{order:2}a-steps[data-orientation=vertical]>a-tabpanel{position:relative;order:1;grid-column:1;width:calc(100% - var(--steps-content-indent));margin-inline-start:var(--steps-content-indent)}a-steps[data-orientation=vertical]:has(>a-tabpanel):has(>a-tabs[orientation=vertical]>a-tab:state(selected):not(:last-child))>a-tabpanel{min-height:max(0px,calc(var(--steps-marker-size) - var(--steps-vertical-gap)))}a-steps[data-orientation=vertical]:has(>a-tabpanel):has(>a-tabs[orientation=vertical]>a-tab:state(selected):not(:last-child))>a-tabpanel:before{content:"";position:absolute;inset-block:0 calc(-1 * var(--steps-vertical-gap));inset-inline-start:calc(-1 * var(--steps-content-indent) + var(--steps-marker-size) / 2 - var(--steps-connector-width) / 2);width:var(--steps-connector-width);min-height:var(--steps-marker-size);background:var(--steps-connector-color);pointer-events:none;z-index:1}a-steps[data-orientation=vertical]>a-tabs[data-steps]>a-tab[data-step-state=completed]:not(:last-child):before{background:var(--steps-complete-connector-color)}a-steps[data-orientation=vertical]:has(>a-tabpanel):has(>a-tabs[data-steps][orientation=vertical]>a-tab[data-step-state=completed]:state(selected):not(:last-child))>a-tabpanel:before{background:var(--steps-complete-connector-color)}@media(forced-colors:active){a-tabs[data-steps][priority=secondary] a-tab:state(selected){background-color:transparent;border:0;box-shadow:none}a-step-marker{color:CanvasText;background-color:Canvas;border-color:CanvasText}a-tabs[data-steps] a-tab:state(selected):not([disabled]) a-step-marker{border-color:Highlight}}}
@@ -1,7 +1,6 @@
1
1
  import type { IconShape } from "../elements/a-icon.shapes";
2
2
  import type { OptionPresentationProps } from "../general_types";
3
3
  import type { TabsProps } from "./Tabs";
4
- import "./Steps.css";
5
4
  /** Named Anta tone used by Steps. */
6
5
  export type StepTone = "neutral" | "brand" | "info" | "success" | "warning" | "critical";
7
6
  /** Process state shown by one step. */
@@ -4,7 +4,6 @@ import { useState } from "../jsx-runtime";
4
4
  import { Icon } from "./Icon";
5
5
  import { Loader } from "./Loader";
6
6
  import { Tabs } from "./Tabs";
7
- import "./Steps.css";
8
7
  const STATE_ICON = {
9
8
  incomplete: "circle-large",
10
9
  completed: "check",
@@ -80,22 +79,12 @@ const Steps = ({
80
79
  ] })
81
80
  };
82
81
  });
83
- const currentIndex = options.findIndex(
84
- (option) => option.value === currentValue
85
- );
86
82
  const vertical = orientation === "vertical";
87
- const hasPanels = children != null && children !== false;
88
- const hasVerticalPanel = vertical && hasPanels;
89
- const panelRow = (currentIndex >= 0 ? currentIndex : options.length - 1) + 2;
90
- const rootStyle = hasVerticalPanel ? {
91
- ...style,
92
- "--steps-panel-row": panelRow
93
- } : style;
94
83
  return /* @__PURE__ */ jsx(
95
84
  "a-steps",
96
85
  {
97
86
  class: className,
98
- style: rootStyle,
87
+ style,
99
88
  id,
100
89
  ...rest,
101
90
  "data-orientation": vertical ? "vertical" : void 0,
@@ -32,9 +32,10 @@ export interface TabOption extends OptionPresentationProps {
32
32
  round?: boolean;
33
33
  /** Per-tab tone override, same vocabulary as `<Tabs tone>` — colors this one tab's
34
34
  * label + icons (all priorities/modes, named or custom color) and, when it's the
35
- * active tab, its indicator. For a **custom literal color** the sliding indicator can't
36
- * adopt it (the shared moving element can't read a descendant's color), so a custom tone
37
- * colors the label everywhere and the indicator only in `noslide`; the six **named**
35
+ * active tab, its indicator. The track keeps the strip's tone. For a **custom literal
36
+ * color** the sliding indicator can't adopt it (the shared moving element can't read
37
+ * a descendant's color), so a custom tone colors the label everywhere and the indicator
38
+ * only in `noslide`; the six **named**
38
39
  * tones color both in every mode. Overrides the strip's `tone` for this tab.
39
40
  * @defaultValue inherits the strip's `tone` */
40
41
  tone?: "neutral" | "brand" | "info" | "success" | "warning" | "critical" | (string & {});
@@ -113,31 +114,27 @@ export interface TabsProps extends Omit<BaseProps, "onChange"> {
113
114
  * per tab so it snaps with no movement. (Browsers without anchor positioning get that
114
115
  * per-tab paint automatically — `noslide` is the explicit opt-out.) */
115
116
  noslide?: boolean;
116
- /** Fully-round the tabs and the sliding indicator (and the primary track
117
- * well). Applies strip-wide; a single tab's `round` rounds just that tab. A
118
- * `number` (px) or CSS length string sets a custom radius on the top-level
119
- * track well only — the tab pills + indicator stay fully round. */
117
+ /** Fully-round the tabs, the sliding indicator, and the primary track.
118
+ * Applies strip-wide; a single tab's `round` rounds just that tab. A
119
+ * `number` (px) or CSS length string sets that radius on all three. */
120
120
  round?: boolean | number | string;
121
121
  /** Disable the whole strip. */
122
122
  disabled?: boolean;
123
123
  }
124
124
  /**
125
- * `<Tabs>` — a tablist with optional panels. The strip renders from the `options`
126
- * array; panels are `<TabPanel>` children that manage their own visibility.
125
+ * Tab strip with optional panels. Give each option a unique `value` and match
126
+ * it to a `TabPanel` to display content for the selected tab.
127
127
  *
128
- * The strip (`<a-tabs>`) and the panels render as flat siblings — there is no wrapper
129
- * element, so `className` / `id` / `style` / `...rest` land on the strip. Laying the
130
- * strip out relative to its panels is the consumer's job: a horizontal strip stacks
131
- * above the panels in normal flow; for a vertical strip beside them, wrap `<Tabs>` in
132
- * your own flex container. Any non-`TabPanel` children render verbatim as siblings too.
128
+ * The strip and panels render as siblings. `className`, `id`, `style`, and extra
129
+ * props apply to the strip. Keep the strip and panels under the same parent.
130
+ * Horizontal tabs stack in normal flow. Use a flex container to place a
131
+ * vertical strip beside its panels. Other children also render as siblings.
133
132
  *
134
- * `<a-tabs>` owns selection off-DOM (it sets each tab's `selected` property and the
135
- * roving `aria-activedescendant` via `ElementInternals`, writing no attribute to any
136
- * tab); this wrapper mirrors the value only to render the strip's roving `tabindex`,
137
- * and the panels read it straight from `<a-tabs>`. Controlled (`value` + `onStateChange`)
138
- * or uncontrolled (`defaultValue`).
133
+ * Pass `value` with `onStateChange` for controlled selection, or `defaultValue`
134
+ * for an initial uncontrolled selection. Panels are optional when the
135
+ * application renders the selected content itself.
139
136
  *
140
- * Requires `@antadesign/anta/elements` (client-side only).
137
+ * See [Install and configure](https://anta.design/install/) for runtime setup.
141
138
  *
142
139
  * @example
143
140
  * ```tsx
@@ -1,6 +1,6 @@
1
1
  import { Fragment, jsx, jsxs } from "@antadesign/anta/jsx-runtime";
2
- import { useState } from "../jsx-runtime";
3
- import { nativeStateChange, neutralToneAttr, optionPresentationAttrs, toneStyle, roundStyle, roundAttr, wrapLabel } from "../anta_helpers";
2
+ import { useNativeEventProps } from "../native-event-props";
3
+ import { nativeStateChange, neutralToneAttr, optionPresentationAttrs, toneStyle, roundStyle, roundAttr, wrapLabel, useSelectionMirror } from "../anta_helpers";
4
4
  import { Tooltip } from "./Tooltip";
5
5
  const Tabs = ({
6
6
  children,
@@ -27,8 +27,7 @@ const Tabs = ({
27
27
  ...rest
28
28
  }) => {
29
29
  const controlled = value !== void 0;
30
- const [internalValue, setInternalValue] = useState(defaultValue);
31
- const currentValue = controlled ? value : internalValue;
30
+ const [currentValue, setInternalValue] = useSelectionMirror(value, defaultValue);
32
31
  const tabs = options ?? [];
33
32
  const seen = /* @__PURE__ */ new Set();
34
33
  for (const t of tabs) {
@@ -48,6 +47,7 @@ const Tabs = ({
48
47
  onChange?.(e);
49
48
  onValueChange?.(e, { value: e.currentTarget?.value ?? null });
50
49
  } : void 0;
50
+ const events = useNativeEventProps({ onstatechange, onchange, onfocusin: onFocus, onfocusout: onBlur });
51
51
  const vertical = orientation === "vertical";
52
52
  const focusValue = currentValue != null && tabs.some((tab) => tab.value === currentValue) ? currentValue : tabs.find((tab) => !disabled && !tab.disabled)?.value;
53
53
  const strip = /* @__PURE__ */ jsx(
@@ -67,10 +67,7 @@ const Tabs = ({
67
67
  noslide: noslide ? "" : void 0,
68
68
  round: roundAttr(round),
69
69
  disabled: disabled ? "" : void 0,
70
- onstatechange,
71
- onchange,
72
- onfocusin: onFocus,
73
- onfocusout: onBlur,
70
+ ...events,
74
71
  class: className,
75
72
  id,
76
73
  style: roundStyle(round, "--tabs-round", toneStyle(tone, "--tabs-tone-source", style)),
@@ -107,7 +104,8 @@ const Tabs = ({
107
104
  );
108
105
  return /* @__PURE__ */ jsxs(Fragment, { children: [
109
106
  strip,
110
- children
107
+ children,
108
+ /* @__PURE__ */ jsx("template", { "data-anta-tabs-end": "" })
111
109
  ] });
112
110
  };
113
111
  export {
@@ -1,59 +1,78 @@
1
1
  import type { BaseProps } from "../general_types";
2
- /** Truncation / expansion axis. `expandable` only takes effect with `truncate`;
3
- * `collapsible` only with `expandable` — so the type forbids `collapsible`
4
- * unless `expandable` is set (a dynamic `expandable={cond}` is still allowed). */
2
+ /** Expansion requires `truncate`. `expandableInert` and `collapsible` require
3
+ * `expandable`; dynamic boolean values are allowed. */
5
4
  export type ExpandMode = {
6
5
  expandable?: never;
6
+ expandableInert?: never;
7
7
  collapsible?: never;
8
8
  } | {
9
- /** Show a fade hint and chevron over the truncated text and let the user
10
- * expand it by clicking the chevron region or pressing Enter while the
11
- * chevron has keyboard focus. Only takes effect together with `truncate`.
12
- * On its own, expanding is **one-way** — the control is removed once
13
- * expanded; add `collapsible` for a two-way toggle. */
9
+ /** Show a fade and expansion control when truncated text overflows.
10
+ * Select the control or focus it and press Enter or Space to reveal all
11
+ * content. Expansion is one-way: the control hides once expanded.
12
+ * Add `collapsible` to allow refolding. Requires `truncate`; disables the
13
+ * automatic tooltip. The control comes first in Tab order. By default,
14
+ * folded text stays selectable and its links remain focusable and clickable.
15
+ * Single-line text fades at the inline end with an inline-end target;
16
+ * multiline text fades over its last line with a full-width target.
17
+ * Folded content clips without scrolling or extra padding, and expansion
18
+ * preserves its width. */
14
19
  expandable: boolean;
15
- /** Let the reader collapse back after expanding: the chevron becomes a
16
- * "Show more" / "Show less" toggle that stays visible while expanded.
17
- * Only takes effect together with `expandable`. */
20
+ /** Make the entire folded, overflowing preview an expand target.
21
+ * JSX applies `inert` to its content, blocking focus, clicks, and text
22
+ * selection and removing it from the accessibility tree until expanded.
23
+ * Fitting text stays interactive, as does server-rendered content before
24
+ * browser measurement. Requires `expandable`. */
25
+ expandableInert?: boolean;
26
+ /** Allow refolding after expansion. The control stays visible, rotates
27
+ * its chevron, and switches between "Show more" and "Show less".
28
+ * Requires `expandable`. The expanded collapse target spans the full
29
+ * width over 16px of bottom padding; removing that padding with custom
30
+ * CSS allows it to overlap content. */
18
31
  collapsible?: boolean;
19
32
  };
20
33
  export type TextProps = BaseProps & {
21
- /** Visual priority. Maps to text-1..text-4 (`primary` = text-1, the
22
- * strongest). The default is `secondary` (text-2) — body text reads a
23
- * step softer than the strongest foreground; pass `primary` for emphasis.
34
+ /** Text emphasis, from `primary` (`--text-1`, strongest) to `quaternary`
35
+ * (`--text-4`). `secondary` uses `--text-2`; `tertiary` uses `--text-3`.
36
+ * Neutral primary/secondary links use `--link-color` and `--link-color-hover`.
37
+ * Tertiary/quaternary links inherit the text color, with `--text-2` and
38
+ * `--text-3` respectively on hover.
24
39
  * @defaultValue secondary */
25
40
  priority?: 'primary' | 'secondary' | 'tertiary' | 'quaternary';
26
- /** Color tint. `neutral` (the default) is the untinted `--text-{N}` scale; a
27
- * named tone applies the matching `--text-{N}-{tone}` palette. Any literal CSS
28
- * color (`'#ff1493'`, `'rebeccapurple'`) is a one-off custom tone — its hue is
29
- * kept while lightness/chroma are pinned per priority in oklch.
41
+ /** Color tint. `neutral` uses `--text-{N}`; named tones use
42
+ * `--text-{N}-{tone}`. A CSS color such as `rebeccapurple` keeps its hue,
43
+ * with lightness and chroma set per priority in oklch. With named tones,
44
+ * links inherit the text color and hover uses the next-stronger tone level;
45
+ * at `primary`, hover changes only the underline.
30
46
  * @defaultValue neutral */
31
47
  tone?: 'neutral' | 'brand' | 'info' | 'success' | 'warning' | 'critical' | (string & {});
32
- /** Type scale. `small` = 13/16, `medium` = 15/20, `large` = 17/24.
48
+ /** Font size / line height in pixels: `small` = 13/16, `medium` = 15/20,
49
+ * `large` = 17/24.
33
50
  * @defaultValue medium */
34
51
  size?: 'small' | 'medium' | 'large';
35
52
  /** Render as inline-block instead of the default block element. */
36
53
  inline?: boolean;
37
- /** Truncate with a trailing ellipsis. `true` (or `1`) clamps to a
38
- * single line; any integer ≥ 2 clamps to that many lines; `0` or a
39
- * negative value means no truncation. A clipped, non-expandable JSX
40
- * `Text` shows its text content in a tooltip by default. Nest a
41
- * `<Tooltip>` to provide your own tooltip instead. Uses the
42
- * `-webkit-line-clamp` technique, supported in all major browsers
43
- * (Firefox 68+, Chrome, Safari, Edge). */
54
+ /** Clamp with a trailing ellipsis: `true` or `1` selects one line, integers
55
+ * ≥ 2 select that many lines, and `0` or negative values disable truncation.
56
+ * Clipped, non-expandable Text shows its content in an automatic tooltip.
57
+ * Nest `<Tooltip>` to replace it or an empty tooltip to suppress it.
58
+ * Uses CSS `-webkit-line-clamp` in `display: -webkit-box`, with `min-width: 0`
59
+ * for flex and grid layouts. */
44
60
  truncate?: boolean | number;
45
61
  } & ExpandMode;
46
62
  /**
47
- * Block-level text container with priority and tone support.
63
+ * Light-DOM text with priority, tone, truncation, and optional expansion.
48
64
  *
49
- * Renders an `<a-text>` web component that scopes its descendants'
50
- * color hierarchy. Links nested inside follow the design system's
51
- * priority-aware link styling. Pass `inline` for an inline-block
52
- * variant, `truncate` for ellipsis truncation, and `expandable`
53
- * (combined with `truncate`) to let the user reveal the full text.
65
+ * Renders `<a-text>` with priority-aware colors for content and links.
66
+ * `inline` selects inline-block layout; `truncate` clamps text with an ellipsis.
67
+ * Pair `expandable` with `truncate` to let the reader reveal all content.
68
+ * Link underlines use 0.5px at 75% alpha, 1px at full alpha on hover,
69
+ * and restore the resting underline while active.
54
70
  *
55
- * Requires `@antadesign/anta/elements` to be imported (client-side only)
56
- * to register the underlying custom element.
71
+ * External CSS renders text and truncation before element registration.
72
+ * The browser element measures overflow and owns expansion off-DOM.
73
+ * Expandable Text places `a-button` before `a-text-content` in Tab order.
74
+ * Granular expansion also requires `@antadesign/anta/elements/a-button`;
75
+ * automatic tooltips require `@antadesign/anta/elements/a-tooltip`.
57
76
  *
58
77
  * @example Basic usage
59
78
  * ```tsx
@@ -62,7 +81,7 @@ export type TextProps = BaseProps & {
62
81
  *
63
82
  * @example Expandable truncated text
64
83
  * ```tsx
65
- * <Text truncate={3} expandable>…long paragraph…</Text>
84
+ * <Text truncate={3} expandable>A long description that the reader can expand.</Text>
66
85
  * ```
67
86
  */
68
- export declare const Text: ({ priority, tone, size, inline, truncate, expandable, collapsible, className, style, children, ...rest }: TextProps) => any;
87
+ export declare const Text: ({ priority, tone, size, inline, truncate, expandable, collapsible, expandableInert, className, style, children, ...rest }: TextProps) => any;
@@ -1,34 +1,47 @@
1
1
  import { jsx, jsxs } from "@antadesign/anta/jsx-runtime";
2
- import { lineClamp, neutralToneAttr, toneStyle } from "../anta_helpers";
2
+ import { lineClamp, nativeStateChange, neutralToneAttr, toneStyle } from "../anta_helpers";
3
+ import { useMemo, useState } from "../jsx-runtime";
4
+ import { useNativeEventProps } from "../native-event-props";
3
5
  import { Tooltip } from "./Tooltip";
4
- const Text = ({ priority, tone, size, inline, truncate, expandable, collapsible, className, style, children, ...rest }) => {
6
+ function ExpandableText({ attributes, children, expandableInert }) {
7
+ const [presentation, setPresentation] = useState({ expanded: false, overflowing: false });
8
+ const onPresentation = useMemo(() => (input) => {
9
+ const { detail, isOwn } = nativeStateChange(input);
10
+ if (!isOwn || !detail) return;
11
+ setPresentation((previous) => previous.expanded === detail.expanded && previous.overflowing === detail.overflowing ? previous : detail);
12
+ }, []);
13
+ const eventProps = useNativeEventProps({ ontextpresentationchange: onPresentation });
14
+ return /* @__PURE__ */ jsxs("a-text", { ...attributes, "expandable-inert": expandableInert ? "" : void 0, ...eventProps, children: [
15
+ /* @__PURE__ */ jsx("a-button", { role: "button", tabIndex: 0, priority: "quaternary", paddingless: "" }),
16
+ /* @__PURE__ */ jsx("a-text-content", { inert: Boolean(expandableInert && presentation.overflowing && !presentation.expanded), children })
17
+ ] });
18
+ }
19
+ const Text = ({ priority, tone, size, inline, truncate, expandable, collapsible, expandableInert, className, style, children, ...rest }) => {
5
20
  const lineCount = lineClamp(truncate);
6
21
  const toneAttr = neutralToneAttr(tone);
7
22
  const computedStyle = toneStyle(
8
23
  toneAttr,
9
24
  "--text-tone-source",
10
- lineCount != null ? { ...style, ["--line-clamp"]: lineCount } : style
25
+ lineCount != null && lineCount > 1 ? { ...style, ["--line-clamp"]: lineCount } : style
11
26
  );
12
27
  const canExpand = expandable && lineCount != null;
13
- return /* @__PURE__ */ jsxs(
14
- "a-text",
15
- {
16
- priority,
17
- tone: toneAttr,
18
- size,
19
- inline: inline ? "" : void 0,
20
- truncate: lineCount != null ? String(lineCount) : void 0,
21
- expandable: canExpand ? "" : void 0,
22
- collapsible: canExpand && collapsible ? "" : void 0,
23
- class: className,
24
- style: computedStyle,
25
- ...rest,
26
- children: [
27
- children,
28
- lineCount != null && !canExpand && /* @__PURE__ */ jsx(Tooltip, { truncatedOnly: true, "data-anta-text-tooltip": "" })
29
- ]
30
- }
31
- );
28
+ const attributes = {
29
+ priority,
30
+ tone: toneAttr,
31
+ size,
32
+ inline: inline ? "" : void 0,
33
+ truncate: lineCount != null ? String(lineCount) : void 0,
34
+ expandable: canExpand ? "" : void 0,
35
+ collapsible: canExpand && collapsible ? "" : void 0,
36
+ class: className,
37
+ style: computedStyle,
38
+ ...rest
39
+ };
40
+ if (canExpand) return /* @__PURE__ */ jsx(ExpandableText, { attributes, expandableInert, children });
41
+ return /* @__PURE__ */ jsxs("a-text", { ...attributes, children: [
42
+ children,
43
+ lineCount != null && !canExpand && /* @__PURE__ */ jsx(Tooltip, { truncatedOnly: true, "data-anta-text-tooltip": "" })
44
+ ] });
32
45
  };
33
46
  export {
34
47
  Text
@@ -1,7 +1,7 @@
1
1
  import type { BaseProps } from "../general_types";
2
2
  export interface TitleProps extends BaseProps {
3
- /** Heading level, 1-6. Drives font-size, line-height, and vertical
4
- * rhythm. Also surfaced to assistive tech via `aria-level`
3
+ /** Heading level, 1–6. Sets the type scale and the
4
+ * `aria-level` exposed to assistive technology
5
5
  * (h1 is typically reserved for the page title).
6
6
  * @defaultValue 2 */
7
7
  level?: 1 | 2 | 3 | 4 | 5 | 6;
@@ -14,46 +14,38 @@ export interface TitleProps extends BaseProps {
14
14
  * kept while lightness/chroma are pinned per priority in oklch.
15
15
  * @defaultValue neutral */
16
16
  tone?: 'neutral' | 'brand' | 'info' | 'success' | 'warning' | 'critical' | (string & {});
17
+ /** Typeface. Serif names the page and its parts; sans serif names objects on
18
+ * the page, such as cards, panels, and metrics; monospace names technical
19
+ * identifiers, such as run IDs, hashes, and file paths. Omit it to let the
20
+ * theme choose by level: the Antithesis theme sets levels 1–3 in serif and
21
+ * 4–6 in sans serif, and other themes use sans serif throughout. */
22
+ font?: 'serif' | 'sans-serif' | 'monospace';
17
23
  /** Truncate with a trailing ellipsis. `true` (or `1`) clamps to a
18
24
  * single line; any integer ≥ 2 clamps to that many lines; `0` or a
19
25
  * negative value means no truncation. A clipped JSX `Title` shows its
20
26
  * text content in a tooltip by default. Nest a `<Tooltip>` to provide
21
- * your own tooltip instead. */
27
+ * your own tooltip instead.
28
+ * @author Vlad Korobov
29
+ */
22
30
  truncate?: boolean | number;
23
31
  }
24
32
  /**
25
33
  * Block-level heading with level 1-6, priority, tone, and optional truncation.
26
34
  *
27
- * Renders an `<a-title>` styled tag (no JS, no shadow DOM) with
28
- * `role="heading"` and `aria-level={level}` set by this wrapper for
29
- * accessibility. Children can be anything — text, icons, badges, links
30
- * — so there are no `icon` / `iconTrailing` props; compose
31
- * inside.
35
+ * The wrapper supplies `role="heading"` and `aria-level`. Compose icons,
36
+ * badges, and links as children. Title has no margins. Use the parent's `gap`
37
+ * or padding to space it within a layout.
32
38
  *
33
- * `<Title>` carries no vertical margins: it's a spacing-neutral atom
34
- * that drops into any container, and the parent owns spacing (a `gap`
35
- * or padding). Raw `<h1>`-`<h6>` do keep per-level top/bottom margins
36
- * (via `src/reset.css`) for document prose rhythm — so use a real
37
- * heading tag if SEO matters or you want that built-in rhythm and don't
38
- * need the `tone` / `priority` props.
39
+ * Native `<h1>`–`<h6>` headings use the same type scale with document margins
40
+ * when Anta's reset stylesheet is loaded.
39
41
  *
40
- * Styling notes (`a-title.css` ships comment-free): `<a-title>` is
41
- * intentionally CSS-only — no JS, no shadow DOM, not even
42
- * `customElements.define`; the browser treats it as a generic unknown
43
- * element and the CSS gives it block layout, the demi-bold variable-font
44
- * weight, and the per-level type scale. The matching `h1`–`h6` rules in
45
- * `src/reset.css` share that type scale and weight, so raw markup reads
46
- * the same as `<Title level={n}>` — they diverge only on margins: raw
47
- * headings carry the document vertical rhythm, `<a-title>` is margin-free.
48
- * The tone × priority color matrix has the same shape as `a-text`'s.
49
- *
50
- * Requires `@antadesign/anta/elements` to be imported (client-side only)
51
- * so the CSS ships with the page.
42
+ * See [Install and configure](https://anta.design/install/) for stylesheet setup.
52
43
  *
53
44
  * @example Basic usage
54
45
  * ```tsx
55
46
  * <Title level={1}>Page title</Title>
56
47
  * <Title level={2} tone="brand">Section</Title>
48
+ * <Title level={3} font="sans-serif">Run 4821: 12 failures</Title>
57
49
  * ```
58
50
  *
59
51
  * @example With children beyond text
@@ -63,4 +55,4 @@ export interface TitleProps extends BaseProps {
63
55
  * </Title>
64
56
  * ```
65
57
  */
66
- export declare const Title: ({ level, priority, tone, truncate, className, style, children, ...rest }: TitleProps) => any;
58
+ export declare const Title: ({ level, priority, tone, font, truncate, className, style, children, ...rest }: TitleProps) => any;
@@ -1,7 +1,7 @@
1
1
  import { jsx, jsxs } from "@antadesign/anta/jsx-runtime";
2
2
  import { lineClamp, neutralToneAttr, toneStyle } from "../anta_helpers";
3
3
  import { Tooltip } from "./Tooltip";
4
- const Title = ({ level = 2, priority, tone, truncate, className, style, children, ...rest }) => {
4
+ const Title = ({ level = 2, priority, tone, font, truncate, className, style, children, ...rest }) => {
5
5
  const lineCount = lineClamp(truncate);
6
6
  const toneAttr = neutralToneAttr(tone);
7
7
  const computedStyle = toneStyle(
@@ -15,6 +15,7 @@ const Title = ({ level = 2, priority, tone, truncate, className, style, children
15
15
  level: String(level),
16
16
  priority,
17
17
  tone: toneAttr,
18
+ font,
18
19
  truncate: lineCount != null ? String(lineCount) : void 0,
19
20
  role: "heading",
20
21
  "aria-level": level,
@@ -2,10 +2,17 @@ import { jsx } from "@antadesign/anta/jsx-runtime";
2
2
  import { useMemo, useSyncExternalStore } from "../jsx-runtime";
3
3
  import { createToaster } from "../toaster";
4
4
  import { Banner } from "./Banner";
5
+ import { useNativeEventProps } from "../native-event-props";
6
+ import { nativeStateChange, isDOMNode } from "../anta_helpers";
5
7
  const ToastItem = ({ entry, store }) => {
6
8
  const content = useMemo(() => entry.render(entry.id), [entry.id, entry.rev]);
7
- const isNode = typeof Node !== "undefined" && content instanceof Node;
9
+ const isNode = isDOMNode(content);
8
10
  const isText = typeof content === "string" || typeof content === "number";
11
+ const eventProps = useNativeEventProps({
12
+ ondismiss: (event) => {
13
+ if (nativeStateChange(event).isOwn) store.remove(entry.id);
14
+ }
15
+ });
9
16
  const common = {
10
17
  slot: entry.placement,
11
18
  duration: entry.duration,
@@ -17,7 +24,7 @@ const ToastItem = ({ entry, store }) => {
17
24
  // announcement) unless requested.
18
25
  role: entry.politeness === "assertive" ? "alert" : entry.politeness === "polite" ? "status" : void 0,
19
26
  // Fires after the exit animation; that's when the entry actually leaves.
20
- ondismiss: () => store.remove(entry.id)
27
+ ...eventProps
21
28
  };
22
29
  if (isNode) return /* @__PURE__ */ jsx("a-toast", { ...common, content });
23
30
  if (isText)