@antadesign/anta 0.3.0 → 0.3.2

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 (51) hide show
  1. package/dist/anta_helpers.d.ts +10 -0
  2. package/dist/anta_helpers.js +13 -1
  3. package/dist/components/Button.js +8 -17
  4. package/dist/components/Checkbox.d.ts +16 -15
  5. package/dist/components/Checkbox.js +10 -6
  6. package/dist/components/Input.d.ts +4 -4
  7. package/dist/components/Input.js +5 -5
  8. package/dist/components/Menu.d.ts +7 -4
  9. package/dist/components/Menu.js +2 -2
  10. package/dist/components/MenuItem.d.ts +18 -7
  11. package/dist/components/MenuItem.js +11 -2
  12. package/dist/components/RadioGroup.d.ts +15 -15
  13. package/dist/components/RadioGroup.js +8 -8
  14. package/dist/components/Tab.d.ts +34 -0
  15. package/dist/components/Tab.js +4 -0
  16. package/dist/components/TabPanel.d.ts +22 -0
  17. package/dist/components/TabPanel.js +4 -0
  18. package/dist/components/Tabs.d.ts +112 -0
  19. package/dist/components/Tabs.js +174 -0
  20. package/dist/components/Tabs.module.css +1 -0
  21. package/dist/components/Tooltip.d.ts +10 -1
  22. package/dist/components/Tooltip.js +4 -0
  23. package/dist/elements/a-button.css +1 -1
  24. package/dist/elements/a-checkbox.css +1 -1
  25. package/dist/elements/a-expander.js +6 -1
  26. package/dist/elements/a-icon.shapes.css +1 -1
  27. package/dist/elements/a-icon.shapes.d.ts +2 -1
  28. package/dist/elements/a-icon.shapes.js +1 -0
  29. package/dist/elements/a-input.js +1 -1
  30. package/dist/elements/a-menu.d.ts +12 -0
  31. package/dist/elements/a-menu.js +70 -21
  32. package/dist/elements/a-radio.css +1 -1
  33. package/dist/elements/a-tab.css +1 -0
  34. package/dist/elements/a-tab.d.ts +14 -0
  35. package/dist/elements/a-tab.js +46 -0
  36. package/dist/elements/a-tabpanel.css +1 -0
  37. package/dist/elements/a-tabs.css +1 -0
  38. package/dist/elements/a-tabs.d.ts +31 -0
  39. package/dist/elements/a-tabs.js +157 -0
  40. package/dist/elements/a-text.css +1 -1
  41. package/dist/elements/a-title.css +1 -1
  42. package/dist/elements/a-tooltip.d.ts +18 -0
  43. package/dist/elements/a-tooltip.js +45 -0
  44. package/dist/elements/index.d.ts +3 -0
  45. package/dist/elements/index.js +7 -0
  46. package/dist/general_types.d.ts +150 -23
  47. package/dist/index.d.ts +6 -0
  48. package/dist/index.js +6 -0
  49. package/dist/jsx-runtime.d.ts +5 -1
  50. package/dist/tokens.css +1 -1
  51. package/package.json +1 -1
@@ -1,4 +1,14 @@
1
1
  export declare function hasChildren(children: React.ReactNode): boolean;
