@charcuterie/ui 3.11.0 → 3.12.0

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.
@@ -0,0 +1,67 @@
1
+ import type { ReactNode } from "react";
2
+ import type { ButtonProps } from "../Button/Button.tsx";
3
+ /** Where the button is in the one action it performs. */
4
+ export type CopyStatus = "copied" | "failed" | "idle";
5
+ export type CopyButtonProps = Omit<ButtonProps, "children" | "isLoading" | "loadingLabel" | "onCopy"> & {
6
+ /**
7
+ * How long the confirmation stays up, in milliseconds.
8
+ *
9
+ * Long enough to be read after the eye has moved back to the form
10
+ * being filled in, short enough that a second copy of a *different*
11
+ * value is not mistaken for the first one's tick.
12
+ */
13
+ confirmDuration?: number;
14
+ /** Resting label. A word, not a glyph — this library ships no icons. */
15
+ children?: ReactNode;
16
+ /** Shown while the copy is confirmed. */
17
+ copiedLabel?: ReactNode;
18
+ /**
19
+ * The clipboard write, injected. Swapped in tests and in a host
20
+ * that owns its own clipboard bridge (Electron, a kiosk shell).
21
+ */
22
+ copy?: (value: string) => Promise<boolean> | boolean;
23
+ /** Shown when the clipboard refused. */
24
+ failedLabel?: ReactNode;
25
+ /**
26
+ * Told what actually happened, every press.
27
+ *
28
+ * `isCopied` is the point of the callback rather than a detail: a
29
+ * consumer that files the mail away on a copy must not file it away
30
+ * on a copy the browser refused.
31
+ */
32
+ onCopy?: (isCopied: boolean, value: string) => void;
33
+ /** The string that goes on the clipboard. */
34
+ value: string;
35
+ };
36
+ /**
37
+ * A button that puts a string on the clipboard and says so.
38
+ *
39
+ * From a consumer, like `Alert` and `BadgeButton` before it: four
40
+ * repos spell this shape by hand — mux-magic's YAML dialog flips its
41
+ * own label on a `setTimeout`, spoolbuddy carries a 15-line
42
+ * `copyToClipboard` with the `execCommand` fallback inline, bambuddy
43
+ * copies a download link from two menus, and mail-sifter's
44
+ * verification-code banner is the fourth. None of the four agree on
45
+ * what happens when the clipboard says no, and three of them cannot
46
+ * tell.
47
+ *
48
+ * **The confirmation is the button, not a toast.** The press and the
49
+ * proof are the same object, so the eye does not travel; a toast is
50
+ * right for something that happened *elsewhere*. A consumer that
51
+ * wants both still gets `onCopy`.
52
+ *
53
+ * **The label is a word.** `Copy` → `Copied`, and the intent goes
54
+ * with it, because a colour change alone is not a message and a tick
55
+ * glyph is an icon this library does not ship.
56
+ *
57
+ * **It announces.** A screen reader is not reliably told that a
58
+ * focused button's own name changed, so the outcome is also written
59
+ * into a `role="status"` region — and the failure says what to do
60
+ * next rather than only that it went wrong.
61
+ *
62
+ * **The timer is cancelled on unmount and on a re-press**, which is
63
+ * the bug in two of the four hand-rolled copies: press, navigate
64
+ * away, and a `setState` lands on nothing.
65
+ */
66
+ export declare const CopyButton: ({ appearance, children, confirmDuration, copiedLabel, copy, failedLabel, intent, onClick, onCopy, value, ...buttonProps }: CopyButtonProps) => ReactNode;
67
+ //# sourceMappingURL=CopyButton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CopyButton.d.ts","sourceRoot":"","sources":["../../src/CopyButton/CopyButton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEtC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAKvD,yDAAyD;AACzD,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAA;AAErD,MAAM,MAAM,eAAe,GAAG,IAAI,CAChC,WAAW,EACX,UAAU,GAAG,WAAW,GAAG,cAAc,GAAG,QAAQ,CACrD,GAAG;IACF;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,wEAAwE;IACxE,QAAQ,CAAC,EAAE,SAAS,CAAA;IACpB,yCAAyC;IACzC,WAAW,CAAC,EAAE,SAAS,CAAA;IACvB;;;OAGG;IACH,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAA;IACpD,wCAAwC;IACxC,WAAW,CAAC,EAAE,SAAS,CAAA;IACvB;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACnD,6CAA6C;IAC7C,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,UAAU,GAAI,2HAYxB,eAAe,KAAG,SAmEpB,CAAA"}
@@ -0,0 +1,76 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useRef, useState } from "react";
3
+ import { Button } from "../Button/Button.js";
4
+ import { VisuallyHidden } from "../VisuallyHidden/VisuallyHidden.js";
5
+ import { copyText as defaultCopyText } from "./copyText.js";
6
+ /**
7
+ * A button that puts a string on the clipboard and says so.
8
+ *
9
+ * From a consumer, like `Alert` and `BadgeButton` before it: four
10
+ * repos spell this shape by hand — mux-magic's YAML dialog flips its
11
+ * own label on a `setTimeout`, spoolbuddy carries a 15-line
12
+ * `copyToClipboard` with the `execCommand` fallback inline, bambuddy
13
+ * copies a download link from two menus, and mail-sifter's
14
+ * verification-code banner is the fourth. None of the four agree on
15
+ * what happens when the clipboard says no, and three of them cannot
16
+ * tell.
17
+ *
18
+ * **The confirmation is the button, not a toast.** The press and the
19
+ * proof are the same object, so the eye does not travel; a toast is
20
+ * right for something that happened *elsewhere*. A consumer that
21
+ * wants both still gets `onCopy`.
22
+ *
23
+ * **The label is a word.** `Copy` → `Copied`, and the intent goes
24
+ * with it, because a colour change alone is not a message and a tick
25
+ * glyph is an icon this library does not ship.
26
+ *
27
+ * **It announces.** A screen reader is not reliably told that a
28
+ * focused button's own name changed, so the outcome is also written
29
+ * into a `role="status"` region — and the failure says what to do
30
+ * next rather than only that it went wrong.
31
+ *
32
+ * **The timer is cancelled on unmount and on a re-press**, which is
33
+ * the bug in two of the four hand-rolled copies: press, navigate
34
+ * away, and a `setState` lands on nothing.
35
+ */
36
+ export const CopyButton = ({ appearance = "solid", children = "Copy", confirmDuration = 2000, copiedLabel = "Copied", copy = defaultCopyText, failedLabel = "Copy failed", intent = "accent", onClick, onCopy, value, ...buttonProps }) => {
37
+ const [status, setStatus] = useState("idle");
38
+ const timerRef = useRef(undefined);
39
+ // One cleanup covers both the unmount and the re-press: every path
40
+ // that starts a timer clears the previous one first.
41
+ useEffect(() => () => {
42
+ clearTimeout(timerRef.current);
43
+ }, []);
44
+ const settle = (next) => {
45
+ setStatus(next);
46
+ clearTimeout(timerRef.current);
47
+ timerRef.current = setTimeout(() => {
48
+ setStatus("idle");
49
+ }, confirmDuration);
50
+ };
51
+ const handleClick = (event) => {
52
+ onClick?.(event);
53
+ if (event.defaultPrevented)
54
+ return;
55
+ void (async () => {
56
+ const isCopied = await copy(value);
57
+ settle(isCopied ? "copied" : "failed");
58
+ onCopy?.(isCopied, value);
59
+ })();
60
+ };
61
+ const label = status === "copied"
62
+ ? copiedLabel
63
+ : status === "failed"
64
+ ? failedLabel
65
+ : children;
66
+ return (_jsxs(_Fragment, { children: [_jsx(Button, { ...buttonProps, appearance: appearance, intent: status === "copied"
67
+ ? "success"
68
+ : status === "failed"
69
+ ? "danger"
70
+ : intent, onClick: handleClick, children: label }), _jsx(VisuallyHidden, { role: "status", children: status === "copied"
71
+ ? "Copied to the clipboard."
72
+ : status === "failed"
73
+ ? "The clipboard refused. Select the value and press Control C."
74
+ : "" })] }));
75
+ };
76
+ //# sourceMappingURL=CopyButton.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CopyButton.js","sourceRoot":"","sources":["../../src/CopyButton/CopyButton.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAEnD,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAsB,CAAA;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,qCAAsC,CAAA;AACrE,OAAO,EAAE,QAAQ,IAAI,eAAe,EAAE,MAAM,eAAe,CAAA;AAwC3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,EACzB,UAAU,GAAG,OAAO,EACpB,QAAQ,GAAG,MAAM,EACjB,eAAe,GAAG,IAAI,EACtB,WAAW,GAAG,QAAQ,EACtB,IAAI,GAAG,eAAe,EACtB,WAAW,GAAG,aAAa,EAC3B,MAAM,GAAG,QAAQ,EACjB,OAAO,EACP,MAAM,EACN,KAAK,EACL,GAAG,WAAW,EACE,EAAa,EAAE;IAC/B,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAa,MAAM,CAAC,CAAA;IACxD,MAAM,QAAQ,GACZ,MAAM,CAAgC,SAAS,CAAC,CAAA;IAElD,mEAAmE;IACnE,qDAAqD;IACrD,SAAS,CACP,GAAG,EAAE,CAAC,GAAG,EAAE;QACT,YAAY,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;IAChC,CAAC,EACD,EAAE,CACH,CAAA;IAED,MAAM,MAAM,GAAG,CAAC,IAAgB,EAAE,EAAE;QAClC,SAAS,CAAC,IAAI,CAAC,CAAA;QACf,YAAY,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;QAC9B,QAAQ,CAAC,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;YACjC,SAAS,CAAC,MAAM,CAAC,CAAA;QACnB,CAAC,EAAE,eAAe,CAAC,CAAA;IACrB,CAAC,CAAA;IAED,MAAM,WAAW,GAAwC,CACvD,KAAK,EACL,EAAE;QACF,OAAO,EAAE,CAAC,KAAK,CAAC,CAAA;QAChB,IAAI,KAAK,CAAC,gBAAgB;YAAE,OAAM;QAElC,KAAK,CAAC,KAAK,IAAI,EAAE;YACf,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,CAAA;YAClC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAA;YACtC,MAAM,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAA;QAC3B,CAAC,CAAC,EAAE,CAAA;IACN,CAAC,CAAA;IAED,MAAM,KAAK,GACT,MAAM,KAAK,QAAQ;QACjB,CAAC,CAAC,WAAW;QACb,CAAC,CAAC,MAAM,KAAK,QAAQ;YACnB,CAAC,CAAC,WAAW;YACb,CAAC,CAAC,QAAQ,CAAA;IAEhB,OAAO,CACL,8BACE,KAAC,MAAM,OACD,WAAW,EACf,UAAU,EAAE,UAAU,EACtB,MAAM,EACJ,MAAM,KAAK,QAAQ;oBACjB,CAAC,CAAC,SAAS;oBACX,CAAC,CAAC,MAAM,KAAK,QAAQ;wBACnB,CAAC,CAAC,QAAQ;wBACV,CAAC,CAAC,MAAM,EAEd,OAAO,EAAE,WAAW,YAEnB,KAAK,GACC,EACT,KAAC,cAAc,IAAC,IAAI,EAAC,QAAQ,YAC1B,MAAM,KAAK,QAAQ;oBAClB,CAAC,CAAC,0BAA0B;oBAC5B,CAAC,CAAC,MAAM,KAAK,QAAQ;wBACnB,CAAC,CAAC,8DAA8D;wBAChE,CAAC,CAAC,EAAE,GACO,IAChB,CACJ,CAAA;AACH,CAAC,CAAA"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Put a string on the clipboard, and say whether it landed.
3
+ *
4
+ * Three routes, tried in order, because the fleet runs in all three
5
+ * conditions:
6
+ *
7
+ * 1. **`navigator.clipboard.writeText`.** The real API. It exists
8
+ * only in a *secure context*, which a `devshare` URL and
9
+ * `localhost` both are — and a plain `http://storeman.octen:8080`
10
+ * dev server is not.
11
+ * 2. **A hidden `<textarea>` plus `document.execCommand("copy")`.**
12
+ * Deprecated, and kept anyway: it is the only thing that works in
13
+ * an insecure context, spoolbuddy already hand-rolls exactly this
14
+ * block, and the alternative is a Copy button that silently does
15
+ * nothing on the household's own LAN.
16
+ * 3. **Give up and report it.** A caller that marks mail done on a
17
+ * copy must not mark it done on a copy that never happened.
18
+ *
19
+ * Never throws. The boolean is the whole result, so a call site is an
20
+ * `if` rather than a `try`.
21
+ */
22
+ export declare const copyText: (value: string) => Promise<boolean>;
23
+ //# sourceMappingURL=copyText.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copyText.d.ts","sourceRoot":"","sources":["../../src/CopyButton/copyText.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,QAAQ,GACnB,OAAO,MAAM,KACZ,OAAO,CAAC,OAAO,CAWjB,CAAA"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Put a string on the clipboard, and say whether it landed.
3
+ *
4
+ * Three routes, tried in order, because the fleet runs in all three
5
+ * conditions:
6
+ *
7
+ * 1. **`navigator.clipboard.writeText`.** The real API. It exists
8
+ * only in a *secure context*, which a `devshare` URL and
9
+ * `localhost` both are — and a plain `http://storeman.octen:8080`
10
+ * dev server is not.
11
+ * 2. **A hidden `<textarea>` plus `document.execCommand("copy")`.**
12
+ * Deprecated, and kept anyway: it is the only thing that works in
13
+ * an insecure context, spoolbuddy already hand-rolls exactly this
14
+ * block, and the alternative is a Copy button that silently does
15
+ * nothing on the household's own LAN.
16
+ * 3. **Give up and report it.** A caller that marks mail done on a
17
+ * copy must not mark it done on a copy that never happened.
18
+ *
19
+ * Never throws. The boolean is the whole result, so a call site is an
20
+ * `if` rather than a `try`.
21
+ */
22
+ export const copyText = async (value) => {
23
+ try {
24
+ // `writeText` rejects on a denied permission and on a document
25
+ // that is not focused — both real, both recoverable below.
26
+ await globalThis.navigator?.clipboard?.writeText(value);
27
+ return true;
28
+ }
29
+ catch {
30
+ // Fall through to the legacy route.
31
+ }
32
+ return copyBySelection(value);
33
+ };
34
+ /**
35
+ * The pre-Clipboard-API route.
36
+ *
37
+ * The textarea is positioned off-screen rather than hidden: a
38
+ * `display: none` element has no selection to copy, and
39
+ * `visibility: hidden` is no better. `readOnly` stops the mobile
40
+ * keyboard appearing for the frame it is in the document.
41
+ */
42
+ const copyBySelection = (value) => {
43
+ const owner = globalThis.document;
44
+ if (!owner?.body)
45
+ return false;
46
+ const field = owner.createElement("textarea");
47
+ field.value = value;
48
+ field.readOnly = true;
49
+ field.setAttribute("aria-hidden", "true");
50
+ field.style.position = "fixed";
51
+ field.style.insetInlineStart = "-9999px";
52
+ field.style.top = "0";
53
+ owner.body.append(field);
54
+ try {
55
+ field.select();
56
+ return owner.execCommand("copy");
57
+ }
58
+ catch {
59
+ return false;
60
+ }
61
+ finally {
62
+ field.remove();
63
+ }
64
+ };
65
+ //# sourceMappingURL=copyText.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copyText.js","sourceRoot":"","sources":["../../src/CopyButton/copyText.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,KAAK,EAC3B,KAAa,EACK,EAAE;IACpB,IAAI,CAAC;QACH,+DAA+D;QAC/D,2DAA2D;QAC3D,MAAM,UAAU,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,KAAK,CAAC,CAAA;QACvD,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,MAAM,CAAC;QACP,oCAAoC;IACtC,CAAC;IAED,OAAO,eAAe,CAAC,KAAK,CAAC,CAAA;AAC/B,CAAC,CAAA;AAED;;;;;;;GAOG;AACH,MAAM,eAAe,GAAG,CAAC,KAAa,EAAW,EAAE;IACjD,MAAM,KAAK,GAAG,UAAU,CAAC,QAAQ,CAAA;IACjC,IAAI,CAAC,KAAK,EAAE,IAAI;QAAE,OAAO,KAAK,CAAA;IAE9B,MAAM,KAAK,GAAG,KAAK,CAAC,aAAa,CAAC,UAAU,CAAC,CAAA;IAC7C,KAAK,CAAC,KAAK,GAAG,KAAK,CAAA;IACnB,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAA;IACrB,KAAK,CAAC,YAAY,CAAC,aAAa,EAAE,MAAM,CAAC,CAAA;IACzC,KAAK,CAAC,KAAK,CAAC,QAAQ,GAAG,OAAO,CAAA;IAC9B,KAAK,CAAC,KAAK,CAAC,gBAAgB,GAAG,SAAS,CAAA;IACxC,KAAK,CAAC,KAAK,CAAC,GAAG,GAAG,GAAG,CAAA;IAErB,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IAExB,IAAI,CAAC;QACH,KAAK,CAAC,MAAM,EAAE,CAAA;QAEd,OAAO,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,CAAA;IAClC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;YAAS,CAAC;QACT,KAAK,CAAC,MAAM,EAAE,CAAA;IAChB,CAAC;AACH,CAAC,CAAA"}
package/dist/index.d.ts CHANGED
@@ -66,6 +66,9 @@ export type { ColorSchemeIcons, ColorSchemeToggleProps, } from "./ColorSchemeTog
66
66
  export { ColorSchemeToggle } from "./ColorSchemeToggle/ColorSchemeToggle.tsx";
