@antadesign/anta 0.3.10 → 0.3.12

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 (37) hide show
  1. package/dist/components/Button.d.ts +4 -46
  2. package/dist/components/Button.js +7 -25
  3. package/dist/components/ButtonCopy.d.ts +45 -21
  4. package/dist/components/ButtonCopy.js +46 -4
  5. package/dist/components/Expander.js +1 -1
  6. package/dist/components/MenuItem.d.ts +2 -8
  7. package/dist/components/MenuItem.js +2 -14
  8. package/dist/components/MenuItemCopy.d.ts +23 -19
  9. package/dist/components/MenuItemCopy.js +38 -3
  10. package/dist/components/Select.d.ts +8 -0
  11. package/dist/components/Select.js +4 -0
  12. package/dist/components/SelectFaceted.d.ts +8 -0
  13. package/dist/components/SelectFaceted.js +4 -0
  14. package/dist/components/copy-props.d.ts +72 -0
  15. package/dist/components/copy-props.js +20 -0
  16. package/dist/elements/a-button.css +1 -1
  17. package/dist/elements/a-button.d.ts +0 -4
  18. package/dist/elements/a-button.js +7 -20
  19. package/dist/elements/a-copy.css +1 -0
  20. package/dist/elements/a-copy.d.ts +16 -0
  21. package/dist/elements/a-copy.js +148 -0
  22. package/dist/elements/a-expander.css +1 -1
  23. package/dist/elements/a-expander.js +20 -19
  24. package/dist/elements/a-menu-item.d.ts +8 -1
  25. package/dist/elements/a-menu-item.js +7 -11
  26. package/dist/elements/a-menu.d.ts +6 -2
  27. package/dist/elements/a-menu.js +35 -5
  28. package/dist/elements/copy-behavior.d.ts +31 -13
  29. package/dist/elements/copy-behavior.js +20 -18
  30. package/dist/elements/index.d.ts +1 -0
  31. package/dist/elements/index.js +3 -0
  32. package/dist/elements/key-activation.d.ts +28 -0
  33. package/dist/elements/key-activation.js +32 -0
  34. package/dist/general_types.d.ts +27 -37
  35. package/dist/index.d.ts +2 -1
  36. package/dist/jsx-runtime.d.ts +2 -1
  37. package/package.json +1 -1
@@ -55,7 +55,8 @@ export type ContentMode = {
55
55
  iconTrailing?: IconShape;
56
56
  };