2
+ /**
3
+ * Normalize a wrapper's label content the way `Button` / `Tabs` do: a bare string
4
+ * or number becomes a `<tag>` — the ellipsis-capable label part (`a-button-label`,
5
+ * `a-tab-label`, …) that carries the optical baseline nudge and truncates cleanly;
6
+ * empty / whitespace strings and `NaN` carry no content and are dropped; a JSX
7
+ * element is the consumer's own structure, passed through unwrapped (so an icon-only
8
+ * child keeps its layout). Shared so the rule lives in one place — don't re-implement
9
+ * it per component.
10
+ */
11
+ export declare function wrapLabel(kids: React.ReactNode, tag: string): React.ReactNode;
2
12
  /**
3
13
  * Unwrap a `statechange` (or any) `CustomEvent` a renderer may deliver wrapped:
4
14
  * React hands a synthetic event with the real one on `.nativeEvent`; Preact passes
@@ -1,6 +1,17 @@
1
+ import { jsx } from "./jsx-runtime";
1
2
  function hasChildren(children) {
2
3
  return Array.isArray(children) ? children.length > 0 : children != null;
3
4
  }
5
+ function wrapLabel(kids, tag) {
6
+ if (kids == null) return kids;
7
+ const arr = Array.isArray(kids) ? kids : [kids];
8
+ return arr.map((child, i) => {
9
+ if (typeof child === "string") return child.trim() === "" ? null : jsx(tag, { children: child }, i);
10
+ if (typeof child === "number") return Number.isNaN(child) ? null : jsx(tag, { children: child }, i);
11
+ if (child == null || typeof child === "boolean") return null;
12
+ return child;
13
+ });
14
+ }
4
15
  function nativeStateChange(e) {
5
16
  const event = "nativeEvent" in e ? e.nativeEvent : e;
6
17
  return { event, detail: event?.detail };
@@ -33,5 +44,6 @@ export {
33
44
  NAMED_TONES,
34
45
  hasChildren,
35
46
  nativeStateChange,
36
- toneStyle
47
+ toneStyle,
48
+ wrapLabel
37
49
  };
@@ -1,19 +1,5 @@
1
1
  import { Fragment, jsx, jsxs } from "@antadesign/anta/jsx-runtime";
2
- import { toneStyle } from "../anta_helpers";
3
- const wrapChildren = (kids) => {
4
- if (kids == null) return kids;
5
- const arr = Array.isArray(kids) ? kids : [kids];
6
- return arr.map((child, i) => {
7
- if (typeof child === "string") {
8
- return child.trim() === "" ? null : /* @__PURE__ */ jsx("a-button-label", { children: child }, i);
9
- }
10
- if (typeof child === "number") {
11
- return Number.isNaN(child) ? null : /* @__PURE__ */ jsx("a-button-label", { children: child }, i);
12
- }
13
- if (child == null || typeof child === "boolean") return null;
14
- return child;
15
- });
16
- };
2
+ import { toneStyle, wrapLabel } from "../anta_helpers";
17
3
  const Button = ({
18
4
  priority,
19
5
  tone,
@@ -38,6 +24,12 @@ const Button = ({
38
24
  const computedStyle = toneStyle(toneAttr, "--button-tone-source", style);
39
25
  const isIconOnly = icon != null && label == null && children == null && iconTrailing == null;
40
26
  const sharedAttrs = {
27
+ // `<a-button>` is a custom element with no implicit ARIA role, so AT would
28
+ // announce it as a generic clickable — and `aria-pressed` below is only
29
+ // valid on a button/switch role. Publish `role="button"` from the wrapper
30
+ // (ARIA lives in the wrapper) for both the element and the `<a href>` path;
31
+ // a consumer's own `role` in `...rest` still wins by spread order.
32
+ role: "button",
41
33
  priority,
42
34
  tone: toneAttr,
43
35
  underline,
@@ -68,7 +60,7 @@ const Button = ({
68
60
  const inner = /* @__PURE__ */ jsxs(Fragment, { children: [
69
61
  icon && /* @__PURE__ */ jsx("a-icon", { shape: icon, "aria-hidden": "true" }),
70
62
  label != null && /* @__PURE__ */ jsx("a-button-label", { children: label }),
71
- wrapChildren(children),
63
+ wrapLabel(children, "a-button-label"),
72
64
  iconTrailing && /* @__PURE__ */ jsx("a-icon", { shape: iconTrailing, "aria-hidden": "true" })
73
65
  ] });
74
66
  if (href != null) {
@@ -76,7 +68,6 @@ const Button = ({
76
68
  "a",
77
69
  {
78
70
  href,
79
- role: "button",
80
71
  ...sharedAttrs,
81
72
  ...rest,
82
73
  children: inner
@@ -11,9 +11,9 @@ type StateDetail = {
11
11
  prev: CheckboxState;
12
12
  };
13
13
  type StateChangeEvent = CustomEvent<StateDetail>;
14
- /** Snapshot passed as the 2nd argument to `onAnyChange` — the new value plus
14
+ /** Snapshot passed as the 2nd argument to `onValueChange` — the new value plus
15
15
  * form-relevant fields, so you don't poke at `event.target`. Mirrors `Input`'s
16
- * `onAnyChange` convention. */
16
+ * `onValueChange` convention. */
17
17
  export interface CheckboxChangeAttrs {
18
18
  checked: boolean;
19
19
  indeterminate: boolean;
@@ -48,21 +48,22 @@ export interface CheckboxProps extends BaseProps {
48
48
  /** Value submitted with the form when checked — like a native checkbox.
49
49
  * @defaultValue "on" */
50
50
  value?: string;
51
- /** Colour variant, or any literal CSS color (`'#ff1493'`, `'rebeccapurple'`)
52
- * for a one-off custom tone. Tints fill, label, hint, and the unselected box
53
- * border. Named tones track light/dark mode automatically via the theme-aware
54
- * role tokens; a custom colour keeps its hue + chroma and pins lightness to the
55
- * fill curve.
51
+ /** Colour of the **mark** the checked-box fill and the unselected box border.
52
+ * A named tone or any literal CSS color (`'#ff1493'`, `'rebeccapurple'`) for a
53
+ * one-off custom tone. Named tones track light/dark mode automatically via the
54
+ * theme-aware role tokens; a custom colour keeps its hue + chroma and pins
55
+ * lightness to the fill curve. The label + hint stay neutral — use `toneText`
56
+ * to recolour those.
56
57
  * @defaultValue 'neutral' */
57
58
  tone?: 'brand' | 'neutral' | 'info' | 'success' | 'warning' | 'critical' | (string & {});
59
+ /** Colour of the **text** — the label and hint — independent of `tone`. A named
60
+ * tone or any literal CSS color. Named tones track light/dark via the theme-aware
61
+ * `--text-*` role tokens. Omit to leave the text neutral.
62
+ * @defaultValue 'neutral' */
63
+ toneText?: 'brand' | 'neutral' | 'info' | 'success' | 'warning' | 'critical' | (string & {});
58
64
  /** Size variant. small=14px, medium=16px, large=18px box.
59
65
  * @defaultValue 'medium' */
60
66
  size?: 'small' | 'medium' | 'large';
61
- /** Visual priority. `primary` fills the checked box with the tone colour and
62
- * draws a white checkmark; `secondary` keeps the box unfilled and draws the
63
- * border + checkmark in the tone colour (an outlined look).
64
- * @defaultValue 'primary' */
65
- priority?: 'primary' | 'secondary';
66
67
  /** Fired on click / Space *before* the element applies any change. Event-first
67
68
  * so `event.preventDefault()` is the synchronous veto (uncontrolled mode);
68
69
  * `detail` carries `{ next, prev }`. In controlled mode the element never
@@ -77,8 +78,8 @@ export interface CheckboxProps extends BaseProps {
77
78
  onChange?: (event: Event) => void;
78
79
  /** Like `onChange`, but with a `{ checked, indeterminate, name, value }` snapshot
79
80
  * as the 2nd argument — the ergonomic "just give me the new value" callback
80
- * (mirrors `Input`'s `onAnyChange`). */
81
- onAnyChange?: (event: Event, attrs: CheckboxChangeAttrs) => void;
81
+ * (mirrors `Input`'s `onValueChange`). */
82
+ onValueChange?: (event: Event, attrs: CheckboxChangeAttrs) => void;
82
83
  }
83
84
  /**
84
85
  * Checkbox. Renders an `<a-checkbox>` web component that owns the visual
@@ -93,5 +94,5 @@ export interface CheckboxProps extends BaseProps {
93
94
  * <Checkbox defaultChecked label="Remember me" hint="On this device" />
94
95
  * ```
95
96
  */
96
- export declare const Checkbox: ({ checked, defaultChecked, disabled, tone, size, priority, onStateChange, onChange, onAnyChange, label, hint, className, style, children, tabIndex, ...rest }: CheckboxProps) => any;
97
+ export declare const Checkbox: ({ checked, defaultChecked, disabled, tone, toneText, size, onStateChange, onChange, onValueChange, label, hint, className, style, children, tabIndex, ...rest }: CheckboxProps) => any;
97
98
  export {};
@@ -13,11 +13,11 @@ const Checkbox = ({
13
13
  defaultChecked,
14
14
  disabled,
15
15
  tone,
16
+ toneText,
16
17
  size,
17
- priority,
18
18
  onStateChange,
19
19
  onChange,
20
- onAnyChange,
20
+ onValueChange,
21
21
  label,
22
22
  hint,
23
23
  className,
@@ -26,7 +26,11 @@ const Checkbox = ({
26
26
  tabIndex,
27
27
  ...rest
28
28
  }) => {
29
- const computedStyle = toneStyle(tone, "--checkbox-tone-source", style);
29
+ const computedStyle = toneStyle(
30
+ toneText,
31
+ "--checkbox-tone-text-source",
32
+ toneStyle(tone, "--checkbox-tone-source", style)
33
+ );
30
34
  const explicitAriaLabel = rest["aria-label"];
31
35
  const ariaLabel = (typeof explicitAriaLabel === "string" ? explicitAriaLabel : void 0) ?? label ?? (typeof children === "string" ? children : void 0);
32
36
  const onstatechange = onStateChange ? (e) => {
@@ -37,9 +41,9 @@ const Checkbox = ({
37
41
  prev: stateToValue(detail.prev)
38
42
  });
39
43
  } : void 0;
40
- const onchange = onChange || onAnyChange ? (e) => {
44
+ const onchange = onChange || onValueChange ? (e) => {
41
45
  onChange?.(e);
42
- onAnyChange?.(e, checkboxAttrsOf(e.currentTarget));
46
+ onValueChange?.(e, checkboxAttrsOf(e.currentTarget));
43
47
  } : void 0;
44
48
  const stateAttr = checked !== void 0 ? valueToState(checked) : void 0;
45
49
  const defaultStateAttr = checked === void 0 && defaultChecked !== void 0 ? valueToState(defaultChecked) : void 0;
@@ -55,8 +59,8 @@ const Checkbox = ({
55
59
  "default-state": defaultStateAttr,
56
60
  disabled: disabled ? "" : void 0,
57
61
  tone: tone && tone !== "neutral" ? tone : void 0,
62
+ "tone-text": toneText && toneText !== "neutral" ? toneText : void 0,
58
63
  size: size && size !== "medium" ? size : void 0,
59
- priority: priority && priority !== "primary" ? priority : void 0,
60
64
  tabIndex: disabled ? -1 : tabIndex ?? 0,
61
65
  onstatechange,
62
66
  onchange,
@@ -1,6 +1,6 @@
1
1
  import type { BaseProps, DOMEventHandlers } from '../general_types';
2
2
  import type { IconShape } from '../elements/a-icon.shapes';
3
- /** Convenience snapshot passed as the 2nd argument to `onAnyChange`. */
3
+ /** Convenience snapshot passed as the 2nd argument to `onValueChange`. */
4
4
  export interface InputChangeAttrs {
5
5
  /** Current value. */
6
6
  value: string;
@@ -114,7 +114,7 @@ export interface InputProps extends BaseProps, DOMEventHandlers {
114
114
  onInput?: (e: any) => void;
115
115
  /** Fires on **commit** (blur / Enter) — the platform `change` semantics, **not**
116
116
  * React's per-keystroke `onChange`. This is a web component, so `onChange` keeps
117
- * the native meaning; reach for `onInput` (every keystroke) or `onAnyChange`
117
+ * the native meaning; reach for `onInput` (every keystroke) or `onValueChange`
118
118
  * (both) for live updates. Read `e.target.value`. */
119
119
  onChange?: (e: any) => void;
120
120
  /** Unified value-change handler — the easy path for state. Fires on `input`
@@ -123,7 +123,7 @@ export interface InputProps extends BaseProps, DOMEventHandlers {
123
123
  * you can do `setForm(s => ({ ...s, [attrs.name]: attrs.value }))` without
124
124
  * digging into the event. Use `event.type` to tell a live edit (`input`) from
125
125
  * a commit (`change`); read `id` / `type` / `className` off `event.target`. */
126
- onAnyChange?: (event: any, attrs: InputChangeAttrs) => void;
126
+ onValueChange?: (event: any, attrs: InputChangeAttrs) => void;
127
127
  /** Fires when the built-in clear button (`clearable`) is clicked, *before*
128
128
  * the field is cleared. Call `e.preventDefault()` to keep the current value
129
129
  * — the clear is cancelled and `onClearInput` won't fire. Backed by the
@@ -156,4 +156,4 @@ export interface InputProps extends BaseProps, DOMEventHandlers {
156
156
  * <Input label="Email" type="email" placeholder="you@example.com" clearable />
157
157
  * ```
158
158
  */
159
- export declare const Input: ({ label, hint, status, statusIcon, tone, size, value, defaultValue, multiline, rows, maxRows, clearable, leading, trailing, type, autoComplete, inputMode, name, placeholder, disabled, readOnly, required, dimActions, spellCheck, maxLength, minLength, pattern, min, max, step, onInput, onChange, onAnyChange, onClearClick, onClearInput, children, className, style, ...rest }: InputProps) => any;
159
+ export declare const Input: ({ label, hint, status, statusIcon, tone, size, value, defaultValue, multiline, rows, maxRows, clearable, leading, trailing, type, autoComplete, inputMode, name, placeholder, disabled, readOnly, required, dimActions, spellCheck, maxLength, minLength, pattern, min, max, step, onInput, onChange, onValueChange, onClearClick, onClearInput, children, className, style, ...rest }: InputProps) => any;
@@ -62,7 +62,7 @@ const Input = ({
62
62
  step,
63
63
  onInput,
64
64
  onChange,
65
- onAnyChange,
65
+ onValueChange,
66
66
  onClearClick,
67
67
  onClearInput,
68
68
  children,
@@ -100,13 +100,13 @@ const Input = ({
100
100
  max,
101
101
  step,
102
102
  "aria-invalid": status === "critical" ? "true" : void 0,
103
- oninput: onInput || onAnyChange ? (e) => {
103
+ oninput: onInput || onValueChange ? (e) => {
104
104
  onInput?.(e);
105
- onAnyChange?.(e, attrsOf(e));
105
+ onValueChange?.(e, attrsOf(e));
106
106
  } : void 0,
107
- onchange: onChange || onAnyChange ? (e) => {
107
+ onchange: onChange || onValueChange ? (e) => {
108
108
  onChange?.(e);
109
- onAnyChange?.(e, attrsOf(e));
109
+ onValueChange?.(e, attrsOf(e));
110
110
  } : void 0,
111
111
  onclearclick: onClearClick ? (e) => onClearClick(nativeStateChange(e).event) : void 0,
112
112
  onclearinput: onClearInput ? (e) => onClearInput(nativeStateChange(e).event) : void 0,
@@ -13,9 +13,12 @@ export interface MenuProps extends BaseProps {
13
13
  * Pairs naturally with `context`; on its own it positions a left-click
14
14
  * menu at the cursor. */
15
15
  coord?: boolean;
16
- /** For a submenu (a `<Menu>` nested inside a `MenuItem`): also open it on
17
- * hover (with intent timing), not only on click. No effect on a root menu. */
18
- hover?: boolean;
16
+ /** Submenu-only (a `<Menu>` nested inside a `MenuItem`); ignored on a root
17
+ * menu. Submenus open on hover by default (with intent timing) as well as on
18
+ * click — set `nohover` to make this submenu click-only. Hover-intent is
19
+ * mouse-only regardless: on touch (and pen) a submenu always opens on tap and
20
+ * stays open until dismissed. */
21
+ nohover?: boolean;
19
22
  /** Gap in pixels between the trigger and the menu.
20
23
  * @defaultValue 4 */
21
24
  offset?: number;
@@ -67,4 +70,4 @@ export interface MenuProps extends BaseProps {
67
70
  * </Menu>
68
71
  * ```
69
72
  */
70
- export declare const Menu: ({ placement, context, coord, hover, offset, open, onStateChange, className, children, ...rest }: MenuProps) => any;
73
+ export declare const Menu: ({ placement, context, coord, nohover, offset, open, onStateChange, className, children, ...rest }: MenuProps) => any;
@@ -4,7 +4,7 @@ const Menu = ({
4
4
  placement,
5
5
  context,
6
6
  coord,
7
- hover,
7
+ nohover,
8
8
  offset,
9
9
  open,
10
10
  onStateChange,
@@ -18,7 +18,7 @@ const Menu = ({
18
18
  placement: placement && placement !== "bottom-start" ? placement : void 0,
19
19
  context: context ? "" : void 0,
20
20
  coord: coord ? "" : void 0,
21
- hover: hover ? "" : void 0,
21
+ nohover: nohover ? "" : void 0,
22
22
  offset: offset != null ? String(offset) : void 0,
23
23
  state: open === void 0 ? void 0 : open ? "open" : "closed",
24
24
  onstatechange: onStateChange ? (e) => {
@@ -7,8 +7,9 @@ export interface MenuItemProps extends BaseProps {
7
7
  label?: string;
8
8
  /** A trailing keyboard-shortcut hint, e.g. `"⌘E"`. */
9
9
  kbd?: string;
10
- /** A trailing icon (ignored when `submenu` is set the chevron takes its
11
- * place). */
10
+ /** A trailing icon. On a `submenu` item this **overrides** the default
11
+ * chevron (omit it to keep the chevron); on a normal item it's the trailing
12
+ * glyph (omit for none). */
12
13
  iconTrailing?: IconShape;
13
14
  /** Disable the item: greyed out, not focusable for activation, no close. */
14
15
  disabled?: boolean;
@@ -20,9 +21,19 @@ export interface MenuItemProps extends BaseProps {
20
21
  * `aria-haspopup="menu"`, and an `aria-expanded` baseline (kept in sync by
21
22
  * the nested menu). Nest the flyout as a `<Menu>` child. */
22
23
  submenu?: boolean;
23
- /** Convenience activation handler fires on click / Enter / Space unless
24
- * the item is disabled. (Mapped to the underlying click.) */
25
- onSelect?: (e: any) => void;
24
+ /** An opaque value identifying this item, handed back in `onSelect`'s detail
25
+ * so a shared handler can tell which row was chosen without a per-item
26
+ * closure. */
27
+ value?: string | number;
28
+ /** Activation handler — fires when *this* item is chosen (click / Enter /
29
+ * Space), unless it's `disabled`. It does **not** fire for a submenu parent
30
+ * (clicking that opens the flyout, which isn't a selection) nor for a
31
+ * selection bubbling up from a nested submenu. Receives the event plus a
32
+ * `{ value, label }` detail. */
33
+ onSelect?: (event: any, detail: {
34
+ value?: string | number;
35
+ label?: string;
36
+ }) => void;
26
37
  /** Item content. With `label` set, children are extra content — most
27
38
  * notably the nested `<Menu>` for a submenu parent. */
28
39
  children?: React.ReactNode;
@@ -41,10 +52,10 @@ export interface MenuItemProps extends BaseProps {
41
52
  * <MenuItem icon="copy" label="Duplicate" kbd="⌘D" onSelect={dup} />
42
53
  * <MenuItem label="Word wrap" data-menu-open onSelect={toggleWrap} />
43
54
  * <MenuItem label="Share" submenu>
44
- * <Menu hover>
55
+ * <Menu>
45
56
  * <MenuItem label="Copy link" onSelect={copyLink} />
46
57
  * </Menu>
47
58
  * </MenuItem>
48
59
  * ```
49
60
  */
50
- export declare const MenuItem: ({ icon, label, kbd, iconTrailing, disabled, tone, submenu, onSelect, className, children, ...rest }: MenuItemProps) => any;
61
+ export declare const MenuItem: ({ icon, label, kbd, iconTrailing, disabled, tone, submenu, value, onSelect, className, children, ...rest }: MenuItemProps) => any;
@@ -7,6 +7,7 @@ const MenuItem = ({
7
7
  disabled,
8
8
  tone,
9
9
  submenu,
10
+ value,
10
11
  onSelect,
11
12
  className,
12
13
  children,
@@ -23,14 +24,22 @@ const MenuItem = ({
23
24
  "aria-haspopup": submenu ? "menu" : void 0,
24
25
  "aria-expanded": submenu ? "false" : void 0,
25
26
  "aria-disabled": disabled ? "true" : void 0,
26
- onClick: disabled ? void 0 : onSelect,
27
+ onClick: disabled || !onSelect ? void 0 : (e) => {
28
+ if (submenu) return;
29
+ const t = e.target;
30
+ if (t?.closest?.("a-menu-item") !== e.currentTarget) return;
31
+ onSelect(e, { value, label });
32
+ },
27
33
  class: className,
28
34
  ...rest,
29
35
  children: [
30
36
  icon && /* @__PURE__ */ jsx("a-icon", { shape: icon, "aria-hidden": "true" }),
31
37
  label != null && /* @__PURE__ */ jsx("a-menu-item-label", { children: label }),
32
38
  kbd && /* @__PURE__ */ jsx("kbd", { children: kbd }),
33
- submenu ? /* @__PURE__ */ jsx("a-icon", { shape: "chevron-right", "aria-hidden": "true" }) : iconTrailing && /* @__PURE__ */ jsx("a-icon", { shape: iconTrailing, "aria-hidden": "true" }),
39
+ /* @__PURE__ */ (() => {
40
+ const trailing = submenu ? iconTrailing ?? "chevron-right" : iconTrailing;
41
+ return trailing ? /* @__PURE__ */ jsx("a-icon", { shape: trailing, "aria-hidden": "true" }) : null;
42
+ })(),
34
43
  children
35
44
  ]
36
45
  }
@@ -8,7 +8,7 @@ type StateDetail = {
8
8
  reason: StateReason;
9
9
  };
10
10
  type StateChangeEvent = CustomEvent<StateDetail>;
11
- /** Snapshot passed as the 2nd argument to `onAnyChange` — the new value plus the
11
+ /** Snapshot passed as the 2nd argument to `onValueChange` — the new value plus the
12
12
  * field name, so you don't poke at `event.target`. Mirrors `Input`/`Checkbox`. */
13
13
  export interface RadioChangeAttrs {
14
14
  value: string | null;
@@ -25,12 +25,12 @@ export interface RadioOption {
25
25
  hint?: React.ReactNode;
26
26
  /** Disable just this option (skipped by keyboard, dropped from the tab order). */
27
27
  disabled?: boolean;
28
- /** Override this one option's tone (defaults to the group's `tone`). */
28
+ /** Override this one option's mark tone (defaults to the group's `tone`). */
29
29
  tone?: "brand" | "neutral" | "info" | "success" | "warning" | "critical" | (string & {});
30
+ /** Override this one option's text tone (defaults to the group's `toneText`). */
31
+ toneText?: "brand" | "neutral" | "info" | "success" | "warning" | "critical" | (string & {});
30
32
  /** Override this one option's size (defaults to the group's `size`). */
31
33
  size?: "small" | "medium" | "large";
32
- /** Override this one option's priority (defaults to the group's `priority`). */
33
- priority?: "primary" | "secondary";
34
34
  }
35
35
  /** Public props for `<RadioGroup>` — the single-select container. */
36
36
  export interface RadioGroupProps extends Omit<BaseProps, "children" | "onChange"> {
@@ -58,7 +58,7 @@ export interface RadioGroupProps extends Omit<BaseProps, "children" | "onChange"
58
58
  onChange?: (event: Event) => void;
59
59
  /** Like `onChange`, but with a `{ value, name }` snapshot as the 2nd argument —
60
60
  * the ergonomic "just give me the new value" callback (mirrors `Input`). */
61
- onAnyChange?: (event: Event, attrs: RadioChangeAttrs) => void;
61
+ onValueChange?: (event: Event, attrs: RadioChangeAttrs) => void;
62
62
  /** Fired when focus enters the group (any option) — wired to `focusin`, since
63
63
  * focus lands on an individual option, not the group element itself. */
64
64
  onFocus?: (event: FocusEvent) => void;
@@ -78,20 +78,20 @@ export interface RadioGroupProps extends Omit<BaseProps, "children" | "onChange"
78
78
  * the neutral default.
79
79
  * @defaultValue 'neutral' */
80
80
  status?: "neutral" | "brand" | "info" | "success" | "warning" | "critical";
81
- /** Tone applied to every option (an option's own `tone` wins), or any literal
82
- * CSS color for a one-off custom tone. Tints fill, label, hint, and the
83
- * unselected ring border. Named tones track light/dark mode.
81
+ /** Mark tone applied to every option (an option's own `tone` wins), or any literal
82
+ * CSS color for a one-off custom tone. Colours the selected-ring fill + dot and
83
+ * the unselected ring border. Named tones track light/dark mode. The option text
84
+ * stays neutral — use `toneText` for that.
84
85
  * @defaultValue 'neutral' */
85
86
  tone?: "brand" | "neutral" | "info" | "success" | "warning" | "critical" | (string & {});
87
+ /** Text tone applied to every option's label + hint (an option's own `toneText`
88
+ * wins), independent of `tone`. A named tone or any literal CSS color. Omit to
89
+ * leave the text neutral.
90
+ * @defaultValue 'neutral' */
91
+ toneText?: "brand" | "neutral" | "info" | "success" | "warning" | "critical" | (string & {});
86
92
  /** Size applied to every option (an option's own `size` wins).
87
93
  * @defaultValue 'medium' */
88
94
  size?: "small" | "medium" | "large";
89
- /** Visual priority applied to every option (an option's own `priority` wins).
90
- * `primary` fills the selected ring with the tone colour and draws a white dot;
91
- * `secondary` keeps the ring unfilled and draws the border + dot in the tone
92
- * colour (an outlined look).
93
- * @defaultValue 'primary' */
94
- priority?: "primary" | "secondary";
95
95
  /** Disable the whole group. */
96
96
  disabled?: boolean;
97
97
  /** Layout + arrow-key axis.
@@ -115,5 +115,5 @@ export interface RadioGroupProps extends Omit<BaseProps, "children" | "onChange"
115
115
  *
116
116
  * Requires `@antadesign/anta/elements` (client-side only).
117
117
  */
118
- export declare const RadioGroup: ({ options, value, defaultValue, onStateChange, onChange, onAnyChange, onFocus, onBlur, name, label, hint, status, tone, size, priority, disabled, orientation, className, style, ...rest }: RadioGroupProps) => any;
118
+ export declare const RadioGroup: ({ options, value, defaultValue, onStateChange, onChange, onValueChange, onFocus, onBlur, name, label, hint, status, tone, toneText, size, disabled, orientation, className, style, ...rest }: RadioGroupProps) => any;
119
119
  export {};
@@ -11,7 +11,7 @@ const RadioGroup = ({
11
11
  defaultValue,
12
12
  onStateChange,
13
13
  onChange,
14
- onAnyChange,
14
+ onValueChange,
15
15
  onFocus,
16
16
  onBlur,
17
17
  name,
@@ -19,8 +19,8 @@ const RadioGroup = ({
19
19
  hint,
20
20
  status,
21
21
  tone,
22
+ toneText,
22
23
  size,
23
- priority,
24
24
  disabled,
25
25
  orientation,
26
26
  className,
@@ -47,9 +47,9 @@ const RadioGroup = ({
47
47
  if (detail.reason === "user" && event.defaultPrevented) return;
48
48
  setInternalValue(detail.next ?? void 0);
49
49
  };
50
- const onchange = onChange || onAnyChange ? (e) => {
50
+ const onchange = onChange || onValueChange ? (e) => {
51
51
  onChange?.(e);
52
- onAnyChange?.(e, radioAttrsOf(e.currentTarget));
52
+ onValueChange?.(e, radioAttrsOf(e.currentTarget));
53
53
  } : void 0;
54
54
  return /* @__PURE__ */ jsxs(
55
55
  "a-radio-group",
@@ -64,8 +64,8 @@ const RadioGroup = ({
64
64
  name,
65
65
  status: status && status !== "neutral" ? status : void 0,
66
66
  tone: tone && tone !== "neutral" ? tone : void 0,
67
+ "tone-text": toneText && toneText !== "neutral" ? toneText : void 0,
67
68
  size: size && size !== "medium" ? size : void 0,
68
- priority: priority && priority !== "primary" ? priority : void 0,
69
69
  disabled: disabled ? "" : void 0,
70
70
  orientation: orientation && orientation !== "vertical" ? orientation : void 0,
71
71
  onstatechange,
@@ -73,7 +73,7 @@ const RadioGroup = ({
73
73
  onfocusin: onFocus,
74
74
  onfocusout: onBlur,
75
75
  class: className,
76
- style: toneStyle(tone, "--radio-tone-source", style),
76
+ style: toneStyle(toneText, "--radio-tone-text-source", toneStyle(tone, "--radio-tone-source", style)),
77
77
  children: [
78
78
  label && /* @__PURE__ */ jsx("a-radio-group-label", { id: labelId, children: label }),
79
79
  hint && /* @__PURE__ */ jsx("a-radio-group-hint", { id: hintId, children: hint }),
@@ -87,10 +87,10 @@ const RadioGroup = ({
87
87
  "aria-disabled": optDisabled ? "true" : void 0,
88
88
  tabIndex: o.value === tabStopValue ? 0 : -1,
89
89
  tone: o.tone && o.tone !== "neutral" ? o.tone : void 0,
90
+ "tone-text": o.toneText && o.toneText !== "neutral" ? o.toneText : void 0,
90
91
  size: o.size && o.size !== "medium" ? o.size : void 0,
91
- priority: o.priority && o.priority !== "primary" ? o.priority : void 0,
92
92
  disabled: o.disabled ? "" : void 0,
93
- style: toneStyle(o.tone, "--radio-tone-source"),
93
+ style: toneStyle(o.toneText, "--radio-tone-text-source", toneStyle(o.tone, "--radio-tone-source")),
94
94
  children: [
95
95
  /* @__PURE__ */ jsx("a-radio-label", { children: o.label }),
96
96
  o.hint != null && /* @__PURE__ */ jsx("a-radio-hint", { children: o.hint })
@@ -0,0 +1,34 @@
1
+ import type { IconShape } from "../elements/a-icon.shapes";
2
+ /** One tab in a `<Tabs>` strip. A **config component**: `Tabs` reads these props to
3
+ * render the underlying `<a-tab>` (`tabindex`, `role`, `aria-controls`, and
4
+ * selection are all `Tabs`' job), so `<Tab>` renders nothing on its own. */
5
+ export interface TabProps {
6
+ /** This tab's identity — pairs it with the `<TabPanel value="…">` of the same
7
+ * value, and the value reported by `onStateChange` / `onChange`. Unique per strip. */
8
+ value: string;
9
+ /** Visible label. Alternatively pass `children`. */
10
+ label?: React.ReactNode;
11
+ /** Tab content when you need more than a string — used if `label` is omitted. */
12
+ children?: React.ReactNode;
13
+ /** Leading icon shape, rendered before the label. */
14
+ icon?: IconShape;
15
+ /** Trailing icon shape, rendered after the label. */
16
+ iconTrailing?: IconShape;
17
+ /** Per-tab tone override, same vocabulary as `<Tabs tone>` — colours this one tab's
18
+ * label + icons (all priorities/modes, named or custom colour) and, when it's the
19
+ * active tab, its indicator. For a **custom literal colour** the sliding indicator can't
20
+ * adopt it (the shared moving element can't read a descendant's colour), so a custom tone
21
+ * colours the label everywhere and the indicator only in `noslide`; the six **named**
22
+ * tones colour both in every mode. Overrides the strip's `tone` for this tab.
23
+ * @defaultValue inherits the strip's `tone` */
24
+ tone?: "neutral" | "brand" | "info" | "success" | "warning" | "critical" | (string & {});
25
+ /** Disable just this tab — skipped by keyboard nav and dropped from the tab order
26
+ * (a disabled-but-selected tab stays reachable, per the ARIA pattern). */
27
+ disabled?: boolean;
28
+ }
29
+ /**
30
+ * A tab inside `<Tabs>`. Configuration only — `Tabs` reads its props and renders the
31
+ * real `<a-tab>`, so this component itself produces no DOM. Use it as a direct child
32
+ * of `<Tabs>`; rendering it elsewhere does nothing.
33
+ */
34
+ export declare const Tab: (_props: TabProps) => null;
@@ -0,0 +1,4 @@
1
+ const Tab = (_props) => null;
2
+ export {
3
+ Tab
4
+ };
@@ -0,0 +1,22 @@
1
+ import type { TabsMounting } from "./Tabs";
2
+ /** A panel paired to the `<Tab>` of the same `value`. A **config component**: `Tabs`
3
+ * reads these props and renders the underlying `<a-tabpanel>` (id wiring, show/hide,
4
+ * `inert`, and the mounting strategy are all `Tabs`' job). */
5
+ export interface TabPanelProps {
6
+ /** Pairs this panel with the `<Tab value="…">` of the same value. */
7
+ value: string;
8
+ /** Panel content — arbitrary React/Preact. */
9
+ children?: React.ReactNode;
10
+ /** Override the `<Tabs mounting>` strategy for just this panel. See `TabsMounting`. */
11
+ mounting?: TabsMounting;
12
+ /** CSS class on the rendered `<a-tabpanel>`. */
13
+ className?: string;
14
+ /** Inline style on the rendered `<a-tabpanel>`. */
15
+ style?: React.CSSProperties;
16
+ }
17
+ /**
18
+ * A tab panel inside `<Tabs>`. Configuration only — `Tabs` reads its props and renders
19
+ * the real `<a-tabpanel>`, so this component itself produces no DOM. Use it as a direct
20
+ * child of `<Tabs>`; rendering it elsewhere does nothing.
21
+ */
22
+ export declare const TabPanel: (_props: TabPanelProps) => null;
@@ -0,0 +1,4 @@
1
+ const TabPanel = (_props) => null;
2
+ export {
3
+ TabPanel
4
+ };