67
67
  export type { ComboboxProps } from "./Combobox/Combobox.tsx";
68
68
  export { Combobox } from "./Combobox/Combobox.tsx";
69
+ export type { CopyButtonProps, CopyStatus, } from "./CopyButton/CopyButton.tsx";
70
+ export { CopyButton } from "./CopyButton/CopyButton.tsx";
71
+ export { copyText } from "./CopyButton/copyText.ts";
69
72
  export { CATEGORICAL_APPEARANCE_CLASS, CATEGORICAL_CONTENT_CLASS, CATEGORICAL_HOVER_CLASS, CATEGORICAL_SOLID_FILL_CLASS, } from "./categoricalStyles.ts";
70
73
  export type { BadgeSize } from "./controlStyles.ts";
71
74
  export { BADGE_SIZE_CLASS, CONTROL_BASE_CLASS, CONTROL_SIZE_CLASS, DOT_SIZE_CLASS, getControlClassName, ICON_CONTROL_SIZE_CLASS, MIN_TOUCH_TARGET_CLASS, SPINNER_SIZE_CLASS, } from "./controlStyles.ts";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,YAAY,EACV,qBAAqB,EACrB,aAAa,EACb,cAAc,GACf,MAAM,2BAA2B,CAAA;AAClC,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAA;AACrD,YAAY,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AACxE,OAAO,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAA;AAC9D,YAAY,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAA;AACnE,OAAO,EACL,aAAa,EACb,wBAAwB,EACxB,0BAA0B,EAC1B,iCAAiC,EACjC,gBAAgB,EAChB,uBAAuB,GACxB,MAAM,iCAAiC,CAAA;AACxC,YAAY,EACV,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,sCAAsC,CAAA;AAC7C,OAAO,EACL,6BAA6B,EAC7B,gBAAgB,EAChB,kBAAkB,EAClB,yBAAyB,GAC1B,MAAM,sCAAsC,CAAA;AAC7C,YAAY,EACV,UAAU,EACV,SAAS,GACV,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AACzC,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AACnD,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AACzC,YAAY,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAA;AAChE,YAAY,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAA;AACrE,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAA;AAC3D,YAAY,EACV,SAAS,EACT,UAAU,GACX,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AACzC,YAAY,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAA;AACtD,YAAY,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAA;AAC1D,YAAY,EACV,aAAa,EACb,eAAe,EACf,UAAU,EACV,SAAS,GACV,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,YAAY,EACZ,mBAAmB,EACnB,cAAc,GACf,MAAM,sBAAsB,CAAA;AAC7B,YAAY,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAC5C,YAAY,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAA;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAA;AACxD,YAAY,EACV,WAAW,EACX,SAAS,EACT,WAAW,GACZ,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AACtC,YAAY,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AAC9D,YAAY,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AAC5D,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AAClD,YAAY,EAAE,wBAAwB,EAAE,MAAM,+CAA+C,CAAA;AAC7F,OAAO,EAAE,mBAAmB,EAAE,MAAM,+CAA+C,CAAA;AACnF,YAAY,EACV,gBAAgB,EAChB,sBAAsB,GACvB,MAAM,2CAA2C,CAAA;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2CAA2C,CAAA;AAC7E,YAAY,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AAC5D,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AAClD,OAAO,EACL,4BAA4B,EAC5B,yBAAyB,EACzB,uBAAuB,EACvB,4BAA4B,GAC7B,MAAM,wBAAwB,CAAA;AAC/B,YAAY,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AACnD,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,cAAc,EACd,mBAAmB,EACnB,uBAAuB,EACvB,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,oBAAoB,CAAA;AAC3B,YAAY,EACV,eAAe,EACf,cAAc,EACd,kBAAkB,EAClB,aAAa,GACd,MAAM,2BAA2B,CAAA;AAClC,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAA;AACrD,YAAY,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAA;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAA;AACxD,YAAY,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAA;AAC7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAClE,YAAY,EACV,iBAAiB,EACjB,eAAe,EACf,qBAAqB,GACtB,MAAM,gCAAgC,CAAA;AACvC,OAAO,EACL,2BAA2B,EAC3B,cAAc,GACf,MAAM,gCAAgC,CAAA;AACvC,YAAY,EACV,SAAS,EACT,SAAS,EACT,sBAAsB,GACvB,MAAM,2BAA2B,CAAA;AAClC,OAAO,EACL,OAAO,EACP,SAAS,EACT,cAAc,EACd,iBAAiB,EACjB,eAAe,EACf,YAAY,EACZ,cAAc,EACd,cAAc,EACd,iBAAiB,EACjB,aAAa,EACb,YAAY,EACZ,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,EACjB,aAAa,EACb,yBAAyB,EACzB,UAAU,EACV,eAAe,EACf,YAAY,EACZ,SAAS,GACV,MAAM,2BAA2B,CAAA;AAClC,YAAY,EACV,WAAW,EACX,UAAU,GACX,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAC5C,YAAY,EACV,eAAe,EACf,cAAc,GACf,MAAM,6BAA6B,CAAA;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAA;AACxD,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AACnD,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AACzC,YAAY,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AACnD,YAAY,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AACxE,OAAO,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAA;AAC9D,YAAY,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAC5C,YAAY,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAA;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAA;AACxD,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AACzD,OAAO,EACL,mBAAmB,EACnB,cAAc,EACd,gBAAgB,EAChB,uBAAuB,EACvB,oBAAoB,EACpB,kBAAkB,EAClB,uBAAuB,GACxB,MAAM,mBAAmB,CAAA;AAC1B,YAAY,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AAC5D,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AAClD,YAAY,EACV,WAAW,EACX,YAAY,GACb,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAA;AAC/C,YAAY,EACV,wBAAwB,EACxB,uBAAuB,GACxB,MAAM,+CAA+C,CAAA;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,+CAA+C,CAAA;AACnF,YAAY,EACV,OAAO,EACP,cAAc,GACf,MAAM,2BAA2B,CAAA;AAClC,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAA;AACrD,YAAY,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAChD,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AACtC,YAAY,EACV,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,qCAAqC,CAAA;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAA;AACpE,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAA;AACtE,YAAY,EACV,YAAY,EACZ,gBAAgB,EAChB,YAAY,EACZ,gBAAgB,GACjB,MAAM,mCAAmC,CAAA;AAC1C,OAAO,EACL,WAAW,EACX,eAAe,GAChB,MAAM,mCAAmC,CAAA;AAC1C,YAAY,EACV,cAAc,EACd,cAAc,GACf,MAAM,2BAA2B,CAAA;AAClC,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAA;AACrD,YAAY,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAA;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAA;AAC7D,YAAY,EACV,QAAQ,EACR,SAAS,GACV,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AACtC,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AACnD,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AACzC,YAAY,EACV,YAAY,EACZ,WAAW,GACZ,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAC5C,YAAY,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AACzD,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAA;AAC/C,YAAY,EACV,gBAAgB,EAChB,eAAe,GAChB,MAAM,+BAA+B,CAAA;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAA;AAC3D,YAAY,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AACvE,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,GAChB,MAAM,gCAAgC,CAAA;AACvC,YAAY,EACV,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,iCAAiC,CAAA;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAA;AAC9D,YAAY,EACV,eAAe,EACf,SAAS,GACV,MAAM,6BAA6B,CAAA;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAA;AACxD,YAAY,EACV,YAAY,EACZ,SAAS,EACT,QAAQ,GACT,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAA;AACxD,OAAO,EACL,kBAAkB,EAClB,aAAa,GACd,MAAM,qCAAqC,CAAA;AAC5C,YAAY,EACV,mBAAmB,EACnB,eAAe,GAChB,MAAM,4BAA4B,CAAA;AACnC,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AAC5D,YAAY,EACV,qBAAqB,EACrB,aAAa,GACd,MAAM,yCAAyC,CAAA;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yCAAyC,CAAA;AAM1E,YAAY,EACV,UAAU,EACV,YAAY,EACZ,iBAAiB,EACjB,WAAW,GACZ,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAC5C,YAAY,EACV,YAAY,EACZ,UAAU,GACX,MAAM,yBAAyB,CAAA;AAChC,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AACnD,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AACzC,YAAY,EACV,aAAa,EACb,aAAa,GACd,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AAClD,YAAY,EACV,WAAW,EACX,UAAU,GACX,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAC5C,YAAY,EACV,wBAAwB,EACxB,aAAa,GACd,MAAM,+CAA+C,CAAA;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,+CAA+C,CAAA;AACnF,YAAY,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AACzD,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAA;AAC/C,YAAY,EACV,IAAI,EACJ,kBAAkB,EAClB,YAAY,EACZ,UAAU,GACX,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAA;AAC/C,YAAY,EACV,gBAAgB,EAChB,WAAW,EACX,UAAU,GACX,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAC5C,YAAY,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAC5C,YAAY,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAC/C,OAAO,EACL,cAAc,EACd,aAAa,EACb,mBAAmB,EACnB,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,mBAAmB,CAAA;AAC1B,YAAY,EACV,OAAO,EACP,cAAc,EACd,eAAe,EACf,SAAS,GACV,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AACtC,YAAY,EACV,kBAAkB,EAClB,aAAa,GACd,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AAClD,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AACnD,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AACzC,YAAY,EACV,WAAW,EACX,gBAAgB,GACjB,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AACrD,YAAY,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAA;AACpE,YAAY,EACV,aAAa,EACb,cAAc,EACd,WAAW,EACX,YAAY,GACb,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAA;AAC/C,YAAY,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AACzD,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAA;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAA;AAClE,YAAY,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAA;AACjF,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAA;AACvE,YAAY,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAA;AAC9E,OAAO,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -46,6 +46,8 @@ export { Checkbox } from "./Checkbox/Checkbox.js";
