@antadesign/anta 0.3.28 → 0.3.29

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 (135) hide show
  1. package/NOTICES.md +32 -1
  2. package/dist/anta_helpers.d.ts +21 -0
  3. package/dist/anta_helpers.js +24 -0
  4. package/dist/box-observation.d.ts +8 -0
  5. package/dist/box-observation.js +41 -0
  6. package/dist/box-types.d.ts +2 -0
  7. package/dist/bundle.css +1 -1
  8. package/dist/bundle.js +64 -27
  9. package/dist/components/Box.d.ts +28 -12
  10. package/dist/components/Box.js +18 -11
  11. package/dist/components/Breadcrumbs.css +1 -1
  12. package/dist/components/Calendar.js +3 -5
  13. package/dist/components/Checkbox.d.ts +2 -2
  14. package/dist/components/Input.d.ts +8 -2
  15. package/dist/components/Input.js +4 -0
  16. package/dist/components/InputAutocomplete.js +3 -12
  17. package/dist/components/InputDate.css +1 -1
  18. package/dist/components/InputDate.js +2 -0
  19. package/dist/components/Menu.d.ts +4 -4
  20. package/dist/components/Menu.js +1 -1
  21. package/dist/components/Panel.d.ts +17 -0
  22. package/dist/components/Panel.js +22 -0
  23. package/dist/components/RadioGroup.d.ts +2 -1
  24. package/dist/components/Select.d.ts +14 -14
  25. package/dist/components/Select.js +47 -35
  26. package/dist/components/SelectFaceted.d.ts +17 -6
  27. package/dist/components/SelectFaceted.js +61 -41
  28. package/dist/components/Steps.css +1 -1
  29. package/dist/components/Switch.d.ts +3 -3
  30. package/dist/components/TabPanel.d.ts +3 -8
  31. package/dist/components/TabPanel.js +2 -1
  32. package/dist/components/Tabs.d.ts +2 -2
  33. package/dist/components/Tabs.js +2 -1
  34. package/dist/components/Tooltip.d.ts +1 -1
  35. package/dist/components/Tooltip.js +1 -1
  36. package/dist/components/select-parts.css +1 -1
  37. package/dist/elements/a-avatar.css +1 -1
  38. package/dist/elements/a-banner.css +1 -1
  39. package/dist/elements/a-box.css +1 -1
  40. package/dist/elements/a-box.d.ts +6 -6
  41. package/dist/elements/a-box.js +74 -23
  42. package/dist/elements/a-button.css +1 -1
  43. package/dist/elements/a-button.d.ts +9 -1
  44. package/dist/elements/a-button.js +64 -1
  45. package/dist/elements/a-calendar.css +1 -1
  46. package/dist/elements/a-capture.css +1 -1
  47. package/dist/elements/a-card.css +1 -1
  48. package/dist/elements/a-checkbox.css +1 -1
  49. package/dist/elements/a-checkbox.d.ts +3 -0
  50. package/dist/elements/a-checkbox.js +17 -1
  51. package/dist/elements/a-copy.css +1 -1
  52. package/dist/elements/a-dialog.css +1 -1
  53. package/dist/elements/a-expander.css +1 -1
  54. package/dist/elements/a-icon.css +1 -1
  55. package/dist/elements/a-icon.shapes.css +1 -1
  56. package/dist/elements/a-input-time.css +1 -1
  57. package/dist/elements/a-input-time.d.ts +8 -0
  58. package/dist/elements/a-input-time.js +115 -8
  59. package/dist/elements/a-input.css +1 -1
  60. package/dist/elements/a-input.d.ts +27 -1
  61. package/dist/elements/a-input.js +176 -35
  62. package/dist/elements/a-loader.css +1 -1
  63. package/dist/elements/a-menu-group.css +1 -1
  64. package/dist/elements/a-menu-item.css +1 -1
  65. package/dist/elements/a-menu-item.js +1 -0
  66. package/dist/elements/a-menu-separator.css +1 -1
  67. package/dist/elements/a-menu.css +1 -1
  68. package/dist/elements/a-menu.d.ts +8 -13
  69. package/dist/elements/a-menu.js +146 -45
  70. package/dist/elements/a-panel.css +1 -0
  71. package/dist/elements/a-panel.d.ts +16 -0
  72. package/dist/elements/a-panel.js +153 -0
  73. package/dist/elements/a-progress.css +1 -1
  74. package/dist/elements/a-radio-group.css +1 -1
  75. package/dist/elements/a-radio.css +1 -1
  76. package/dist/elements/a-radio.d.ts +4 -0
  77. package/dist/elements/a-radio.js +18 -0
  78. package/dist/elements/a-slider.css +1 -1
  79. package/dist/elements/a-slider.d.ts +1 -0
  80. package/dist/elements/a-slider.js +3 -3
  81. package/dist/elements/a-switch.css +1 -1
  82. package/dist/elements/a-switch.d.ts +3 -0
  83. package/dist/elements/a-switch.js +17 -1
  84. package/dist/elements/a-tab.css +1 -1
  85. package/dist/elements/a-tabpanel.css +1 -1
  86. package/dist/elements/a-tabs.css +1 -1
  87. package/dist/elements/a-tag.css +1 -1
  88. package/dist/elements/a-text.css +1 -1
  89. package/dist/elements/a-title.css +1 -1
  90. package/dist/elements/a-toast.css +1 -1
  91. package/dist/elements/a-toaster.css +1 -1
  92. package/dist/elements/a-tooltip.css +1 -1
  93. package/dist/elements/a-tooltip.js +30 -7
  94. package/dist/elements/focus.d.ts +9 -0
  95. package/dist/elements/focus.js +41 -0
  96. package/dist/elements/index.d.ts +1 -0
  97. package/dist/elements/index.js +3 -0
  98. package/dist/elements/panel-focus.d.ts +10 -0
  99. package/dist/elements/panel-focus.js +86 -0
  100. package/dist/elements/shadow-aria.d.ts +10 -0
  101. package/dist/elements/shadow-aria.js +155 -0
  102. package/dist/general_types.d.ts +48 -19
  103. package/dist/generate-icons.mjs +3 -0
  104. package/dist/index.d.ts +4 -1
  105. package/dist/index.js +2 -0
  106. package/dist/jsx-runtime.d.ts +10 -1
  107. package/dist/reset.css +1 -1
  108. package/dist/theme-antithesis.css +1 -1
  109. package/dist/theme-antune.css +1 -1
  110. package/dist/tokens.css +1 -1
  111. package/docs/accessibility.md +4 -2
  112. package/docs/changelog.md +82 -4
  113. package/docs/colors.md +6 -6
  114. package/docs/components/box.md +98 -34
  115. package/docs/components/breadcrumbs.md +33 -0
  116. package/docs/components/button.md +2 -2
  117. package/docs/components/capture.md +8 -8
  118. package/docs/components/checkbox.md +9 -4
  119. package/docs/components/input-autocomplete.md +6 -0
  120. package/docs/components/input-date.md +8 -2
  121. package/docs/components/input.md +99 -40
  122. package/docs/components/menu.md +3 -3
  123. package/docs/components/panel.md +189 -0
  124. package/docs/components/radio.md +4 -2
  125. package/docs/components/select-faceted.md +57 -2
  126. package/docs/components/select.md +63 -51
  127. package/docs/components/steps.md +4 -4
  128. package/docs/components/switch.md +12 -6
  129. package/docs/components/tabs.md +21 -8
  130. package/docs/components/tooltip.md +6 -4
  131. package/docs/index.md +1 -0
  132. package/docs/install-config.md +5 -4
  133. package/docs/normalization.md +3 -1
  134. package/docs/theming.md +1 -1
  135. package/package.json +4 -1
