@charcuterie/ui 0.1.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/CHANGELOG.md +13 -0
- package/README.md +161 -0
- package/dist/Alert/Alert.d.ts +88 -0
- package/dist/Alert/Alert.d.ts.map +1 -0
- package/dist/Alert/Alert.js +67 -0
- package/dist/Alert/Alert.js.map +1 -0
- package/dist/Badge/Badge.d.ts +54 -0
- package/dist/Badge/Badge.d.ts.map +1 -0
- package/dist/Badge/Badge.js +54 -0
- package/dist/Badge/Badge.js.map +1 -0
- package/dist/Badge/useIsTextClipped.d.ts +22 -0
- package/dist/Badge/useIsTextClipped.d.ts.map +1 -0
- package/dist/Badge/useIsTextClipped.js +57 -0
- package/dist/Badge/useIsTextClipped.js.map +1 -0
- package/dist/Button/Button.d.ts +58 -0
- package/dist/Button/Button.d.ts.map +1 -0
- package/dist/Button/Button.js +37 -0
- package/dist/Button/Button.js.map +1 -0
- package/dist/Card/Card.d.ts +44 -0
- package/dist/Card/Card.d.ts.map +1 -0
- package/dist/Card/Card.js +59 -0
- package/dist/Card/Card.js.map +1 -0
- package/dist/EmptyState/EmptyState.d.ts +42 -0
- package/dist/EmptyState/EmptyState.d.ts.map +1 -0
- package/dist/EmptyState/EmptyState.js +37 -0
- package/dist/EmptyState/EmptyState.js.map +1 -0
- package/dist/IconButton/IconButton.d.ts +34 -0
- package/dist/IconButton/IconButton.d.ts.map +1 -0
- package/dist/IconButton/IconButton.js +23 -0
- package/dist/IconButton/IconButton.js.map +1 -0
- package/dist/LiveStatusIndicator/LiveStatusIndicator.d.ts +37 -0
- package/dist/LiveStatusIndicator/LiveStatusIndicator.d.ts.map +1 -0
- package/dist/LiveStatusIndicator/LiveStatusIndicator.js +39 -0
- package/dist/LiveStatusIndicator/LiveStatusIndicator.js.map +1 -0
- package/dist/MediaTile/MediaTile.d.ts +46 -0
- package/dist/MediaTile/MediaTile.d.ts.map +1 -0
- package/dist/MediaTile/MediaTile.js +79 -0
- package/dist/MediaTile/MediaTile.js.map +1 -0
- package/dist/MediaTile/mediaStatus.d.ts +22 -0
- package/dist/MediaTile/mediaStatus.d.ts.map +1 -0
- package/dist/MediaTile/mediaStatus.js +24 -0
- package/dist/MediaTile/mediaStatus.js.map +1 -0
- package/dist/Modal/Modal.d.ts +66 -0
- package/dist/Modal/Modal.d.ts.map +1 -0
- package/dist/Modal/Modal.js +111 -0
- package/dist/Modal/Modal.js.map +1 -0
- package/dist/Modal/lockScrollBehind.d.ts +22 -0
- package/dist/Modal/lockScrollBehind.d.ts.map +1 -0
- package/dist/Modal/lockScrollBehind.js +48 -0
- package/dist/Modal/lockScrollBehind.js.map +1 -0
- package/dist/Popover/Popover.d.ts +66 -0
- package/dist/Popover/Popover.d.ts.map +1 -0
- package/dist/Popover/Popover.js +88 -0
- package/dist/Popover/Popover.js.map +1 -0
- package/dist/ProgressBar/ProgressBar.d.ts +51 -0
- package/dist/ProgressBar/ProgressBar.d.ts.map +1 -0
- package/dist/ProgressBar/ProgressBar.js +50 -0
- package/dist/ProgressBar/ProgressBar.js.map +1 -0
- package/dist/ProgressBar/progressValue.d.ts +44 -0
- package/dist/ProgressBar/progressValue.d.ts.map +1 -0
- package/dist/ProgressBar/progressValue.js +55 -0
- package/dist/ProgressBar/progressValue.js.map +1 -0
- package/dist/SegmentedControl/SegmentedControl.d.ts +59 -0
- package/dist/SegmentedControl/SegmentedControl.d.ts.map +1 -0
- package/dist/SegmentedControl/SegmentedControl.js +129 -0
- package/dist/SegmentedControl/SegmentedControl.js.map +1 -0
- package/dist/SegmentedControl/SegmentedOption.d.ts +28 -0
- package/dist/SegmentedControl/SegmentedOption.d.ts.map +1 -0
- package/dist/SegmentedControl/SegmentedOption.js +40 -0
- package/dist/SegmentedControl/SegmentedOption.js.map +1 -0
- package/dist/Skeleton/Skeleton.d.ts +30 -0
- package/dist/Skeleton/Skeleton.d.ts.map +1 -0
- package/dist/Skeleton/Skeleton.js +43 -0
- package/dist/Skeleton/Skeleton.js.map +1 -0
- package/dist/Spinner/Spinner.d.ts +37 -0
- package/dist/Spinner/Spinner.d.ts.map +1 -0
- package/dist/Spinner/Spinner.js +33 -0
- package/dist/Spinner/Spinner.js.map +1 -0
- package/dist/Tabs/TabTrigger.d.ts +32 -0
- package/dist/Tabs/TabTrigger.d.ts.map +1 -0
- package/dist/Tabs/TabTrigger.js +62 -0
- package/dist/Tabs/TabTrigger.js.map +1 -0
- package/dist/Tabs/Tabs.d.ts +95 -0
- package/dist/Tabs/Tabs.d.ts.map +1 -0
- package/dist/Tabs/Tabs.js +195 -0
- package/dist/Tabs/Tabs.js.map +1 -0
- package/dist/VisuallyHidden/VisuallyHidden.d.ts +25 -0
- package/dist/VisuallyHidden/VisuallyHidden.d.ts.map +1 -0
- package/dist/VisuallyHidden/VisuallyHidden.js +23 -0
- package/dist/VisuallyHidden/VisuallyHidden.js.map +1 -0
- package/dist/controlStyles.d.ts +50 -0
- package/dist/controlStyles.d.ts.map +1 -0
- package/dist/controlStyles.js +60 -0
- package/dist/controlStyles.js.map +1 -0
- package/dist/expectNoAxeViolations.testHelpers.d.ts +19 -0
- package/dist/expectNoAxeViolations.testHelpers.d.ts.map +1 -0
- package/dist/expectNoAxeViolations.testHelpers.js +32 -0
- package/dist/expectNoAxeViolations.testHelpers.js.map +1 -0
- package/dist/index.d.ts +75 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +55 -0
- package/dist/index.js.map +1 -0
- package/dist/intentStyles.d.ts +76 -0
- package/dist/intentStyles.d.ts.map +1 -0
- package/dist/intentStyles.js +150 -0
- package/dist/intentStyles.js.map +1 -0
- package/dist/mountStory.testHelpers.d.ts +30 -0
- package/dist/mountStory.testHelpers.d.ts.map +1 -0
- package/dist/mountStory.testHelpers.js +19 -0
- package/dist/mountStory.testHelpers.js.map +1 -0
- package/dist/statusIntent.d.ts +33 -0
- package/dist/statusIntent.d.ts.map +1 -0
- package/dist/statusIntent.js +99 -0
- package/dist/statusIntent.js.map +1 -0
- package/dist/styles.css +130 -0
- package/dist/testing/expectAgentDrivable.d.ts +53 -0
- package/dist/testing/expectAgentDrivable.d.ts.map +1 -0
- package/dist/testing/expectAgentDrivable.js +163 -0
- package/dist/testing/expectAgentDrivable.js.map +1 -0
- package/dist/testing/index.d.ts +11 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +10 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/toClassName.d.ts +12 -0
- package/dist/toClassName.d.ts.map +1 -0
- package/dist/toClassName.js +12 -0
- package/dist/toClassName.js.map +1 -0
- package/dist/tokens.d.ts +16 -0
- package/dist/tokens.d.ts.map +1 -0
- package/dist/tokens.js +16 -0
- package/dist/tokens.js.map +1 -0
- package/package.json +70 -0
- package/src/Alert/Alert.mdx +70 -0
- package/src/Alert/Alert.stories.tsx +218 -0
- package/src/Alert/Alert.test.tsx +112 -0
- package/src/Alert/Alert.tsx +166 -0
- package/src/Badge/Badge.mdx +43 -0
- package/src/Badge/Badge.stories.tsx +229 -0
- package/src/Badge/Badge.test.tsx +153 -0
- package/src/Badge/Badge.tsx +130 -0
- package/src/Badge/useIsTextClipped.ts +77 -0
- package/src/Button/Button.mdx +44 -0
- package/src/Button/Button.stories.tsx +175 -0
- package/src/Button/Button.test.tsx +114 -0
- package/src/Button/Button.tsx +125 -0
- package/src/Card/Card.mdx +53 -0
- package/src/Card/Card.stories.tsx +207 -0
- package/src/Card/Card.test.tsx +56 -0
- package/src/Card/Card.tsx +142 -0
- package/src/EmptyState/EmptyState.mdx +40 -0
- package/src/EmptyState/EmptyState.stories.tsx +183 -0
- package/src/EmptyState/EmptyState.test.tsx +41 -0
- package/src/EmptyState/EmptyState.tsx +114 -0
- package/src/IconButton/IconButton.mdx +34 -0
- package/src/IconButton/IconButton.stories.tsx +191 -0
- package/src/IconButton/IconButton.test.tsx +70 -0
- package/src/IconButton/IconButton.tsx +54 -0
- package/src/LiveStatusIndicator/LiveStatusIndicator.mdx +43 -0
- package/src/LiveStatusIndicator/LiveStatusIndicator.stories.tsx +199 -0
- package/src/LiveStatusIndicator/LiveStatusIndicator.test.tsx +63 -0
- package/src/LiveStatusIndicator/LiveStatusIndicator.tsx +116 -0
- package/src/MediaTile/MediaTile.mdx +51 -0
- package/src/MediaTile/MediaTile.stories.tsx +211 -0
- package/src/MediaTile/MediaTile.test.tsx +41 -0
- package/src/MediaTile/MediaTile.tsx +227 -0
- package/src/MediaTile/mediaStatus.ts +28 -0
- package/src/Modal/Modal.mdx +113 -0
- package/src/Modal/Modal.stories.tsx +272 -0
- package/src/Modal/Modal.test.tsx +248 -0
- package/src/Modal/Modal.tsx +228 -0
- package/src/Modal/lockScrollBehind.ts +59 -0
- package/src/Popover/Popover.mdx +102 -0
- package/src/Popover/Popover.stories.tsx +247 -0
- package/src/Popover/Popover.test.tsx +191 -0
- package/src/Popover/Popover.tsx +164 -0
- package/src/ProgressBar/ProgressBar.mdx +48 -0
- package/src/ProgressBar/ProgressBar.stories.tsx +232 -0
- package/src/ProgressBar/ProgressBar.test.tsx +74 -0
- package/src/ProgressBar/ProgressBar.tsx +172 -0
- package/src/ProgressBar/progressValue.test.ts +101 -0
- package/src/ProgressBar/progressValue.ts +87 -0
- package/src/SegmentedControl/SegmentedControl.mdx +71 -0
- package/src/SegmentedControl/SegmentedControl.stories.tsx +150 -0
- package/src/SegmentedControl/SegmentedControl.test.tsx +208 -0
- package/src/SegmentedControl/SegmentedControl.tsx +219 -0
- package/src/SegmentedControl/SegmentedOption.tsx +94 -0
- package/src/Skeleton/Skeleton.mdx +30 -0
- package/src/Skeleton/Skeleton.stories.tsx +130 -0
- package/src/Skeleton/Skeleton.test.tsx +47 -0
- package/src/Skeleton/Skeleton.tsx +106 -0
- package/src/Spinner/Spinner.mdx +36 -0
- package/src/Spinner/Spinner.stories.tsx +118 -0
- package/src/Spinner/Spinner.test.tsx +38 -0
- package/src/Spinner/Spinner.tsx +92 -0
- package/src/Tabs/TabTrigger.tsx +126 -0
- package/src/Tabs/Tabs.mdx +126 -0
- package/src/Tabs/Tabs.stories.tsx +187 -0
- package/src/Tabs/Tabs.test.tsx +283 -0
- package/src/Tabs/Tabs.tsx +333 -0
- package/src/VisuallyHidden/VisuallyHidden.mdx +29 -0
- package/src/VisuallyHidden/VisuallyHidden.stories.tsx +58 -0
- package/src/VisuallyHidden/VisuallyHidden.test.tsx +31 -0
- package/src/VisuallyHidden/VisuallyHidden.tsx +43 -0
- package/src/argTypes.storyHelpers.ts +115 -0
- package/src/board.storyHelpers.tsx +150 -0
- package/src/controlStyles.ts +79 -0
- package/src/expectNoAxeViolations.testHelpers.ts +41 -0
- package/src/icons.storyHelpers.tsx +116 -0
- package/src/index.ts +132 -0
- package/src/intentStyles.ts +207 -0
- package/src/mdxReferences.test.ts +95 -0
- package/src/mountStory.testHelpers.ts +41 -0
- package/src/sourceRules.test.ts +303 -0
- package/src/statusIntent.test.ts +136 -0
- package/src/statusIntent.ts +137 -0
- package/src/storyControls.test.ts +128 -0
- package/src/styles.css +130 -0
- package/src/tailwindCandidates.test.ts +377 -0
- package/src/testing/expectAgentDrivable.test.tsx +71 -0
- package/src/testing/expectAgentDrivable.ts +273 -0
- package/src/testing/index.ts +17 -0
- package/src/toClassName.ts +13 -0
- package/src/tokens.ts +16 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { ComponentPropsWithRef, ReactNode } from "react";
|
|
2
|
+
export type ModalSize = "full" | "lg" | "md" | "sm" | "xl";
|
|
3
|
+
export type ModalProps = Omit<ComponentPropsWithRef<"dialog">, "onClose" | "open"> & {
|
|
4
|
+
/** The footer row. Buttons, usually. */
|
|
5
|
+
footer?: ReactNode;
|
|
6
|
+
heading: string;
|
|
7
|
+
headingLevel?: 2 | 3 | 4;
|
|
8
|
+
/**
|
|
9
|
+
* Escape and a backdrop press both close. Off for the one
|
|
10
|
+
* honest case — a destructive confirm the user has to answer —
|
|
11
|
+
* and off means Escape is *cancelled* rather than ignored, so
|
|
12
|
+
* the browser cannot close a dialog the app still owns.
|
|
13
|
+
*/
|
|
14
|
+
isDismissable?: boolean;
|
|
15
|
+
isVisible: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Every route out lands here: the close button, Escape, a
|
|
18
|
+
* backdrop press. Wire it to a `useVisibility()`'s `hide`.
|
|
19
|
+
*/
|
|
20
|
+
onClose: () => void;
|
|
21
|
+
size?: ModalSize;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Four repos, and **plex-channels and ripdeck independently
|
|
25
|
+
* converged on native `<dialog>`** — which is the design here
|
|
26
|
+
* rather than a shortcut. `showModal()` gives a focus trap,
|
|
27
|
+
* Escape, `::backdrop`, `inert` on everything behind it, and the
|
|
28
|
+
* **top layer**, from the platform, correctly, in every browser
|
|
29
|
+
* the fleet runs.
|
|
30
|
+
*
|
|
31
|
+
* What is not free — and the reason a component exists at all —
|
|
32
|
+
* is that a native `<dialog>` is a *self-owning* control: call
|
|
33
|
+
* `showModal()` and it decides it is open. That is the same
|
|
34
|
+
* conflict Radix has, and it gets the same answer as everywhere
|
|
35
|
+
* else in this library: **`isVisible` is the truth, and an effect
|
|
36
|
+
* makes the element agree with it.** Nothing here reads
|
|
37
|
+
* `dialogElement.open` as state; it is read only to avoid calling
|
|
38
|
+
* a method that would throw.
|
|
39
|
+
*
|
|
40
|
+
* ### Why it is not portalled
|
|
41
|
+
*
|
|
42
|
+
* The top layer is a *paint* concept: a `<dialog>` renders above
|
|
43
|
+
* everything while staying exactly where it is in the DOM. So it
|
|
44
|
+
* needs no portal — and that matters well past tidiness, because a
|
|
45
|
+
* portal moves the node to `document.body`, out of whatever
|
|
46
|
+
* element a test or an agent scoped its queries to.
|
|
47
|
+
* `canvas.getByRole("dialog")` finds this one. It would not find a
|
|
48
|
+
* portalled one, and the story would have to reach for `screen`
|
|
49
|
+
* and lose its scoping.
|
|
50
|
+
*
|
|
51
|
+
* ### `open:flex`, not `flex`
|
|
52
|
+
*
|
|
53
|
+
* A closed `<dialog>` is hidden by a UA rule that any
|
|
54
|
+
* `display: flex` of ours would beat — so the modal would render
|
|
55
|
+
* permanently, in the page flow, with no error. The layout is
|
|
56
|
+
* therefore behind Tailwind's `open:` variant, which is the
|
|
57
|
+
* `[open]` attribute the browser manages.
|
|
58
|
+
*
|
|
59
|
+
* ### The accessible name
|
|
60
|
+
*
|
|
61
|
+
* `heading` is required and is a string, not a `ReactNode`. A
|
|
62
|
+
* dialog with no name is announced as "dialog" and nothing else,
|
|
63
|
+
* which is what every hand-rolled modal in the inventory does.
|
|
64
|
+
*/
|
|
65
|
+
export declare const Modal: ({ children, className, footer, heading, headingLevel, isDismissable, isVisible, onClose, size, ...dialogProps }: ModalProps) => ReactNode;
|
|
66
|
+
//# sourceMappingURL=Modal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Modal.d.ts","sourceRoot":"","sources":["../../src/Modal/Modal.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,qBAAqB,EACrB,SAAS,EACV,MAAM,OAAO,CAAA;AAOd,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;AAE1D,MAAM,MAAM,UAAU,GAAG,IAAI,CAC3B,qBAAqB,CAAC,QAAQ,CAAC,EAC/B,SAAS,GAAG,MAAM,CACnB,GAAG;IACF,wCAAwC;IACxC,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB,OAAO,EAAE,MAAM,CAAA;IACf,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IACxB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,SAAS,EAAE,OAAO,CAAA;IAClB;;;OAGG;IACH,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,IAAI,CAAC,EAAE,SAAS,CAAA;CACjB,CAAA;AAqBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,eAAO,MAAM,KAAK,GAAI,iHAWnB,UAAU,KAAG,SAsHf,CAAA"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useUniqueId } from "@charcuterie/logic";
|
|
3
|
+
import { useEffect, useRef } from "react";
|
|
4
|
+
import { Button } from "../Button/Button.js";
|
|
5
|
+
import { toClassName } from "../toClassName.js";
|
|
6
|
+
import { lockScrollBehind } from "./lockScrollBehind.js";
|
|
7
|
+
/**
|
|
8
|
+
* `85dvh` rather than `85vh` — on a phone the two differ by the
|
|
9
|
+
* address bar, and a dialog whose footer is under it is a dialog
|
|
10
|
+
* with no buttons.
|
|
11
|
+
*/
|
|
12
|
+
const SIZE_CLASS = {
|
|
13
|
+
sm: "max-h-[85dvh] w-full max-w-sm",
|
|
14
|
+
md: "max-h-[85dvh] w-full max-w-md",
|
|
15
|
+
lg: "max-h-[85dvh] w-full max-w-2xl",
|
|
16
|
+
// M5 added this, because the scale jumped from 42rem straight to
|
|
17
|
+
// the whole viewport and rip-deck's capture tail lands in the
|
|
18
|
+
// gap: a MakeMKV robot log is fixed-width `MSG:5072,0,1,"…"`
|
|
19
|
+
// lines that wrap badly at 42rem, and a full-screen dialog over a
|
|
20
|
+
// nine-bay dashboard hides the thing being diagnosed. 56rem is
|
|
21
|
+
// what that app's hand-rolled `<dialog>` used before the swap.
|
|
22
|
+
xl: "max-h-[85dvh] w-full max-w-4xl",
|
|
23
|
+
full: "h-[100dvh] max-h-[100dvh] w-full max-w-full rounded-none",
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Four repos, and **plex-channels and ripdeck independently
|
|
27
|
+
* converged on native `<dialog>`** — which is the design here
|
|
28
|
+
* rather than a shortcut. `showModal()` gives a focus trap,
|
|
29
|
+
* Escape, `::backdrop`, `inert` on everything behind it, and the
|
|
30
|
+
* **top layer**, from the platform, correctly, in every browser
|
|
31
|
+
* the fleet runs.
|
|
32
|
+
*
|
|
33
|
+
* What is not free — and the reason a component exists at all —
|
|
34
|
+
* is that a native `<dialog>` is a *self-owning* control: call
|
|
35
|
+
* `showModal()` and it decides it is open. That is the same
|
|
36
|
+
* conflict Radix has, and it gets the same answer as everywhere
|
|
37
|
+
* else in this library: **`isVisible` is the truth, and an effect
|
|
38
|
+
* makes the element agree with it.** Nothing here reads
|
|
39
|
+
* `dialogElement.open` as state; it is read only to avoid calling
|
|
40
|
+
* a method that would throw.
|
|
41
|
+
*
|
|
42
|
+
* ### Why it is not portalled
|
|
43
|
+
*
|
|
44
|
+
* The top layer is a *paint* concept: a `<dialog>` renders above
|
|
45
|
+
* everything while staying exactly where it is in the DOM. So it
|
|
46
|
+
* needs no portal — and that matters well past tidiness, because a
|
|
47
|
+
* portal moves the node to `document.body`, out of whatever
|
|
48
|
+
* element a test or an agent scoped its queries to.
|
|
49
|
+
* `canvas.getByRole("dialog")` finds this one. It would not find a
|
|
50
|
+
* portalled one, and the story would have to reach for `screen`
|
|
51
|
+
* and lose its scoping.
|
|
52
|
+
*
|
|
53
|
+
* ### `open:flex`, not `flex`
|
|
54
|
+
*
|
|
55
|
+
* A closed `<dialog>` is hidden by a UA rule that any
|
|
56
|
+
* `display: flex` of ours would beat — so the modal would render
|
|
57
|
+
* permanently, in the page flow, with no error. The layout is
|
|
58
|
+
* therefore behind Tailwind's `open:` variant, which is the
|
|
59
|
+
* `[open]` attribute the browser manages.
|
|
60
|
+
*
|
|
61
|
+
* ### The accessible name
|
|
62
|
+
*
|
|
63
|
+
* `heading` is required and is a string, not a `ReactNode`. A
|
|
64
|
+
* dialog with no name is announced as "dialog" and nothing else,
|
|
65
|
+
* which is what every hand-rolled modal in the inventory does.
|
|
66
|
+
*/
|
|
67
|
+
export const Modal = ({ children, className, footer, heading, headingLevel = 2, isDismissable = true, isVisible, onClose, size = "md", ...dialogProps }) => {
|
|
68
|
+
const dialogRef = useRef(null);
|
|
69
|
+
const headingId = useUniqueId();
|
|
70
|
+
const Heading = `h${headingLevel}`;
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
const dialogElement = dialogRef.current;
|
|
73
|
+
if (!dialogElement) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
// Guarded both ways. `showModal()` on an already-open dialog
|
|
77
|
+
// throws `InvalidStateError`, and `close()` on a closed one
|
|
78
|
+
// fires a spurious `close` event — either turns a re-render
|
|
79
|
+
// into a bug.
|
|
80
|
+
if (isVisible && !dialogElement.open) {
|
|
81
|
+
dialogElement.showModal();
|
|
82
|
+
}
|
|
83
|
+
if (!isVisible && dialogElement.open) {
|
|
84
|
+
dialogElement.close();
|
|
85
|
+
}
|
|
86
|
+
}, [isVisible]);
|
|
87
|
+
useEffect(() => (isVisible ? lockScrollBehind() : undefined), [isVisible]);
|
|
88
|
+
return (_jsxs("dialog", { ...dialogProps, "aria-labelledby": headingId, className: toClassName(
|
|
89
|
+
// `m-auto` and `p-0` undo the UA stylesheet, which centres
|
|
90
|
+
// by margin and adds padding of its own.
|
|
91
|
+
"m-auto flex-col overflow-hidden rounded-lg border border-border-default bg-surface-overlay p-0 text-content-primary shadow-high backdrop:bg-scrim open:flex", SIZE_CLASS[size], className), onCancel: (cancelEvent) => {
|
|
92
|
+
// Escape. Cancelled rather than ignored when the dialog is
|
|
93
|
+
// not dismissable: letting the browser close it would
|
|
94
|
+
// leave `isVisible` true and the element shut, which is
|
|
95
|
+
// precisely the desync this component exists to prevent.
|
|
96
|
+
cancelEvent.preventDefault();
|
|
97
|
+
if (isDismissable) {
|
|
98
|
+
onClose();
|
|
99
|
+
}
|
|
100
|
+
}, onClick: (clickEvent) => {
|
|
101
|
+
// The backdrop is not an element — a press on it targets
|
|
102
|
+
// the `<dialog>` itself, while a press on the content
|
|
103
|
+
// targets something inside. Comparing target to
|
|
104
|
+
// currentTarget is the whole test.
|
|
105
|
+
if (isDismissable &&
|
|
106
|
+
clickEvent.target === clickEvent.currentTarget) {
|
|
107
|
+
onClose();
|
|
108
|
+
}
|
|
109
|
+
}, ref: dialogRef, children: [_jsxs("header", { className: "flex shrink-0 items-start justify-between gap-3 border-b border-border-subtle p-4", children: [_jsx(Heading, { className: "font-semibold text-lg leading-tight", id: headingId, children: heading }), isDismissable ? (_jsx(Button, { appearance: "ghost", intent: "neutral", onClick: onClose, size: "sm", children: "Close" })) : null] }), _jsx("div", { className: "min-h-0 flex-1 overflow-auto p-4", children: children }), footer ? (_jsx("footer", { className: "flex shrink-0 flex-wrap justify-end gap-2 border-t border-border-subtle p-4", children: footer })) : null] }));
|
|
110
|
+
};
|
|
111
|
+
//# sourceMappingURL=Modal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Modal.js","sourceRoot":"","sources":["../../src/Modal/Modal.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one thing `showModal()` does not do.
|
|
3
|
+
*
|
|
4
|
+
* A native modal makes everything behind it `inert` — unclickable,
|
|
5
|
+
* untabbable, invisible to a screen reader — and then lets you
|
|
6
|
+
* scroll it anyway. On a phone that reads as the dialog sliding
|
|
7
|
+
* around; on a long page it loses the user's place entirely.
|
|
8
|
+
*
|
|
9
|
+
* Counted rather than boolean, because nested dialogs are legal
|
|
10
|
+
* (`showModal()` stacks in the top layer) and a naive
|
|
11
|
+
* lock/unlock pair has the inner one's cleanup unlock the page
|
|
12
|
+
* while the outer is still open. The original value is captured
|
|
13
|
+
* on the *first* lock, so restoring is a restore rather than a
|
|
14
|
+
* guess at what an app's own stylesheet wanted.
|
|
15
|
+
*
|
|
16
|
+
* Not a React hook: this is process-wide state, and two components
|
|
17
|
+
* sharing it through module scope is the honest expression of
|
|
18
|
+
* that. `Modal` calls it from an effect and returns the release as
|
|
19
|
+
* the cleanup.
|
|
20
|
+
*/
|
|
21
|
+
export declare const lockScrollBehind: () => (() => void);
|
|
22
|
+
//# sourceMappingURL=lockScrollBehind.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lockScrollBehind.d.ts","sourceRoot":"","sources":["../../src/Modal/lockScrollBehind.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAMH,eAAO,MAAM,gBAAgB,QAAO,CAAC,MAAM,IAAI,CAiC9C,CAAA"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one thing `showModal()` does not do.
|
|
3
|
+
*
|
|
4
|
+
* A native modal makes everything behind it `inert` — unclickable,
|
|
5
|
+
* untabbable, invisible to a screen reader — and then lets you
|
|
6
|
+
* scroll it anyway. On a phone that reads as the dialog sliding
|
|
7
|
+
* around; on a long page it loses the user's place entirely.
|
|
8
|
+
*
|
|
9
|
+
* Counted rather than boolean, because nested dialogs are legal
|
|
10
|
+
* (`showModal()` stacks in the top layer) and a naive
|
|
11
|
+
* lock/unlock pair has the inner one's cleanup unlock the page
|
|
12
|
+
* while the outer is still open. The original value is captured
|
|
13
|
+
* on the *first* lock, so restoring is a restore rather than a
|
|
14
|
+
* guess at what an app's own stylesheet wanted.
|
|
15
|
+
*
|
|
16
|
+
* Not a React hook: this is process-wide state, and two components
|
|
17
|
+
* sharing it through module scope is the honest expression of
|
|
18
|
+
* that. `Modal` calls it from an effect and returns the release as
|
|
19
|
+
* the cleanup.
|
|
20
|
+
*/
|
|
21
|
+
let lockCount = 0;
|
|
22
|
+
let previousOverflow = "";
|
|
23
|
+
export const lockScrollBehind = () => {
|
|
24
|
+
if (typeof document === "undefined") {
|
|
25
|
+
return () => { };
|
|
26
|
+
}
|
|
27
|
+
const { documentElement } = document;
|
|
28
|
+
if (lockCount === 0) {
|
|
29
|
+
previousOverflow = documentElement.style.overflow;
|
|
30
|
+
documentElement.style.overflow = "hidden";
|
|
31
|
+
}
|
|
32
|
+
lockCount += 1;
|
|
33
|
+
let isReleased = false;
|
|
34
|
+
return () => {
|
|
35
|
+
// Idempotent, because React 19's StrictMode runs an effect's
|
|
36
|
+
// cleanup twice and a double decrement would unlock the page
|
|
37
|
+
// under a dialog that is still open.
|
|
38
|
+
if (isReleased) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
isReleased = true;
|
|
42
|
+
lockCount -= 1;
|
|
43
|
+
if (lockCount === 0) {
|
|
44
|
+
documentElement.style.overflow = previousOverflow;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=lockScrollBehind.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lockScrollBehind.js","sourceRoot":"","sources":["../../src/Modal/lockScrollBehind.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,IAAI,SAAS,GAAG,CAAC,CAAA;AAEjB,IAAI,gBAAgB,GAAG,EAAE,CAAA;AAEzB,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAiB,EAAE;IACjD,IAAI,OAAO,QAAQ,KAAK,WAAW,EAAE,CAAC;QACpC,OAAO,GAAG,EAAE,GAAE,CAAC,CAAA;IACjB,CAAC;IAED,MAAM,EAAE,eAAe,EAAE,GAAG,QAAQ,CAAA;IAEpC,IAAI,SAAS,KAAK,CAAC,EAAE,CAAC;QACpB,gBAAgB,GAAG,eAAe,CAAC,KAAK,CAAC,QAAQ,CAAA;QAEjD,eAAe,CAAC,KAAK,CAAC,QAAQ,GAAG,QAAQ,CAAA;IAC3C,CAAC;IAED,SAAS,IAAI,CAAC,CAAA;IAEd,IAAI,UAAU,GAAG,KAAK,CAAA;IAEtB,OAAO,GAAG,EAAE;QACV,6DAA6D;QAC7D,6DAA6D;QAC7D,qCAAqC;QACrC,IAAI,UAAU,EAAE,CAAC;YACf,OAAM;QACR,CAAC;QAED,UAAU,GAAG,IAAI,CAAA;QAEjB,SAAS,IAAI,CAAC,CAAA;QAEd,IAAI,SAAS,KAAK,CAAC,EAAE,CAAC;YACpB,eAAe,CAAC,KAAK,CAAC,QAAQ,GAAG,gBAAgB,CAAA;QACnD,CAAC;IACH,CAAC,CAAA;AACH,CAAC,CAAA"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { Placement } from "@floating-ui/react";
|
|
2
|
+
import type { ReactElement, ReactNode } from "react";
|
|
3
|
+
export type PopoverProps = {
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
className?: string;
|
|
6
|
+
/**
|
|
7
|
+
* Required, and it becomes the panel's `aria-label`. A
|
|
8
|
+
* `role="dialog"` takes **no accessible name from its content**,
|
|
9
|
+
* so an unnamed one is announced as "dialog" and is unfindable
|
|
10
|
+
* by `getByRole("dialog", { name })` — the same trap `Spinner`
|
|
11
|
+
* walked into in M3 with `role="status"`.
|
|
12
|
+
*/
|
|
13
|
+
heading: string;
|
|
14
|
+
isVisible: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Outside press and Escape both land here, through floating-ui's
|
|
17
|
+
* `useDismiss`. Wire it to a `useVisibility()`'s `hide`.
|
|
18
|
+
*/
|
|
19
|
+
onDismiss: () => void;
|
|
20
|
+
placement?: Placement;
|
|
21
|
+
/**
|
|
22
|
+
* The control the panel hangs off. **Cloned, not wrapped** — an
|
|
23
|
+
* extra `<div>` around a button is how a toolbar's layout
|
|
24
|
+
* quietly changes.
|
|
25
|
+
*/
|
|
26
|
+
trigger: ReactElement;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Replaces mux-magic's `@radix-ui/react-popover` re-export, and it
|
|
30
|
+
* is a rewrite rather than a swap for one reason: Radix owns
|
|
31
|
+
* `open`, so wrapping it leaves `useVisibility` and Radix both
|
|
32
|
+
* believing they hold it. `@floating-ui/react` is the layer Radix,
|
|
33
|
+
* Base UI, and Ark UI are all *built on*, and it is controlled by
|
|
34
|
+
* construction — you pass state in and it never stores any.
|
|
35
|
+
*
|
|
36
|
+
* What floating-ui is used for is what only it can do: collision
|
|
37
|
+
* handling (`flip`, `shift`), a real dismiss layer, and focus
|
|
38
|
+
* management. Positioning strategy, the top layer, and the ARIA
|
|
39
|
+
* wiring come from the platform and from `useRole`.
|
|
40
|
+
*
|
|
41
|
+
* ### The top layer, from the platform — not a portal
|
|
42
|
+
*
|
|
43
|
+
* `popover="manual"` puts the panel in the top layer, which is
|
|
44
|
+
* what a portal is normally reached for: no `z-index` contest, and
|
|
45
|
+
* no `overflow: hidden` ancestor clipping it. Unlike a portal it
|
|
46
|
+
* **stays where it is in the DOM**, so `canvas.getByRole("dialog")`
|
|
47
|
+
* still finds it and a story keeps its scoping. Same argument as
|
|
48
|
+
* `Modal`, one layer down.
|
|
49
|
+
*
|
|
50
|
+
* `manual`, not `auto`, and that is the state-ownership decision
|
|
51
|
+
* again: `auto` brings the UA's own light-dismiss, which closes the
|
|
52
|
+
* element by itself and leaves `isVisible` true. `useDismiss` does
|
|
53
|
+
* the same job through our callback, so Charcuterie stays the only
|
|
54
|
+
* thing that decides.
|
|
55
|
+
*
|
|
56
|
+
* ### Two UA defaults that have to be undone
|
|
57
|
+
*
|
|
58
|
+
* `[popover]` ships `position: fixed; inset: 0; margin: auto`,
|
|
59
|
+
* which centres the panel in the viewport and fights every
|
|
60
|
+
* coordinate floating-ui computes — hence `inset-auto m-0`, and
|
|
61
|
+
* `strategy: "fixed"` so the numbers are viewport-relative like the
|
|
62
|
+
* top layer itself. Getting either wrong reads as a positioning
|
|
63
|
+
* bug rather than as a UA default.
|
|
64
|
+
*/
|
|
65
|
+
export declare const Popover: ({ children, className, heading, isVisible, onDismiss, placement, trigger, }: PopoverProps) => ReactNode;
|
|
66
|
+
//# sourceMappingURL=Popover.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Popover.d.ts","sourceRoot":"","sources":["../../src/Popover/Popover.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAYnD,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAIpD,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,EAAE,SAAS,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;;;OAMG;IACH,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,OAAO,CAAA;IAClB;;;OAGG;IACH,SAAS,EAAE,MAAM,IAAI,CAAA;IACrB,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB;;;;OAIG;IACH,OAAO,EAAE,YAAY,CAAA;CACtB,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,eAAO,MAAM,OAAO,GAAI,6EAQrB,YAAY,KAAG,SA2EjB,CAAA"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useClonedChild } from "@charcuterie/logic";
|
|
3
|
+
import { autoUpdate, FloatingFocusManager, flip, offset, shift, useDismiss, useFloating, useInteractions, useRole, } from "@floating-ui/react";
|
|
4
|
+
import { toClassName } from "../toClassName.js";
|
|
5
|
+
/**
|
|
6
|
+
* Replaces mux-magic's `@radix-ui/react-popover` re-export, and it
|
|
7
|
+
* is a rewrite rather than a swap for one reason: Radix owns
|
|
8
|
+
* `open`, so wrapping it leaves `useVisibility` and Radix both
|
|
9
|
+
* believing they hold it. `@floating-ui/react` is the layer Radix,
|
|
10
|
+
* Base UI, and Ark UI are all *built on*, and it is controlled by
|
|
11
|
+
* construction — you pass state in and it never stores any.
|
|
12
|
+
*
|
|
13
|
+
* What floating-ui is used for is what only it can do: collision
|
|
14
|
+
* handling (`flip`, `shift`), a real dismiss layer, and focus
|
|
15
|
+
* management. Positioning strategy, the top layer, and the ARIA
|
|
16
|
+
* wiring come from the platform and from `useRole`.
|
|
17
|
+
*
|
|
18
|
+
* ### The top layer, from the platform — not a portal
|
|
19
|
+
*
|
|
20
|
+
* `popover="manual"` puts the panel in the top layer, which is
|
|
21
|
+
* what a portal is normally reached for: no `z-index` contest, and
|
|
22
|
+
* no `overflow: hidden` ancestor clipping it. Unlike a portal it
|
|
23
|
+
* **stays where it is in the DOM**, so `canvas.getByRole("dialog")`
|
|
24
|
+
* still finds it and a story keeps its scoping. Same argument as
|
|
25
|
+
* `Modal`, one layer down.
|
|
26
|
+
*
|
|
27
|
+
* `manual`, not `auto`, and that is the state-ownership decision
|
|
28
|
+
* again: `auto` brings the UA's own light-dismiss, which closes the
|
|
29
|
+
* element by itself and leaves `isVisible` true. `useDismiss` does
|
|
30
|
+
* the same job through our callback, so Charcuterie stays the only
|
|
31
|
+
* thing that decides.
|
|
32
|
+
*
|
|
33
|
+
* ### Two UA defaults that have to be undone
|
|
34
|
+
*
|
|
35
|
+
* `[popover]` ships `position: fixed; inset: 0; margin: auto`,
|
|
36
|
+
* which centres the panel in the viewport and fights every
|
|
37
|
+
* coordinate floating-ui computes — hence `inset-auto m-0`, and
|
|
38
|
+
* `strategy: "fixed"` so the numbers are viewport-relative like the
|
|
39
|
+
* top layer itself. Getting either wrong reads as a positioning
|
|
40
|
+
* bug rather than as a UA default.
|
|
41
|
+
*/
|
|
42
|
+
export const Popover = ({ children, className, heading, isVisible, onDismiss, placement = "bottom-start", trigger, }) => {
|
|
43
|
+
const { context, floatingStyles, refs } = useFloating({
|
|
44
|
+
// Read-only. Charcuterie remains the sole owner; floating-ui
|
|
45
|
+
// is told what is true and never decides it.
|
|
46
|
+
open: isVisible,
|
|
47
|
+
onOpenChange: (isNextVisible) => {
|
|
48
|
+
if (!isNextVisible) {
|
|
49
|
+
onDismiss();
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
placement,
|
|
53
|
+
middleware: [offset(8), flip(), shift({ padding: 8 })],
|
|
54
|
+
strategy: "fixed",
|
|
55
|
+
whileElementsMounted: autoUpdate,
|
|
56
|
+
});
|
|
57
|
+
// `useRole` writes `aria-expanded`, `aria-haspopup`, and
|
|
58
|
+
// `aria-controls` on the trigger and `id` + `role="dialog"` on
|
|
59
|
+
// the panel, from one source. Hand-writing them alongside is how
|
|
60
|
+
// an `aria-controls` ends up pointing at an id that moved.
|
|
61
|
+
const { getFloatingProps, getReferenceProps } = useInteractions([
|
|
62
|
+
useDismiss(context),
|
|
63
|
+
useRole(context, { role: "dialog" }),
|
|
64
|
+
]);
|
|
65
|
+
const clonedTrigger = useClonedChild(trigger, {
|
|
66
|
+
...getReferenceProps(),
|
|
67
|
+
ref: refs.setReference,
|
|
68
|
+
});
|
|
69
|
+
return (_jsxs(_Fragment, { children: [clonedTrigger, isVisible ? (_jsx(FloatingFocusManager, { context: context, modal: false, children: _jsx("div", { ...getFloatingProps(), "aria-label": heading, className: toClassName("inset-auto m-0 max-w-xs rounded-md border border-border-default bg-surface-overlay p-3 text-content-primary text-sm shadow-medium", className), popover: "manual",
|
|
70
|
+
// Duplicated from `getFloatingProps()` on purpose, and
|
|
71
|
+
// the two cannot differ — `useRole(context, { role:
|
|
72
|
+
// "dialog" })` above is where it comes from. Stated
|
|
73
|
+
// here because a linter cannot see a role through a
|
|
74
|
+
// spread, and neither can the next reader.
|
|
75
|
+
role: "dialog", ref: (node) => {
|
|
76
|
+
refs.setFloating(node);
|
|
77
|
+
// In a ref callback rather than an effect, because a
|
|
78
|
+
// `[popover]` is `display: none` until it is shown —
|
|
79
|
+
// and `FloatingFocusManager` is a *child*, so its
|
|
80
|
+
// effect runs first and would be focusing into a
|
|
81
|
+
// hidden element. Refs are set during commit, before
|
|
82
|
+
// any of that.
|
|
83
|
+
if (node && !node.matches(":popover-open")) {
|
|
84
|
+
node.showPopover();
|
|
85
|
+
}
|
|
86
|
+
}, style: floatingStyles, children: children }) })) : null] }));
|
|
87
|
+
};
|
|
88
|
+
//# sourceMappingURL=Popover.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Popover.js","sourceRoot":"","sources":["../../src/Popover/Popover.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAEnD,OAAO,EACL,UAAU,EACV,oBAAoB,EACpB,IAAI,EACJ,MAAM,EACN,KAAK,EACL,UAAU,EACV,WAAW,EACX,eAAe,EACf,OAAO,GACR,MAAM,oBAAoB,CAAA;AAG3B,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AA4B/C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,EACtB,QAAQ,EACR,SAAS,EACT,OAAO,EACP,SAAS,EACT,SAAS,EACT,SAAS,GAAG,cAAc,EAC1B,OAAO,GACM,EAAa,EAAE;IAC5B,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,GAAG,WAAW,CAAC;QACpD,6DAA6D;QAC7D,6CAA6C;QAC7C,IAAI,EAAE,SAAS;QACf,YAAY,EAAE,CAAC,aAAa,EAAE,EAAE;YAC9B,IAAI,CAAC,aAAa,EAAE,CAAC;gBACnB,SAAS,EAAE,CAAA;YACb,CAAC;QACH,CAAC;QACD,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,yDAAyD;IACzD,+DAA+D;IAC/D,iEAAiE;IACjE,2DAA2D;IAC3D,MAAM,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,GAC3C,eAAe,CAAC;QACd,UAAU,CAAC,OAAO,CAAC;QACnB,OAAO,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;KACrC,CAAC,CAAA;IAEJ,MAAM,aAAa,GAAG,cAAc,CAAC,OAAO,EAAE;QAC5C,GAAG,iBAAiB,EAAE;QACtB,GAAG,EAAE,IAAI,CAAC,YAAY;KACvB,CAAC,CAAA;IAEF,OAAO,CACL,8BACG,aAAa,EAEb,SAAS,CAAC,CAAC,CAAC,CACX,KAAC,oBAAoB,IACnB,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,KAAK,YAEZ,iBACM,gBAAgB,EAAE,gBACV,OAAO,EACnB,SAAS,EAAE,WAAW,CACpB,mIAAmI,EACnI,SAAS,CACV,EACD,OAAO,EAAC,QAAQ;oBAChB,uDAAuD;oBACvD,oDAAoD;oBACpD,oDAAoD;oBACpD,oDAAoD;oBACpD,2CAA2C;oBAC3C,IAAI,EAAC,QAAQ,EACb,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE;wBACZ,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAA;wBAEtB,qDAAqD;wBACrD,qDAAqD;wBACrD,kDAAkD;wBAClD,iDAAiD;wBACjD,qDAAqD;wBACrD,eAAe;wBACf,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,CAAC;4BAC3C,IAAI,CAAC,WAAW,EAAE,CAAA;wBACpB,CAAC;oBACH,CAAC,EACD,KAAK,EAAE,cAAc,YAEpB,QAAQ,GACL,GACe,CACxB,CAAC,CAAC,CAAC,IAAI,IACP,CACJ,CAAA;AACH,CAAC,CAAA"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { IntentName } from "@charcuterie/tokens";
|
|
2
|
+
import type { ComponentPropsWithRef, ReactNode } from "react";
|
|
3
|
+
import type { ProgressThreshold } from "./progressValue.ts";
|
|
4
|
+
export type ProgressBarSize = "lg" | "md" | "sm";
|
|
5
|
+
export type ProgressBarProps = Omit<ComponentPropsWithRef<"div">, "children"> & {
|
|
6
|
+
intent?: IntentName;
|
|
7
|
+
/**
|
|
8
|
+
* Indeterminate means "working, no measurable progress yet" — not
|
|
9
|
+
* zero and not unknown-therefore-full. rip-deck's is the
|
|
10
|
+
* AACS/BD+ preamble: ~25 s of a real Blu-ray emitting nothing, in
|
|
11
|
+
* which a full bar reads as a finished rip and an empty one as a
|
|
12
|
+
* wedged drive.
|
|
13
|
+
*/
|
|
14
|
+
isIndeterminate?: boolean;
|
|
15
|
+
isLabelVisible?: boolean;
|
|
16
|
+
isValueShown?: boolean;
|
|
17
|
+
/** Required. A progressbar with no name is a grey rectangle. */
|
|
18
|
+
label: string;
|
|
19
|
+
max?: number;
|
|
20
|
+
size?: ProgressBarSize;
|
|
21
|
+
thresholds?: readonly ProgressThreshold[];
|
|
22
|
+
value?: number;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* The union of what the fleet has: rip-deck's ARIA and its
|
|
26
|
+
* indeterminate sweep, plus threshold colours nobody has yet.
|
|
27
|
+
*
|
|
28
|
+
* Five repos hand-roll a progress bar and **only rip-deck's has
|
|
29
|
+
* `role="progressbar"`** — the other four are a `<div>` with a
|
|
30
|
+
* percentage width, invisible to assistive technology and to
|
|
31
|
+
* `getByRole("progressbar")`.
|
|
32
|
+
*
|
|
33
|
+
* Three corrections to rip-deck's version, which is otherwise the
|
|
34
|
+
* best in the fleet:
|
|
35
|
+
*
|
|
36
|
+
* - **The role goes on the track, not the fill.** rip-deck puts
|
|
37
|
+
* `role="progressbar"` on the inner filled element, so the
|
|
38
|
+
* widget's box is the *filled portion* — a 4% rip is a
|
|
39
|
+
* progressbar 4px wide as far as AT and a Playwright bounding
|
|
40
|
+
* box are concerned.
|
|
41
|
+
* - **The name comes from a real label**, wired with
|
|
42
|
+
* `aria-labelledby` when it is visible and `VisuallyHidden` when
|
|
43
|
+
* it is not, rather than a hardcoded `aria-label` string that
|
|
44
|
+
* cannot be translated or reused.
|
|
45
|
+
* - **`aria-valuenow` is omitted while indeterminate**, which is
|
|
46
|
+
* what tells AT "unknown" rather than "zero". rip-deck gets this
|
|
47
|
+
* right by rendering a separate element; stating it on one
|
|
48
|
+
* element is the same answer without the duplication.
|
|
49
|
+
*/
|
|
50
|
+
export declare const ProgressBar: ({ className, intent, isIndeterminate, isLabelVisible, isValueShown, label, max, size, thresholds, value, ...divProps }: ProgressBarProps) => ReactNode;
|
|
51
|
+
//# sourceMappingURL=ProgressBar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProgressBar.d.ts","sourceRoot":"","sources":["../../src/ProgressBar/ProgressBar.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AACrD,OAAO,KAAK,EACV,qBAAqB,EACrB,SAAS,EACV,MAAM,OAAO,CAAA;AAKd,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAO3D,MAAM,MAAM,eAAe,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;AAEhD,MAAM,MAAM,gBAAgB,GAAG,IAAI,CACjC,qBAAqB,CAAC,KAAK,CAAC,EAC5B,UAAU,CACX,GAAG;IACF,MAAM,CAAC,EAAE,UAAU,CAAA;IACnB;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,gEAAgE;IAChE,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,eAAe,CAAA;IACtB,UAAU,CAAC,EAAE,SAAS,iBAAiB,EAAE,CAAA;IACzC,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAQD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,WAAW,GAAI,wHAYzB,gBAAgB,KAAG,SAqFrB,CAAA"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useUniqueId } from "@charcuterie/logic";
|
|
3
|
+
import { INTENT_SOLID_FILL_CLASS } from "../intentStyles.js";
|
|
4
|
+
import { toClassName } from "../toClassName.js";
|
|
5
|
+
import { VisuallyHidden } from "../VisuallyHidden/VisuallyHidden.js";
|
|
6
|
+
import { getProgressIntent, toProgressPercent, toProgressValue, } from "./progressValue.js";
|
|
7
|
+
const TRACK_SIZE_CLASS = {
|
|
8
|
+
sm: "h-1",
|
|
9
|
+
md: "h-2",
|
|
10
|
+
lg: "h-3",
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* The union of what the fleet has: rip-deck's ARIA and its
|
|
14
|
+
* indeterminate sweep, plus threshold colours nobody has yet.
|
|
15
|
+
*
|
|
16
|
+
* Five repos hand-roll a progress bar and **only rip-deck's has
|
|
17
|
+
* `role="progressbar"`** — the other four are a `<div>` with a
|
|
18
|
+
* percentage width, invisible to assistive technology and to
|
|
19
|
+
* `getByRole("progressbar")`.
|
|
20
|
+
*
|
|
21
|
+
* Three corrections to rip-deck's version, which is otherwise the
|
|
22
|
+
* best in the fleet:
|
|
23
|
+
*
|
|
24
|
+
* - **The role goes on the track, not the fill.** rip-deck puts
|
|
25
|
+
* `role="progressbar"` on the inner filled element, so the
|
|
26
|
+
* widget's box is the *filled portion* — a 4% rip is a
|
|
27
|
+
* progressbar 4px wide as far as AT and a Playwright bounding
|
|
28
|
+
* box are concerned.
|
|
29
|
+
* - **The name comes from a real label**, wired with
|
|
30
|
+
* `aria-labelledby` when it is visible and `VisuallyHidden` when
|
|
31
|
+
* it is not, rather than a hardcoded `aria-label` string that
|
|
32
|
+
* cannot be translated or reused.
|
|
33
|
+
* - **`aria-valuenow` is omitted while indeterminate**, which is
|
|
34
|
+
* what tells AT "unknown" rather than "zero". rip-deck gets this
|
|
35
|
+
* right by rendering a separate element; stating it on one
|
|
36
|
+
* element is the same answer without the duplication.
|
|
37
|
+
*/
|
|
38
|
+
export const ProgressBar = ({ className, intent = "accent", isIndeterminate = false, isLabelVisible = false, isValueShown = false, label, max = 100, size = "md", thresholds, value = 0, ...divProps }) => {
|
|
39
|
+
const labelId = useUniqueId();
|
|
40
|
+
const percent = toProgressPercent(value, max);
|
|
41
|
+
const clampedValue = toProgressValue(value, max);
|
|
42
|
+
const fillIntent = getProgressIntent(percent, intent, thresholds);
|
|
43
|
+
return (_jsxs("div", { ...divProps, className: toClassName("flex flex-col gap-1", className), children: [isLabelVisible || isValueShown ? (_jsxs("div", { className: "flex items-baseline justify-between gap-2 text-sm", children: [isLabelVisible ? (_jsx("span", { className: "text-content-secondary", id: labelId, children: label })) : (_jsx(VisuallyHidden, { id: labelId, children: label })), isValueShown && !isIndeterminate ? (_jsxs("span", { className: "text-content-muted tabular-nums", children: [percent, "%"] })) : null] })) : (_jsx(VisuallyHidden, { id: labelId, children: label })), _jsx("div", { "aria-busy": isIndeterminate || undefined, "aria-labelledby": labelId, "aria-valuemax": max, "aria-valuemin": 0, "aria-valuenow": isIndeterminate ? undefined : clampedValue, className: toClassName("relative w-full overflow-hidden rounded-full bg-surface-sunken", TRACK_SIZE_CLASS[size]), role: "progressbar", children: isIndeterminate ? (_jsx("span", { className: toClassName(
|
|
44
|
+
// The sweep animates `inset-inline-start`, so it runs
|
|
45
|
+
// the other way in RTL for free — and its
|
|
46
|
+
// reduced-motion fallback hatches the whole track
|
|
47
|
+
// rather than parking at one end.
|
|
48
|
+
"charcuterie-sweep absolute inset-y-0 w-2/5 rounded-full", INTENT_SOLID_FILL_CLASS[fillIntent]) })) : (_jsx("span", { className: toClassName("block h-full rounded-full transition-[inline-size] duration-(--duration-normal) ease-standard", INTENT_SOLID_FILL_CLASS[fillIntent]), style: { inlineSize: `${percent}%` } })) })] }));
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=ProgressBar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProgressBar.js","sourceRoot":"","sources":["../../src/ProgressBar/ProgressBar.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAOhD,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAA;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,qCAAsC,CAAA;AAErE,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,GAChB,MAAM,oBAAoB,CAAA;AA2B3B,MAAM,gBAAgB,GAAoC;IACxD,EAAE,EAAE,KAAK;IACT,EAAE,EAAE,KAAK;IACT,EAAE,EAAE,KAAK;CACV,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,EAC1B,SAAS,EACT,MAAM,GAAG,QAAQ,EACjB,eAAe,GAAG,KAAK,EACvB,cAAc,GAAG,KAAK,EACtB,YAAY,GAAG,KAAK,EACpB,KAAK,EACL,GAAG,GAAG,GAAG,EACT,IAAI,GAAG,IAAI,EACX,UAAU,EACV,KAAK,GAAG,CAAC,EACT,GAAG,QAAQ,EACM,EAAa,EAAE;IAChC,MAAM,OAAO,GAAG,WAAW,EAAE,CAAA;IAE7B,MAAM,OAAO,GAAG,iBAAiB,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;IAE7C,MAAM,YAAY,GAAG,eAAe,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;IAEhD,MAAM,UAAU,GAAG,iBAAiB,CAClC,OAAO,EACP,MAAM,EACN,UAAU,CACX,CAAA;IAED,OAAO,CACL,kBACM,QAAQ,EACZ,SAAS,EAAE,WAAW,CACpB,qBAAqB,EACrB,SAAS,CACV,aAEA,cAAc,IAAI,YAAY,CAAC,CAAC,CAAC,CAChC,eAAK,SAAS,EAAC,mDAAmD,aAC/D,cAAc,CAAC,CAAC,CAAC,CAChB,eACE,SAAS,EAAC,wBAAwB,EAClC,EAAE,EAAE,OAAO,YAEV,KAAK,GACD,CACR,CAAC,CAAC,CAAC,CACF,KAAC,cAAc,IAAC,EAAE,EAAE,OAAO,YACxB,KAAK,GACS,CAClB,EAEA,YAAY,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAClC,gBAAM,SAAS,EAAC,iCAAiC,aAC9C,OAAO,SACH,CACR,CAAC,CAAC,CAAC,IAAI,IACJ,CACP,CAAC,CAAC,CAAC,CACF,KAAC,cAAc,IAAC,EAAE,EAAE,OAAO,YACxB,KAAK,GACS,CAClB,EAED,2BACa,eAAe,IAAI,SAAS,qBACtB,OAAO,mBACT,GAAG,mBACH,CAAC,mBAEd,eAAe,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,YAAY,EAE5C,SAAS,EAAE,WAAW,CACpB,gEAAgE,EAChE,gBAAgB,CAAC,IAAI,CAAC,CACvB,EACD,IAAI,EAAC,aAAa,YAEjB,eAAe,CAAC,CAAC,CAAC,CACjB,eACE,SAAS,EAAE,WAAW;oBACpB,sDAAsD;oBACtD,0CAA0C;oBAC1C,kDAAkD;oBAClD,kCAAkC;oBAClC,yDAAyD,EACzD,uBAAuB,CAAC,UAAU,CAAC,CACpC,GACD,CACH,CAAC,CAAC,CAAC,CACF,eACE,SAAS,EAAE,WAAW,CACpB,+FAA+F,EAC/F,uBAAuB,CAAC,UAAU,CAAC,CACpC,EACD,KAAK,EAAE,EAAE,UAAU,EAAE,GAAG,OAAO,GAAG,EAAE,GACpC,CACH,GACG,IACF,CACP,CAAA;AACH,CAAC,CAAA"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { IntentName } from "@charcuterie/tokens";
|
|
2
|
+
/**
|
|
3
|
+
* A threshold is "from this percentage upward, use this intent".
|
|
4
|
+
* Order does not matter — the highest matching entry wins — because
|
|
5
|
+
* a caller sorting a config array by hand is a bug waiting for the
|
|
6
|
+
* day someone appends to it.
|
|
7
|
+
*/
|
|
8
|
+
export type ProgressThreshold = {
|
|
9
|
+
from: number;
|
|
10
|
+
intent: IntentName;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Clamped, rounded, and NaN-proof, in a file a Node test can reach
|
|
14
|
+
* without a browser.
|
|
15
|
+
*
|
|
16
|
+
* All three cases are real. rip-deck's `fillPercent` comes from a
|
|
17
|
+
* ripper's stdout, and a progress value that arrives as `-1`,
|
|
18
|
+
* `101`, or `NaN` from a log parse currently renders as a bar that
|
|
19
|
+
* overflows its track or vanishes. `max: 0` is the one that looks
|
|
20
|
+
* hypothetical and is not: it is "0 of 0 files done", which every
|
|
21
|
+
* empty queue produces on its first render.
|
|
22
|
+
*/
|
|
23
|
+
export declare const toProgressPercent: (value: number, max: number) => number;
|
|
24
|
+
/**
|
|
25
|
+
* The same clamp in the value's own units, for `aria-valuenow`.
|
|
26
|
+
*
|
|
27
|
+
* Reporting the raw prop there would hand assistive technology a
|
|
28
|
+
* `valuenow` outside its own `valuemin`/`valuemax` — which some
|
|
29
|
+
* screen readers render as a nonsense percentage and others drop
|
|
30
|
+
* entirely — while the bar on screen showed the clamped one. The
|
|
31
|
+
* two must not disagree.
|
|
32
|
+
*/
|
|
33
|
+
export declare const toProgressValue: (value: number, max: number) => number;
|
|
34
|
+
/**
|
|
35
|
+
* The threshold colour, or the component's own intent when no
|
|
36
|
+
* threshold applies.
|
|
37
|
+
*
|
|
38
|
+
* This is the piece rip-deck hardcodes as `FILL_CLASS` keyed by a
|
|
39
|
+
* rip state, and mux-magic does not have at all. Generalising it to
|
|
40
|
+
* "percentage → intent" covers both the "green when done" case and
|
|
41
|
+
* the "amber past 80% of the disk" case with one mechanism.
|
|
42
|
+
*/
|
|
43
|
+
export declare const getProgressIntent: (percent: number, intent: IntentName, thresholds?: readonly ProgressThreshold[]) => IntentName;
|
|
44
|
+
//# sourceMappingURL=progressValue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"progressValue.d.ts","sourceRoot":"","sources":["../../src/ProgressBar/progressValue.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAErD;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,UAAU,CAAA;CACnB,CAAA;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB,GAC5B,OAAO,MAAM,EACb,KAAK,MAAM,WAcZ,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,GAC1B,OAAO,MAAM,EACb,KAAK,MAAM,WAOZ,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,GAC5B,SAAS,MAAM,EACf,QAAQ,UAAU,EAClB,aAAa,SAAS,iBAAiB,EAAE,KACxC,UAWF,CAAA"}
|