46
46
  export { ColorSchemeSwitcher } from "./ColorSchemeSwitcher/ColorSchemeSwitcher.js";
47
47
  export { ColorSchemeToggle } from "./ColorSchemeToggle/ColorSchemeToggle.js";
48
48
  export { Combobox } from "./Combobox/Combobox.js";
49
+ export { CopyButton } from "./CopyButton/CopyButton.js";
50
+ export { copyText } from "./CopyButton/copyText.js";
49
51
  export { CATEGORICAL_APPEARANCE_CLASS, CATEGORICAL_CONTENT_CLASS, CATEGORICAL_HOVER_CLASS, CATEGORICAL_SOLID_FILL_CLASS, } from "./categoricalStyles.js";
50
52
  export { BADGE_SIZE_CLASS, CONTROL_BASE_CLASS, CONTROL_SIZE_CLASS, DOT_SIZE_CLASS, getControlClassName, ICON_CONTROL_SIZE_CLASS, MIN_TOUCH_TARGET_CLASS, SPINNER_SIZE_CLASS, } from "./controlStyles.js";
51
53
  export { DataTable } from "./DataTable/DataTable.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@charcuterie/ui",
3
- "version": "3.11.0",
3
+ "version": "3.12.0",
4
4
  "description": "The Charcuterie components. Tokens for look, @charcuterie/logic for state, ARIA that agents can actually drive.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -0,0 +1,84 @@