@@ -1,9 +1,9 @@
1
- import type { BoxContextChange, BoxDisplay, BoxMeasurementChange } from '../box-types';
1
+ import type { BoxContextChange, BoxDisplay, BoxMeasurementChange, BoxObservation } from '../box-types';
2
2
  import type { BaseProps } from '../general_types';
3
3
  /** JSX props for the observing light-DOM `<a-box>` container. */
4
4
  export interface BoxProps extends BaseProps {
5
- /** Layout model for the host. All other layout, sizing, mask, and shadow
6
- * properties stay ordinary `className` / `style` CSS on the Box itself.
5
+ /** Layout model for the host. Sizing, alignment, mask, and shadow properties
6
+ * stay ordinary `className` / `style` CSS on the Box itself.
7
7
  * @defaultValue block */
8
8
  display?: BoxDisplay;
9
9
  /** Fully-round corners (`border-radius: 999px`, clamped to the box). Pass a
@@ -14,12 +14,28 @@ export interface BoxProps extends BaseProps {
14
14
  * pixels; a string is any CSS length or two-value gap (`'1rem'`,
15
15
  * `'8px 16px'`). Applies while the Box is a flex or grid container. */
16
16
  gap?: number | string;
17
- /** What the Box watches, when a handler is not what turns it on. `'size'`
18
- * keeps the overflow CSS states (`:state(clipped-x)`, `:state(scrollable-y)`,
19
- * …) current — reach for it when your own CSS is the only reader. `'context'`
20
- * and `'all'` are there for symmetry; passing `onMeasureChange` or
21
- * `onContextChange` already turns the matching half on. */
22
- observe?: 'size' | 'context' | 'all';
17
+ /** Inner spacing, matching CSS `padding`. Numbers are pixels; strings accept
18
+ * CSS shorthand, percentages, and custom properties. Omission adds no style. */
19
+ padding?: number | string;
20
+ /** Outer spacing, matching CSS `margin`. Numbers are pixels; strings accept
21
+ * CSS shorthand, `auto`, negative lengths, and custom properties.
22
+ * Omission adds no style. */
23
+ margin?: number | string;
24
+ /** One selection or an array of selections, in any order. `'size'` watches width
25
+ * and height; `'context'` watches rendering context; `'overflow'` watches
26
+ * content dimensions and clipping. `'edges'` reports which edges hide content;
27
+ * `'scroll'` reports offsets, potentially every frame; `'all'` selects everything.
28
+ * Selections are independent: use `['size', 'edges']` to combine them.
29
+ * A measurement handler implies `'size'` when no measurement is selected;
30
+ * a context handler adds `'context'`. Size skips content and scroll observers;
31
+ * overflow adds content observation; hidden edges and scroll add scroll reads.
32
+ * Without handlers or `fade`, omission stays idle. */
33
+ observe?: BoxObservation | readonly BoxObservation[];
34
+ /** Minimum interval between measurement events, in milliseconds. The first
35
+ * report has no added delay; a trailing report delivers the latest values.
36
+ * Active observers and CSS clipping states are not throttled.
37
+ * @defaultValue 0 */
38
+ throttle?: number;
23
39
  /** Fades out every edge that currently hides clipped content, and drops the
24
40
  * fade from an edge once the reader scrolls to it. */
25
41
  fade?: boolean;
@@ -27,8 +43,8 @@ export interface BoxProps extends BaseProps {
27
43
  * length.
28
44
  * @defaultValue 24 */
29
45
  fadeSize?: number | string;
30
- /** Fired after Box geometry or its content-overflow state changes. `detail`
31
- * contains the changed fields and a full current snapshot. */
46
+ /** Fired when a selected measurement field changes. `detail` contains all
47
+ * fields changed since the last event and a full current snapshot. */
32
48
  onMeasureChange?: (event: CustomEvent<BoxMeasurementChange>, detail: BoxMeasurementChange) => void;
33
49
  /** Fired after Box's browser and local rendering context changes. `detail`
34
50
  * contains the changed fields and a full current snapshot. */
@@ -49,4 +65,4 @@ export interface BoxProps extends BaseProps {
49
65
  * </Box>
50
66
  * ```
51
67
  */
52
- export declare const Box: ({ display, round, gap, observe, fade, fadeSize, onMeasureChange, onContextChange, className, style, children, ...rest }: BoxProps) => any;
68
+ export declare const Box: ({ display, round, gap, padding, margin, observe, throttle, fade, fadeSize, onMeasureChange, onContextChange, className, style, children, ...rest }: BoxProps) => any;
@@ -6,19 +6,22 @@ import {
6
6
  roundAttr,
7
7
  roundStyle
8
8
  } from "../anta_helpers";
9
+ import { boxObservation } from "../box-observation";
9
10
  function observeAttr(observe, onMeasureChange, onContextChange) {
10
- const size = observe === "size" || observe === "all" || onMeasureChange != null;
11
- const context = observe === "context" || observe === "all" || onContextChange != null;
12
- if (size && context) return "all";
13
- if (size) return "size";
14
- if (context) return "context";
15
- return void 0;
11
+ const tokens = [...new Set(observe == null ? [] : typeof observe === "string" ? [observe] : observe)];
12
+ const { fields, context } = boxObservation(tokens.join(" ") || null);
13
+ if (onMeasureChange != null && fields.size === 0) tokens.push("size");
14
+ if (onContextChange != null && !context) tokens.push("context");
15
+ return tokens.join(" ") || void 0;
16
16
  }
17
17
  const Box = ({
18
18
  display,
19
19
  round,
20
20
  gap,
21
+ padding,
22
+ margin,
21
23
  observe,
24
+ throttle,
22
25
  fade,
23
26
  fadeSize,
24
27
  onMeasureChange,
@@ -28,23 +31,27 @@ const Box = ({
28
31
  children,
29
32
  ...rest
30
33
  }) => {
34
+ let boxStyle = roundStyle(round, "--box-round", style);
35
+ boxStyle = lengthStyle(gap, "--box-gap", boxStyle);
36
+ boxStyle = lengthStyle(padding, "--box-padding", boxStyle);
37
+ boxStyle = lengthStyle(margin, "--box-margin", boxStyle);
38
+ boxStyle = lengthStyle(fade ? fadeSize : void 0, "--box-fade-size", boxStyle);
31
39
  return /* @__PURE__ */ jsx(
32
40
  "a-box",
33
41
  {
34
42
  display: display === "block" ? void 0 : display,
35
43
  round: roundAttr(round),
36
44
  gap: gap != null ? "" : void 0,
45
+ padding: padding != null ? "" : void 0,
46
+ margin: margin != null ? "" : void 0,
37
47
  observe: observeAttr(observe, onMeasureChange, onContextChange),
48
+ throttle,
38
49
  fade: fade ? "" : void 0,
39
50
  "fade-size": fade && fadeSize != null ? cssLength(fadeSize) : void 0,
40
51
  onmeasurechange: customEventHandler(onMeasureChange),
41
52
  oncontextchange: customEventHandler(onContextChange),
42
53
  class: className,
43
- style: lengthStyle(
44
- fade ? fadeSize : void 0,
45
- "--box-fade-size",
46
- lengthStyle(gap, "--box-gap", roundStyle(round, "--box-round", style))
47
- ),
54
+ style: boxStyle,
48
55
  ...rest,
49
56
  children
50
57
  }
@@ -1 +1 @@
1
- @layer anta.components{a-breadcrumbs{--breadcrumb-gap: 1px;--breadcrumb-separator-color: var(--text-5);--breadcrumb-separator-icon-size: 16px;--breadcrumb-separator-font-size: 15px;display:flex;align-items:center;gap:var(--breadcrumb-gap);width:max-content;min-width:100%;max-width:100%;overflow-x:auto}a-breadcrumbs[data-size=small]{--breadcrumb-separator-icon-size: 14px;--breadcrumb-separator-font-size: 13px}a-breadcrumbs[data-size=large]{--breadcrumb-separator-icon-size: 18px;--breadcrumb-separator-font-size: 17px}a-breadcrumbs[data-paddingless]{--breadcrumb-gap: .75ch}a-breadcrumbs[data-separator-icon]{--breadcrumb-gap: 0}a-breadcrumbs>*{flex:none}a-breadcrumb-separator{display:inline-flex;flex:none;align-items:center;justify-content:center;color:var(--breadcrumb-separator-color);font-family:var(--sans-serif);font-size:var(--breadcrumb-separator-font-size);line-height:1;user-select:none}a-breadcrumb-separator>a-icon{--icon-size: var(--breadcrumb-separator-icon-size)}}
1
+ @layer base,anta,components,utilities;@layer anta.reset,anta.components,anta.theme;@layer anta.components{a-breadcrumbs{--breadcrumb-gap: 1px;--breadcrumb-separator-color: var(--text-5);--breadcrumb-separator-icon-size: 16px;--breadcrumb-separator-font-size: 15px;display:flex;align-items:center;gap:var(--breadcrumb-gap);width:max-content;min-width:100%;max-width:100%}a-breadcrumbs[data-size=small]{--breadcrumb-separator-icon-size: 14px;--breadcrumb-separator-font-size: 13px}a-breadcrumbs[data-size=large]{--breadcrumb-separator-icon-size: 18px;--breadcrumb-separator-font-size: 17px}a-breadcrumbs[data-paddingless]{--breadcrumb-gap: .75ch}a-breadcrumbs[data-separator-icon]{--breadcrumb-gap: 0}a-breadcrumbs>*{flex:none}a-breadcrumb-separator{display:inline-flex;flex:none;align-items:center;justify-content:center;color:var(--breadcrumb-separator-color);font-family:var(--sans-serif);font-size:var(--breadcrumb-separator-font-size);line-height:1;user-select:none}a-breadcrumb-separator>a-icon{--icon-size: var(--breadcrumb-separator-icon-size)}}
@@ -1,7 +1,7 @@
1
1
  import { jsx, jsxs } from "@antadesign/anta/jsx-runtime";
2
2
  import cn from "clsx";
3
3
  import { Temporal } from "temporal-polyfill";
4
- import { useId, useMemo, useState } from "../jsx-runtime";
4
+ import { useMemo, useState } from "../jsx-runtime";
5
5
  import { nativeStateChange } from "../anta_helpers";
6
6
  import { Button } from "./Button";
7
7
  import { Menu } from "./Menu";
@@ -50,7 +50,6 @@ const Calendar = ({
50
50
  }
51
51
  const [focusReq, setFocusReq] = useState(null);
52
52
  const [jumpOpen, setJumpOpen] = useState(false);
53
- const headingId = useId();
54
53
  const month = buildMonth({ anchor: effectiveCursor, locale: resolvedLocale, min: minD, max: maxD, selected, today });
55
54
  const cursorIso = effectiveCursor.toString();
56
55
  const [lastFocusSignal, setLastFocusSignal] = useState(focusSignal);
@@ -154,7 +153,6 @@ const Calendar = ({
154
153
  /* @__PURE__ */ jsx(
155
154
  Button,
156
155
  {
157
- id: headingId,
158
156
  "data-part": "heading",
159
157
  priority: "tertiary",
160
158
  size,
@@ -181,8 +179,7 @@ const Calendar = ({
181
179
  "a-calendar",
182
180
  {
183
181
  role: "group",
184
- "aria-labelledby": headingId,
185
- "aria-label": ariaLabel,
182
+ "aria-label": ariaLabel ?? month.heading,
186
183
  name,
187
184
  value: controlled ? value : void 0,
188
185
  defaultvalue: !controlled ? defaultValue : void 0,
@@ -212,6 +209,7 @@ const Calendar = ({
212
209
  disabled: disabled || d.disabled,
213
210
  tabIndex: d.iso === cursorIso ? 0 : -1,
214
211
  "aria-label": d.label,
212
+ "aria-hidden": d.outside ? "true" : void 0,
215
213
  "aria-current": d.today ? "date" : void 0,
216
214
  "data-part": "day-cell",
217
215
  "data-date": d.iso,
@@ -27,8 +27,8 @@ export interface CheckboxProps extends BaseProps {
27
27
  * renders first. Required unless `children` or `aria-label` is provided
28
28
  * (a `role="checkbox"` takes its name from the author, not the markup). */
29
29
  label?: string;
30
- /** Secondary text rendered under the label — explanatory copy, like
31
- * Input's hint. Not part of the accessible name. */
30
+ /** Secondary text rendered under the label and exposed as the checkbox's
31
+ * accessible description. Not part of the accessible name. */
32
32
  hint?: React.ReactNode;
33
33
  /** Controlled checked state. When provided the checkbox is controlled — it
34
34
  * renders exactly this and never self-applies; `onStateChange` is a *request*
@@ -102,6 +102,10 @@ export interface InputProps extends BaseProps, DOMEventHandlers {
102
102
  disabled?: boolean;
103
103
  /** Make the field read-only. */
104
104
  readOnly?: boolean;
105
+ /** Render the field surface with a native button as its focus target. This is
106
+ * available for Input-styled popup triggers; the value becomes
107
+ * the button text and the placeholder is shown while it is empty. */
108
+ button?: boolean;
105
109
  /** Mark the field required (drives native validity). */
106
110
  required?: boolean;
107
111
  /** Dim the `leading` / `trailing` adornments at rest; they brighten to full
@@ -153,7 +157,9 @@ export interface InputProps extends BaseProps, DOMEventHandlers {
153
157
  /** Fires when the field loses focus. */
154
158
  onBlur?: (e: any) => void;
155
159
  /** ARIA `role` for the field — e.g. `combobox` when the input drives a
156
- * suggestion `listbox` (see `InputAutocomplete`). Left unset by default. */
160
+ * suggestion `listbox` (see `InputAutocomplete`). The custom element
161
+ * delegates it, together with standard `aria-*` props, to the focused native
162
+ * shadow control. Left unset by default. */
157
163
  role?: string;
158
164
  }
159
165
  /**
@@ -173,4 +179,4 @@ export interface InputProps extends BaseProps, DOMEventHandlers {
173
179
  * <Input label="Email" type="email" placeholder="you@example.com" clearable />
174
180
  * ```
175
181
  */
176
- export declare const Input: ({ label, hint, status, statusIcon, tone, size, round, value, defaultValue, multiline, rows, maxRows, clearable, leading, trailing, type, autoComplete, inputMode, autoFocus, name, placeholder, truncate, disabled, readOnly, required, dimActions, spellCheck, maxLength, minLength, pattern, min, max, step, onInput, onChange, onValueChange, onClearClick, onClearInput, children, className, style, ...rest }: InputProps) => any;
182
+ export declare const Input: ({ label, hint, status, statusIcon, tone, size, round, value, defaultValue, multiline, rows, maxRows, clearable, leading, trailing, type, autoComplete, inputMode, autoFocus, name, placeholder, truncate, disabled, readOnly, button, required, dimActions, spellCheck, maxLength, minLength, pattern, min, max, step, role, onInput, onChange, onValueChange, onClearClick, onClearInput, children, className, style, ...rest }: InputProps) => any;
@@ -55,6 +55,7 @@ const Input = ({
55
55
  truncate = true,
56
56
  disabled,
57
57
  readOnly,
58
+ button,
58
59
  required,
59
60
  dimActions,
60
61
  spellCheck,
@@ -64,6 +65,7 @@ const Input = ({
64
65
  min,
65
66
  max,
66
67
  step,
68
+ role,
67
69
  onInput,
68
70
  onChange,
69
71
  onValueChange,
@@ -98,6 +100,7 @@ const Input = ({
98
100
  truncate: presence(truncate),
99
101
  disabled: presence(disabled),
100
102
  readonly: presence(readOnly),
103
+ button: presence(button),
101
104
  required: presence(required),
102
105
  "dim-actions": presence(dimActions),
103
106
  autocomplete: autoComplete ?? (!multiline && rows == null && type ? AUTOCOMPLETE_BY_TYPE[type] : void 0),
@@ -111,6 +114,7 @@ const Input = ({
111
114
  max,
112
115
  step,
113
116
  "aria-invalid": status === "critical" ? "true" : void 0,
117
+ role: role ?? (isSearch ? "searchbox" : void 0),
114
118
  oninput: onInput || onValueChange ? (e) => {
115
119
  onInput?.(e);
116
120
  onValueChange?.(e, attrsOf(e));
@@ -1,6 +1,6 @@
1
1
  import { Fragment, jsx, jsxs } from "@antadesign/anta/jsx-runtime";
2
- import { useState, useMemo, useId } from "../jsx-runtime";
3
- import { nativeStateChange, optionPresentationAttrs } from "../anta_helpers";
2
+ import { useState, useMemo } from "../jsx-runtime";
3
+ import { optionPresentationAttrs } from "../anta_helpers";
4
4
  import { normalizeOpt, matchQueryRegex, matchesQuery, highlight } from "./select-options";
5
5
  import { Input } from "./Input";
6
6
  import { Menu } from "./Menu";
@@ -15,12 +15,10 @@ const InputAutocomplete = (props) => {
15
15
  filter = true,
16
16
  ...rest
17
17
  } = props;
18
- const rid = useId();
19
18
  const controlled = value !== void 0;
20
19
  const [internal, setInternal] = useState(defaultValue ?? "");
21
20
  const text = controlled ? value : internal;
22
21
  const [open, setOpen] = useState(false);
23
- const [activeId, setActiveId] = useState(null);
24
22
  const options = useMemo(() => suggestions.map(normalizeOpt), [suggestions]);
25
23
  const custom = typeof filter === "function";
26
24
  const queryRe = filter !== false && !custom ? matchQueryRegex(text) : null;
@@ -44,10 +42,8 @@ const InputAutocomplete = (props) => {
44
42
  "data-menu-search": "",
45
43
  role: "combobox",
46
44
  "aria-haspopup": "listbox",
47
- "aria-controls": `${rid}-list`,
48
45
  "aria-expanded": menuOpen ? "true" : "false",
49
46
  "aria-autocomplete": "list",
50
- "aria-activedescendant": menuOpen && activeId ? activeId : void 0,
51
47
  onFocus: () => setOpen(true),
52
48
  onInput: (e) => {
53
49
  setText(e.currentTarget.value);
@@ -61,23 +57,18 @@ const InputAutocomplete = (props) => {
61
57
  /* @__PURE__ */ jsx(
62
58
  Menu,
63
59
  {
64
- id: `${rid}-list`,
65
60
  role: "listbox",
66
61
  open: menuOpen,
67
62
  onStateChange: (_e, { next }) => {
68
63
  setOpen(next);
69
- if (!next) setActiveId(null);
70
64
  },
71
- onactivedescendant: (e) => setActiveId(nativeStateChange(e).detail?.id ?? null),
72
65
  children: visible.map((opt, i) => {
73
66
  const { className: optionClassName, style: optionStyle, ...optionAttrs } = optionPresentationAttrs(opt, true);
74
67
  return /* @__PURE__ */ jsx(
75
68
  MenuItem,
76
69
  {
77
70
  ...optionAttrs,
78
- id: `${rid}-o${i}`,
79
71
  role: "option",
80
- "aria-selected": activeId === `${rid}-o${i}` ? "true" : "false",
81
72
  icon: opt.icon,
82
73
  label: highlight(opt.label ?? opt.value, queryRe),
83
74
  hint: opt.hint ? highlight(opt.hint, queryRe) : opt.hint,
@@ -89,7 +80,7 @@ const InputAutocomplete = (props) => {
89
80
  className: optionClassName,
90
81
  style: optionStyle
91
82
  },
92
- `${rid}-${opt.value}-${i}`
83
+ `${opt.value}-${i}`
93
84
  );
94
85
  })
95
86
  }
@@ -1 +1 @@
1
- @layer anta.components{a-input-date-time-container{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-top:6px;padding-top:8px;border-top:1px solid var(--border-3)}}
1
+ @layer base,anta,components,utilities;@layer anta.reset,anta.components,anta.theme;@layer anta.components{a-input-date-time-container{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-top:6px;padding-top:8px;border-top:1px solid var(--border-3)}}
@@ -156,6 +156,8 @@ const InputDate = ({
156
156
  /* @__PURE__ */ jsx(
157
157
  Menu,
158
158
  {
159
+ role: "dialog",
160
+ "aria-label": time ? "Choose date and time" : "Choose date",
159
161
  open,
160
162
  placement: placement ?? "bottom-start",
161
163
  offset,
@@ -61,10 +61,10 @@ export interface MenuProps extends BaseProps {
61
61
  }) => void;
62
62
  /** Combobox-mode cursor report (raw element event). Fires when the active
63
63
  * option changes as arrow keys move the cursor while focus stays in a
64
- * `[data-menu-search]` filter field; `detail.id` is the active option's `id`
65
- * (`null` when none). The reactive layer that renders the field reflects this
66
- * onto its `aria-activedescendant` — the element can't write that light-DOM
67
- * attribute itself. Passed straight through to the element. */
64
+ * `[data-menu-search]` filter field; `detail.id` is an authored option `id`,
65
+ * or `null`. Built-in Anta Inputs receive the active option through a direct
66
+ * ARIA element relationship; this remains available to custom fields and
67
+ * observers. Passed straight through to the element. */
68
68
  onactivedescendant?: (e: CustomEvent<{
69
69
  id: string | null;
70
70
  }>) => void;
@@ -39,7 +39,7 @@ const Menu = ({
39
39
  round: roundAttr(round),
40
40
  "stop-propagation": stopPropagation === void 0 || stopPropagation === false ? void 0 : stopPropagation === true ? "" : Array.isArray(stopPropagation) ? stopPropagation.join(" ") : stopPropagation,
41
41
  role,
42
- "aria-orientation": "vertical",
42
+ "aria-orientation": role === "menu" || role === "listbox" ? "vertical" : void 0,
43
43
  class: className,
44
44
  style: lengthStyle(inset, "--menu-padding", roundStyle(round, "--menu-round", style)),
45
45
  ...rest,
@@ -0,0 +1,17 @@
1
+ import type { BaseProps, DOMEventHandlers } from '../general_types';
2
+ export interface PanelProps extends BaseProps, DOMEventHandlers {
3
+ /** Fill the browser viewport and contain keyboard focus within the panel.
4
+ * When supplied, the application owns the state. */
5
+ maximized?: boolean;
6
+ /** Initial viewport maximization for an uncontrolled panel, read once on connect. */
7
+ defaultMaximized?: boolean;
8
+ /** Requested maximization change. Update `maximized` to accept a controlled
9
+ * request, or prevent the event to veto an uncontrolled request. */
10
+ onStateChange?: (event: CustomEvent, detail: {
11
+ next: boolean;
12
+ prev: boolean;
13
+ }) => void;
14
+ }
15
+ /** A scroll container that fills its parent and can maximize to the viewport.
16
+ * Percentage height requires a parent with a defined height. */
17
+ export declare const Panel: ({ maximized, defaultMaximized, onStateChange, className, children, ...rest }: PanelProps) => any;
@@ -0,0 +1,22 @@
1
+ import { jsx } from "@antadesign/anta/jsx-runtime";
2
+ import { nativeStateChange } from "../anta_helpers";
3
+ const Panel = ({ maximized, defaultMaximized, onStateChange, className, children, ...rest }) => /* @__PURE__ */ jsx(
4
+ "a-panel",
5
+ {
6
+ state: maximized === void 0 ? void 0 : maximized ? "maximized" : "normal",
7
+ "default-state": maximized === void 0 && defaultMaximized ? "maximized" : void 0,
8
+ onstatechange: onStateChange ? (event) => {
9
+ const { event: native, detail, isOwn } = nativeStateChange(event);
10
+ if (isOwn && detail) onStateChange(native, {
11
+ next: detail.next === "maximized",
12
+ prev: detail.prev === "maximized"
13
+ });
14
+ } : void 0,
15
+ class: className,
16
+ ...rest,
17
+ children
18
+ }
19
+ );
20
+ export {
21
+ Panel
22
+ };
@@ -21,7 +21,8 @@ export interface RadioOption extends OptionPresentationProps {
21
21
  value: string;
22
22
  /** The visible label. */
23
23
  label?: React.ReactNode;
24
- /** Secondary text under the label — explanatory copy, like `Input`'s hint. */
24
+ /** Secondary text under the label and exposed as this radio option's
25
+ * accessible description. */
25
26
  hint?: React.ReactNode;
26
27
  /** Disable just this option (skipped by keyboard, dropped from the tab order). */
27
28
  disabled?: boolean;
@@ -163,25 +163,25 @@ export interface SelectCommonProps<V extends OptionValue = string> extends Omit<
163
163
  indicator?: 'none' | 'check' | 'radio';
164
164
  /** Text shown when nothing is selected. */
165
165
  placeholder?: string;
166
- /** Leading icon shown at the left of the field (the default trigger's `Input`
167
- * `leading` slot). With a custom `renderTrigger`, it's passed through as
166
+ /** Leading icon shown at the left of the field. With a custom
167
+ * `renderTrigger`, it's passed through as
168
168
  * `state.icon` instead — the consumer places it. */
169
169
  icon?: IconShape;
170
- /** Content for the default trigger's `leading` slot, such as a key prefix
170
+ /** Content before the default trigger's value, such as a key prefix
171
171
  * before the value. It replaces the icon derived from `icon`. Include an
172
172
  * `<Icon>` in this content when both are needed. Ignored by `renderTrigger`. */
173
173
  leading?: React.ReactNode;
174
- /** Field label, above the trigger (Input's `label`). */
174
+ /** Field label, above the trigger. */
175
175
  label?: string;
176
- /** Helper text under the field (Input's `hint`). */
176
+ /** Helper text under the field. */
177
177
  hint?: string;
178
178
  /** Field size.
179
179
  * @defaultValue medium */
180
180
  size?: 'small' | 'medium' | 'large';
181
- /** Validation/feedback tone for the field (Input's `status`).
181
+ /** Validation/feedback tone for the field.
182
182
  * @defaultValue neutral */
183
183
  status?: 'neutral' | 'brand' | 'info' | 'success' | 'warning' | 'critical';
184
- /** Glyph shown before the `hint` when `status` is set (Input's `statusIcon`).
184
+ /** Glyph shown before the `hint` when `status` is set.
185
185
  * Each status has a default; pass a shape to override, or `false` to drop it. */
186
186
  statusIcon?: IconShape | (string & {}) | false;
187
187
  /** Round the field corners — `true` for fully round, or a number / CSS length. */
@@ -234,7 +234,7 @@ export interface SelectCommonProps<V extends OptionValue = string> extends Omit<
234
234
  * A, B, C` (labels comma-joined) in place of the bare `3 selected`. Applies
235
235
  * to the multi-count case only: `All` stays `All`, a single pick stays its
236
236
  * own label, and an empty selection stays the `placeholder`. The list flows
237
- * into the read-only field, so it ellipsizes at the field's width when long
237
+ * into the Button label, so it ellipsizes at the field's width when long
238
238
  * (`3 selected: Engineering, Des… `). `renderSummary` overrides this. */
239
239
  verbose?: boolean;
240
240
  /** `multiple` only: build the trigger's selection summary text yourself,
@@ -242,7 +242,7 @@ export interface SelectCommonProps<V extends OptionValue = string> extends Omit<
242
242
  * the resolved selected options (`selected.length` is the count) and runs only
243
243
  * while something is selected — an empty selection still shows the
244
244
  * `placeholder`. Return a **string**: it flows into the default trigger's
245
- * read-only field, so a long summary ellipsizes at the field's width just
245
+ * Button label, so a long summary ellipsizes at the field's width just
246
246
  * like a long value (`Engineering, Design, … `). Return `undefined` to fall
247
247
  * back to the default for that case (e.g. customize only the count, keeping
248
248
  * the single-label case built-in). For rich content (chips, multiple nodes)
@@ -253,9 +253,9 @@ export interface SelectCommonProps<V extends OptionValue = string> extends Omit<
253
253
  * one focusable element, such as an Anta `Button`. The menu is positioned
254
254
  * relative to that element and opens when it is clicked. Do not return a
255
255
  * fragment, multiple siblings, or a non-focusable wrapper. Add
256
- * `aria-haspopup="menu"` and `aria-expanded={state.open}` to the element, on a
257
- * role that supports them (an Anta `Button` already carries `role="button"`;
258
- * otherwise add `role="combobox"`).
256
+ * `aria-haspopup={filter ? 'dialog' : 'menu'}` and
257
+ * `aria-expanded={state.open}` to the returned button. An Anta `Button`
258
+ * already carries the correct role.
259
259
  * Field props (`label`, `hint`, `size`, `status`, `placeholder`, and `round`) and
260
260
  * `className` / `style` apply only to the default field. Add styling and
261
261
  * attributes to the returned element instead. */
@@ -352,8 +352,8 @@ export type SelectedItem<V extends OptionValue = string> = SelectedOption<V> | S
352
352
  */
353
353
  export declare function optionsWithSelection<V extends OptionValue = string>(options: SelectItem<V>[], values: V | V[] | undefined): SelectedItem<V>[];
354
354
  /**
355
- * `<Select>` lets people choose one or more options from a dropdown. It uses an
356
- * `<Input>` as its read-only trigger and a `<Menu>` for its options. `selection` sets behavior:
355
+ * `<Select>` lets people choose one or more options from a dropdown. It uses a
356
+ * `<Button>` as its trigger and a `<Menu>` for its options. `selection` sets behavior:
357
357
  * `'single'` (default; `value` is a string, menu closes on pick) or `'multiple'`
358
358
  * (checkboxes, `value` is a string array, menu stays open while toggling, the
359
359
  * field shows an "N selected" count). For single-select, `indicator` picks the
@@ -1,8 +1,9 @@
1
1
  import { Fragment, jsx, jsxs } from "@antadesign/anta/jsx-runtime";
2
- import { useState, useId } from "../jsx-runtime";
3
- import { ISOLATE_HINT, optionPresentationAttrs } from "../anta_helpers";
2
+ import { useState } from "../jsx-runtime";
3
+ import { ISOLATE_HINT, ISOLATE_HINT_DELAY, optionPresentationAttrs } from "../anta_helpers";
4
4
  import { normalizeOpt, matchQueryRegex, matchesQuery, highlight } from "./select-options";
5
5
  import { Input } from "./Input";
6
+ import { Button } from "./Button";
6
7
  import { Icon } from "./Icon";
7
8
  import { Menu } from "./Menu";
8
9
  import { MenuItem } from "./MenuItem";
@@ -81,8 +82,7 @@ const Select = (props) => {
81
82
  const currentRaw = controlled ? value : internal;
82
83
  const [open, setOpen] = useState(false);
83
84
  const [query, setQuery] = useState("");
84
- const [activeId, setActiveId] = useState(null);
85
- const uid = useId();
85
+ const popupLabel = `${label ?? rest["aria-label"] ?? "Select"} options`;
86
86
  const isSubmenu = (it) => typeof it === "object" && Array.isArray(it.submenu);
87
87
  const isGroup = (it) => typeof it === "object" && Array.isArray(it.options);
88
88
  const collectLeaves = (items, group, disabled2, out) => {
@@ -177,7 +177,6 @@ const Select = (props) => {
177
177
  MenuItem,
178
178
  {
179
179
  ...optionAttrs,
180
- id: `${uid}-opt-${o.value}`,
181
180
  selectionIndicator: menuItemIndicator,
182
181
  ...ariaSelectable,
183
182
  indicator: customMark ?? void 0,
@@ -194,7 +193,7 @@ const Select = (props) => {
194
193
  style: optionStyle,
195
194
  children: [
196
195
  custom,
197
- tip && /* @__PURE__ */ jsx(Tooltip, { follow: true, ...hintOnly ? { delay: 700 } : {}, children: tip })
196
+ tip && /* @__PURE__ */ jsx(Tooltip, { ...hintOnly ? { delay: ISOLATE_HINT_DELAY, placement: "left" } : { follow: true }, children: tip })
198
197
  ]
199
198
  },
200
199
  String(o.value)
@@ -255,48 +254,36 @@ const Select = (props) => {
255
254
  }
256
255
  return out;
257
256
  };
258
- return /* @__PURE__ */ jsxs(Fragment, { children: [
259
- renderTrigger ? renderTrigger({ open, value: currentRaw, selected: selectedOptions, disabled: !!disabled, icon }) : /* @__PURE__ */ jsx(
260
- Input,
257
+ const content = /* @__PURE__ */ jsxs(Fragment, { children: [
258
+ renderTrigger ? renderTrigger({ open, value: currentRaw, selected: selectedOptions, disabled: !!disabled, icon }) : /* @__PURE__ */ jsxs(
259
+ Button,
261
260
  {
262
- label,
263
- hint,
264
- placeholder,
265
- value: display,
266
- readOnly: true,
267
- dimActions: true,
268
261
  disabled,
269
- leading: leading ?? (icon ? /* @__PURE__ */ jsx(Icon, { shape: icon }) : void 0),
270
262
  size,
271
- status,
272
- statusIcon,
273
263
  round,
274
- role: "combobox",
275
- "aria-haspopup": "menu",
264
+ "aria-label": typeof label === "string" || typeof label === "number" ? String(label) : void 0,
265
+ "aria-invalid": status === "critical" ? "true" : void 0,
266
+ "aria-haspopup": filtering ? "dialog" : "menu",
276
267
  "aria-expanded": open ? "true" : "false",
277
- trailing: (
278
- // The named tag applies the Select-specific rotation while the icon remains
279
- // a normal currentColor glyph.
280
- /* @__PURE__ */ jsx("a-select-chevron", { open: open ? "" : void 0, style: statusColor ? { color: statusColor } : void 0, children: /* @__PURE__ */ jsx(Icon, { shape: "chevron-down" }) })
281
- ),
282
- className,
283
- style,
284
- ...rest
268
+ ...rest,
269
+ children: [
270
+ (leading ?? icon) && /* @__PURE__ */ jsx("a-select-leading", { "aria-hidden": "true", children: leading ?? /* @__PURE__ */ jsx(Icon, { shape: icon }) }),
271
+ /* @__PURE__ */ jsx("a-button-label", { "data-placeholder": !display ? "" : void 0, children: display || placeholder }),
272
+ /* @__PURE__ */ jsx("a-select-chevron", { open: open ? "" : void 0, "aria-hidden": "true", style: statusColor ? { color: statusColor } : void 0, children: /* @__PURE__ */ jsx(Icon, { shape: "chevron-down" }) })
273
+ ]
285
274
  }
286
275
  ),
287
276
  /* @__PURE__ */ jsxs(
288
277
  Menu,
289
278
  {
279
+ role: filtering ? "dialog" : void 0,
280
+ "aria-label": filtering ? popupLabel : void 0,
290
281
  placement,
291
282
  offset,
292
283
  onStateChange: (_e, { next }) => {
293
284
  setOpen(next);
294
- if (!next) {
295
- setQuery("");
296
- setActiveId(null);
297
- }
285
+ if (!next) setQuery("");
298
286
  },
299
- onactivedescendant: (e) => setActiveId((e.nativeEvent ?? e).detail?.id ?? null),
300
287
  children: [
301
288
  filtering && // `slot="header"` pins the field in the Menu's fixed header region (above
302
289
  // the scrolling options); `data-menu-search` puts the menu in combobox
@@ -310,7 +297,6 @@ const Select = (props) => {
310
297
  placeholder: "Filter\u2026",
311
298
  "aria-label": "Filter options",
312
299
  "aria-autocomplete": "list",
313
- "aria-activedescendant": open && activeId ? activeId : void 0,
314
300
  onInput: (e) => setQuery(e.currentTarget.value)
315
301
  }
316
302
  ) }),
@@ -333,12 +319,38 @@ const Select = (props) => {
333
319
  clearable && selectedValues.length > 0 && // Pinned in the footer so it never scrolls away in a long / filtered list.
334
320
  /* @__PURE__ */ jsxs(Fragment, { children: [
335
321
  /* @__PURE__ */ jsx(MenuSeparator, { slot: "footer" }),
336
- /* @__PURE__ */ jsx("a-select-footer", { slot: "footer", children: /* @__PURE__ */ jsx(MenuItem, { icon: "x", label: clearLabel, "data-menu-open": "", onSelect: clear }) })
322
+ /* @__PURE__ */ jsx("a-select-footer", { slot: "footer", children: /* @__PURE__ */ jsx(
323
+ MenuItem,
324
+ {
325
+ icon: "x",
326
+ label: clearLabel,
327
+ role: filtering ? "button" : void 0,
328
+ "data-menu-open": "",
329
+ onSelect: clear
330
+ }
331
+ ) })
337
332
  ] })
338
333
  ]
339
334
  }
340
335
  )
341
336
  ] });
337
+ if (renderTrigger) return content;
338
+ const statusGlyph = {
339
+ brand: "circle-small-solid",
340
+ info: "info",
341
+ success: "circle-check",
342
+ warning: "warning-triangle",
343
+ critical: "warning-diamond"
344
+ };
345
+ const glyph = statusIcon === void 0 ? status ? statusGlyph[status] : void 0 : statusIcon;
346
+ return /* @__PURE__ */ jsxs("a-select-field", { size, status, disabled: disabled ? "" : void 0, class: className, style, children: [
347
+ label != null && /* @__PURE__ */ jsx("a-select-label", { children: label }),
348
+ content,
349
+ hint != null && /* @__PURE__ */ jsxs("a-select-hint", { children: [
350
+ glyph && /* @__PURE__ */ jsx(Icon, { shape: glyph, "aria-hidden": "true" }),
351
+ hint
352
+ ] })
353
+ ] });
342
354
  };
343
355
  export {
344
356
  Select,