@blakesteve/roster 5.0.0 → 5.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/README.md +55 -8
- package/dist/components/atoms/Chip/Chip.cjs +1 -1
- package/dist/components/atoms/Chip/Chip.js +27 -27
- package/dist/components/atoms/Disclosure/Disclosure.cjs +1 -1
- package/dist/components/atoms/Disclosure/Disclosure.js +42 -44
- package/dist/components/atoms/Stat/Stat.cjs +1 -1
- package/dist/components/atoms/Stat/Stat.d.ts +27 -2
- package/dist/components/atoms/Stat/Stat.js +38 -13
- package/dist/components/atoms/Switch/Switch.cjs +1 -1
- package/dist/components/atoms/Switch/Switch.d.ts +11 -1
- package/dist/components/atoms/Switch/Switch.js +38 -36
- package/dist/components/atoms/Switch/switch-variants.cjs +1 -1
- package/dist/components/atoms/Switch/switch-variants.js +1 -1
- package/dist/components/molecules/LiquidTabs/LiquidNav.cjs +1 -0
- package/dist/components/molecules/LiquidTabs/LiquidNav.d.ts +62 -0
- package/dist/components/molecules/LiquidTabs/LiquidNav.js +78 -0
- package/dist/components/molecules/LiquidTabs/LiquidTabs.cjs +1 -0
- package/dist/components/molecules/LiquidTabs/LiquidTabs.d.ts +69 -0
- package/dist/components/molecules/LiquidTabs/LiquidTabs.js +92 -0
- package/dist/components/molecules/LiquidTabs/liquid-pill.cjs +1 -0
- package/dist/components/molecules/LiquidTabs/liquid-pill.d.ts +56 -0
- package/dist/components/molecules/LiquidTabs/liquid-pill.js +129 -0
- package/dist/components/molecules/LiquidTabs/liquid-tab-id.cjs +1 -0
- package/dist/components/molecules/LiquidTabs/liquid-tab-id.d.ts +12 -0
- package/dist/components/molecules/LiquidTabs/liquid-tab-id.js +6 -0
- package/dist/components/molecules/Toast/Toaster.cjs +1 -1
- package/dist/components/molecules/Toast/Toaster.d.ts +7 -0
- package/dist/components/molecules/Toast/Toaster.js +67 -45
- package/dist/components/organisms/Dialog/Dialog.cjs +1 -1
- package/dist/components/organisms/Dialog/Dialog.js +102 -79
- package/dist/components/organisms/Navbar/Navbar.cjs +1 -1
- package/dist/components/organisms/Navbar/Navbar.js +157 -157
- package/dist/components/organisms/Sheet/Sheet.cjs +1 -0
- package/dist/components/organisms/Sheet/Sheet.d.ts +82 -0
- package/dist/components/organisms/Sheet/Sheet.js +303 -0
- package/dist/components/organisms/Sheet/sheet-drag.cjs +1 -0
- package/dist/components/organisms/Sheet/sheet-drag.d.ts +40 -0
- package/dist/components/organisms/Sheet/sheet-drag.js +22 -0
- package/dist/hooks/useCountdown.cjs +1 -1
- package/dist/hooks/useCountdown.d.ts +9 -0
- package/dist/hooks/useCountdown.js +20 -23
- package/dist/index.d.ts +4 -1
- package/dist/internal/motion.cjs +1 -0
- package/dist/internal/motion.d.ts +12 -0
- package/dist/internal/motion.js +21 -0
- package/dist/internal/page-inert.cjs +1 -0
- package/dist/internal/page-inert.d.ts +51 -0
- package/dist/internal/page-inert.js +36 -0
- package/dist/meta.json +3 -3
- package/dist/roster.cjs +1 -1
- package/dist/roster.css +1 -1
- package/dist/roster.js +128 -122
- package/package.json +3 -4
- package/dist/components/atoms/LiquidTabs/LiquidTabs.cjs +0 -1
- package/dist/components/atoms/LiquidTabs/LiquidTabs.d.ts +0 -39
- package/dist/components/atoms/LiquidTabs/LiquidTabs.js +0 -120
- package/dist/node_modules/date-fns/_lib/getRoundingMethod.cjs +0 -1
- package/dist/node_modules/date-fns/_lib/getRoundingMethod.js +0 -9
- package/dist/node_modules/date-fns/_lib/getTimezoneOffsetInMilliseconds.cjs +0 -1
- package/dist/node_modules/date-fns/_lib/getTimezoneOffsetInMilliseconds.js +0 -18
- package/dist/node_modules/date-fns/_lib/normalizeDates.cjs +0 -1
- package/dist/node_modules/date-fns/_lib/normalizeDates.js +0 -11
- package/dist/node_modules/date-fns/_lib/normalizeInterval.cjs +0 -1
- package/dist/node_modules/date-fns/_lib/normalizeInterval.js +0 -8
- package/dist/node_modules/date-fns/add.cjs +0 -1
- package/dist/node_modules/date-fns/add.js +0 -19
- package/dist/node_modules/date-fns/addDays.cjs +0 -1
- package/dist/node_modules/date-fns/addDays.js +0 -9
- package/dist/node_modules/date-fns/addMonths.cjs +0 -1
- package/dist/node_modules/date-fns/addMonths.js +0 -19
- package/dist/node_modules/date-fns/compareAsc.cjs +0 -1
- package/dist/node_modules/date-fns/compareAsc.js +0 -8
- package/dist/node_modules/date-fns/constants.cjs +0 -1
- package/dist/node_modules/date-fns/constants.js +0 -7
- package/dist/node_modules/date-fns/constructFrom.cjs +0 -1
- package/dist/node_modules/date-fns/constructFrom.js +0 -7
- package/dist/node_modules/date-fns/differenceInCalendarDays.cjs +0 -1
- package/dist/node_modules/date-fns/differenceInCalendarDays.js +0 -15
- package/dist/node_modules/date-fns/differenceInCalendarMonths.cjs +0 -1
- package/dist/node_modules/date-fns/differenceInCalendarMonths.js +0 -12
- package/dist/node_modules/date-fns/differenceInCalendarYears.cjs +0 -1
- package/dist/node_modules/date-fns/differenceInCalendarYears.js +0 -12
- package/dist/node_modules/date-fns/differenceInDays.cjs +0 -1
- package/dist/node_modules/date-fns/differenceInDays.js +0 -21
- package/dist/node_modules/date-fns/differenceInHours.cjs +0 -1
- package/dist/node_modules/date-fns/differenceInHours.js +0 -14
- package/dist/node_modules/date-fns/differenceInMilliseconds.cjs +0 -1
- package/dist/node_modules/date-fns/differenceInMilliseconds.js +0 -7
- package/dist/node_modules/date-fns/differenceInMinutes.cjs +0 -1
- package/dist/node_modules/date-fns/differenceInMinutes.js +0 -10
- package/dist/node_modules/date-fns/differenceInMonths.cjs +0 -1
- package/dist/node_modules/date-fns/differenceInMonths.js +0 -23
- package/dist/node_modules/date-fns/differenceInSeconds.cjs +0 -1
- package/dist/node_modules/date-fns/differenceInSeconds.js +0 -9
- package/dist/node_modules/date-fns/differenceInYears.cjs +0 -1
- package/dist/node_modules/date-fns/differenceInYears.js +0 -16
- package/dist/node_modules/date-fns/endOfDay.cjs +0 -1
- package/dist/node_modules/date-fns/endOfDay.js +0 -8
- package/dist/node_modules/date-fns/endOfMonth.cjs +0 -1
- package/dist/node_modules/date-fns/endOfMonth.js +0 -8
- package/dist/node_modules/date-fns/intervalToDuration.cjs +0 -1
- package/dist/node_modules/date-fns/intervalToDuration.js +0 -25
- package/dist/node_modules/date-fns/isAfter.cjs +0 -1
- package/dist/node_modules/date-fns/isAfter.js +0 -7
- package/dist/node_modules/date-fns/isLastDayOfMonth.cjs +0 -1
- package/dist/node_modules/date-fns/isLastDayOfMonth.js +0 -10
- package/dist/node_modules/date-fns/startOfDay.cjs +0 -1
- package/dist/node_modules/date-fns/startOfDay.js +0 -8
- package/dist/node_modules/date-fns/toDate.cjs +0 -1
- package/dist/node_modules/date-fns/toDate.js +0 -7
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface SheetProps {
|
|
3
|
+
isOpen: boolean;
|
|
4
|
+
/** Called by Escape, a backdrop click, the close button and a dismissing drag. */
|
|
5
|
+
onClose: () => void;
|
|
6
|
+
/**
|
|
7
|
+
* Called once the leave transition has finished and the sheet is gone.
|
|
8
|
+
*
|
|
9
|
+
* Clear the sheet's content here rather than in `onClose`. Cleared in
|
|
10
|
+
* `onClose`, it empties while it is still sliding out.
|
|
11
|
+
*/
|
|
12
|
+
onAfterClose?: () => void;
|
|
13
|
+
/**
|
|
14
|
+
* The sheet's accessible name, rendered as an `h2`. Required, because a
|
|
15
|
+
* dialog without a name is announced as "dialog" and nothing else.
|
|
16
|
+
*
|
|
17
|
+
* Changing it while the sheet is open counts as a content swap: focus moves
|
|
18
|
+
* to the new title so a screen reader announces it. Not while `busy`: a
|
|
19
|
+
* title that changes during loading is a provisional one being refined, and
|
|
20
|
+
* the reader keeps their place.
|
|
21
|
+
*/
|
|
22
|
+
title: string;
|
|
23
|
+
/** Hides the title visually. It stays the accessible name. */
|
|
24
|
+
hideTitle?: boolean;
|
|
25
|
+
/** Wired to the dialog's `aria-describedby`. */
|
|
26
|
+
description?: React.ReactNode;
|
|
27
|
+
/** A slot in the header, before the close button: previous and next, say. */
|
|
28
|
+
actions?: React.ReactNode;
|
|
29
|
+
/**
|
|
30
|
+
* The sheet's width from 768px up, where it centers. A number is px. Below
|
|
31
|
+
* 768px the sheet is always full width.
|
|
32
|
+
*/
|
|
33
|
+
maxWidth?: number | string;
|
|
34
|
+
/** What receives focus on open. Defaults to the close button. */
|
|
35
|
+
initialFocus?: React.RefObject<HTMLElement | null>;
|
|
36
|
+
/**
|
|
37
|
+
* Where focus goes on close, over whatever opened the sheet.
|
|
38
|
+
*
|
|
39
|
+
* A sheet opened on page load from a deep link has no opener, so without
|
|
40
|
+
* this focus falls to `<body>`.
|
|
41
|
+
*/
|
|
42
|
+
returnFocus?: React.RefObject<HTMLElement | null> | HTMLElement | null;
|
|
43
|
+
/** Sets `aria-busy` on the content region while its content loads. */
|
|
44
|
+
busy?: boolean;
|
|
45
|
+
/** Drag the handle or header down to dismiss. The close button stays either way. */
|
|
46
|
+
dragToDismiss?: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Counts as a content swap when it changes, like `title` does. For content
|
|
49
|
+
* that changes under an unchanged title.
|
|
50
|
+
*/
|
|
51
|
+
contentKey?: React.Key;
|
|
52
|
+
/** Applied to the panel. */
|
|
53
|
+
className?: string;
|
|
54
|
+
children: React.ReactNode;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* A panel anchored to the bottom of the screen, for detail that should not
|
|
58
|
+
* take the reader off the page: full width on a phone, centered at `maxWidth`
|
|
59
|
+
* from 768px.
|
|
60
|
+
*
|
|
61
|
+
* Three stacked parts, and only the last scrolls: a drag handle, a header with
|
|
62
|
+
* the title, the `actions` slot and a close button, and the content. The header
|
|
63
|
+
* is a sibling of the scroller rather than sticky inside it, so it can never
|
|
64
|
+
* cover the element that has focus.
|
|
65
|
+
*
|
|
66
|
+
* Built on Headless UI's `Dialog`, so the focus trap, Escape and the scroll
|
|
67
|
+
* lock are its. The rest of the page is made `inert` and `aria-hidden` by
|
|
68
|
+
* Headless UI and Roster together, every child of `<body>` but the dialog
|
|
69
|
+
* layer and the toast host. The scroll lock pads `<html>`
|
|
70
|
+
* for the scrollbar it hides; a fixed element elsewhere on the page can still
|
|
71
|
+
* shift by that width.
|
|
72
|
+
*
|
|
73
|
+
* Renders an empty `<span hidden>` where it is placed, to find out whether it
|
|
74
|
+
* sits inside a scoped `.dark` subtree and which part of the page it was
|
|
75
|
+
* opened from. The sheet itself is portaled to `<body>`, so it could not tell
|
|
76
|
+
* otherwise.
|
|
77
|
+
*
|
|
78
|
+
* The bottom padding includes `env(safe-area-inset-bottom)`, which is 0 unless
|
|
79
|
+
* the page's viewport meta sets `viewport-fit=cover`.
|
|
80
|
+
*/
|
|
81
|
+
declare const Sheet: ({ isOpen, onClose, onAfterClose, title, hideTitle, description, actions, maxWidth, initialFocus, returnFocus, busy, dragToDismiss, contentKey, className, children, }: SheetProps) => import("react/jsx-runtime").JSX.Element;
|
|
82
|
+
export { Sheet };
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsxs as d, Fragment as G, jsx as n } from "react/jsx-runtime";
|
|
3
|
+
import * as s from "react";
|
|
4
|
+
import { Description as K } from "../../../node_modules/@headlessui/react/dist/components/description/description.js";
|
|
5
|
+
import { Dialog as Q, DialogBackdrop as H, DialogPanel as J, DialogTitle as Z } from "../../../node_modules/@headlessui/react/dist/components/dialog/dialog.js";
|
|
6
|
+
import { TransitionChild as W } from "../../../node_modules/@headlessui/react/dist/components/transition/transition.js";
|
|
7
|
+
import { cn as f } from "../../../lib/utils.js";
|
|
8
|
+
import { useDarkScope as O } from "../../../internal/popup.js";
|
|
9
|
+
import { useReducedMotion as tt } from "../../../internal/motion.js";
|
|
10
|
+
import { lockPage as et } from "../../../internal/page-inert.js";
|
|
11
|
+
import { sheetDragOutcome as rt, sheetReleaseVelocity as st, exceedsSheetTapSlop as nt } from "./sheet-drag.js";
|
|
12
|
+
const ot = "rst:transition-transform rst:duration-(--roster-sheet-enter-duration) rst:ease-(--roster-sheet-enter-easing) rst:data-leave:duration-(--roster-sheet-leave-duration) rst:data-leave:ease-(--roster-sheet-leave-easing) rst:data-closed:translate-y-full", at = "rst:transition-opacity rst:duration-(--roster-sheet-fade-duration) rst:ease-out rst:data-closed:opacity-0", it = "rst:transition-opacity rst:duration-(--roster-sheet-enter-duration) rst:ease-out rst:data-leave:duration-(--roster-sheet-leave-duration) rst:data-closed:opacity-0", ct = "rst:transition-opacity rst:duration-(--roster-sheet-fade-duration) rst:ease-out rst:data-closed:opacity-0", ut = [
|
|
13
|
+
"input:not([type=checkbox]):not([type=radio]):not([type=button]):not([type=submit]):not([type=reset]):not([type=range]):not([type=color]):not([type=file]):not([type=image])",
|
|
14
|
+
"textarea",
|
|
15
|
+
"select",
|
|
16
|
+
"[contenteditable]:not([contenteditable=false])"
|
|
17
|
+
].join(",");
|
|
18
|
+
function lt(r) {
|
|
19
|
+
return r ? "current" in r ? r.current : r : null;
|
|
20
|
+
}
|
|
21
|
+
function dt({ target: r }) {
|
|
22
|
+
const l = s.useRef(r), p = s.useRef(!1);
|
|
23
|
+
return s.useEffect(() => {
|
|
24
|
+
l.current = r;
|
|
25
|
+
}), s.useEffect(() => (p.current = !1, () => {
|
|
26
|
+
p.current = !0, queueMicrotask(() => {
|
|
27
|
+
if (!p.current) return;
|
|
28
|
+
const c = lt(l.current);
|
|
29
|
+
c?.isConnected && c.focus();
|
|
30
|
+
});
|
|
31
|
+
}), []), null;
|
|
32
|
+
}
|
|
33
|
+
function ft() {
|
|
34
|
+
return /* @__PURE__ */ n(
|
|
35
|
+
"svg",
|
|
36
|
+
{
|
|
37
|
+
"aria-hidden": "true",
|
|
38
|
+
focusable: "false",
|
|
39
|
+
viewBox: "0 0 20 20",
|
|
40
|
+
className: "rst:h-5 rst:w-5",
|
|
41
|
+
fill: "none",
|
|
42
|
+
stroke: "currentColor",
|
|
43
|
+
strokeWidth: "2",
|
|
44
|
+
strokeLinecap: "round",
|
|
45
|
+
children: /* @__PURE__ */ n("path", { d: "M5 5l10 10M15 5L5 15" })
|
|
46
|
+
}
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
const Rt = ({
|
|
50
|
+
isOpen: r,
|
|
51
|
+
onClose: l,
|
|
52
|
+
onAfterClose: p,
|
|
53
|
+
title: c,
|
|
54
|
+
hideTitle: j = !1,
|
|
55
|
+
description: C,
|
|
56
|
+
actions: L,
|
|
57
|
+
maxWidth: b = 560,
|
|
58
|
+
initialFocus: v,
|
|
59
|
+
returnFocus: z,
|
|
60
|
+
busy: h = !1,
|
|
61
|
+
dragToDismiss: x = !0,
|
|
62
|
+
contentKey: m,
|
|
63
|
+
className: Y,
|
|
64
|
+
children: B
|
|
65
|
+
}) => {
|
|
66
|
+
const { ref: E, inDarkScope: T } = O(), N = tt();
|
|
67
|
+
s.useLayoutEffect(() => {
|
|
68
|
+
if (r)
|
|
69
|
+
return et(E.current);
|
|
70
|
+
}, [r, E]);
|
|
71
|
+
const i = s.useRef(null), D = s.useRef(null), I = s.useRef(null), R = s.useRef(null), k = s.useRef(null), w = s.useId(), P = s.useRef({ title: c, contentKey: m, open: r, busy: h });
|
|
72
|
+
s.useEffect(() => {
|
|
73
|
+
const t = P.current;
|
|
74
|
+
if (P.current = { title: c, contentKey: m, open: r, busy: h }, !t.open || !r) return;
|
|
75
|
+
const e = t.contentKey !== m, o = t.title !== c && !t.busy;
|
|
76
|
+
!e && !o || (I.current?.focus(), k.current && (k.current.scrollTop = 0));
|
|
77
|
+
}, [c, m, r, h]), s.useEffect(() => {
|
|
78
|
+
if (!r) return;
|
|
79
|
+
const t = requestAnimationFrame(() => {
|
|
80
|
+
const e = i.current, o = document.activeElement;
|
|
81
|
+
!e || o && e.contains(o) || (v?.current ?? R.current)?.focus();
|
|
82
|
+
});
|
|
83
|
+
return () => cancelAnimationFrame(t);
|
|
84
|
+
}, [r, v]);
|
|
85
|
+
const [S, M] = s.useState(null);
|
|
86
|
+
s.useEffect(() => {
|
|
87
|
+
if (!r) return;
|
|
88
|
+
const t = window.visualViewport;
|
|
89
|
+
if (!t) return;
|
|
90
|
+
const e = () => {
|
|
91
|
+
const o = document.activeElement, u = !!o && !!i.current?.contains(o) && o.matches(ut);
|
|
92
|
+
M(u ? Math.round(t.height) : null);
|
|
93
|
+
};
|
|
94
|
+
return t.addEventListener("resize", e), document.addEventListener("focusin", e), document.addEventListener("focusout", e), () => {
|
|
95
|
+
t.removeEventListener("resize", e), document.removeEventListener("focusin", e), document.removeEventListener("focusout", e), M(null);
|
|
96
|
+
};
|
|
97
|
+
}, [r]);
|
|
98
|
+
const a = s.useRef(null), g = s.useRef(!1), A = s.useRef(r);
|
|
99
|
+
s.useEffect(() => {
|
|
100
|
+
A.current = r;
|
|
101
|
+
}, [r]);
|
|
102
|
+
const y = (t) => {
|
|
103
|
+
i.current?.style.setProperty("--rst-sheet-drag", `${t}px`);
|
|
104
|
+
}, F = (t) => {
|
|
105
|
+
const e = i.current;
|
|
106
|
+
a.current = null, e && (delete e.dataset.dragging, t === "close" ? (l(), requestAnimationFrame(() => {
|
|
107
|
+
A.current && !a.current && y(0);
|
|
108
|
+
})) : y(0));
|
|
109
|
+
};
|
|
110
|
+
s.useEffect(() => {
|
|
111
|
+
!r && a.current && (a.current = null, i.current && delete i.current.dataset.dragging), r && !a.current && y(0);
|
|
112
|
+
}, [r]);
|
|
113
|
+
const _ = (t) => {
|
|
114
|
+
a.current || (g.current = !1, !(!x || !r) && (t.pointerType === "mouse" && (t.button !== 0 || !D.current?.contains(t.target)) || (a.current = {
|
|
115
|
+
pointerId: t.pointerId,
|
|
116
|
+
x0: t.clientX,
|
|
117
|
+
y0: t.clientY,
|
|
118
|
+
dy: 0,
|
|
119
|
+
phase: "pending",
|
|
120
|
+
samples: [{ t: t.timeStamp, y: t.clientY }]
|
|
121
|
+
})));
|
|
122
|
+
}, q = (t) => {
|
|
123
|
+
const e = a.current;
|
|
124
|
+
if (!e || t.pointerId !== e.pointerId) return;
|
|
125
|
+
const o = t.clientX - e.x0, u = t.clientY - e.y0;
|
|
126
|
+
if (e.phase === "pending") {
|
|
127
|
+
if (!nt(o, u)) return;
|
|
128
|
+
if (Math.abs(o) > Math.abs(u)) {
|
|
129
|
+
e.phase = "ignored";
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
e.phase = "dragging", g.current = !0;
|
|
133
|
+
try {
|
|
134
|
+
t.currentTarget.setPointerCapture(t.pointerId);
|
|
135
|
+
} catch {
|
|
136
|
+
}
|
|
137
|
+
i.current && (i.current.dataset.dragging = "");
|
|
138
|
+
}
|
|
139
|
+
e.phase === "dragging" && (e.dy = u, e.samples.push({ t: t.timeStamp, y: t.clientY }), e.samples.length > 32 && e.samples.shift(), y(Math.max(0, u)));
|
|
140
|
+
}, $ = (t) => {
|
|
141
|
+
const e = a.current;
|
|
142
|
+
if (!e || t.pointerId !== e.pointerId) return;
|
|
143
|
+
if (e.phase !== "dragging") {
|
|
144
|
+
a.current = null;
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
e.samples.push({ t: t.timeStamp, y: t.clientY });
|
|
148
|
+
const o = t.clientY - e.y0, u = i.current?.getBoundingClientRect().height ?? 0;
|
|
149
|
+
F(rt(o, u, st(e.samples)));
|
|
150
|
+
}, U = (t) => {
|
|
151
|
+
const e = a.current;
|
|
152
|
+
!e || t.pointerId !== e.pointerId || (e.phase === "dragging" ? F("stay") : a.current = null);
|
|
153
|
+
}, V = (t) => {
|
|
154
|
+
!g.current || t.detail === 0 || (g.current = !1, t.preventDefault(), t.stopPropagation());
|
|
155
|
+
}, X = {
|
|
156
|
+
"--rst-sheet-max-width": typeof b == "number" ? `${b}px` : b,
|
|
157
|
+
...S !== null && { "--rst-sheet-keyboard-cap": `${S}px` }
|
|
158
|
+
};
|
|
159
|
+
return /* @__PURE__ */ d(G, { children: [
|
|
160
|
+
/* @__PURE__ */ n("span", { ref: E, hidden: !0 }),
|
|
161
|
+
/* @__PURE__ */ d(
|
|
162
|
+
Q,
|
|
163
|
+
{
|
|
164
|
+
open: r,
|
|
165
|
+
as: "div",
|
|
166
|
+
onClose: l,
|
|
167
|
+
initialFocus: v ?? R,
|
|
168
|
+
className: f(
|
|
169
|
+
"rst:font-ui rst:relative rst:z-50 rst:focus:outline-hidden",
|
|
170
|
+
T && "dark"
|
|
171
|
+
),
|
|
172
|
+
children: [
|
|
173
|
+
/* @__PURE__ */ n(
|
|
174
|
+
H,
|
|
175
|
+
{
|
|
176
|
+
transition: !0,
|
|
177
|
+
"data-testid": "sheet-backdrop",
|
|
178
|
+
className: f(
|
|
179
|
+
"rst:fixed rst:inset-0 rst:bg-(--roster-sheet-backdrop)",
|
|
180
|
+
N ? ct : it
|
|
181
|
+
)
|
|
182
|
+
}
|
|
183
|
+
),
|
|
184
|
+
/* @__PURE__ */ n("div", { className: "rst:fixed rst:inset-0 rst:flex rst:items-end rst:justify-center", children: /* @__PURE__ */ n(W, { afterLeave: p, children: /* @__PURE__ */ d(
|
|
185
|
+
J,
|
|
186
|
+
{
|
|
187
|
+
ref: i,
|
|
188
|
+
style: X,
|
|
189
|
+
"data-testid": "sheet-panel",
|
|
190
|
+
className: f(
|
|
191
|
+
/* 92dvh, or the visual viewport while the keyboard is up,
|
|
192
|
+
whichever is shorter. */
|
|
193
|
+
"rst:relative rst:flex rst:max-h-[min(92dvh,var(--rst-sheet-keyboard-cap,92dvh))] rst:w-full rst:flex-col",
|
|
194
|
+
"rst:md:max-w-(--rst-sheet-max-width)",
|
|
195
|
+
"rst:rounded-t-2xl rst:border rst:border-b-0 rst:elevation-overlay",
|
|
196
|
+
"rst:bg-[var(--roster-popover-bg)] rst:border-[var(--roster-popover-border)] rst:text-[var(--roster-popover-text)]",
|
|
197
|
+
/* The ring offset paints the gap between a focused control and
|
|
198
|
+
its ring, so it has to be this surface, not the page. */
|
|
199
|
+
"rst:[--roster-ring-offset:var(--roster-popover-bg)]",
|
|
200
|
+
"rst:pb-[env(safe-area-inset-bottom)]",
|
|
201
|
+
"rst:translate-y-[var(--rst-sheet-drag,0px)]",
|
|
202
|
+
N ? at : ot,
|
|
203
|
+
"rst:data-dragging:transition-none",
|
|
204
|
+
Y
|
|
205
|
+
),
|
|
206
|
+
children: [
|
|
207
|
+
/* @__PURE__ */ d(
|
|
208
|
+
"div",
|
|
209
|
+
{
|
|
210
|
+
"data-testid": "sheet-drag-zone",
|
|
211
|
+
className: f("rst:shrink-0", x && "rst:touch-none"),
|
|
212
|
+
onPointerDown: _,
|
|
213
|
+
onPointerMove: q,
|
|
214
|
+
onPointerUp: $,
|
|
215
|
+
onPointerCancel: U,
|
|
216
|
+
onClickCapture: V,
|
|
217
|
+
children: [
|
|
218
|
+
/* @__PURE__ */ n(
|
|
219
|
+
"div",
|
|
220
|
+
{
|
|
221
|
+
ref: D,
|
|
222
|
+
"aria-hidden": "true",
|
|
223
|
+
"data-testid": "sheet-handle",
|
|
224
|
+
className: f(
|
|
225
|
+
/* The grip sits near the top edge, where a sheet's grabber
|
|
226
|
+
is expected, inside a 44px strip. The header below pulls
|
|
227
|
+
up over the strip's lower part, so a touch there drags
|
|
228
|
+
too (the header is a drag zone) and a mouse drags from
|
|
229
|
+
the 32px above it, the full width of the sheet. */
|
|
230
|
+
"rst:flex rst:h-11 rst:items-start rst:justify-center rst:pt-2",
|
|
231
|
+
x && "rst:cursor-grab rst:active:cursor-grabbing"
|
|
232
|
+
),
|
|
233
|
+
children: /* @__PURE__ */ n("span", { className: "rst:h-1 rst:w-10 rst:rounded-full rst:bg-current rst:opacity-30" })
|
|
234
|
+
}
|
|
235
|
+
),
|
|
236
|
+
/* @__PURE__ */ d("div", { className: "rst:-mt-3 rst:flex rst:items-start rst:gap-2 rst:px-5 rst:pb-4", children: [
|
|
237
|
+
/* @__PURE__ */ d("div", { className: "rst:min-w-0 rst:flex-1 rst:pt-2", children: [
|
|
238
|
+
/* @__PURE__ */ n(
|
|
239
|
+
Z,
|
|
240
|
+
{
|
|
241
|
+
as: "h2",
|
|
242
|
+
id: w,
|
|
243
|
+
ref: I,
|
|
244
|
+
tabIndex: -1,
|
|
245
|
+
className: f(
|
|
246
|
+
"rst:text-lg rst:font-semibold rst:text-inherit rst:focus:outline-hidden",
|
|
247
|
+
j && "rst:sr-only"
|
|
248
|
+
),
|
|
249
|
+
children: c
|
|
250
|
+
}
|
|
251
|
+
),
|
|
252
|
+
C && /* @__PURE__ */ n(
|
|
253
|
+
K,
|
|
254
|
+
{
|
|
255
|
+
as: "p",
|
|
256
|
+
className: "rst:mt-1 rst:text-sm rst:text-inherit rst:opacity-75",
|
|
257
|
+
children: C
|
|
258
|
+
}
|
|
259
|
+
)
|
|
260
|
+
] }),
|
|
261
|
+
L && /* 44px tall like the close button, so actions of any
|
|
262
|
+
height center on the same line as it. */
|
|
263
|
+
/* @__PURE__ */ n("div", { className: "rst:flex rst:h-11 rst:shrink-0 rst:items-center rst:gap-1", children: L }),
|
|
264
|
+
/* @__PURE__ */ n(
|
|
265
|
+
"button",
|
|
266
|
+
{
|
|
267
|
+
ref: R,
|
|
268
|
+
type: "button",
|
|
269
|
+
onClick: l,
|
|
270
|
+
"aria-label": "Close",
|
|
271
|
+
className: "rst:inline-flex rst:size-11 rst:shrink-0 rst:-mr-2 rst:cursor-pointer rst:items-center rst:justify-center rst:rounded-md rst:bg-transparent rst:text-inherit rst:opacity-60 rst:transition-opacity rst:hover:opacity-100 rst:focus:outline-hidden rst:focus-visible:opacity-100 rst:focus-visible:ring-2 rst:focus-visible:ring-ring rst:focus-visible:ring-offset-2 rst:ring-offset-background",
|
|
272
|
+
children: /* @__PURE__ */ n(ft, {})
|
|
273
|
+
}
|
|
274
|
+
)
|
|
275
|
+
] })
|
|
276
|
+
]
|
|
277
|
+
}
|
|
278
|
+
),
|
|
279
|
+
/* @__PURE__ */ n(
|
|
280
|
+
"div",
|
|
281
|
+
{
|
|
282
|
+
ref: k,
|
|
283
|
+
role: "region",
|
|
284
|
+
"aria-labelledby": w,
|
|
285
|
+
tabIndex: 0,
|
|
286
|
+
"data-testid": "sheet-content",
|
|
287
|
+
"aria-busy": h || void 0,
|
|
288
|
+
className: "rst:min-h-0 rst:flex-1 rst:overflow-y-auto rst:overscroll-contain rst:px-5 rst:pb-4 rst:focus:outline-hidden rst:ring-inset rst:focus-visible:ring-2 rst:focus-visible:ring-ring",
|
|
289
|
+
children: B
|
|
290
|
+
}
|
|
291
|
+
),
|
|
292
|
+
/* @__PURE__ */ n(dt, { target: z })
|
|
293
|
+
]
|
|
294
|
+
}
|
|
295
|
+
) }) })
|
|
296
|
+
]
|
|
297
|
+
}
|
|
298
|
+
)
|
|
299
|
+
] });
|
|
300
|
+
};
|
|
301
|
+
export {
|
|
302
|
+
Rt as Sheet
|
|
303
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const S=8,r=.3,n=.5,T=16,_=100;function s(t,e,E){return E<=-n||t<=S?"stay":t>e*r||E>=n&&t>=T?"close":"stay"}function u(t,e){return Math.hypot(t,e)>S}function I(t){if(t.length<2)return 0;const e=t[t.length-1],E=t.find(c=>e.t-c.t<=_)??e,o=e.t-E.t;return o>0?(e.y-E.y)/o:0}exports.SHEET_CLOSE_DISTANCE=r;exports.SHEET_FLICK_MIN_DISTANCE=T;exports.SHEET_FLICK_VELOCITY=n;exports.SHEET_TAP_SLOP=S;exports.SHEET_VELOCITY_WINDOW=_;exports.exceedsSheetTapSlop=u;exports.sheetDragOutcome=s;exports.sheetReleaseVelocity=I;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* When a drag on a sheet's handle or header dismisses it.
|
|
3
|
+
*
|
|
4
|
+
* Pure, and kept out of the component so the thresholds can be tested with
|
|
5
|
+
* literal numbers. jsdom has no layout, so a test that read the height from the
|
|
6
|
+
* DOM would be testing zero.
|
|
7
|
+
*/
|
|
8
|
+
/** Movement at or under this, in px, is a tap rather than a drag. */
|
|
9
|
+
export declare const SHEET_TAP_SLOP = 8;
|
|
10
|
+
/** A drag further than this share of the sheet's height closes it. */
|
|
11
|
+
export declare const SHEET_CLOSE_DISTANCE = 0.3;
|
|
12
|
+
/** A downward flick at or above this speed, in px/ms, closes the sheet... */
|
|
13
|
+
export declare const SHEET_FLICK_VELOCITY = 0.5;
|
|
14
|
+
/** ...as long as it traveled at least this far, in px. */
|
|
15
|
+
export declare const SHEET_FLICK_MIN_DISTANCE = 16;
|
|
16
|
+
/** Release velocity is averaged over this much of the end of the drag, in ms. */
|
|
17
|
+
export declare const SHEET_VELOCITY_WINDOW = 100;
|
|
18
|
+
export type SheetDragOutcome = "close" | "stay";
|
|
19
|
+
/**
|
|
20
|
+
* @param dy downward travel in px; negative is upward
|
|
21
|
+
* @param sheetHeight the sheet's rendered height in px
|
|
22
|
+
* @param velocity px/ms at release, downward positive, from `sheetReleaseVelocity`
|
|
23
|
+
*/
|
|
24
|
+
export declare function sheetDragOutcome(dy: number, sheetHeight: number, velocity: number): SheetDragOutcome;
|
|
25
|
+
/** Whether a pointer that moved this far has stopped being a tap. */
|
|
26
|
+
export declare function exceedsSheetTapSlop(dx: number, dy: number): boolean;
|
|
27
|
+
export interface SheetDragSample {
|
|
28
|
+
/** A timestamp in ms, from the pointer event. */
|
|
29
|
+
t: number;
|
|
30
|
+
/** The pointer's clientY in px. */
|
|
31
|
+
y: number;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Downward speed in px/ms over the last `SHEET_VELOCITY_WINDOW` ms of samples.
|
|
35
|
+
*
|
|
36
|
+
* The window is measured back from the LAST sample, not from now: a finger
|
|
37
|
+
* that stops and then lifts has a last sample from when it stopped, and the
|
|
38
|
+
* pause belongs in the average. Zero when the window holds a single instant.
|
|
39
|
+
*/
|
|
40
|
+
export declare function sheetReleaseVelocity(samples: readonly SheetDragSample[]): number;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const e = 8, S = 0.3, r = 0.5, I = 16, o = 100;
|
|
2
|
+
function C(t, E, _) {
|
|
3
|
+
return _ <= -0.5 || t <= 8 ? "stay" : t > E * 0.3 || _ >= 0.5 && t >= 16 ? "close" : "stay";
|
|
4
|
+
}
|
|
5
|
+
function c(t, E) {
|
|
6
|
+
return Math.hypot(t, E) > 8;
|
|
7
|
+
}
|
|
8
|
+
function L(t) {
|
|
9
|
+
if (t.length < 2) return 0;
|
|
10
|
+
const E = t[t.length - 1], _ = t.find((T) => E.t - T.t <= 100) ?? E, n = E.t - _.t;
|
|
11
|
+
return n > 0 ? (E.y - _.y) / n : 0;
|
|
12
|
+
}
|
|
13
|
+
export {
|
|
14
|
+
S as SHEET_CLOSE_DISTANCE,
|
|
15
|
+
I as SHEET_FLICK_MIN_DISTANCE,
|
|
16
|
+
r as SHEET_FLICK_VELOCITY,
|
|
17
|
+
e as SHEET_TAP_SLOP,
|
|
18
|
+
o as SHEET_VELOCITY_WINDOW,
|
|
19
|
+
c as exceedsSheetTapSlop,
|
|
20
|
+
C as sheetDragOutcome,
|
|
21
|
+
L as sheetReleaseVelocity
|
|
22
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use client";"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("react"),l=o=>{const e=o.getTime(),n=r.useCallback(()=>{if(Number.isNaN(e))return{days:0,hours:0,minutes:0,seconds:0,isFinished:!1};const s=e-Date.now();if(s<0)return{days:0,hours:0,minutes:0,seconds:0,isFinished:!0};const t=Math.floor(s/1e3);return{days:Math.floor(t/86400),hours:Math.floor(t%86400/3600),minutes:Math.floor(t%3600/60),seconds:t%60,isFinished:!1}},[e]),[a,i]=r.useState(n),[u,c]=r.useState(e);return Object.is(u,e)||(c(e),i(n())),r.useEffect(()=>{if(Number.isNaN(e))return;const s=setInterval(()=>{const t=n();i(t),t.isFinished&&clearInterval(s)},1e3);return()=>clearInterval(s)},[e,n]),a};exports.useCountdown=l;
|
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
interface CountdownResult {
|
|
2
|
+
/**
|
|
3
|
+
* Whole days remaining, as the full total rather than a remainder within a
|
|
4
|
+
* month. A target a year out reads 365, so a display that assumes two digits
|
|
5
|
+
* needs room for three.
|
|
6
|
+
*/
|
|
2
7
|
days: number;
|
|
8
|
+
/** Hours past the whole days, 0 to 23. */
|
|
3
9
|
hours: number;
|
|
10
|
+
/** Minutes past the whole hours, 0 to 59. */
|
|
4
11
|
minutes: number;
|
|
12
|
+
/** Seconds past the whole minutes, 0 to 59. */
|
|
5
13
|
seconds: number;
|
|
14
|
+
/** True once the target has passed. Stays false for an invalid target. */
|
|
6
15
|
isFinished: boolean;
|
|
7
16
|
}
|
|
8
17
|
export declare const useCountdown: (targetDate: Date) => CountdownResult;
|
|
@@ -1,33 +1,30 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { useCallback as
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
if (
|
|
2
|
+
import { useCallback as l, useState as i, useEffect as f } from "react";
|
|
3
|
+
const m = (o) => {
|
|
4
|
+
const e = o.getTime(), n = l(() => {
|
|
5
|
+
if (Number.isNaN(e))
|
|
6
|
+
return { days: 0, hours: 0, minutes: 0, seconds: 0, isFinished: !1 };
|
|
7
|
+
const s = e - Date.now();
|
|
8
|
+
if (s < 0)
|
|
9
9
|
return { days: 0, hours: 0, minutes: 0, seconds: 0, isFinished: !0 };
|
|
10
|
-
const
|
|
11
|
-
start: t,
|
|
12
|
-
end: s
|
|
13
|
-
});
|
|
10
|
+
const t = Math.floor(s / 1e3);
|
|
14
11
|
return {
|
|
15
|
-
days:
|
|
16
|
-
hours:
|
|
17
|
-
minutes:
|
|
18
|
-
seconds:
|
|
12
|
+
days: Math.floor(t / 86400),
|
|
13
|
+
hours: Math.floor(t % 86400 / 3600),
|
|
14
|
+
minutes: Math.floor(t % 3600 / 60),
|
|
15
|
+
seconds: t % 60,
|
|
19
16
|
isFinished: !1
|
|
20
17
|
};
|
|
21
|
-
}, [e]), [
|
|
22
|
-
return Object.is(
|
|
18
|
+
}, [e]), [a, r] = i(n), [u, c] = i(e);
|
|
19
|
+
return Object.is(u, e) || (c(e), r(n())), f(() => {
|
|
23
20
|
if (Number.isNaN(e)) return;
|
|
24
|
-
const
|
|
25
|
-
const
|
|
26
|
-
|
|
21
|
+
const s = setInterval(() => {
|
|
22
|
+
const t = n();
|
|
23
|
+
r(t), t.isFinished && clearInterval(s);
|
|
27
24
|
}, 1e3);
|
|
28
|
-
return () => clearInterval(
|
|
29
|
-
}, [e, n]),
|
|
25
|
+
return () => clearInterval(s);
|
|
26
|
+
}, [e, n]), a;
|
|
30
27
|
};
|
|
31
28
|
export {
|
|
32
|
-
|
|
29
|
+
m as useCountdown
|
|
33
30
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -37,7 +37,6 @@ export * from './components/atoms/Switch/switch-variants';
|
|
|
37
37
|
export * from './components/atoms/Textarea/Textarea';
|
|
38
38
|
export * from './components/atoms/Textarea/textarea-variants';
|
|
39
39
|
export * from './components/atoms/AvatarStrip/AvatarStrip';
|
|
40
|
-
export * from './components/atoms/LiquidTabs/LiquidTabs';
|
|
41
40
|
export * from './components/atoms/Tooltip/Tooltip';
|
|
42
41
|
export * from './components/atoms/CollapsibleSection/CollapsibleSection';
|
|
43
42
|
export * from './components/atoms/SegmentBar/SegmentBar';
|
|
@@ -58,6 +57,9 @@ export * from './components/molecules/RadioGroup/RadioGroup';
|
|
|
58
57
|
export * from './components/molecules/RadioGroup/radio-group-variants';
|
|
59
58
|
export * from './components/molecules/Breadcrumbs/Breadcrumbs';
|
|
60
59
|
export * from './components/molecules/Breadcrumbs/breadcrumb-variants';
|
|
60
|
+
export * from './components/molecules/LiquidTabs/LiquidTabs';
|
|
61
|
+
export * from './components/molecules/LiquidTabs/LiquidNav';
|
|
62
|
+
export * from './components/molecules/LiquidTabs/liquid-tab-id';
|
|
61
63
|
export * from './components/molecules/CallToAction/CallToAction';
|
|
62
64
|
export * from './components/molecules/CallToAction/call-to-action-variants';
|
|
63
65
|
export * from './components/molecules/EmptyState/EmptyState';
|
|
@@ -72,6 +74,7 @@ export * from './components/organisms/Dialog/Dialog';
|
|
|
72
74
|
export * from './components/organisms/Footer/Footer';
|
|
73
75
|
export * from './components/organisms/Navbar/Navbar';
|
|
74
76
|
export * from './components/organisms/Navbar/navbar-variants';
|
|
77
|
+
export * from './components/organisms/Sheet/Sheet';
|
|
75
78
|
export * from './components/organisms/Table/Table';
|
|
76
79
|
export * from './components/organisms/Table/table-variants';
|
|
77
80
|
export * from './hooks/useCountdown';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const c=require("react");function i(e){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e){for(const n in e)if(n!=="default"){const r=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(t,n,r.get?r:{enumerable:!0,get:()=>e[n]})}}return t.default=e,Object.freeze(t)}const d=i(c),a="(prefers-reduced-motion: reduce)";function o(){return typeof window>"u"||typeof window.matchMedia!="function"?null:window.matchMedia(a)}function u(){return o()?.matches??!1}function s(e){const t=o();return t?(t.addEventListener("change",e),()=>t.removeEventListener("change",e)):()=>{}}function f(){return d.useSyncExternalStore(s,u,()=>!1)}exports.prefersReducedMotion=u;exports.useReducedMotion=f;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Read at the moment of asking. For code that animates once, then forgets. */
|
|
2
|
+
export declare function prefersReducedMotion(): boolean;
|
|
3
|
+
/**
|
|
4
|
+
* The same preference as React state, so a component re-renders when the
|
|
5
|
+
* setting changes while it is on screen.
|
|
6
|
+
*
|
|
7
|
+
* `false` on the server, and during hydration, which renders what the server
|
|
8
|
+
* did before correcting itself. A component rendered on the client after that
|
|
9
|
+
* reads the real value on its first render. A portaled overlay does not render
|
|
10
|
+
* on the server anyway, and opens after hydration, so it animates correctly.
|
|
11
|
+
*/
|
|
12
|
+
export declare function useReducedMotion(): boolean;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import * as r from "react";
|
|
3
|
+
const u = "(prefers-reduced-motion: reduce)";
|
|
4
|
+
function t() {
|
|
5
|
+
return typeof window > "u" || typeof window.matchMedia != "function" ? null : window.matchMedia(u);
|
|
6
|
+
}
|
|
7
|
+
function i() {
|
|
8
|
+
return t()?.matches ?? !1;
|
|
9
|
+
}
|
|
10
|
+
function o(n) {
|
|
11
|
+
const e = t();
|
|
12
|
+
return e ? (e.addEventListener("change", n), () => e.removeEventListener("change", n)) : () => {
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
function c() {
|
|
16
|
+
return r.useSyncExternalStore(o, i, () => !1);
|
|
17
|
+
}
|
|
18
|
+
export {
|
|
19
|
+
i as prefersReducedMotion,
|
|
20
|
+
c as useReducedMotion
|
|
21
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const u="data-roster-toaster",d="headlessui-portal-root",f={[u]:""},n=[],i=new Map,o=new Set;let r=null;function c(e){return e.id===d||e.hasAttribute(u)||n.includes(e)}function l(e){i.set(e,e.getAttribute("aria-hidden")),e.inert=!0,e.setAttribute("aria-hidden","true")}function h(e){if(!i.has(e))return;const t=i.get(e);i.delete(e),e.inert=!1,t===null?e.removeAttribute("aria-hidden"):e.setAttribute("aria-hidden",t)}function s(){const e=document.body;for(const t of Array.from(i.keys()))(!n.length||t.parentElement!==e||c(t))&&h(t);if(n.length)for(const t of Array.from(e.children))!(t instanceof HTMLElement)||i.has(t)||c(t)||(t.inert?o.add(t):o.has(t)||l(t));n.length||o.clear(),n.length&&!r?(r=new MutationObserver(s),r.observe(e,{childList:!0})):!n.length&&r&&(r.disconnect(),r=null)}function A(e){if(typeof document>"u")return()=>{};const t=e?.closest("body > *")??null;n.push(t),s();let a=!1;return()=>{a||(a=!0,n.splice(n.indexOf(t),1),s())}}exports.TOASTER_MARKER=f;exports.lockPage=A;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Makes the page behind an open `Dialog` or `Sheet` inert and hidden from
|
|
3
|
+
* assistive technology, all of it.
|
|
4
|
+
*
|
|
5
|
+
* Internal, and not exported from the package.
|
|
6
|
+
*
|
|
7
|
+
* Headless UI does part of this and not the rest. It marks exactly one child
|
|
8
|
+
* of `<body>`: the one the dialog is rendered from, found with
|
|
9
|
+
* `closest("body > *:not(#headlessui-portal-root)")`, plus the dialog's
|
|
10
|
+
* sibling portals. A page laid out as `body > header, main, footer` gets only
|
|
11
|
+
* its `<main>` marked, and the header and footer stay reachable by a screen
|
|
12
|
+
* reader's virtual cursor. A toast host mounted inside that one child goes the
|
|
13
|
+
* other way: it is marked, and a toast shown over the dialog is not announced.
|
|
14
|
+
*
|
|
15
|
+
* So while any lock is held, every direct child of `<body>` is `inert` and
|
|
16
|
+
* `aria-hidden`, except three:
|
|
17
|
+
*
|
|
18
|
+
* - Headless UI's portal root, which holds the dialog itself and any dialog
|
|
19
|
+
* stacked on it. Headless UI handles what is inside it.
|
|
20
|
+
* - Anything carrying `data-roster-toaster`, which `Toaster` renders into.
|
|
21
|
+
* - The child each lock was taken from. That one is Headless UI's, and it is
|
|
22
|
+
* left to Headless UI because two owners of one element can not both
|
|
23
|
+
* restore it: each records what it found, and whichever restores second
|
|
24
|
+
* writes back the other's `inert`, leaving the page stuck. Which one goes
|
|
25
|
+
* second depends on render timing, so skipping the element is the only
|
|
26
|
+
* order that is always right.
|
|
27
|
+
*
|
|
28
|
+
* The same reasoning covers an element that is already `inert` when a lock
|
|
29
|
+
* reaches it: someone else marked it (a dialog built on Headless UI directly,
|
|
30
|
+
* say, with a Roster one opened inside it) and will restore it. It stays
|
|
31
|
+
* theirs until the last lock is released, even if they let go of it in the
|
|
32
|
+
* meantime. Headless UI does let go and re-mark when the dialog on top
|
|
33
|
+
* changes, and marking it in that gap would make a second owner after all.
|
|
34
|
+
* The cost is that such an element can be live while a lock is held; the
|
|
35
|
+
* alternative is a page left inert after every dialog has closed.
|
|
36
|
+
*
|
|
37
|
+
* Locks are counted. The page is marked on the first and restored on the
|
|
38
|
+
* last. Each element the lock marked gets back the `aria-hidden` it had and
|
|
39
|
+
* is made not inert, which is what it was, so a page that marked something
|
|
40
|
+
* itself keeps it.
|
|
41
|
+
*/
|
|
42
|
+
/** Put on the element `Toaster` renders into, so a toast stays announced. */
|
|
43
|
+
export declare const TOASTER_MARKER: {
|
|
44
|
+
readonly "data-roster-toaster": "";
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Takes a lock for a dialog rendered at `anchor`: any element in the tree
|
|
48
|
+
* where the dialog is written, not inside its portal. Returns the release,
|
|
49
|
+
* which is safe to call more than once.
|
|
50
|
+
*/
|
|
51
|
+
export declare function lockPage(anchor: Element | null): () => void;
|