57
57
  /** Submit axis — anchors (href) don't carry form-submission props; buttons
58
- * don't carry anchor props. */
58
+ * don't carry anchor props. (Copy is no longer a Button concern — `ButtonCopy`
59
+ * composes a `<a-copy>` child; see `copy-props.ts`.) */
59
60
  export type SubmitMode = {
60
61
  /** Renders as `<a role="button">` instead of `<a-button>`. */
61
62
  href: string;
@@ -100,50 +101,7 @@ export type PriorityMode = {
100
101
  /** Drops outer padding to zero. */
101
102
  paddingless?: boolean;
102
103
  };
103
- /** Copy axis — turns the button into a copy control that writes to the clipboard
104
- * on click and flashes a success / failure state (see `<a-button>`'s copy
105
- * behavior). **Exactly one** of `copy`, `copyNode`, or `copyLazy` may be set;
106
- * the union makes the others `never` in each mode. For the batteries-included
107
- * preset, use `ButtonCopy`. */
108
- export type CopyMode = {
109
- copy?: never;
110
- copyNode?: never;
111
- copyLazy?: never;
112
- onCopied?: never;
113
- onCopyRequest?: never;
114
- } | {
115
- /** Text copied to the clipboard on click. */
116
- copy: string;
117
- copyNode?: never;
118
- copyLazy?: never;
119
- onCopyRequest?: never;
120
- /** Fires after the copy attempt with whether it succeeded. */
121
- onCopied?: (ok: boolean) => void;
122
- } | {
123
- /** Copy a DOM node as rich text instead of a string. `true` copies the
124
- * nearest ancestor marked `data-copy-source`; a string is a CSS selector
125
- * for an ancestor region (`closest`). The copy control is stripped from
126
- * the copied output. */
127
- copyNode: boolean | string;
128
- copy?: never;
129
- copyLazy?: never;
130
- onCopyRequest?: never;
131
- /** Fires after the copy attempt with whether it succeeded. */
132
- onCopied?: (ok: boolean) => void;
133
- } | {
134
- /** Lazy copy: the content isn't computed or held in the DOM until the
135
- * click. The click fires `onCopyRequest(provide)`; call `provide(text)`
136
- * with the value — synchronously, or after an `await` (the browser's
137
- * transient-activation window still covers the write). */
138
- copyLazy: true;
139
- copy?: never;
140
- copyNode?: never;
141
- /** Supplies the lazily-computed content on click: call `provide(text)`. */
142
- onCopyRequest: (provide: (text: string) => void) => void;
143
- /** Fires after the copy attempt with whether it succeeded. */
144
- onCopied?: (ok: boolean) => void;
145
- };
146
- export type ButtonProps = BaseButtonProps & PriorityMode & ContentMode & SubmitMode & CopyMode & BaseProps;
104
+ export type ButtonProps = BaseButtonProps & PriorityMode & ContentMode & SubmitMode & BaseProps;
147
105
  /**
148
106
  * Action button.
149
107
  *
@@ -164,4 +122,4 @@ export type ButtonProps = BaseButtonProps & PriorityMode & ContentMode & SubmitM
164
122
  * <Button href="/docs" target="_blank" label="Read the docs" />
165
123
  * ```
166
124
  */
167
- export declare const Button: ({ priority, tone, underline, icon, iconTrailing, paddingless, label, size, loading, disabled, selected, round, href, type, form, copy, copyNode, copyLazy, onCopied, onCopyRequest, className, style, children, ...rest }: ButtonProps) => any;
125
+ export declare const Button: ({ priority, tone, underline, icon, iconTrailing, paddingless, label, size, loading, disabled, selected, round, href, type, form, className, style, children, ...rest }: ButtonProps) => any;
@@ -1,5 +1,5 @@
1
1
  import { Fragment, jsx, jsxs } from "@antadesign/anta/jsx-runtime";
2
- import { toneStyle, roundStyle, roundAttr, wrapLabel, nativeStateChange } from "../anta_helpers";
2
+ import { toneStyle, roundStyle, roundAttr, wrapLabel } from "../anta_helpers";
3
3
  const Button = ({
4
4
  priority,
5
5
  tone,
@@ -16,21 +16,14 @@ const Button = ({
16
16
  href,
17
17
  type,
18
18
  form,
19
- copy,
20
- copyNode,
21
- copyLazy,
22
- onCopied,
23
- onCopyRequest,
24
19
  className,
25
20
  style,
26
21
  children,
27
22
  ...rest
28
23
  }) => {
29
- const isCopy = copy != null || copyNode != null || copyLazy === true;
30
24
  const toneAttr = tone || void 0;
31
25
  const computedStyle = roundStyle(round, "--button-round", toneStyle(toneAttr, "--button-tone-source", style));
32
- const leadingIcon = icon ?? (isCopy ? "copy" : void 0);
33
- const isIconOnly = leadingIcon != null && label == null && children == null && iconTrailing == null;
26
+ const isIconOnly = icon != null && label == null && children == null && iconTrailing == null;
34
27
  const sharedAttrs = {
35
28
  // `<a-button>` is a custom element with no implicit ARIA role, so AT would
36
29
  // announce it as a generic clickable — and `aria-pressed` below is only
@@ -60,26 +53,15 @@ const Button = ({
60
53
  "aria-disabled": disabled || loading ? "true" : void 0,
61
54
  "aria-busy": loading ? "true" : void 0,
62
55
  "aria-pressed": selected ? "true" : void 0,
63
- // Icon-only buttons get an accessible name: "Copy" for a copy control (its
64
- // glyph carries no text), else the icon shape. Consumer's own `aria-label`
65
- // (via ...rest) wins by spread order.
66
- "aria-label": isIconOnly ? isCopy ? "Copy" : icon : void 0,
67
- // Copy behavior — the element reads these and performs the write itself.
68
- copy: copy != null ? copy : void 0,
69
- "copy-node": copyNode === true ? "" : typeof copyNode === "string" ? copyNode : void 0,
70
- "copy-lazy": copyLazy ? "" : void 0,
71
- // Marks the control so `copy-node` serialization strips it from the copied
72
- // node (a copy button inside the copied region shouldn't paste itself).
73
- "data-copy-node-button": copyNode != null && copyNode !== false ? "" : void 0,
74
- oncopydone: onCopied ? (e) => onCopied(nativeStateChange(e).detail?.ok ?? false) : void 0,
75
- // The element hands `provide` on the request event; forward it so the
76
- // consumer supplies the lazily-computed content.
77
- oncopyrequest: onCopyRequest ? (e) => onCopyRequest(nativeStateChange(e).detail.provide) : void 0,
56
+ // Icon-only buttons get an accessible name from the icon shape. Consumer's
57
+ // own `aria-label` (via ...rest) wins by spread order — that's the channel
58
+ // ButtonCopy uses to name an icon-only copy button "Copy".
59
+ "aria-label": isIconOnly ? icon : void 0,
78
60
  class: className,
79
61
  style: computedStyle
80
62
  };
81
63
  const inner = /* @__PURE__ */ jsxs(Fragment, { children: [
82
- leadingIcon && /* @__PURE__ */ jsx("a-icon", { shape: leadingIcon, "aria-hidden": "true" }),
64
+ icon && /* @__PURE__ */ jsx("a-icon", { shape: icon, "aria-hidden": "true" }),
83
65
  label != null && /* @__PURE__ */ jsx("a-button-label", { children: label }),
84
66
  wrapLabel(children, "a-button-label"),
85
67
  iconTrailing && /* @__PURE__ */ jsx("a-icon", { shape: iconTrailing, "aria-hidden": "true" })
@@ -1,32 +1,56 @@
1
1
  import { type ButtonProps } from './Button';
2
- /** `ButtonProps` narrowed so a copy target is required — a copy button must copy
3
- * something. Intersecting with the target union drops the "no copy prop" member
4
- * of `CopyMode` (its `copy?: never` makes each combination `never`). */
5
- export type ButtonCopyProps = ButtonProps & ({
6
- copy: string;
7
- } | {
8
- copyNode: boolean | string;
9
- } | {
10
- copyLazy: true;
11
- });
2
+ import { type CopyTarget } from './copy-props';
3
+ /** A copy button is a plain action control, so `ButtonCopy` keeps the `Button`
4
+ * axes that fit — tone / size / priority styling, `disabled` / `loading`, a
5
+ * leading `icon` + `label` — and pins the ones that don't to `never`: `selected`
6
+ * (it isn't a toggle), the whole submit/link axis (`href` / `target` / `rel` /
7
+ * `download` / `ping` / `type` / `form` — a copy button neither navigates nor
8
+ * submits), and the public `iconTrailing` (the glyph's side is `iconPlacement`'s
9
+ * job). Plus a required copy target and the placement knob. (Pinning to `never`
10
+ * keeps the intersection expanding fully in the docs props table, which `Omit`
11
+ * wouldn't.) */
12
+ export type ButtonCopyProps = ButtonProps & {
13
+ selected?: never;
14
+ href?: never;
15
+ target?: never;
16
+ rel?: never;
17
+ download?: never;
18
+ ping?: never;
19
+ type?: never;
20
+ form?: never;
21
+ iconTrailing?: never;
22
+ } & CopyTarget & {
23
+ /** Where the copy glyph sits relative to the label — or `'none'` to omit it,
24
+ * in which case the feedback is a ghost of the label floating up (`toast`)
25
+ * plus a brief success / failure tone flash.
26
+ * @defaultValue 'leading' */
27
+ iconPlacement?: 'leading' | 'trailing' | 'none';
28
+ };
12
29
  /**
13
30
  * Copy button — a `Button` preset for copy-to-clipboard. Set `copy` for a literal
14
- * string, `copyNode` to copy a DOM region, or `copyLazy` + `onCopyRequest` to
15
- * compute the content on click. The `<a-button>` element performs the write and
16
- * reports the result; this wrapper flips the leading icon to a check (success) or
17
- * ✕ (failure) and retones to `success` / `critical` for ~2s — a JSX re-render, no
18
- * element state (see `useCopyFeedback`).
31
+ * string, `copyNode` to copy a DOM region, or `copyUrl` to copy the current page
32
+ * URL. For content computed on demand, keep `copy` reactive and refresh it in
33
+ * `onCopyRequest` (fired on pointerdown / keydown).
19
34
  *
20
- * With a `label` it's a labeled button; without one it's an icon-only copy button.
21
- * Everything else is a normal `Button` prop — `tone`, `priority`, `size`, `icon`
22
- * (the resting glyph), `onCopied`.
35
+ * It composes a plain `<Button>` with a slotted `<a-copy>` child that performs
36
+ * the write — the button itself carries no copy behavior. This wrapper flips the
37
+ * copy glyph to a check (success) or ✕ (failure) and retones to `success` /
38
+ * `critical` for ~2s (a re-render, no element state — see `useCopyFeedback`).
39
+ * `iconPlacement` puts that glyph leading (default), trailing, or `'none'`; with
40
+ * `'none'` the `<a-copy>` floats a ghost of the label upward instead.
41
+ *
42
+ * With a `label` it's a labeled button; without one it's an icon-only copy button
43
+ * (named "Copy" for assistive tech). Everything else is a normal `Button` prop —
44
+ * `tone`, `priority`, `size`, `icon` (the resting glyph), `onCopied`.
23
45
  *
24
46
  * @example
25
47
  * ```tsx
26
48
  * <ButtonCopy copy="npm i @antadesign/anta" label="Copy install" />
27
- * <ButtonCopy copy="https://anta.design" /> // icon-only
49
+ * <ButtonCopy copy="https://anta.design" /> // icon-only
50
+ * <ButtonCopy copy={code} label="Copy" iconPlacement="trailing" />
51
+ * <ButtonCopy copy={code} label="Copy snippet" iconPlacement="none" /> // ghost feedback
28
52
  * <ButtonCopy copyNode=".snippet" label="Copy block" priority="tertiary" />
29
- * <ButtonCopy copyLazy label="Copy report" onCopyRequest={(p) => p(buildReport())} />
53
+ * <ButtonCopy copyUrl label="Copy link" /> // copies location.href
30
54
  * ```
31
55
  */
32
- export declare const ButtonCopy: ({ icon, tone, onCopied, ...rest }: ButtonCopyProps) => any;
56
+ export declare const ButtonCopy: ({ icon, iconPlacement, tone, onCopied, onCopyRequest, copy, copyNode, copyUrl, copyWithUrl, label, children, "aria-label": ariaLabel, ...rest }: ButtonCopyProps) => any;
@@ -1,9 +1,51 @@
1
- import { jsx } from "@antadesign/anta/jsx-runtime";
1
+ import { jsx, jsxs } from "@antadesign/anta/jsx-runtime";
2
2
  import { Button } from "./Button";
3
3
  import { useCopyFeedback } from "../anta_helpers";
4
- const ButtonCopy = ({ icon, tone, onCopied, ...rest }) => {
5
- const { shownIcon, shownTone, handleCopied } = useCopyFeedback(icon, tone, onCopied);
6
- return /* @__PURE__ */ jsx(Button, { icon: shownIcon, tone: shownTone, onCopied: handleCopied, ...rest });
4
+ import { copyElementProps, isNodeCopy } from "./copy-props";
5
+ const ButtonCopy = ({
6
+ icon,
7
+ iconPlacement = "leading",
8
+ tone,
9
+ onCopied,
10
+ onCopyRequest,
11
+ copy,
12
+ copyNode,
13
+ copyUrl,
14
+ copyWithUrl,
15
+ label,
16
+ children,
17
+ "aria-label": ariaLabel,
18
+ ...rest
19
+ }) => {
20
+ const restingIcon = iconPlacement === "none" ? void 0 : icon ?? "copy";
21
+ const { shownIcon, shownTone, handleCopied } = useCopyFeedback(restingIcon, tone, onCopied);
22
+ const iconSlot = iconPlacement === "trailing" ? { iconTrailing: shownIcon } : iconPlacement === "none" ? {} : { icon: shownIcon };
23
+ const hasText = label != null || children != null;
24
+ const copyAttrs = copyElementProps({
25
+ copy,
26
+ copyNode,
27
+ copyUrl,
28
+ copyWithUrl,
29
+ onCopyRequest,
30
+ onCopied: handleCopied,
31
+ // Ghost feedback only makes sense when there's no glyph to swap.
32
+ toast: iconPlacement === "none"
33
+ });
34
+ return /* @__PURE__ */ jsxs(
35
+ Button,
36
+ {
37
+ ...iconSlot,
38
+ label,
39
+ tone: shownTone,
40
+ "aria-label": ariaLabel ?? (hasText ? void 0 : "Copy"),
41
+ "data-copy-node-button": isNodeCopy({ copyNode }) ? "" : void 0,
42
+ ...rest,
43
+ children: [
44
+ children,
45
+ /* @__PURE__ */ jsx("a-copy", { ...copyAttrs })
46
+ ]
47
+ }
48
+ );
7
49
  };
8
50
  export {
9
51
  ButtonCopy
@@ -44,7 +44,7 @@ const Expander = ({
44
44
  ...rest,
45
45
  children: [
46
46
  titleNode,
47
- actions != null && /* @__PURE__ */ jsx("span", { slot: "actions", style: { display: "contents" }, children: actions }),
47
+ actions != null && /* @__PURE__ */ jsx("span", { slot: "actions", children: actions }),
48
48
  /* @__PURE__ */ jsx("a-expander-details", { children })
49
49
  ]
50
50
  }
@@ -1,6 +1,5 @@
1
1
  import type { BaseProps } from '../general_types';
2
2
  import type { IconShape } from '../elements/a-icon.shapes';
3
- import type { CopyMode } from './Button';
4
3
  /** Props shared by every menu item, link or not. */
5
4
  export interface MenuItemCommonProps extends BaseProps {
6
5
  /** Leading icon shape. */
@@ -84,11 +83,6 @@ export type MenuItemLinkMode = {
84
83
  selectionIndicator?: never;
85
84
  indeterminate?: never;
86
85
  indicator?: never;
87
- copy?: never;
88
- copyNode?: never;
89
- copyLazy?: never;
90
- onCopied?: never;
91
- onCopyRequest?: never;
92
86
  };
93
87
  export type MenuItemActionMode = {
94
88
  href?: never;
@@ -120,7 +114,7 @@ export type MenuItemActionMode = {
120
114
  * passive (aria-hidden, no pointer events) so the row owns the click. */
121
115
  indicator?: React.ReactNode;
122
116
  };
123
- export type MenuItemProps = MenuItemCommonProps & (MenuItemLinkMode | (MenuItemActionMode & CopyMode));
117
+ export type MenuItemProps = MenuItemCommonProps & (MenuItemLinkMode | MenuItemActionMode);
124
118
  /**
125
119
  * MenuItem — a single selectable row inside a `Menu`. Composes a leading
126
120
  * `icon`, a `label` (or `children`), an optional trailing `kbd` hint, and an
@@ -141,4 +135,4 @@ export type MenuItemProps = MenuItemCommonProps & (MenuItemLinkMode | (MenuItemA
141
135
  * </MenuItem>
142
136
  * ```
143
137
  */
144
- export declare const MenuItem: ({ icon, label, hint, kbd, iconTrailing, disabled, selected, selectionIndicator, indeterminate, indicator, tone, toneSelected, submenu, value, onSelect, href, target, rel, download, ping, copy, copyNode, copyLazy, onCopied, onCopyRequest, role: roleOverride, className, style, children, ...rest }: MenuItemProps) => any;
138
+ export declare const MenuItem: ({ icon, label, hint, kbd, iconTrailing, disabled, selected, selectionIndicator, indeterminate, indicator, tone, toneSelected, submenu, value, onSelect, href, target, rel, download, ping, role: roleOverride, className, style, children, ...rest }: MenuItemProps) => any;
@@ -1,5 +1,5 @@
1
1
  import { jsx, jsxs } from "@antadesign/anta/jsx-runtime";
2
- import { toneStyle, nativeStateChange } from "../anta_helpers";
2
+ import { toneStyle } from "../anta_helpers";
3
3
  const MenuItem = ({
4
4
  icon,
5
5
  label,
@@ -21,19 +21,13 @@ const MenuItem = ({
21
21
  rel,
22
22
  download,
23
23
  ping,
24
- copy,
25
- copyNode,
26
- copyLazy,
27
- onCopied,
28
- onCopyRequest,
29
24
  role: roleOverride,
30
25
  className,
31
26
  style,
32
27
  children,
33
28
  ...rest
34
29
  }) => {
35
- const isCopy = copy != null || copyNode != null || copyLazy === true;
36
- const leadingIcon = icon ?? (isCopy ? "copy" : void 0);
30
+ const leadingIcon = icon;
37
31
  const checkable = selectionIndicator === "checkbox" || selectionIndicator === "radio" || selectionIndicator === "check";
38
32
  const role = selectionIndicator === "checkbox" ? "menuitemcheckbox" : selectionIndicator === "radio" || selectionIndicator === "check" ? "menuitemradio" : "menuitem";
39
33
  const ariaChecked = !checkable ? void 0 : selectionIndicator === "checkbox" && indeterminate ? "mixed" : selected ? "true" : "false";
@@ -83,12 +77,6 @@ const MenuItem = ({
83
77
  "aria-haspopup": submenu ? "menu" : void 0,
84
78
  "aria-disabled": disabled ? "true" : void 0,
85
79
  onmenuselect: onSelect ? (e) => onSelect(e, { value, label }) : void 0,
86
- copy: copy != null ? copy : void 0,
87
- "copy-node": copyNode === true ? "" : typeof copyNode === "string" ? copyNode : void 0,
88
- "copy-lazy": copyLazy ? "" : void 0,
89
- "data-copy-node-button": copyNode != null && copyNode !== false ? "" : void 0,
90
- oncopydone: onCopied ? (e) => onCopied(nativeStateChange(e).detail?.ok ?? false) : void 0,
91
- oncopyrequest: onCopyRequest ? (e) => onCopyRequest(nativeStateChange(e).detail.provide) : void 0,
92
80
  class: className,
93
81
  ...rest,
94
82
  children: [
@@ -1,33 +1,37 @@
1
1
  import { type MenuItemCommonProps, type MenuItemActionMode } from './MenuItem';
2
- import type { CopyMode } from './Button';
3
- /** The action-mode menu-item props plus a required copy target (a copying row
4
- * must copy something). The target intersection drops `CopyMode`'s "no copy
5
- * prop" member. */
6
- export type MenuItemCopyProps = MenuItemCommonProps & MenuItemActionMode & CopyMode & ({
7
- copy: string;
8
- } | {
9
- copyNode: boolean | string;
10
- } | {
11
- copyLazy: true;
12
- });
2
+ import { type CopyTarget } from './copy-props';
3
+ /** Action-mode menu-item props plus a required copy target (a copying row must
4
+ * copy something). The action-mode props that don't fit a copy row are pinned to
5
+ * `never`: `submenu` (a copy row has no flyout) and the selection-indicator axis
6
+ * (`selectionIndicator` / `indeterminate` / `indicator` — a copy row isn't a
7
+ * checkable option). Pinning (not `Omit`) keeps the intersection expanding fully
8
+ * in the docs props table. */
9
+ export type MenuItemCopyProps = MenuItemCommonProps & MenuItemActionMode & {
10
+ submenu?: never;
11
+ selectionIndicator?: never;
12
+ indeterminate?: never;
13
+ indicator?: never;
14
+ } & CopyTarget;
13
15
  /**
14
16
  * Copying menu item — a `MenuItem` preset for copy-to-clipboard rows inside a
15
17
  * `Menu`. Set `copy` for a literal string, `copyNode` to copy a DOM region, or
16
- * `copyLazy` + `onCopyRequest` to compute the content on select. The
17
- * `<a-menu-item>` element performs the write when the row is chosen; this wrapper
18
+ * `copyUrl` to copy the current page URL. For content computed on demand, keep
19
+ * `copy` reactive and refresh it in `onCopyRequest` (fired on pointerdown / keydown).
20
+ *
21
+ * It composes a plain `<MenuItem>` with a slotted `<a-copy>` child that performs
22
+ * the write when the row is chosen — the item itself carries no copy behavior.
23
+ * The row is kept open (`data-menu-open`) so the feedback shows: this wrapper
18
24
  * flips the leading icon to a check / ✕ and retones for ~2s (see `useCopyFeedback`).
19
25
  *
20
- * The menu closes on select by default, so the feedback shows only when the row
21
- * is kept open (`data-menu-open`). Defaults `label` to "Copy" and the leading
22
- * `icon` to `copy`; override either. Other props pass through — `tone`, `kbd`,
23
- * `onCopied`.
26
+ * Defaults `label` to "Copy" and the leading `icon` to `copy`; override either.
27
+ * Other props pass through — `tone`, `kbd`, `onCopied`.
24
28
  *
25
29
  * @example
26
30
  * ```tsx
27
31
  * <Menu>
28
32
  * <MenuItemCopy copy={shareUrl} label="Copy link" kbd="⌘C" />
29
- * <MenuItemCopy copyNode=".invoice" label="Copy invoice" data-menu-open />
33
+ * <MenuItemCopy copyNode=".invoice" label="Copy invoice" />
30
34
  * </Menu>
31
35
  * ```
32
36
  */
33
- export declare const MenuItemCopy: ({ label, icon, tone, onCopied, ...rest }: MenuItemCopyProps) => any;
37
+ export declare const MenuItemCopy: ({ label, icon, tone, onCopied, onCopyRequest, copy, copyNode, copyUrl, copyWithUrl, children, ...rest }: MenuItemCopyProps) => any;
@@ -1,9 +1,44 @@
1
- import { jsx } from "@antadesign/anta/jsx-runtime";
1
+ import { jsx, jsxs } from "@antadesign/anta/jsx-runtime";
2
2
  import { MenuItem } from "./MenuItem";
3
3
  import { useCopyFeedback } from "../anta_helpers";
4
- const MenuItemCopy = ({ label = "Copy", icon = "copy", tone, onCopied, ...rest }) => {
4
+ import { copyElementProps, isNodeCopy } from "./copy-props";
5
+ const MenuItemCopy = ({
6
+ label = "Copy",
7
+ icon = "copy",
8
+ tone,
9
+ onCopied,
10
+ onCopyRequest,
11
+ copy,
12
+ copyNode,
13
+ copyUrl,
14
+ copyWithUrl,
15
+ children,
16
+ ...rest
17
+ }) => {
5
18
  const { shownIcon, shownTone, handleCopied } = useCopyFeedback(icon, tone, onCopied);
6
- return /* @__PURE__ */ jsx(MenuItem, { label, icon: shownIcon, tone: shownTone, onCopied: handleCopied, ...rest });
19
+ const copyAttrs = copyElementProps({
20
+ copy,
21
+ copyNode,
22
+ copyUrl,
23
+ copyWithUrl,
24
+ onCopyRequest,
25
+ onCopied: handleCopied
26
+ });
27
+ return /* @__PURE__ */ jsxs(
28
+ MenuItem,
29
+ {
30
+ label,
31
+ icon: shownIcon,
32
+ tone: shownTone,
33
+ "data-menu-open": "",
34
+ "data-copy-node-button": isNodeCopy({ copyNode }) ? "" : void 0,
35
+ ...rest,
36
+ children: [
37
+ children,
38
+ /* @__PURE__ */ jsx("a-copy", { ...copyAttrs })
39
+ ]
40
+ }
41
+ );
7
42
  };
8
43
  export {
9
44
  MenuItemCopy
@@ -1,5 +1,6 @@
1
1
  import type { BaseProps } from '../general_types';
2
2
  import type { IconShape } from '../elements/a-icon.shapes';
3
+ import { type MenuProps } from './Menu';
3
4
  /** One option in a `<Select>`. Pass a bare string as shorthand for
4
5
  * `{ value: s, label: s }`. Carries an index signature so you can attach
5
6
  * arbitrary fields (a `ranAt` date, a `status`, …) and read them back in
@@ -131,6 +132,13 @@ export interface SelectCommonProps extends Omit<BaseProps, 'children'> {
131
132
  * logical pick (both rows toggle together; the trigger resolves to the last). Dev
132
133
  * builds `console.warn` on a duplicate. */
133
134
  options: SelectItem[];
135
+ /** Preferred placement of the options menu relative to the trigger. The menu
136
+ * auto-flips vertically and clamps horizontally when needed.
137
+ * @defaultValue bottom-start */
138
+ placement?: MenuProps['placement'];
139
+ /** Gap in pixels between the trigger and the options menu.
140
+ * @defaultValue 4 */
141
+ offset?: number;
134
142
  /** The per-row mark for **single**-select: `'none'` (a tint-only highlight),
135
143
  * `'check'` (a trailing checkmark on the selected row, keeping the tint — the
136
144
  * canonical Select look), or `'radio'` (a leading radio on every row).
@@ -37,6 +37,8 @@ function optionsWithSelection(options, values) {
37
37
  const Select = (props) => {
38
38
  const {
39
39
  options,
40
+ placement,
41
+ offset,
40
42
  selection,
41
43
  indicator,
42
44
  value,
@@ -274,6 +276,8 @@ const Select = (props) => {
274
276
  /* @__PURE__ */ jsxs(
275
277
  Menu,
276
278
  {
279
+ placement,
280
+ offset,
277
281
  onStateChange: (_e, { next }) => {
278
282
  setOpen(next);
279
283
  if (!next) {
@@ -1,6 +1,7 @@
1
1
  import type { BaseProps } from '../general_types';
2
2
  import type { IconShape } from '../elements/a-icon.shapes';
3
3
  import type { SelectItem, SelectOption } from './Select';
4
+ import { type MenuProps } from './Menu';
4
5
  interface FacetBase {
5
6
  /** The facet's namespace — the key its value is stored under in the value
6
7
  * record, and what `onValueChange`'s `attrs.facet` reports. Unique across
@@ -108,6 +109,13 @@ export interface SelectFacetedTriggerState {
108
109
  export interface SelectFacetedProps extends Omit<BaseProps, 'children'> {
109
110
  /** The facets (dimensions) to filter across, each with its own editor kind. */
110
111
  facets: SelectFacet[];
112
+ /** Preferred placement of the root filter menu relative to its trigger. The
113
+ * menu auto-flips vertically and clamps horizontally when needed.
114
+ * @defaultValue bottom-start */
115
+ placement?: MenuProps['placement'];
116
+ /** Gap in pixels between the trigger and the filter menu.
117
+ * @defaultValue 4 */
118
+ offset?: number;
111
119
  /** Controlled value — the facet-keyed record. When provided, the consumer
112
120
  * owns state: a pick only *requests* a change via `onValueChange` (reject by
113
121
  * not updating). Leave undefined for uncontrolled. */
@@ -27,6 +27,8 @@ const defaultMatch = (o, query) => matchesQuery(o, matchQueryRegex(query));
27
27
  const SelectFaceted = (props) => {
28
28
  const {
29
29
  facets,
30
+ placement,
31
+ offset,
30
32
  value,
31
33
  defaultValue,
32
34
  onValueChange,
@@ -284,6 +286,8 @@ const SelectFaceted = (props) => {
284
286
  /* @__PURE__ */ jsxs(
285
287
  Menu,
286
288
  {
289
+ placement,
290
+ offset,
287
291
  open,
288
292
  onStateChange: (_e, { next }) => {
289
293
  setOpen(next);
@@ -0,0 +1,72 @@
1
+ /**
2
+ * The copy target for a copy preset (`ButtonCopy` / `MenuItemCopy`) — exactly
3
+ * one of a literal string, a DOM region, or the page URL. The write itself is
4
+ * performed by the slotted `<a-copy>` element; these props map to its attributes
5
+ * via `copyElementProps`. `copyWithUrl` / `onCopyRequest` are only meaningful for
6
+ * the string target, so the union pins them `never` elsewhere.
7
+ */
8
+ export type CopyTarget = {
9
+ /** Text copied to the clipboard on activation. */
10
+ copy: string;
11
+ /** Prefix the copied text with `// URL: <current page URL>`. */
12
+ copyWithUrl?: boolean;
13
+ /** Compute the copy content lazily. Fires on pointerdown / keydown; update
14
+ * `copy` (a state change) here and the activation copies the latest value.
15
+ * The gap lets the update land even off the UI thread — only the
16
+ * serializable `copy` string crosses. */
17
+ onCopyRequest?: () => void;
18
+ /** Fires after the copy attempt with whether it succeeded. */
19
+ onCopied?: (ok: boolean) => void;
20
+ copyNode?: never;
21
+ copyUrl?: never;
22
+ } | {
23
+ /** Copy a DOM node as rich text (`text/html`) + plain text. `true` copies
24
+ * the nearest ancestor marked `data-copy-source`; a string is a CSS
25
+ * selector for an ancestor region (`closest`). The copy control is stripped
26
+ * from the copied output. */
27
+ copyNode: boolean | string;
28
+ /** Fires after the copy attempt with whether it succeeded. */
29
+ onCopied?: (ok: boolean) => void;
30
+ copy?: never;
31
+ copyUrl?: never;
32
+ copyWithUrl?: never;
33
+ onCopyRequest?: never;
34
+ } | {
35
+ /** Copy the current page URL (`location.href`). */
36
+ copyUrl: true;
37
+ /** Fires after the copy attempt with whether it succeeded. */
38
+ onCopied?: (ok: boolean) => void;
39
+ copy?: never;
40
+ copyNode?: never;
41
+ copyWithUrl?: never;
42
+ onCopyRequest?: never;
43
+ };
44
+ /** Everything `copyElementProps` reads: the target plus the resolved `onCopied`
45
+ * (the preset passes its feedback-wrapped handler) and the `toast` opt-in. */
46
+ type CopyElementInput = {
47
+ copy?: string;
48
+ copyNode?: boolean | string;
49
+ copyUrl?: true;
50
+ copyWithUrl?: boolean;
51
+ onCopyRequest?: () => void;
52
+ onCopied?: (ok: boolean) => void;
53
+ toast?: boolean;
54
+ };
55
+ /** Project the copy-target props onto `<a-copy>` attributes + event handlers.
56
+ * Shared by `ButtonCopy` / `MenuItemCopy` so the mapping (and the cross-renderer
57
+ * `copydone` detail unwrap) lives in one place. */
58
+ export declare function copyElementProps(p: CopyElementInput): {
59
+ readonly copy: string | undefined;
60
+ readonly 'copy-node': string | undefined;
61
+ readonly 'copy-url': "" | undefined;
62
+ readonly 'copy-with-url': "" | undefined;
63
+ readonly toast: "" | undefined;
64
+ readonly oncopydone: ((e: any) => void) | undefined;
65
+ readonly oncopyrequest: (() => void) | undefined;
66
+ };
67
+ /** True when these props copy a DOM node — the host control must then be marked
68
+ * `data-copy-node-button` so the serializer strips it from the copied region. */
69
+ export declare function isNodeCopy(p: {
70
+ copyNode?: boolean | string;
71
+ }): boolean;
72
+ export {};
@@ -0,0 +1,20 @@
1
+ import { nativeStateChange } from "../anta_helpers";
2
+ function copyElementProps(p) {
3
+ const { copy, copyNode, copyUrl, copyWithUrl, onCopyRequest, onCopied, toast } = p;
4
+ return {
5
+ copy: copy != null ? copy : void 0,
6
+ "copy-node": copyNode === true ? "" : typeof copyNode === "string" ? copyNode : void 0,
7
+ "copy-url": copyUrl ? "" : void 0,
8
+ "copy-with-url": copyWithUrl ? "" : void 0,
9
+ toast: toast ? "" : void 0,
10
+ oncopydone: onCopied ? (e) => onCopied(nativeStateChange(e).detail?.ok ?? false) : void 0,
11
+ oncopyrequest: onCopyRequest ? () => onCopyRequest() : void 0
12
+ };
13
+ }
14
+ function isNodeCopy(p) {
15
+ return p.copyNode != null && p.copyNode !== false;
16
+ }
17
+ export {
18
+ copyElementProps,
19
+ isNodeCopy
20
+ };