@charcuterie/ui 0.1.1 → 1.0.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.
- package/README.md +9 -0
- package/dist/Accordion/Accordion.d.ts +82 -0
- package/dist/Accordion/Accordion.d.ts.map +1 -0
- package/dist/Accordion/Accordion.js +108 -0
- package/dist/Accordion/Accordion.js.map +1 -0
- package/dist/Accordion/AccordionSection.d.ts +28 -0
- package/dist/Accordion/AccordionSection.d.ts.map +1 -0
- package/dist/Accordion/AccordionSection.js +53 -0
- package/dist/Accordion/AccordionSection.js.map +1 -0
- package/dist/Field/Field.d.ts +104 -0
- package/dist/Field/Field.d.ts.map +1 -0
- package/dist/Field/Field.js +115 -0
- package/dist/Field/Field.js.map +1 -0
- package/dist/Field/FieldGroup.d.ts +58 -0
- package/dist/Field/FieldGroup.d.ts.map +1 -0
- package/dist/Field/FieldGroup.js +65 -0
- package/dist/Field/FieldGroup.js.map +1 -0
- package/dist/FileDropZone/FileDropZone.d.ts +63 -0
- package/dist/FileDropZone/FileDropZone.d.ts.map +1 -0
- package/dist/FileDropZone/FileDropZone.js +122 -0
- package/dist/FileDropZone/FileDropZone.js.map +1 -0
- package/dist/LogViewer/LogViewer.d.ts +90 -0
- package/dist/LogViewer/LogViewer.d.ts.map +1 -0
- package/dist/LogViewer/LogViewer.js +165 -0
- package/dist/LogViewer/LogViewer.js.map +1 -0
- package/dist/Menu/Menu.d.ts +81 -0
- package/dist/Menu/Menu.d.ts.map +1 -0
- package/dist/Menu/Menu.js +199 -0
- package/dist/Menu/Menu.js.map +1 -0
- package/dist/Menu/MenuAction.d.ts +24 -0
- package/dist/Menu/MenuAction.d.ts.map +1 -0
- package/dist/Menu/MenuAction.js +37 -0
- package/dist/Menu/MenuAction.js.map +1 -0
- package/dist/Select/Select.d.ts +87 -0
- package/dist/Select/Select.d.ts.map +1 -0
- package/dist/Select/Select.js +51 -0
- package/dist/Select/Select.js.map +1 -0
- package/dist/SortableTableHeader/SortableTableHeader.d.ts +61 -0
- package/dist/SortableTableHeader/SortableTableHeader.d.ts.map +1 -0
- package/dist/SortableTableHeader/SortableTableHeader.js +56 -0
- package/dist/SortableTableHeader/SortableTableHeader.js.map +1 -0
- package/dist/Toast/Toast.d.ts +54 -0
- package/dist/Toast/Toast.d.ts.map +1 -0
- package/dist/Toast/Toast.js +121 -0
- package/dist/Toast/Toast.js.map +1 -0
- package/dist/Toast/ToastRegion.d.ts +57 -0
- package/dist/Toast/ToastRegion.d.ts.map +1 -0
- package/dist/Toast/ToastRegion.js +41 -0
- package/dist/Toast/ToastRegion.js.map +1 -0
- package/dist/Toast/toastLifecycle.d.ts +34 -0
- package/dist/Toast/toastLifecycle.d.ts.map +1 -0
- package/dist/Toast/toastLifecycle.js +25 -0
- package/dist/Toast/toastLifecycle.js.map +1 -0
- package/dist/Tooltip/Tooltip.d.ts +82 -0
- package/dist/Tooltip/Tooltip.d.ts.map +1 -0
- package/dist/Tooltip/Tooltip.js +124 -0
- package/dist/Tooltip/Tooltip.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -1
- package/dist/mountStory.testHelpers.d.ts +0 -11
- package/dist/mountStory.testHelpers.d.ts.map +1 -1
- package/dist/mountStory.testHelpers.js +27 -0
- package/dist/mountStory.testHelpers.js.map +1 -1
- package/dist/slotProps.d.ts +110 -0
- package/dist/slotProps.d.ts.map +1 -0
- package/dist/slotProps.js +39 -0
- package/dist/slotProps.js.map +1 -0
- package/package.json +3 -3
- package/src/Accordion/Accordion.mdx +83 -0
- package/src/Accordion/Accordion.stories.tsx +146 -0
- package/src/Accordion/Accordion.test.tsx +163 -0
- package/src/Accordion/Accordion.tsx +182 -0
- package/src/Accordion/AccordionSection.tsx +163 -0
- package/src/Field/Field.mdx +144 -0
- package/src/Field/Field.stories.tsx +280 -0
- package/src/Field/Field.test.tsx +344 -0
- package/src/Field/Field.tsx +212 -0
- package/src/Field/FieldGroup.tsx +138 -0
- package/src/FileDropZone/FileDropZone.mdx +78 -0
- package/src/FileDropZone/FileDropZone.stories.tsx +136 -0
- package/src/FileDropZone/FileDropZone.test.tsx +230 -0
- package/src/FileDropZone/FileDropZone.tsx +234 -0
- package/src/LogViewer/LogViewer.mdx +123 -0
- package/src/LogViewer/LogViewer.stories.tsx +169 -0
- package/src/LogViewer/LogViewer.test.tsx +236 -0
- package/src/LogViewer/LogViewer.tsx +261 -0
- package/src/Menu/Menu.mdx +103 -0
- package/src/Menu/Menu.stories.tsx +161 -0
- package/src/Menu/Menu.test.tsx +202 -0
- package/src/Menu/Menu.tsx +300 -0
- package/src/Menu/MenuAction.tsx +95 -0
- package/src/Select/Select.mdx +74 -0
- package/src/Select/Select.stories.tsx +126 -0
- package/src/Select/Select.test.tsx +129 -0
- package/src/Select/Select.tsx +200 -0
- package/src/SortableTableHeader/SortableTableHeader.mdx +67 -0
- package/src/SortableTableHeader/SortableTableHeader.stories.tsx +207 -0
- package/src/SortableTableHeader/SortableTableHeader.test.tsx +180 -0
- package/src/SortableTableHeader/SortableTableHeader.tsx +131 -0
- package/src/Toast/Toast.mdx +84 -0
- package/src/Toast/Toast.stories.tsx +192 -0
- package/src/Toast/Toast.test.tsx +217 -0
- package/src/Toast/Toast.tsx +224 -0
- package/src/Toast/ToastRegion.tsx +98 -0
- package/src/Toast/toastLifecycle.ts +45 -0
- package/src/Tooltip/Tooltip.mdx +69 -0
- package/src/Tooltip/Tooltip.stories.tsx +104 -0
- package/src/Tooltip/Tooltip.test.tsx +138 -0
- package/src/Tooltip/Tooltip.tsx +193 -0
- package/src/index.ts +47 -0
- package/src/mountStory.testHelpers.ts +30 -0
- package/src/slotProps.ts +143 -0
- package/src/sourceRules.test.ts +221 -30
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useStatus } from "@charcuterie/logic";
|
|
3
|
+
import { useEffect, useRef } from "react";
|
|
4
|
+
import { IconButton } from "../IconButton/IconButton.js";
|
|
5
|
+
import { INTENT_APPEARANCE_CLASS, INTENT_CONTENT_CLASS, } from "../intentStyles.js";
|
|
6
|
+
import { toClassName } from "../toClassName.js";
|
|
7
|
+
import { toastTransitions } from "./toastLifecycle.js";
|
|
8
|
+
const ENTER_CLASS = {
|
|
9
|
+
entering: "translate-y-2 opacity-0",
|
|
10
|
+
exiting: "translate-y-1 opacity-0",
|
|
11
|
+
removed: "opacity-0",
|
|
12
|
+
visible: "translate-y-0 opacity-100",
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* One toast, and its whole job is the four-state machine the plan
|
|
16
|
+
* specified and M2 left unbuilt.
|
|
17
|
+
*
|
|
18
|
+
* ### Why a `Status`, when a boolean and a timeout would do
|
|
19
|
+
*
|
|
20
|
+
* Because a boolean cannot express *why* the node is still mounted.
|
|
21
|
+
* A toast that is leaving is still painted, still occupies its slot,
|
|
22
|
+
* and must not be announced again — and `isVisible === false` says
|
|
23
|
+
* none of that. The states are what a reader needs to know the
|
|
24
|
+
* difference between "arriving", "leaving", and "gone but not yet
|
|
25
|
+
* unmounted", and `createStatus` makes the illegal ones throw:
|
|
26
|
+
* `visible → removed` skips the exit and is rejected, and `removed`
|
|
27
|
+
* is terminal so a late timer cannot remove the same toast twice.
|
|
28
|
+
*
|
|
29
|
+
* That last one is not hypothetical. Hover-to-pause plus a dismiss
|
|
30
|
+
* button means two independent timers can be in flight, and the
|
|
31
|
+
* hand-rolled version of this component reconciles them with a
|
|
32
|
+
* `clearTimeout` and a ref. Here the second one throws.
|
|
33
|
+
*
|
|
34
|
+
* ### It does not announce itself
|
|
35
|
+
*
|
|
36
|
+
* No `role="status"` and no `aria-live` on this element — the
|
|
37
|
+
* `ToastRegion` around it owns that, and a live region inside a live
|
|
38
|
+
* region is a message announced twice. See that component for the
|
|
39
|
+
* reason there is only ever one, and it is polite.
|
|
40
|
+
*/
|
|
41
|
+
export const Toast = ({ children, className, duration = 5000, exitDuration = 200, intent = "neutral", onRemove, title, }) => {
|
|
42
|
+
const { is, status, transitionTo } = useStatus({
|
|
43
|
+
initialState: "entering",
|
|
44
|
+
transitions: toastTransitions,
|
|
45
|
+
});
|
|
46
|
+
const onRemoveRef = useRef(onRemove);
|
|
47
|
+
onRemoveRef.current = onRemove;
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
if (!is("entering")) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
// A frame, not zero. The element has to be painted in its
|
|
53
|
+
// `entering` position before the class changes, or the browser
|
|
54
|
+
// coalesces both into one style recalculation and there is no
|
|
55
|
+
// transition to see — the single most common reason a CSS
|
|
56
|
+
// enter-animation "does nothing".
|
|
57
|
+
const frame = globalThis.requestAnimationFrame(() => {
|
|
58
|
+
// Guarded, because `is` and `transitionTo` are stable — this
|
|
59
|
+
// effect runs once, so the frame is *not* cancelled when the
|
|
60
|
+
// status changes underneath it. A dismiss during the enter
|
|
61
|
+
// frame moves the toast to `exiting`, and `exiting → visible`
|
|
62
|
+
// is a legal transition (it is how hover-to-pause works), so
|
|
63
|
+
// an unguarded write here brings a dismissed toast straight
|
|
64
|
+
// back and restarts its duration timer.
|
|
65
|
+
if (is("entering")) {
|
|
66
|
+
transitionTo("visible");
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
return () => {
|
|
70
|
+
globalThis.cancelAnimationFrame(frame);
|
|
71
|
+
};
|
|
72
|
+
}, [is, transitionTo]);
|
|
73
|
+
useEffect(() => {
|
|
74
|
+
if (status !== "visible" || duration === 0) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const timer = globalThis.setTimeout(() => {
|
|
78
|
+
transitionTo("exiting");
|
|
79
|
+
}, duration);
|
|
80
|
+
return () => {
|
|
81
|
+
globalThis.clearTimeout(timer);
|
|
82
|
+
};
|
|
83
|
+
}, [duration, status, transitionTo]);
|
|
84
|
+
useEffect(() => {
|
|
85
|
+
if (status !== "exiting") {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const timer = globalThis.setTimeout(() => {
|
|
89
|
+
transitionTo("removed");
|
|
90
|
+
}, exitDuration);
|
|
91
|
+
return () => {
|
|
92
|
+
globalThis.clearTimeout(timer);
|
|
93
|
+
};
|
|
94
|
+
}, [exitDuration, status, transitionTo]);
|
|
95
|
+
useEffect(() => {
|
|
96
|
+
if (status === "removed") {
|
|
97
|
+
onRemoveRef.current();
|
|
98
|
+
}
|
|
99
|
+
}, [status]);
|
|
100
|
+
return (_jsxs("li", { className: toClassName("pointer-events-auto flex items-start gap-3 rounded-md border p-3 shadow-medium transition-[opacity,transform] duration-(--duration-normal) ease-standard", INTENT_APPEARANCE_CLASS[intent].soft, ENTER_CLASS[status], className),
|
|
101
|
+
// Pausing on hover is WCAG 2.2.1's "pause" for a moving
|
|
102
|
+
// deadline, and it is the reason `exiting → visible` is a
|
|
103
|
+
// legal transition rather than an oddity in the table.
|
|
104
|
+
onMouseEnter: () => {
|
|
105
|
+
if (status === "exiting") {
|
|
106
|
+
transitionTo("visible");
|
|
107
|
+
}
|
|
108
|
+
}, children: [_jsxs("div", { className: "flex min-w-0 flex-col gap-0.5", children: [_jsx("span", { className: toClassName("font-medium text-sm", INTENT_CONTENT_CLASS[intent]), children: title }), children === undefined ? null : (_jsx("span", { className: "text-content-secondary text-xs", children: children }))] }), _jsx(IconButton, { appearance: "ghost", className: "ms-auto shrink-0",
|
|
109
|
+
// The name has to be distinct per toast, or a stack of three
|
|
110
|
+
// gives `getByRole("button", { name: "Dismiss" })` three
|
|
111
|
+
// matches and `expectAgentDrivable` fails the story — which
|
|
112
|
+
// is the point of that helper: an agent picking one of three
|
|
113
|
+
// at random is worse than finding none.
|
|
114
|
+
label: `Dismiss ${title}`, onClick: () => {
|
|
115
|
+
if (status !== "exiting" &&
|
|
116
|
+
status !== "removed") {
|
|
117
|
+
transitionTo("exiting");
|
|
118
|
+
}
|
|
119
|
+
}, size: "sm", children: _jsx("svg", { "aria-hidden": "true", className: "size-[1.15em] shrink-0", fill: "none", focusable: false, stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.75, viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg", children: _jsx("path", { d: "m6 6 12 12M18 6 6 18" }) }) })] }));
|
|
120
|
+
};
|
|
121
|
+
//# sourceMappingURL=Toast.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Toast.js","sourceRoot":"","sources":["../../src/Toast/Toast.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { IntentName } from "@charcuterie/tokens";
|
|
2
|
+
import type { ReactNode } from "react";
|
|
3
|
+
export type ToastRecord = {
|
|
4
|
+
description?: ReactNode;
|
|
5
|
+
/** `0` pins this one open. See `Toast`'s `duration`. */
|
|
6
|
+
duration?: number;
|
|
7
|
+
intent?: IntentName;
|
|
8
|
+
key: string;
|
|
9
|
+
title: string;
|
|
10
|
+
};
|
|
11
|
+
export type ToastRegionProps = {
|
|
12
|
+
className?: string;
|
|
13
|
+
/**
|
|
14
|
+
* The region's accessible name. `role="status"` takes **none from
|
|
15
|
+
* its content** — the trap `Spinner` walked into in M3 and
|
|
16
|
+
* `Popover` in M4.
|
|
17
|
+
*/
|
|
18
|
+
label?: string;
|
|
19
|
+
onDismiss: (key: string) => void;
|
|
20
|
+
toasts: ToastRecord[];
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* The live region, and the list is the caller's.
|
|
24
|
+
*
|
|
25
|
+
* ### One region, and it is polite
|
|
26
|
+
*
|
|
27
|
+
* Not two. The usual arrangement — a polite region and an assertive
|
|
28
|
+
* one, so a danger toast interrupts — was rejected because the
|
|
29
|
+
* interrupting case does not belong in a toast at all. A message
|
|
30
|
+
* that must be heard *now* is one the user has to be able to go back
|
|
31
|
+
* and read, and a toast is gone in five seconds; if it matters that
|
|
32
|
+
* much it is an `Alert` on the page, which this library already
|
|
33
|
+
* ships and which stays put.
|
|
34
|
+
*
|
|
35
|
+
* That is the same line `Field` draws for its error text, and it is
|
|
36
|
+
* worth keeping the two consistent: **this library announces once,
|
|
37
|
+
* in the place the user can act on it.**
|
|
38
|
+
*
|
|
39
|
+
* ### The stack does not own the toasts
|
|
40
|
+
*
|
|
41
|
+
* `toasts` comes in and `onDismiss` goes out — there is no
|
|
42
|
+
* `toast()` function, no imperative queue, and no context provider.
|
|
43
|
+
* An app already has a store (mux-magic has Jotai, rip-deck has its
|
|
44
|
+
* own), and a component library that ships a second one is asking
|
|
45
|
+
* every consumer to keep two lists of the same notifications in
|
|
46
|
+
* sync. The lifecycle *inside* one toast is state a store cannot
|
|
47
|
+
* see, which is why `Toast` owns that and nothing more.
|
|
48
|
+
*
|
|
49
|
+
* ### `pointer-events-none` on the container, `auto` on each toast
|
|
50
|
+
*
|
|
51
|
+
* A fixed overlay across the bottom of the viewport swallows every
|
|
52
|
+
* click in that band, including on the app behind it, and it does so
|
|
53
|
+
* invisibly. The container passes clicks through and each toast
|
|
54
|
+
* takes them back.
|
|
55
|
+
*/
|
|
56
|
+
export declare const ToastRegion: ({ className, label, onDismiss, toasts, }: ToastRegionProps) => ReactNode;
|
|
57
|
+
//# sourceMappingURL=ToastRegion.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ToastRegion.d.ts","sourceRoot":"","sources":["../../src/Toast/ToastRegion.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AACrD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAKtC,MAAM,MAAM,WAAW,GAAG;IACxB,WAAW,CAAC,EAAE,SAAS,CAAA;IACvB,wDAAwD;IACxD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,UAAU,CAAA;IACnB,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;IAChC,MAAM,EAAE,WAAW,EAAE,CAAA;CACtB,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,eAAO,MAAM,WAAW,GAAI,0CAKzB,gBAAgB,KAAG,SA+BrB,CAAA"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { toClassName } from "../toClassName.js";
|
|
3
|
+
import { Toast } from "./Toast.js";
|
|
4
|
+
/**
|
|
5
|
+
* The live region, and the list is the caller's.
|
|
6
|
+
*
|
|
7
|
+
* ### One region, and it is polite
|
|
8
|
+
*
|
|
9
|
+
* Not two. The usual arrangement — a polite region and an assertive
|
|
10
|
+
* one, so a danger toast interrupts — was rejected because the
|
|
11
|
+
* interrupting case does not belong in a toast at all. A message
|
|
12
|
+
* that must be heard *now* is one the user has to be able to go back
|
|
13
|
+
* and read, and a toast is gone in five seconds; if it matters that
|
|
14
|
+
* much it is an `Alert` on the page, which this library already
|
|
15
|
+
* ships and which stays put.
|
|
16
|
+
*
|
|
17
|
+
* That is the same line `Field` draws for its error text, and it is
|
|
18
|
+
* worth keeping the two consistent: **this library announces once,
|
|
19
|
+
* in the place the user can act on it.**
|
|
20
|
+
*
|
|
21
|
+
* ### The stack does not own the toasts
|
|
22
|
+
*
|
|
23
|
+
* `toasts` comes in and `onDismiss` goes out — there is no
|
|
24
|
+
* `toast()` function, no imperative queue, and no context provider.
|
|
25
|
+
* An app already has a store (mux-magic has Jotai, rip-deck has its
|
|
26
|
+
* own), and a component library that ships a second one is asking
|
|
27
|
+
* every consumer to keep two lists of the same notifications in
|
|
28
|
+
* sync. The lifecycle *inside* one toast is state a store cannot
|
|
29
|
+
* see, which is why `Toast` owns that and nothing more.
|
|
30
|
+
*
|
|
31
|
+
* ### `pointer-events-none` on the container, `auto` on each toast
|
|
32
|
+
*
|
|
33
|
+
* A fixed overlay across the bottom of the viewport swallows every
|
|
34
|
+
* click in that band, including on the app behind it, and it does so
|
|
35
|
+
* invisibly. The container passes clicks through and each toast
|
|
36
|
+
* takes them back.
|
|
37
|
+
*/
|
|
38
|
+
export const ToastRegion = ({ className, label = "Notifications", onDismiss, toasts, }) => (_jsx("div", { "aria-label": label, "aria-atomic": "false", className: toClassName("pointer-events-none fixed inset-x-0 bottom-0 z-50 flex flex-col items-center gap-2 p-4", className), role: "status", children: _jsx("ul", { className: "pointer-events-none flex w-full max-w-sm list-none flex-col gap-2 p-0", children: toasts.map((toast) => (_jsx(Toast, { duration: toast.duration, intent: toast.intent, onRemove: () => {
|
|
39
|
+
onDismiss(toast.key);
|
|
40
|
+
}, title: toast.title, children: toast.description }, toast.key))) }) }));
|
|
41
|
+
//# sourceMappingURL=ToastRegion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ToastRegion.js","sourceRoot":"","sources":["../../src/Toast/ToastRegion.tsx"],"names":[],"mappings":";AAGA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAa,CAAA;AAuBnC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,EAC1B,SAAS,EACT,KAAK,GAAG,eAAe,EACvB,SAAS,EACT,MAAM,GACW,EAAa,EAAE,CAAC,CACjC,4BACc,KAAK,iBAML,OAAO,EACnB,SAAS,EAAE,WAAW,CACpB,wFAAwF,EACxF,SAAS,CACV,EACD,IAAI,EAAC,QAAQ,YAEb,aAAI,SAAS,EAAC,uEAAuE,YAClF,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CACrB,KAAC,KAAK,IACJ,QAAQ,EAAE,KAAK,CAAC,QAAQ,EACxB,MAAM,EAAE,KAAK,CAAC,MAAM,EAEpB,QAAQ,EAAE,GAAG,EAAE;gBACb,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;YACtB,CAAC,EACD,KAAK,EAAE,KAAK,CAAC,KAAK,YAEjB,KAAK,CAAC,WAAW,IANb,KAAK,CAAC,GAAG,CAOR,CACT,CAAC,GACC,GACD,CACP,CAAA"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { StatusTransitions } from "@charcuterie/logic";
|
|
2
|
+
/**
|
|
3
|
+
* The one machine the plan wrote down and M2 did not build:
|
|
4
|
+
*
|
|
5
|
+
* > | Toast lifecycle | entering → visible → exiting → removed |
|
|
6
|
+
*
|
|
7
|
+
* It is here rather than in `@charcuterie/logic/core` beside
|
|
8
|
+
* `asyncTransitions` and `connectionTransitions` on purpose. Those
|
|
9
|
+
* two describe *data* — a fetch, a socket — and a Preact app with no
|
|
10
|
+
* components at all still wants them. This one describes an
|
|
11
|
+
* **animation**, which only exists because something is being
|
|
12
|
+
* painted, so it belongs to the component layer.
|
|
13
|
+
*/
|
|
14
|
+
export type ToastStatus = "entering" | "exiting" | "removed" | "visible";
|
|
15
|
+
/**
|
|
16
|
+
* `visible → removed` is deliberately **not** a legal transition,
|
|
17
|
+
* and neither is anything out of `removed`.
|
|
18
|
+
*
|
|
19
|
+
* The first means a toast cannot skip its exit — a dismissal that
|
|
20
|
+
* unmounts the node immediately is the flicker every hand-rolled
|
|
21
|
+
* toast stack has, and making it illegal turns that into a thrown
|
|
22
|
+
* error in a test rather than a jump nobody files.
|
|
23
|
+
*
|
|
24
|
+
* The second makes `removed` terminal, which is what lets the region
|
|
25
|
+
* call `onDismiss` exactly once. `createStatus` throws on an illegal
|
|
26
|
+
* transition, so a second timer firing after the first is a loud
|
|
27
|
+
* failure instead of a duplicate removal.
|
|
28
|
+
*
|
|
29
|
+
* `exiting → visible` **is** legal: pointing at a toast that is
|
|
30
|
+
* already sliding away has to bring it back, or the user is chasing
|
|
31
|
+
* a disappearing message with the cursor.
|
|
32
|
+
*/
|
|
33
|
+
export declare const toastTransitions: StatusTransitions<ToastStatus>;
|
|
34
|
+
//# sourceMappingURL=toastLifecycle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toastLifecycle.d.ts","sourceRoot":"","sources":["../../src/Toast/toastLifecycle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAE3D;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,WAAW,GACnB,UAAU,GACV,SAAS,GACT,SAAS,GACT,SAAS,CAAA;AAEb;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,gBAAgB,EAAE,iBAAiB,CAAC,WAAW,CAMzD,CAAA"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `visible → removed` is deliberately **not** a legal transition,
|
|
3
|
+
* and neither is anything out of `removed`.
|
|
4
|
+
*
|
|
5
|
+
* The first means a toast cannot skip its exit — a dismissal that
|
|
6
|
+
* unmounts the node immediately is the flicker every hand-rolled
|
|
7
|
+
* toast stack has, and making it illegal turns that into a thrown
|
|
8
|
+
* error in a test rather than a jump nobody files.
|
|
9
|
+
*
|
|
10
|
+
* The second makes `removed` terminal, which is what lets the region
|
|
11
|
+
* call `onDismiss` exactly once. `createStatus` throws on an illegal
|
|
12
|
+
* transition, so a second timer firing after the first is a loud
|
|
13
|
+
* failure instead of a duplicate removal.
|
|
14
|
+
*
|
|
15
|
+
* `exiting → visible` **is** legal: pointing at a toast that is
|
|
16
|
+
* already sliding away has to bring it back, or the user is chasing
|
|
17
|
+
* a disappearing message with the cursor.
|
|
18
|
+
*/
|
|
19
|
+
export const toastTransitions = {
|
|
20
|
+
entering: ["visible", "exiting"],
|
|
21
|
+
exiting: ["removed", "visible"],
|
|
22
|
+
removed: [],
|
|
23
|
+
visible: ["exiting"],
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=toastLifecycle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toastLifecycle.js","sourceRoot":"","sources":["../../src/Toast/toastLifecycle.ts"],"names":[],"mappings":"AAoBA;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAC3B;IACE,QAAQ,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC;IAChC,OAAO,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC;IAC/B,OAAO,EAAE,EAAE;IACX,OAAO,EAAE,CAAC,SAAS,CAAC;CACrB,CAAA"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { Placement } from "@floating-ui/react";
|
|
2
|
+
import type { ReactElement, ReactNode } from "react";
|
|
3
|
+
import type { SlotProps } from "../slotProps.ts";
|
|
4
|
+
export type TooltipProps = SlotProps & {
|
|
5
|
+
/**
|
|
6
|
+
* The control the tip describes. **Cloned, not wrapped** — the
|
|
7
|
+
* same slot contract as `Popover`'s trigger.
|
|
8
|
+
*
|
|
9
|
+
* It has to be something focusable. A tooltip on a `<span>` is
|
|
10
|
+
* pointer-only, which is the state mux-magic's is in today.
|
|
11
|
+
*/
|
|
12
|
+
children: ReactElement;
|
|
13
|
+
className?: string;
|
|
14
|
+
/** Milliseconds of hover before it opens. */
|
|
15
|
+
delay?: number;
|
|
16
|
+
/**
|
|
17
|
+
* Text, and text only. `role="tooltip"` has no way to move focus
|
|
18
|
+
* into itself, so a link or a button inside one is unreachable by
|
|
19
|
+
* keyboard and unreadable by touch — if it needs a control, it is
|
|
20
|
+
* a `Popover`.
|
|
21
|
+
*/
|
|
22
|
+
label: string;
|
|
23
|
+
placement?: Placement;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Replaces mux-magic's `FieldTooltip`, which is 130 lines of
|
|
27
|
+
* hand-rolled positioning — a `computePosition` that reimplements
|
|
28
|
+
* `flip` and `shift` against `window.innerHeight` — and has three
|
|
29
|
+
* defects that all render perfectly:
|
|
30
|
+
*
|
|
31
|
+
* 1. **Nothing references the tip.** It sets `role="tooltip"` and
|
|
32
|
+
* no `aria-describedby` anywhere, so the control it belongs to
|
|
33
|
+
* never mentions it. A screen reader reads the button, says
|
|
34
|
+
* nothing about the tip, and the tip itself is a floating node
|
|
35
|
+
* nobody is pointed at. `role="tooltip"` is not a live region;
|
|
36
|
+
* it does nothing on its own.
|
|
37
|
+
* 2. **Pointer only.** `onPointerEnter`/`onPointerLeave` with no
|
|
38
|
+
* `onFocus`/`onBlur`, so a keyboard user cannot open it at all.
|
|
39
|
+
* 3. **No dismiss.** Escape does nothing, which WCAG 1.4.13
|
|
40
|
+
* requires of any content shown on hover.
|
|
41
|
+
*
|
|
42
|
+
* All three come from the same place: the ARIA is written by hand
|
|
43
|
+
* beside the behaviour instead of falling out of it. Here `useRole`
|
|
44
|
+
* writes `aria-describedby` on the trigger and `role` + `id` on the
|
|
45
|
+
* tip from one source, `useFocus` is what makes it keyboard-openable,
|
|
46
|
+
* and `useDismiss` is Escape.
|
|
47
|
+
*
|
|
48
|
+
* ### Not a `title`, and not a substitute for a name
|
|
49
|
+
*
|
|
50
|
+
* A `title` attribute is unstyleable, has a ~1s delay nobody can
|
|
51
|
+
* change, and does not exist on touch. `Badge` still uses one — for
|
|
52
|
+
* a *truncation* readout, where the full text is already in
|
|
53
|
+
* `textContent` and the tip is a convenience
|
|
54
|
+
* ([decision](../../../docs/decisions/2026-07-30-a-badge-truncates-with-text-overflow.md)).
|
|
55
|
+
* That is the line: a `title` may repeat something already
|
|
56
|
+
* available, and a `Tooltip` may add something, but **neither may be
|
|
57
|
+
* the only place a control's name exists**. An icon button still
|
|
58
|
+
* needs its `aria-label`; the tip is extra.
|
|
59
|
+
*
|
|
60
|
+
* ### Touch has no hover, and this component does not pretend
|
|
61
|
+
*
|
|
62
|
+
* There is no long-press fallback here. A tooltip is supplementary
|
|
63
|
+
* by construction, so on the kiosk it simply never appears, and
|
|
64
|
+
* anything a touch user *must* read belongs in a `Field`'s
|
|
65
|
+
* `description` instead. Building a long-press would make the tip
|
|
66
|
+
* load-bearing on exactly the surface where it is least reliable.
|
|
67
|
+
*
|
|
68
|
+
* ### A slot is a pass-through
|
|
69
|
+
*
|
|
70
|
+
* A `Tooltip` is the natural thing to put between a `Field` and its
|
|
71
|
+
* control — mux-magic's `FieldLabel` renders a `FieldTooltip` for
|
|
72
|
+
* exactly that reason. Both components clone onto their one child, so
|
|
73
|
+
* an outer `Field` used to hand *this component* the `id`,
|
|
74
|
+
* `aria-describedby`, `aria-invalid` and `required` meant for the
|
|
75
|
+
* `<input>`, and this component dropped all four without a word.
|
|
76
|
+
*
|
|
77
|
+
* Anything in `SlotProps` that arrives from above is forwarded to the
|
|
78
|
+
* trigger, and `aria-describedby` is **merged** with the tip's own id
|
|
79
|
+
* rather than overwriting it. `slotProps.ts` has the reasoning.
|
|
80
|
+
*/
|
|
81
|
+
export declare const Tooltip: ({ children, className, delay, label, placement, ...receivedSlotProps }: TooltipProps) => ReactNode;
|
|
82
|
+
//# sourceMappingURL=Tooltip.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Tooltip.d.ts","sourceRoot":"","sources":["../../src/Tooltip/Tooltip.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAanD,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEpD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAIhD,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG;IACrC;;;;;;OAMG;IACH,QAAQ,EAAE,YAAY,CAAA;IACtB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,6CAA6C;IAC7C,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;;;OAKG;IACH,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,CAAC,EAAE,SAAS,CAAA;CACtB,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AACH,eAAO,MAAM,OAAO,GAAI,wEAOrB,YAAY,KAAG,SAoFjB,CAAA"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useClonedChild, useVisibility, } from "@charcuterie/logic";
|
|
3
|
+
import { autoUpdate, flip, offset, shift, useDismiss, useFloating, useFocus, useHover, useInteractions, useRole, } from "@floating-ui/react";
|
|
4
|
+
import { mergeSlotProps } from "../slotProps.js";
|
|
5
|
+
import { toClassName } from "../toClassName.js";
|
|
6
|
+
/**
|
|
7
|
+
* Replaces mux-magic's `FieldTooltip`, which is 130 lines of
|
|
8
|
+
* hand-rolled positioning — a `computePosition` that reimplements
|
|
9
|
+
* `flip` and `shift` against `window.innerHeight` — and has three
|
|
10
|
+
* defects that all render perfectly:
|
|
11
|
+
*
|
|
12
|
+
* 1. **Nothing references the tip.** It sets `role="tooltip"` and
|
|
13
|
+
* no `aria-describedby` anywhere, so the control it belongs to
|
|
14
|
+
* never mentions it. A screen reader reads the button, says
|
|
15
|
+
* nothing about the tip, and the tip itself is a floating node
|
|
16
|
+
* nobody is pointed at. `role="tooltip"` is not a live region;
|
|
17
|
+
* it does nothing on its own.
|
|
18
|
+
* 2. **Pointer only.** `onPointerEnter`/`onPointerLeave` with no
|
|
19
|
+
* `onFocus`/`onBlur`, so a keyboard user cannot open it at all.
|
|
20
|
+
* 3. **No dismiss.** Escape does nothing, which WCAG 1.4.13
|
|
21
|
+
* requires of any content shown on hover.
|
|
22
|
+
*
|
|
23
|
+
* All three come from the same place: the ARIA is written by hand
|
|
24
|
+
* beside the behaviour instead of falling out of it. Here `useRole`
|
|
25
|
+
* writes `aria-describedby` on the trigger and `role` + `id` on the
|
|
26
|
+
* tip from one source, `useFocus` is what makes it keyboard-openable,
|
|
27
|
+
* and `useDismiss` is Escape.
|
|
28
|
+
*
|
|
29
|
+
* ### Not a `title`, and not a substitute for a name
|
|
30
|
+
*
|
|
31
|
+
* A `title` attribute is unstyleable, has a ~1s delay nobody can
|
|
32
|
+
* change, and does not exist on touch. `Badge` still uses one — for
|
|
33
|
+
* a *truncation* readout, where the full text is already in
|
|
34
|
+
* `textContent` and the tip is a convenience
|
|
35
|
+
* ([decision](../../../docs/decisions/2026-07-30-a-badge-truncates-with-text-overflow.md)).
|
|
36
|
+
* That is the line: a `title` may repeat something already
|
|
37
|
+
* available, and a `Tooltip` may add something, but **neither may be
|
|
38
|
+
* the only place a control's name exists**. An icon button still
|
|
39
|
+
* needs its `aria-label`; the tip is extra.
|
|
40
|
+
*
|
|
41
|
+
* ### Touch has no hover, and this component does not pretend
|
|
42
|
+
*
|
|
43
|
+
* There is no long-press fallback here. A tooltip is supplementary
|
|
44
|
+
* by construction, so on the kiosk it simply never appears, and
|
|
45
|
+
* anything a touch user *must* read belongs in a `Field`'s
|
|
46
|
+
* `description` instead. Building a long-press would make the tip
|
|
47
|
+
* load-bearing on exactly the surface where it is least reliable.
|
|
48
|
+
*
|
|
49
|
+
* ### A slot is a pass-through
|
|
50
|
+
*
|
|
51
|
+
* A `Tooltip` is the natural thing to put between a `Field` and its
|
|
52
|
+
* control — mux-magic's `FieldLabel` renders a `FieldTooltip` for
|
|
53
|
+
* exactly that reason. Both components clone onto their one child, so
|
|
54
|
+
* an outer `Field` used to hand *this component* the `id`,
|
|
55
|
+
* `aria-describedby`, `aria-invalid` and `required` meant for the
|
|
56
|
+
* `<input>`, and this component dropped all four without a word.
|
|
57
|
+
*
|
|
58
|
+
* Anything in `SlotProps` that arrives from above is forwarded to the
|
|
59
|
+
* trigger, and `aria-describedby` is **merged** with the tip's own id
|
|
60
|
+
* rather than overwriting it. `slotProps.ts` has the reasoning.
|
|
61
|
+
*/
|
|
62
|
+
export const Tooltip = ({ children, className, delay = 200, label, placement = "top", ...receivedSlotProps }) => {
|
|
63
|
+
const { isVisible, setIsVisible } = useVisibility();
|
|
64
|
+
const { context, floatingStyles, refs } = useFloating({
|
|
65
|
+
// Read-only, as everywhere: floating-ui is told what is true and
|
|
66
|
+
// never decides it.
|
|
67
|
+
open: isVisible,
|
|
68
|
+
onOpenChange: setIsVisible,
|
|
69
|
+
placement,
|
|
70
|
+
middleware: [offset(6), flip(), shift({ padding: 8 })],
|
|
71
|
+
strategy: "fixed",
|
|
72
|
+
whileElementsMounted: autoUpdate,
|
|
73
|
+
});
|
|
74
|
+
const { getFloatingProps, getReferenceProps } = useInteractions([
|
|
75
|
+
useHover(context, {
|
|
76
|
+
// `move: false` — a tooltip that re-opens because the
|
|
77
|
+
// pointer twitched inside the trigger is the flicker every
|
|
78
|
+
// hand-rolled one has.
|
|
79
|
+
move: false,
|
|
80
|
+
restMs: delay,
|
|
81
|
+
}),
|
|
82
|
+
// The line mux-magic is missing. Without it the tip is
|
|
83
|
+
// pointer-only, which is a WCAG 2.1.1 failure on a control
|
|
84
|
+
// whose explanation lives there.
|
|
85
|
+
useFocus(context),
|
|
86
|
+
useDismiss(context, { referencePress: false }),
|
|
87
|
+
useRole(context, { role: "tooltip" }),
|
|
88
|
+
]);
|
|
89
|
+
const clonedTrigger = useClonedChild(children,
|
|
90
|
+
// `mergeSlotProps` rather than a spread, because
|
|
91
|
+
// `getReferenceProps()` writes an `aria-describedby` of its own —
|
|
92
|
+
// `useRole` pointing the trigger at the tip — and an outer
|
|
93
|
+
// `Field` writes one naming its description and its error. A
|
|
94
|
+
// spread keeps whichever went last.
|
|
95
|
+
mergeSlotProps(receivedSlotProps, {
|
|
96
|
+
...getReferenceProps(),
|
|
97
|
+
ref: refs.setReference,
|
|
98
|
+
}));
|
|
99
|
+
return (_jsxs(_Fragment, { children: [clonedTrigger, isVisible ? (_jsx("div", { ...getFloatingProps(), className: toClassName(
|
|
100
|
+
// `intent-neutral-solid` + its own `on-solid`, rather
|
|
101
|
+
// than `surface-inverse` + `content-on-accent`. The
|
|
102
|
+
// second pair looks like the obvious one and is not a
|
|
103
|
+
// *pair* at all — nothing in the token set promises those
|
|
104
|
+
// two contrast, and in `daylight` dark they land at
|
|
105
|
+
// 2.9:1. The `solid`/`on-solid` roles exist precisely to
|
|
106
|
+
// be a guaranteed couple, and the contrast gate checks
|
|
107
|
+
// them as one.
|
|
108
|
+
"inset-auto m-0 max-w-xs rounded-md bg-intent-neutral-solid px-2 py-1 text-intent-neutral-on-solid text-xs shadow-medium", className),
|
|
109
|
+
// No `popover="manual"` and no `FloatingFocusManager`,
|
|
110
|
+
// unlike `Popover`. Both exist to manage focus, and focus
|
|
111
|
+
// never enters a tooltip — moving it here is what makes
|
|
112
|
+
// one unescapable. The trade is that a tooltip is not in
|
|
113
|
+
// the top layer, so it can be clipped by an
|
|
114
|
+
// `overflow: hidden` ancestor; `strategy: "fixed"` keeps
|
|
115
|
+
// that to ancestors that actually clip fixed descendants.
|
|
116
|
+
ref: refs.setFloating,
|
|
117
|
+
// Duplicated from `getFloatingProps()` deliberately, and
|
|
118
|
+
// the two cannot differ — `useRole(context, { role:
|
|
119
|
+
// "tooltip" })` above is where it comes from. Stated here
|
|
120
|
+
// because a linter cannot see a role through a spread, and
|
|
121
|
+
// neither can the next reader.
|
|
122
|
+
role: "tooltip", style: floatingStyles, children: label })) : null] }));
|
|
123
|
+
};
|
|
124
|
+
//# sourceMappingURL=Tooltip.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Tooltip.js","sourceRoot":"","sources":["../../src/Tooltip/Tooltip.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,cAAc,EACd,aAAa,GACd,MAAM,oBAAoB,CAAA;AAE3B,OAAO,EACL,UAAU,EACV,IAAI,EACJ,MAAM,EACN,KAAK,EACL,UAAU,EACV,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,eAAe,EACf,OAAO,GACR,MAAM,oBAAoB,CAAA;AAI3B,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAwB/C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,EACtB,QAAQ,EACR,SAAS,EACT,KAAK,GAAG,GAAG,EACX,KAAK,EACL,SAAS,GAAG,KAAK,EACjB,GAAG,iBAAiB,EACP,EAAa,EAAE;IAC5B,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,GAAG,aAAa,EAAE,CAAA;IAEnD,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,GAAG,WAAW,CAAC;QACpD,iEAAiE;QACjE,oBAAoB;QACpB,IAAI,EAAE,SAAS;QACf,YAAY,EAAE,YAAY;QAC1B,SAAS;QACT,UAAU,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;QACtD,QAAQ,EAAE,OAAO;QACjB,oBAAoB,EAAE,UAAU;KACjC,CAAC,CAAA;IAEF,MAAM,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,GAC3C,eAAe,CAAC;QACd,QAAQ,CAAC,OAAO,EAAE;YAChB,sDAAsD;YACtD,2DAA2D;YAC3D,uBAAuB;YACvB,IAAI,EAAE,KAAK;YACX,MAAM,EAAE,KAAK;SACd,CAAC;QACF,uDAAuD;QACvD,2DAA2D;QAC3D,iCAAiC;QACjC,QAAQ,CAAC,OAAO,CAAC;QACjB,UAAU,CAAC,OAAO,EAAE,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC;QAC9C,OAAO,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;KACtC,CAAC,CAAA;IAEJ,MAAM,aAAa,GAAG,cAAc,CAClC,QAAQ;IACR,iDAAiD;IACjD,kEAAkE;IAClE,2DAA2D;IAC3D,6DAA6D;IAC7D,oCAAoC;IACpC,cAAc,CAAC,iBAAiB,EAAE;QAChC,GAAG,iBAAiB,EAAE;QACtB,GAAG,EAAE,IAAI,CAAC,YAAY;KACvB,CAAC,CACH,CAAA;IAED,OAAO,CACL,8BACG,aAAa,EAEb,SAAS,CAAC,CAAC,CAAC,CACX,iBACM,gBAAgB,EAAE,EACtB,SAAS,EAAE,WAAW;gBACpB,sDAAsD;gBACtD,oDAAoD;gBACpD,sDAAsD;gBACtD,0DAA0D;gBAC1D,oDAAoD;gBACpD,yDAAyD;gBACzD,uDAAuD;gBACvD,eAAe;gBACf,yHAAyH,EACzH,SAAS,CACV;gBACD,uDAAuD;gBACvD,0DAA0D;gBAC1D,wDAAwD;gBACxD,yDAAyD;gBACzD,4CAA4C;gBAC5C,yDAAyD;gBACzD,0DAA0D;gBAC1D,GAAG,EAAE,IAAI,CAAC,WAAW;gBACrB,yDAAyD;gBACzD,oDAAoD;gBACpD,0DAA0D;gBAC1D,2DAA2D;gBAC3D,+BAA+B;gBAC/B,IAAI,EAAC,SAAS,EACd,KAAK,EAAE,cAAc,YAEpB,KAAK,GACF,CACP,CAAC,CAAC,CAAC,IAAI,IACP,CACJ,CAAA;AACH,CAAC,CAAA"}
|
package/dist/index.d.ts
CHANGED
|
@@ -30,6 +30,8 @@
|
|
|
30
30
|
* `@charcuterie/tokens/theme.css` by its own name, which is what
|
|
31
31
|
* this package's README has always told it to do.
|
|
32
32
|
*/
|
|
33
|
+
export type { AccordionHeadingLevel, AccordionItem, AccordionProps, } from "./Accordion/Accordion.tsx";
|
|
34
|
+
export { Accordion } from "./Accordion/Accordion.tsx";
|
|
33
35
|
export type { AlertProps, AlertSize, } from "./Alert/Alert.tsx";
|
|
34
36
|
export { Alert } from "./Alert/Alert.tsx";
|
|
35
37
|
export type { BadgeProps } from "./Badge/Badge.tsx";
|
|
@@ -42,16 +44,26 @@ export type { BadgeSize } from "./controlStyles.ts";
|
|
|
42
44
|
export { BADGE_SIZE_CLASS, CONTROL_SIZE_CLASS, DOT_SIZE_CLASS, ICON_CONTROL_SIZE_CLASS, MIN_TOUCH_TARGET_CLASS, SPINNER_SIZE_CLASS, } from "./controlStyles.ts";
|
|
43
45
|
export type { EmptyStateProps, EmptyStateSize, } from "./EmptyState/EmptyState.tsx";
|
|
44
46
|
export { EmptyState } from "./EmptyState/EmptyState.tsx";
|
|
47
|
+
export type { FieldProps } from "./Field/Field.tsx";
|
|
48
|
+
export { Field } from "./Field/Field.tsx";
|
|
49
|
+
export type { FieldGroupProps } from "./Field/FieldGroup.tsx";
|
|
50
|
+
export { FieldGroup } from "./Field/FieldGroup.tsx";
|
|
51
|
+
export type { FileDropZoneProps } from "./FileDropZone/FileDropZone.tsx";
|
|
52
|
+
export { FileDropZone } from "./FileDropZone/FileDropZone.tsx";
|
|
45
53
|
export type { IconButtonProps } from "./IconButton/IconButton.tsx";
|
|
46
54
|
export { IconButton } from "./IconButton/IconButton.tsx";
|
|
47
55
|
export type { IntentAppearance } from "./intentStyles.ts";
|
|
48
56
|
export { DISABLED_CLASS, FOCUS_RING_CLASS, INTENT_APPEARANCE_CLASS, INTENT_CONTENT_CLASS, INTENT_HOVER_CLASS, INTENT_SOLID_FILL_CLASS, } from "./intentStyles.ts";
|
|
49
57
|
export type { LiveStatusIndicatorProps, LiveStatusIndicatorSize, } from "./LiveStatusIndicator/LiveStatusIndicator.tsx";
|
|
50
58
|
export { LiveStatusIndicator } from "./LiveStatusIndicator/LiveStatusIndicator.tsx";
|
|
59
|
+
export type { LogLine, LogViewerProps, } from "./LogViewer/LogViewer.tsx";
|
|
60
|
+
export { LogViewer } from "./LogViewer/LogViewer.tsx";
|
|
51
61
|
export type { MediaTileProps, MediaTileRatio, } from "./MediaTile/MediaTile.tsx";
|
|
52
62
|
export { MediaTile } from "./MediaTile/MediaTile.tsx";
|
|
53
63
|
export type { MediaStatus } from "./MediaTile/mediaStatus.ts";
|
|
54
64
|
export { mediaTransitions } from "./MediaTile/mediaStatus.ts";
|
|
65
|
+
export type { MenuItem, MenuProps, } from "./Menu/Menu.tsx";
|
|
66
|
+
export { Menu } from "./Menu/Menu.tsx";
|
|
55
67
|
export type { ModalProps, ModalSize, } from "./Modal/Modal.tsx";
|
|
56
68
|
export { Modal } from "./Modal/Modal.tsx";
|
|
57
69
|
export type { PopoverProps } from "./Popover/Popover.tsx";
|
|
@@ -62,13 +74,27 @@ export type { ProgressThreshold } from "./ProgressBar/progressValue.ts";
|
|
|
62
74
|
export { getProgressIntent, toProgressPercent, toProgressValue, } from "./ProgressBar/progressValue.ts";
|
|
63
75
|
export type { SegmentedControlProps, SegmentedItem, } from "./SegmentedControl/SegmentedControl.tsx";
|
|
64
76
|
export { SegmentedControl } from "./SegmentedControl/SegmentedControl.tsx";
|
|
77
|
+
export type { SelectItem, SelectOption, SelectOptionGroup, SelectProps, } from "./Select/Select.tsx";
|
|
78
|
+
export { Select } from "./Select/Select.tsx";
|
|
65
79
|
export type { SkeletonProps, SkeletonShape, } from "./Skeleton/Skeleton.tsx";
|
|
66
80
|
export { Skeleton } from "./Skeleton/Skeleton.tsx";
|
|
81
|
+
export type { SortableTableHeaderProps, SortDirection, } from "./SortableTableHeader/SortableTableHeader.tsx";
|
|
82
|
+
export { SortableTableHeader } from "./SortableTableHeader/SortableTableHeader.tsx";
|
|
67
83
|
export type { SpinnerProps } from "./Spinner/Spinner.tsx";
|
|
68
84
|
export { Spinner } from "./Spinner/Spinner.tsx";
|
|
85
|
+
export type { SlotProps } from "./slotProps.ts";
|
|
86
|
+
export { mergeSlotProps } from "./slotProps.ts";
|
|
69
87
|
export { getAsyncIntent, getAsyncLabel, getConnectionIntent, getConnectionLabel, getIsConnectionBusy, } from "./statusIntent.ts";
|
|
70
88
|
export type { TabItem, TabsActivation, TabsOrientation, TabsProps, } from "./Tabs/Tabs.tsx";
|
|
71
89
|
export { Tabs } from "./Tabs/Tabs.tsx";
|
|
90
|
+
export type { ToastProps } from "./Toast/Toast.tsx";
|
|
91
|
+
export { Toast } from "./Toast/Toast.tsx";
|
|
92
|
+
export type { ToastRecord, ToastRegionProps, } from "./Toast/ToastRegion.tsx";
|
|
93
|
+
export { ToastRegion } from "./Toast/ToastRegion.tsx";
|
|
94
|
+
export type { ToastStatus } from "./Toast/toastLifecycle.ts";
|
|
95
|
+
export { toastTransitions } from "./Toast/toastLifecycle.ts";
|
|
96
|
+
export type { TooltipProps } from "./Tooltip/Tooltip.tsx";
|
|
97
|
+
export { Tooltip } from "./Tooltip/Tooltip.tsx";
|
|
72
98
|
export { toClassName } from "./toClassName.ts";
|
|
73
99
|
export type { VisuallyHiddenProps } from "./VisuallyHidden/VisuallyHidden.tsx";
|
|
74
100
|
export { VisuallyHidden } from "./VisuallyHidden/VisuallyHidden.tsx";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|