1
+ import { Canvas, Controls, Meta } from "@storybook/addon-docs/blocks";
2
+
3
+ import * as CopyButtonStories from "./CopyButton.stories";
4
+
5
+ <Meta of={CopyButtonStories} />
6
+
7
+ # CopyButton
8
+
9
+ **A button that puts a string on the clipboard and says so.** Press it, the label turns to
10
+ `Copied`, and the caller is told whether that is true.
11
+
12
+ <Canvas of={CopyButtonStories.Default} />
13
+
14
+ ## Props
15
+
16
+ <Controls />
17
+
18
+ ## Where it came from
19
+
20
+ Four repos spell this shape by hand, and no two agree:
21
+
22
+ | Repo | How it copies | What it does when the clipboard says no |
23
+ | --- | --- | --- |
24
+ | mux-magic (`YamlModal`) | flips its own label on a `setTimeout` | nothing — the label still says `Copied!` |
25
+ | spoolbuddy (`Settings`) | 15 lines inline, with the `execCommand` fallback | a toast |
26
+ | bambuddy (`ArchivesPage`) | a menu item, twice in one file | a toast |
27
+ | mail-sifter | a verification-code banner | **marks the mail done anyway** |
28
+
29
+ The last row is why the failure path is a first-class state here rather than a `catch` that
30
+ shrugs. That consumer files the mail away on a copy, so a copy that did not happen has to be
31
+ distinguishable from one that did.
32
+
33
+ ## The confirmation is the button
34
+
35
+ The press and the proof are the same object, so the eye does not travel. A toast is the
36
+ right shape for something that happened **somewhere else** — a background job, another pane
37
+ — and the wrong shape for the thing directly under the pointer. A consumer that wants a
38
+ toast as well still gets one from `onCopy`.
39
+
40
+ <Canvas of={CopyButtonStories.Confirmed} />
41
+
42
+ ## The label is a word, and so is the failure
43
+
44
+ `Copy` → `Copied`, with the intent moving to `success` underneath it. The colour is not the
45
+ message: a colour change alone is invisible to a screen reader, unreliable for a
46
+ colour-blind reader, and this library [ships no icons](?path=/docs/guides-building-an-app--docs),
47
+ so a tick glyph is not available to carry it either.
48
+
49
+ The refusal says what to do next rather than only that something went wrong.
50
+
51
+ <Canvas of={CopyButtonStories.Refused} />
52
+
53
+ ## Three routes to the clipboard
54
+
55
+ `copyText.ts` tries them in order and never throws:
56
+
57
+ 1. **`navigator.clipboard.writeText`** — the real API, and it exists only in a *secure
58
+ context*. A `devshare` URL and `localhost` are secure; a plain `http://` dev server on
59
+ the LAN is not.
60
+ 2. **A hidden `<textarea>` and `document.execCommand("copy")`** — deprecated, kept because
61
+ it is the only thing that works in that insecure context, and because spoolbuddy already
62
+ carries this exact block inline.
63
+ 3. **Report the failure**, so the caller can hold on to whatever it was about to discard.
64
+
65
+ `copy` is injectable, which is how the `Refused` story above exists and how a host with its
66
+ own clipboard bridge — Electron, a kiosk shell — supplies it.
67
+
68
+ ## Own labels
69
+
70
+ The labels are content. A surface that copies one specific thing should say which thing.
71
+
72
+ <Canvas of={CopyButtonStories.OwnLabels} />
73
+
74
+ <Canvas of={CopyButtonStories.AllAppearances} />
75
+
76
+ ## What it does not do
77
+
78
+ **It does not own the value.** No `children`-as-value, no reading text out of a sibling
79
+ node: the string is a prop, because the thing on screen is regularly not the thing worth
80
+ copying (a masked key, a truncated URL, a code split across two spans).
81
+
82
+ **It does not clear the timer for you and hope.** The confirmation timer is cancelled on
83
+ unmount and on a re-press — two of the four hand-rolled copies set state on an unmounted
84
+ component if you press and navigate away.
@@ -0,0 +1,111 @@
1
+ import type { Meta, StoryObj } from "@storybook/react"
2
+ import { userEvent, within } from "storybook/test"
3
+
4
+ import {
5
+ StoryCell,
6
+ StoryRow,
7
+ StorySection,
8
+ } from "../board.storyHelpers.tsx"
9
+ import { CopyButton } from "./CopyButton.tsx"
10
+
11
+ const meta = {
12
+ title: "Components/Actions/CopyButton",
13
+ component: CopyButton,
14
+ parameters: { layout: "padded" },
15
+ // The component's own defaults, restated — Storybook does not
16
+ // seed `args` from docgen, so an unstated default shows in the
17
+ // props table with nothing selected in its control.
18
+ args: {
19
+ appearance: "solid",
20
+ confirmDuration: 2000,
21
+ intent: "accent",
22
+ isDisabled: false,
23
+ size: "md",
24
+ value: "335590",
25
+ },
26
+ } satisfies Meta<typeof CopyButton>
27
+
28
+ export default meta
29
+
30
+ type Story = StoryObj<typeof meta>
31
+
32
+ export const Default: Story = {}
33
+
34
+ /**
35
+ * The confirmation, held open. `confirmDuration` is enormous here so
36
+ * the state can be read, hovered and screenshotted — a two-second
37
+ * default is right in an app and useless in a docs page.
38
+ */
39
+ export const Confirmed: Story = {
40
+ args: {
41
+ confirmDuration: 600_000,
42
+ // Injected, not real. A headless browser refuses
43
+ // `navigator.clipboard` outright — the document is not focused —
44
+ // so a story that used the real one would document the *failure*
45
+ // state under a name that promises the success one.
46
+ copy: () => true,
47
+ value: "335590",
48
+ },
49
+ // Driven, not faked: the story presses the button the way a reader
50
+ // would. No assertion — those live in `CopyButton.test.tsx`.
51
+ play: async ({ canvasElement }) => {
52
+ await userEvent.click(
53
+ within(canvasElement).getByRole("button", {
54
+ name: "Copy",
55
+ }),
56
+ )
57
+ },
58
+ }
59
+
60
+ /**
61
+ * The clipboard refused. Injected rather than provoked: a story
62
+ * cannot revoke the permission, and the failure path is the half of
63
+ * this component the hand-rolled copies in the fleet do not have.
64
+ */
65
+ export const Refused: Story = {
66
+ args: {
67
+ confirmDuration: 600_000,
68
+ copy: () => false,
69
+ },
70
+ play: async ({ canvasElement }) => {
71
+ await userEvent.click(
72
+ within(canvasElement).getByRole("button", {
73
+ name: "Copy",
74
+ }),
75
+ )
76
+ },
77
+ }
78
+
79
+ /** Every appearance, so a toolbar's ghost copy is a real option. */
80
+ export const AllAppearances: Story = {
81
+ render: (args) => (
82
+ <StorySection title="Appearances">
83
+ <StoryRow>
84
+ <StoryCell label="solid">
85
+ <CopyButton {...args} appearance="solid" />
86
+ </StoryCell>
87
+ <StoryCell label="soft">
88
+ <CopyButton {...args} appearance="soft" />
89
+ </StoryCell>
90
+ <StoryCell label="outline">
91
+ <CopyButton {...args} appearance="outline" />
92
+ </StoryCell>
93
+ <StoryCell label="ghost">
94
+ <CopyButton {...args} appearance="ghost" />
95
+ </StoryCell>
96
+ </StoryRow>
97
+ </StorySection>
98
+ ),
99
+ }
100
+
101
+ /**
102
+ * A caller's own words. The label is content, so a one-off surface
103
+ * that copies something specific says which thing it copies.
104
+ */
105
+ export const OwnLabels: Story = {
106
+ args: {
107
+ children: "Copy code",
108
+ copiedLabel: "Code copied",
109
+ value: "335590",
110
+ },
111
+ }
@@ -0,0 +1,227 @@
1
+ import {
2
+ composeStories,
3
+ composeStory,
4
+ } from "@storybook/react"
5
+ import {
6
+ expect,
7
+ fn,
8
+ userEvent,
9
+ waitFor,
10
+ } from "storybook/test"
11
+ import { test, vi } from "vitest"
12
+
13
+ import { expectNoAxeViolations } from "../expectNoAxeViolations.testHelpers.ts"
14
+ import { mountStory } from "../mountStory.testHelpers.ts"
15
+ import { expectAgentDrivable } from "../testing/index.ts"
16
+ import meta, * as stories from "./CopyButton.stories.tsx"
17
+ import { copyText } from "./copyText.ts"
18
+
19
+ const { Confirmed, Default, Refused } =
20
+ composeStories(stories)
21
+
22
+ test("is a button an agent can find by role and name", async () => {
23
+ const { canvas } = await mountStory(Default)
24
+
25
+ const button = expectAgentDrivable(canvas, {
26
+ name: "Copy",
27
+ role: "button",
28
+ })
29
+
30
+ // Never `submit`. A copy control inside a form that reloads the
31
+ // page is a bug every repo in the fleet has shipped once.
32
+ await expect(button).toHaveAttribute("type", "button")
33
+ })
34
+
35
+ test("copies the value and confirms in place", async () => {
36
+ const copy = fn(async () => true)
37
+
38
+ const { canvas } = await mountStory(
39
+ composeStory({ args: { copy, value: "335590" } }, meta),
40
+ )
41
+
42
+ await userEvent.click(
43
+ canvas.getByRole("button", { name: "Copy" }),
44
+ )
45
+
46
+ await expect(copy).toHaveBeenCalledWith("335590")
47
+ // The press and its proof are the same object — no toast, no
48
+ // second place to look.
49
+ await expect(
50
+ canvas.getByRole("button", { name: "Copied" }),
51
+ ).toBeVisible()
52
+ })
53
+
54
+ /**
55
+ * The half the four hand-rolled copies in the fleet do not have.
56
+ *
57
+ * A refused clipboard has to *say so*, because the consumer's next
58
+ * move usually destroys the thing that held the value — mail-sifter
59
+ * marks the mail done on a copy.
60
+ */
61
+ test("says so when the clipboard refuses", async () => {
62
+ const onCopy = fn()
63
+
64
+ const { canvas } = await mountStory(
65
+ composeStory(
66
+ { args: { copy: () => false, onCopy } },
67
+ meta,
68
+ ),
69
+ )
70
+
71
+ await userEvent.click(
72
+ canvas.getByRole("button", { name: "Copy" }),
73
+ )
74
+
75
+ await expect(
76
+ canvas.getByRole("button", { name: "Copy failed" }),
77
+ ).toBeVisible()
78
+ await expect(onCopy).toHaveBeenCalledWith(false, "335590")
79
+ })
80
+
81
+ test("tells the caller what happened, both ways", async () => {
82
+ const onCopy = fn()
83
+
84
+ const { canvas } = await mountStory(
85
+ composeStory(
86
+ { args: { copy: async () => true, onCopy } },
87
+ meta,
88
+ ),
89
+ )
90
+
91
+ await userEvent.click(
92
+ canvas.getByRole("button", { name: "Copy" }),
93
+ )
94
+
95
+ await expect(onCopy).toHaveBeenCalledWith(true, "335590")
96
+ })
97
+
98
+ /**
99
+ * A focused button whose own accessible name changes is not
100
+ * reliably announced, so the outcome is written into a live region
101
+ * as well.
102
+ */
103
+ test("announces the outcome in a status region", async () => {
104
+ const { canvas } = await mountStory(Confirmed)
105
+
106
+ await expect(
107
+ canvas.getByRole("status"),
108
+ ).toHaveTextContent("Copied to the clipboard.")
109
+ })
110
+
111
+ test("the failure says what to do instead", async () => {
112
+ const { canvas } = await mountStory(Refused)
113
+
114
+ await expect(
115
+ canvas.getByRole("status"),
116
+ ).toHaveTextContent(
117
+ "The clipboard refused. Select the value and press Control C.",
118
+ )
119
+ })
120
+
121
+ /** The confirmation goes back on its own. */
122
+ test("returns to the resting label", async () => {
123
+ const { canvas } = await mountStory(
124
+ composeStory(
125
+ { args: { confirmDuration: 20, copy: () => true } },
126
+ meta,
127
+ ),
128
+ )
129
+
130
+ await userEvent.click(
131
+ canvas.getByRole("button", { name: "Copy" }),
132
+ )
133
+ await expect(
134
+ canvas.getByRole("button", { name: "Copied" }),
135
+ ).toBeVisible()
136
+
137
+ await waitFor(async () => {
138
+ await expect(
139
+ canvas.getByRole("button", { name: "Copy" }),
140
+ ).toBeVisible()
141
+ })
142
+ })
143
+
144
+ /**
145
+ * A caller's `onClick` runs first and can call it off — the escape
146
+ * hatch for "confirm before this leaves the screen".
147
+ */
148
+ test("a prevented click copies nothing", async () => {
149
+ const copy = fn(() => true)
150
+
151
+ const { canvas } = await mountStory(
152
+ composeStory(
153
+ {
154
+ args: {
155
+ copy,
156
+ onClick: (event: MouseEvent) => {
157
+ event.preventDefault()
158
+ },
159
+ },
160
+ },
161
+ meta,
162
+ ),
163
+ )
164
+
165
+ await userEvent.click(
166
+ canvas.getByRole("button", { name: "Copy" }),
167
+ )
168
+
169
+ await expect(copy).not.toHaveBeenCalled()
170
+ })
171
+
172
+ test("has no axe violations", async () => {
173
+ const { canvasElement } = await mountStory(Default)
174
+
175
+ await expectNoAxeViolations(canvasElement)
176
+ })
177
+
178
+ /**
179
+ * `copyText`'s own contract, exercised here rather than in a
180
+ * node-side `.ts` file, because it is a DOM routine and the `ui`
181
+ * project has no DOM.
182
+ *
183
+ * The real clipboard is unavailable in this chromium — the document
184
+ * is not focused, so `navigator.clipboard.writeText` rejects — which
185
+ * makes this an honest test of the fallback chain rather than of the
186
+ * happy path.
187
+ */
188
+ test("copyText reports failure rather than throwing", async () => {
189
+ const execCommand = vi
190
+ .spyOn(document, "execCommand")
191
+ .mockReturnValue(false)
192
+
193
+ await expect(copyText("335590")).resolves.toBe(false)
194
+
195
+ execCommand.mockRestore()
196
+ })
197
+
198
+ test("copyText falls back to the selection route", async () => {
199
+ const execCommand = vi
200
+ .spyOn(document, "execCommand")
201
+ .mockReturnValue(true)
202
+
203
+ await expect(copyText("335590")).resolves.toBe(true)
204
+ await expect(execCommand).toHaveBeenCalledWith("copy")
205
+
206
+ execCommand.mockRestore()
207
+ })
208
+
209
+ /**
210
+ * The textarea is a means, not a side effect. A leaked one is a
211
+ * focusable, screen-reader-visible node holding the copied value,
212
+ * left in the document for good.
213
+ */
214
+ test("copyText leaves no textarea behind", async () => {
215
+ const execCommand = vi
216
+ .spyOn(document, "execCommand")
217
+ .mockImplementation(() => {
218
+ throw new Error("refused mid-copy")
219
+ })
220
+
221
+ await expect(copyText("335590")).resolves.toBe(false)
222
+ await expect(
223
+ document.querySelectorAll("textarea"),
224
+ ).toHaveLength(0)
225
+
226
+ execCommand.mockRestore()
227
+ })
@@ -0,0 +1,155 @@
1
+ import type { ReactNode } from "react"
2
+ import { useEffect, useRef, useState } from "react"
3
+ import type { ButtonProps } from "../Button/Button.tsx"
4
+ import { Button } from "../Button/Button.tsx"
5
+ import { VisuallyHidden } from "../VisuallyHidden/VisuallyHidden.tsx"
6
+ import { copyText as defaultCopyText } from "./copyText.ts"
7
+
8
+ /** Where the button is in the one action it performs. */
9
+ export type CopyStatus = "copied" | "failed" | "idle"
10
+
11
+ export type CopyButtonProps = Omit<
12
+ ButtonProps,
13
+ "children" | "isLoading" | "loadingLabel" | "onCopy"
14
+ > & {
15
+ /**
16
+ * How long the confirmation stays up, in milliseconds.
17
+ *
18
+ * Long enough to be read after the eye has moved back to the form
19
+ * being filled in, short enough that a second copy of a *different*
20
+ * value is not mistaken for the first one's tick.
21
+ */
22
+ confirmDuration?: number
23
+ /** Resting label. A word, not a glyph — this library ships no icons. */
24
+ children?: ReactNode
25
+ /** Shown while the copy is confirmed. */
26
+ copiedLabel?: ReactNode
27
+ /**
28
+ * The clipboard write, injected. Swapped in tests and in a host
29
+ * that owns its own clipboard bridge (Electron, a kiosk shell).
30
+ */
31
+ copy?: (value: string) => Promise<boolean> | boolean
32
+ /** Shown when the clipboard refused. */
33
+ failedLabel?: ReactNode
34
+ /**
35
+ * Told what actually happened, every press.
36
+ *
37
+ * `isCopied` is the point of the callback rather than a detail: a
38
+ * consumer that files the mail away on a copy must not file it away
39
+ * on a copy the browser refused.
40
+ */
41
+ onCopy?: (isCopied: boolean, value: string) => void
42
+ /** The string that goes on the clipboard. */
43
+ value: string
44
+ }
45
+
46
+ /**
47
+ * A button that puts a string on the clipboard and says so.
48
+ *
49
+ * From a consumer, like `Alert` and `BadgeButton` before it: four
50
+ * repos spell this shape by hand — mux-magic's YAML dialog flips its
51
+ * own label on a `setTimeout`, spoolbuddy carries a 15-line
52
+ * `copyToClipboard` with the `execCommand` fallback inline, bambuddy
53
+ * copies a download link from two menus, and mail-sifter's
54
+ * verification-code banner is the fourth. None of the four agree on
55
+ * what happens when the clipboard says no, and three of them cannot
56
+ * tell.
57
+ *
58
+ * **The confirmation is the button, not a toast.** The press and the
59
+ * proof are the same object, so the eye does not travel; a toast is
60
+ * right for something that happened *elsewhere*. A consumer that
61
+ * wants both still gets `onCopy`.
62
+ *
63
+ * **The label is a word.** `Copy` → `Copied`, and the intent goes
64
+ * with it, because a colour change alone is not a message and a tick
65
+ * glyph is an icon this library does not ship.
66
+ *
67
+ * **It announces.** A screen reader is not reliably told that a
68
+ * focused button's own name changed, so the outcome is also written
69
+ * into a `role="status"` region — and the failure says what to do
70
+ * next rather than only that it went wrong.
71
+ *
72
+ * **The timer is cancelled on unmount and on a re-press**, which is
73
+ * the bug in two of the four hand-rolled copies: press, navigate
74
+ * away, and a `setState` lands on nothing.
75
+ */
76
+ export const CopyButton = ({
77
+ appearance = "solid",
78
+ children = "Copy",
79
+ confirmDuration = 2000,
80
+ copiedLabel = "Copied",
81
+ copy = defaultCopyText,
82
+ failedLabel = "Copy failed",
83
+ intent = "accent",
84
+ onClick,
85
+ onCopy,
86
+ value,
87
+ ...buttonProps
88
+ }: CopyButtonProps): ReactNode => {
89
+ const [status, setStatus] = useState<CopyStatus>("idle")
90
+ const timerRef =
91
+ useRef<ReturnType<typeof setTimeout>>(undefined)
92
+
93
+ // One cleanup covers both the unmount and the re-press: every path
94
+ // that starts a timer clears the previous one first.
95
+ useEffect(
96
+ () => () => {
97
+ clearTimeout(timerRef.current)
98
+ },
99
+ [],
100
+ )
101
+
102
+ const settle = (next: CopyStatus) => {
103
+ setStatus(next)
104
+ clearTimeout(timerRef.current)
105
+ timerRef.current = setTimeout(() => {
106
+ setStatus("idle")
107
+ }, confirmDuration)
108
+ }
109
+
110
+ const handleClick: NonNullable<ButtonProps["onClick"]> = (
111
+ event,
112
+ ) => {
113
+ onClick?.(event)
114
+ if (event.defaultPrevented) return
115
+
116
+ void (async () => {
117
+ const isCopied = await copy(value)
118
+ settle(isCopied ? "copied" : "failed")
119
+ onCopy?.(isCopied, value)
120
+ })()
121
+ }
122
+
123
+ const label =
124
+ status === "copied"
125
+ ? copiedLabel
126
+ : status === "failed"
127
+ ? failedLabel
128
+ : children
129
+
130
+ return (
131
+ <>
132
+ <Button
133
+ {...buttonProps}
134
+ appearance={appearance}
135
+ intent={
136
+ status === "copied"
137
+ ? "success"
138
+ : status === "failed"
139
+ ? "danger"
140
+ : intent
141
+ }
142
+ onClick={handleClick}
143
+ >
144
+ {label}
145
+ </Button>
146
+ <VisuallyHidden role="status">
147
+ {status === "copied"
148
+ ? "Copied to the clipboard."
149
+ : status === "failed"
150
+ ? "The clipboard refused. Select the value and press Control C."
151
+ : ""}
152
+ </VisuallyHidden>
153
+ </>
154
+ )
155
+ }
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Put a string on the clipboard, and say whether it landed.
3
+ *
4
+ * Three routes, tried in order, because the fleet runs in all three
5
+ * conditions:
6
+ *
7
+ * 1. **`navigator.clipboard.writeText`.** The real API. It exists
8
+ * only in a *secure context*, which a `devshare` URL and
9
+ * `localhost` both are — and a plain `http://storeman.octen:8080`
10
+ * dev server is not.
11
+ * 2. **A hidden `<textarea>` plus `document.execCommand("copy")`.**
12
+ * Deprecated, and kept anyway: it is the only thing that works in
13
+ * an insecure context, spoolbuddy already hand-rolls exactly this
14
+ * block, and the alternative is a Copy button that silently does
15
+ * nothing on the household's own LAN.
16
+ * 3. **Give up and report it.** A caller that marks mail done on a
17
+ * copy must not mark it done on a copy that never happened.
18
+ *
19
+ * Never throws. The boolean is the whole result, so a call site is an
20
+ * `if` rather than a `try`.
21
+ */
22
+ export const copyText = async (
23
+ value: string,
24
+ ): Promise<boolean> => {
25
+ try {
26
+ // `writeText` rejects on a denied permission and on a document
27
+ // that is not focused — both real, both recoverable below.
28
+ await globalThis.navigator?.clipboard?.writeText(value)
29
+ return true
30
+ } catch {
31
+ // Fall through to the legacy route.
32
+ }
33
+
34
+ return copyBySelection(value)
35
+ }
36
+
37
+ /**
38
+ * The pre-Clipboard-API route.
39
+ *
40
+ * The textarea is positioned off-screen rather than hidden: a
41
+ * `display: none` element has no selection to copy, and
42
+ * `visibility: hidden` is no better. `readOnly` stops the mobile
43
+ * keyboard appearing for the frame it is in the document.
44
+ */
45
+ const copyBySelection = (value: string): boolean => {
46
+ const owner = globalThis.document
47
+ if (!owner?.body) return false
48
+
49
+ const field = owner.createElement("textarea")
50
+ field.value = value
51
+ field.readOnly = true
52
+ field.setAttribute("aria-hidden", "true")
53
+ field.style.position = "fixed"
54
+ field.style.insetInlineStart = "-9999px"
55
+ field.style.top = "0"
56
+
57
+ owner.body.append(field)
58
+
59
+ try {
60
+ field.select()
61
+
62
+ return owner.execCommand("copy")
63
+ } catch {
64
+ return false
65
+ } finally {
66
+ field.remove()
67
+ }
68
+ }
package/src/index.ts CHANGED
@@ -110,6 +110,12 @@ export type {
110
110
  export { ColorSchemeToggle } from "./ColorSchemeToggle/ColorSchemeToggle.tsx"
111
111
  export type { ComboboxProps } from "./Combobox/Combobox.tsx"
112
112
  export { Combobox } from "./Combobox/Combobox.tsx"
113
+ export type {
114
+ CopyButtonProps,
115
+ CopyStatus,
116
+ } from "./CopyButton/CopyButton.tsx"
117
+ export { CopyButton } from "./CopyButton/CopyButton.tsx"
118
+ export { copyText } from "./CopyButton/copyText.ts"
113
119
  export {
114
120
  CATEGORICAL_APPEARANCE_CLASS,
115
121
  CATEGORICAL_CONTENT_CLASS,
@@ -459,7 +459,13 @@ test("the barrel is the only place components are re-exported", async () => {
459
459
  // member of `Badge/` and so stays out of this count and out of the
460
460
  // barrel as a component. Its PROPS type is exported, because a
461
461
  // consumer writing a wrapper needs to name the visual half.
462
- expect(componentNames.length).toBe(53)
462
+ //
463
+ // `CopyButton` — the clipboard write, with a failure state — is
464
+ // +1 -> 54. `copyText.ts` is its member: it stays out of this
465
+ // count by the `<Name>/<Name>.tsx` rule, and it IS exported from
466
+ // the barrel as a function, because a host with its own clipboard
467
+ // bridge needs the fallback chain without the button.
468
+ expect(componentNames.length).toBe(54)
463
469
 
464
470
  for (const name of componentNames) {
465
471
  expect(barrel).toContain(`export { ${name} }`)