@stackone/malachite 2.68.1 → 2.69.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/COMPONENTS.md +1 -0
- package/dist/components/ToastHost.js +59 -0
- package/dist/components/ToastHost.js.map +1 -0
- package/dist/components/ToastItem.js +51 -0
- package/dist/components/ToastItem.js.map +1 -0
- package/dist/components/ToastProvider.js +54 -0
- package/dist/components/ToastProvider.js.map +1 -0
- package/dist/components/overlayBehaviour.js +112 -107
- package/dist/components/overlayBehaviour.js.map +1 -1
- package/dist/components/portalOverlay.js +30 -24
- package/dist/components/portalOverlay.js.map +1 -1
- package/dist/components/toastContext.js +12 -0
- package/dist/components/toastContext.js.map +1 -0
- package/dist/components/toastTypes.js +6 -0
- package/dist/components/toastTypes.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +329 -325
- package/dist/index.js.map +1 -1
- package/dist/tailwind.css.js +1 -1
- package/package.json +1 -1
package/COMPONENTS.md
CHANGED
|
@@ -44,6 +44,7 @@ The catalog of components exported from `@stackone/malachite`. **Reach for one o
|
|
|
44
44
|
- **`UsageCard`** — A small metered card: a title (optionally a link via `titleLink`, drawn with a trailing arrow), a right-aligned `detail` such as "700/1,000", and a body, usually a `Progress`. Used by `Sidebar.Usage`, and fine on its own, e.g. on a billing page. _Key props:_ `title`, `titleLink`, `detail`, `children`, `aria-label` (required; names the group), `busy` (sets `aria-busy` only).
|
|
45
45
|
- **`Progress`** — Progress bar.
|
|
46
46
|
- **`LoadingBar`** — Indeterminate full-width loading line; the variant colour sweeps across a pale track for work of unknown duration. Toggle `active` rather than unmounting, so the reserved height prevents layout shift. _Key props:_ `active`, `LoadingBarVariant` (`default` | `warning` | `error`), `LoadingBarSize` (`small` | `medium` | `large`), `aria-label`, `aria-labelledby`, `className`, `style`.
|
|
47
|
+
- **`ToastProvider`** — Transient top-centre toasts for the outcome of an action. Wrap the app once in `ToastProvider` and call `useToast().show({ message, variant })` anywhere beneath it. Each toast auto-dismisses, pauses while hovered and dismisses on click; at most three show at once. Toasts are announced through always-mounted live regions (`status` for success, `alert` for error), and the pills themselves are hidden from assistive tech and never take focus, so they cannot fight a dialog's focus trap. The host mounts on the first toast and joins the top layer, so toasts paint above elevated side panels. _Key props:_ `ToastProvider`: `children`, `duration` (ms, default 3000). `useToast()` → `show({ message, variant })`, `ToastVariant` (`success` | `error`, default `success`).
|
|
47
48
|
- **`Spinner`** — Loading spinner.
|
|
48
49
|
- **`Skeleton`** — Loading placeholders. Includes `Skeleton.Avatar` and `Skeleton.Input`. The shimmer stops under `prefers-reduced-motion`, leaving the plain placeholder.
|
|
49
50
|
- **`Tooltip`** — Hover/focus tooltip; also works on disabled controls (see CLAUDE.md). It describes its trigger once shown, so `describesTrigger={false}` where the same sentence is already on screen and referenced — otherwise a screen reader reads it twice. _Key props:_ `text`, `placement`, `delay`, `maxWidth`, `shouldShow`, `triggerAs`, `describesTrigger`, `isShrinkable`, `fill`, `wrapChildren`, `suppressed` (holds the tooltip back, e.g. while the popup its trigger opens is up), `showOnFocus` (false where script can move focus onto the trigger, e.g. an option a panel focuses on open), `focusableTrigger` (makes a trigger that cannot take focus — text, a static `Tag` — a tab stop, so the tooltip is not mouse-only; not for focusable children).
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { jsx as i } from "react/jsx-runtime";
|
|
2
|
+
import { useRef as a, useLayoutEffect as n } from "react";
|
|
3
|
+
import { createPortal as c } from "react-dom";
|
|
4
|
+
import { ShadowRootWrapper as l } from "../ShadowRootWrapper.js";
|
|
5
|
+
import d from "./ToastItem.js";
|
|
6
|
+
import { keepAboveOverlayStack as u } from "./overlayBehaviour.js";
|
|
7
|
+
import { ensureToastStyles as h, overlayIdentity as v } from "./portalOverlay.js";
|
|
8
|
+
import { leaveTopLayer as x, raiseToTopLayer as y } from "./topLayer.js";
|
|
9
|
+
const T = {
|
|
10
|
+
position: "fixed",
|
|
11
|
+
top: 0,
|
|
12
|
+
left: 0,
|
|
13
|
+
right: 0,
|
|
14
|
+
pointerEvents: "none"
|
|
15
|
+
}, w = ({ toasts: t, duration: m, onDismiss: f }) => {
|
|
16
|
+
var p;
|
|
17
|
+
const e = a(null), r = (p = t[t.length - 1]) == null ? void 0 : p.id;
|
|
18
|
+
n(() => {
|
|
19
|
+
h();
|
|
20
|
+
}, []), n(() => {
|
|
21
|
+
const o = e.current;
|
|
22
|
+
if (o) {
|
|
23
|
+
if (r === void 0) {
|
|
24
|
+
x(o);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
y(o);
|
|
28
|
+
}
|
|
29
|
+
}, [r]);
|
|
30
|
+
const s = r !== void 0;
|
|
31
|
+
return n(() => {
|
|
32
|
+
const o = e.current;
|
|
33
|
+
if (!(!o || !s))
|
|
34
|
+
return u(o);
|
|
35
|
+
}, [s]), c(
|
|
36
|
+
/* @__PURE__ */ i(
|
|
37
|
+
l,
|
|
38
|
+
{
|
|
39
|
+
hostRef: e,
|
|
40
|
+
hostStyle: T,
|
|
41
|
+
hostProps: v("toast"),
|
|
42
|
+
children: /* @__PURE__ */ i("div", { className: "flex flex-col items-center gap-[8px] px-[16px] pt-[24px]", children: t.map((o) => /* @__PURE__ */ i(
|
|
43
|
+
d,
|
|
44
|
+
{
|
|
45
|
+
toast: o,
|
|
46
|
+
duration: m,
|
|
47
|
+
onDismiss: f
|
|
48
|
+
},
|
|
49
|
+
o.id
|
|
50
|
+
)) })
|
|
51
|
+
}
|
|
52
|
+
),
|
|
53
|
+
document.body
|
|
54
|
+
);
|
|
55
|
+
};
|
|
56
|
+
export {
|
|
57
|
+
w as default
|
|
58
|
+
};
|
|
59
|
+
//# sourceMappingURL=ToastHost.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ToastHost.js","sources":["../../src/components/ToastHost.tsx"],"sourcesContent":["import { useLayoutEffect, useRef } from 'react';\nimport { createPortal } from 'react-dom';\nimport { ShadowRootWrapper } from '../ShadowRootWrapper';\nimport ToastItem from './ToastItem';\nimport { keepAboveOverlayStack } from './overlayBehaviour';\nimport { ensureToastStyles, overlayIdentity } from './portalOverlay';\nimport type { QueuedToast } from './toastTypes';\nimport { leaveTopLayer, raiseToTopLayer } from './topLayer';\n\ninterface ToastHostProps {\n toasts: QueuedToast[];\n duration: number;\n onDismiss: (id: number) => void;\n}\n\nconst HOST_STYLE: React.CSSProperties = {\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n pointerEvents: 'none',\n};\n\nconst ToastHost: React.FC<ToastHostProps> = ({ toasts, duration, onDismiss }) => {\n const hostRef = useRef<HTMLDivElement | null>(null);\n const newestId = toasts[toasts.length - 1]?.id;\n\n useLayoutEffect(() => {\n ensureToastStyles();\n }, []);\n\n useLayoutEffect(() => {\n const host = hostRef.current;\n if (!host) {\n return;\n }\n if (newestId === undefined) {\n leaveTopLayer(host);\n return;\n }\n raiseToTopLayer(host);\n }, [newestId]);\n\n const visible = newestId !== undefined;\n useLayoutEffect(() => {\n const host = hostRef.current;\n if (!host || !visible) {\n return;\n }\n return keepAboveOverlayStack(host);\n }, [visible]);\n\n return createPortal(\n <ShadowRootWrapper\n hostRef={hostRef}\n hostStyle={HOST_STYLE}\n hostProps={overlayIdentity('toast')}\n >\n <div className=\"flex flex-col items-center gap-[8px] px-[16px] pt-[24px]\">\n {toasts.map((toast) => (\n <ToastItem\n key={toast.id}\n toast={toast}\n duration={duration}\n onDismiss={onDismiss}\n />\n ))}\n </div>\n </ShadowRootWrapper>,\n document.body,\n );\n};\n\nexport default ToastHost;\n"],"names":["HOST_STYLE","ToastHost","toasts","duration","onDismiss","hostRef","useRef","newestId","_a","useLayoutEffect","ensureToastStyles","host","leaveTopLayer","raiseToTopLayer","visible","keepAboveOverlayStack","createPortal","jsx","ShadowRootWrapper","overlayIdentity","toast","ToastItem"],"mappings":";;;;;;;;AAeA,MAAMA,IAAkC;AAAA,EACpC,UAAU;AAAA,EACV,KAAK;AAAA,EACL,MAAM;AAAA,EACN,OAAO;AAAA,EACP,eAAe;AACnB,GAEMC,IAAsC,CAAC,EAAE,QAAAC,GAAQ,UAAAC,GAAU,WAAAC,QAAgB;;AAC7E,QAAMC,IAAUC,EAA8B,IAAI,GAC5CC,KAAWC,IAAAN,EAAOA,EAAO,SAAS,CAAC,MAAxB,gBAAAM,EAA2B;AAE5C,EAAAC,EAAgB,MAAM;AAClB,IAAAC,EAAA;AAAA,EACJ,GAAG,CAAA,CAAE,GAELD,EAAgB,MAAM;AAClB,UAAME,IAAON,EAAQ;AACrB,QAAKM,GAGL;AAAA,UAAIJ,MAAa,QAAW;AACxB,QAAAK,EAAcD,CAAI;AAClB;AAAA,MACJ;AACA,MAAAE,EAAgBF,CAAI;AAAA;AAAA,EACxB,GAAG,CAACJ,CAAQ,CAAC;AAEb,QAAMO,IAAUP,MAAa;AAC7B,SAAAE,EAAgB,MAAM;AAClB,UAAME,IAAON,EAAQ;AACrB,QAAI,GAACM,KAAQ,CAACG;AAGd,aAAOC,EAAsBJ,CAAI;AAAA,EACrC,GAAG,CAACG,CAAO,CAAC,GAELE;AAAA,IACH,gBAAAC;AAAA,MAACC;AAAA,MAAA;AAAA,QACG,SAAAb;AAAA,QACA,WAAWL;AAAA,QACX,WAAWmB,EAAgB,OAAO;AAAA,QAElC,4BAAC,OAAA,EAAI,WAAU,4DACV,UAAAjB,EAAO,IAAI,CAACkB,MACT,gBAAAH;AAAA,UAACI;AAAA,UAAA;AAAA,YAEG,OAAAD;AAAA,YACA,UAAAjB;AAAA,YACA,WAAAC;AAAA,UAAA;AAAA,UAHKgB,EAAM;AAAA,QAAA,CAKlB,EAAA,CACL;AAAA,MAAA;AAAA,IAAA;AAAA,IAEJ,SAAS;AAAA,EAAA;AAEjB;"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { jsxs as x, jsx as l } from "react/jsx-runtime";
|
|
2
|
+
import { useState as v, useRef as m, useEffect as p } from "react";
|
|
3
|
+
import g from "./CustomIcons/CheckCircleFilled.js";
|
|
4
|
+
import h from "./CustomIcons/ErrorCircleFilled.js";
|
|
5
|
+
const f = {
|
|
6
|
+
success: "text-[var(--malachite-text-success,rgb(2,122,66))] supports-[color:color-mix(in_srgb,red,red)]:text-[color-mix(in_srgb,var(--malachite-text-success,rgb(2,122,66))_70%,var(--malachite-tooltip-foreground,rgb(255,255,255)))]",
|
|
7
|
+
error: "text-[var(--malachite-text-destructive,rgb(237,53,54))] supports-[color:color-mix(in_srgb,red,red)]:text-[color-mix(in_srgb,var(--malachite-text-destructive,rgb(237,53,54))_70%,var(--malachite-tooltip-foreground,rgb(255,255,255)))]"
|
|
8
|
+
}, E = ({ toast: r, duration: u, onDismiss: a }) => {
|
|
9
|
+
const [i, n] = v(!1), s = m(null), o = m(u);
|
|
10
|
+
p(() => {
|
|
11
|
+
const e = s.current;
|
|
12
|
+
if (!e)
|
|
13
|
+
return;
|
|
14
|
+
const t = () => n(!0), c = () => n(!1);
|
|
15
|
+
return e.addEventListener("pointerenter", t), e.addEventListener("pointerleave", c), () => {
|
|
16
|
+
e.removeEventListener("pointerenter", t), e.removeEventListener("pointerleave", c);
|
|
17
|
+
};
|
|
18
|
+
}, []), p(() => {
|
|
19
|
+
if (i)
|
|
20
|
+
return;
|
|
21
|
+
const e = Date.now(), t = setTimeout(() => a(r.id), o.current);
|
|
22
|
+
return () => {
|
|
23
|
+
clearTimeout(t), o.current = Math.max(0, o.current - (Date.now() - e));
|
|
24
|
+
};
|
|
25
|
+
}, [i, a, r.id]);
|
|
26
|
+
const d = r.variant === "error" ? h : g;
|
|
27
|
+
return (
|
|
28
|
+
// aria-hidden: the provider's live regions are the announced copy.
|
|
29
|
+
/* @__PURE__ */ x(
|
|
30
|
+
"div",
|
|
31
|
+
{
|
|
32
|
+
ref: s,
|
|
33
|
+
"aria-hidden": "true",
|
|
34
|
+
"data-toast": r.variant,
|
|
35
|
+
onClick: (e) => {
|
|
36
|
+
e.stopPropagation(), a(r.id);
|
|
37
|
+
},
|
|
38
|
+
className: "pointer-events-auto flex max-w-[480px] cursor-pointer items-start gap-[8px] rounded-[var(--malachite-radius-xxxl,16px)] bg-[var(--malachite-tooltip-background,rgb(59,59,59))] px-[12px] py-[8px] text-[length:var(--malachite-font-size-medium,14px)] leading-[20px] text-[var(--malachite-tooltip-foreground,rgb(255,255,255))] [box-shadow:var(--malachite-tooltip-shadow,0px_0px_10px_0px_rgba(0,0,0,0.2))] animate-[malachite-toast-in_150ms_ease-out] motion-reduce:animate-none",
|
|
39
|
+
style: { overflowWrap: "anywhere" },
|
|
40
|
+
children: [
|
|
41
|
+
/* @__PURE__ */ l(d, { size: 16, className: `mt-[2px] shrink-0 ${f[r.variant]}` }),
|
|
42
|
+
/* @__PURE__ */ l("span", { children: r.message })
|
|
43
|
+
]
|
|
44
|
+
}
|
|
45
|
+
)
|
|
46
|
+
);
|
|
47
|
+
};
|
|
48
|
+
export {
|
|
49
|
+
E as default
|
|
50
|
+
};
|
|
51
|
+
//# sourceMappingURL=ToastItem.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ToastItem.js","sources":["../../src/components/ToastItem.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from 'react';\nimport CheckCircleFilled from './CustomIcons/CheckCircleFilled';\nimport ErrorCircleFilled from './CustomIcons/ErrorCircleFilled';\nimport type { QueuedToast, ToastVariant } from './toastTypes';\n\n// The plain status tokens fall under 3:1 on the pill; the mix clears it in both themes.\nconst ICON_COLOR: Record<ToastVariant, string> = {\n success:\n 'text-[var(--malachite-text-success,rgb(2,122,66))] supports-[color:color-mix(in_srgb,red,red)]:text-[color-mix(in_srgb,var(--malachite-text-success,rgb(2,122,66))_70%,var(--malachite-tooltip-foreground,rgb(255,255,255)))]',\n error: 'text-[var(--malachite-text-destructive,rgb(237,53,54))] supports-[color:color-mix(in_srgb,red,red)]:text-[color-mix(in_srgb,var(--malachite-text-destructive,rgb(237,53,54))_70%,var(--malachite-tooltip-foreground,rgb(255,255,255)))]',\n};\n\ninterface ToastItemProps {\n toast: QueuedToast;\n duration: number;\n onDismiss: (id: number) => void;\n}\n\nconst ToastItem: React.FC<ToastItemProps> = ({ toast, duration, onDismiss }) => {\n const [paused, setPaused] = useState(false);\n const ref = useRef<HTMLDivElement>(null);\n const remaining = useRef(duration);\n\n // React's onPointerEnter never fires across this portal's shadow boundary.\n useEffect(() => {\n const el = ref.current;\n if (!el) {\n return;\n }\n const pause = () => setPaused(true);\n const resume = () => setPaused(false);\n el.addEventListener('pointerenter', pause);\n el.addEventListener('pointerleave', resume);\n return () => {\n el.removeEventListener('pointerenter', pause);\n el.removeEventListener('pointerleave', resume);\n };\n }, []);\n\n useEffect(() => {\n if (paused) {\n return;\n }\n const startedAt = Date.now();\n const timeout = setTimeout(() => onDismiss(toast.id), remaining.current);\n return () => {\n clearTimeout(timeout);\n remaining.current = Math.max(0, remaining.current - (Date.now() - startedAt));\n };\n }, [paused, onDismiss, toast.id]);\n\n const Icon = toast.variant === 'error' ? ErrorCircleFilled : CheckCircleFilled;\n\n return (\n // aria-hidden: the provider's live regions are the announced copy.\n <div\n ref={ref}\n aria-hidden=\"true\"\n data-toast={toast.variant}\n onClick={(event) => {\n // A portal bubbles through the React tree, to the provider's ancestors.\n event.stopPropagation();\n onDismiss(toast.id);\n }}\n className=\"pointer-events-auto flex max-w-[480px] cursor-pointer items-start gap-[8px] rounded-[var(--malachite-radius-xxxl,16px)] bg-[var(--malachite-tooltip-background,rgb(59,59,59))] px-[12px] py-[8px] text-[length:var(--malachite-font-size-medium,14px)] leading-[20px] text-[var(--malachite-tooltip-foreground,rgb(255,255,255))] [box-shadow:var(--malachite-tooltip-shadow,0px_0px_10px_0px_rgba(0,0,0,0.2))] animate-[malachite-toast-in_150ms_ease-out] motion-reduce:animate-none\"\n style={{ overflowWrap: 'anywhere' }}\n >\n <Icon size={16} className={`mt-[2px] shrink-0 ${ICON_COLOR[toast.variant]}`} />\n <span>{toast.message}</span>\n </div>\n );\n};\n\nexport default ToastItem;\n"],"names":["ICON_COLOR","ToastItem","toast","duration","onDismiss","paused","setPaused","useState","ref","useRef","remaining","useEffect","el","pause","resume","startedAt","timeout","Icon","ErrorCircleFilled","CheckCircleFilled","jsxs","event","jsx"],"mappings":";;;;AAMA,MAAMA,IAA2C;AAAA,EAC7C,SACI;AAAA,EACJ,OAAO;AACX,GAQMC,IAAsC,CAAC,EAAE,OAAAC,GAAO,UAAAC,GAAU,WAAAC,QAAgB;AAC5E,QAAM,CAACC,GAAQC,CAAS,IAAIC,EAAS,EAAK,GACpCC,IAAMC,EAAuB,IAAI,GACjCC,IAAYD,EAAON,CAAQ;AAGjC,EAAAQ,EAAU,MAAM;AACZ,UAAMC,IAAKJ,EAAI;AACf,QAAI,CAACI;AACD;AAEJ,UAAMC,IAAQ,MAAMP,EAAU,EAAI,GAC5BQ,IAAS,MAAMR,EAAU,EAAK;AACpC,WAAAM,EAAG,iBAAiB,gBAAgBC,CAAK,GACzCD,EAAG,iBAAiB,gBAAgBE,CAAM,GACnC,MAAM;AACT,MAAAF,EAAG,oBAAoB,gBAAgBC,CAAK,GAC5CD,EAAG,oBAAoB,gBAAgBE,CAAM;AAAA,IACjD;AAAA,EACJ,GAAG,CAAA,CAAE,GAELH,EAAU,MAAM;AACZ,QAAIN;AACA;AAEJ,UAAMU,IAAY,KAAK,IAAA,GACjBC,IAAU,WAAW,MAAMZ,EAAUF,EAAM,EAAE,GAAGQ,EAAU,OAAO;AACvE,WAAO,MAAM;AACT,mBAAaM,CAAO,GACpBN,EAAU,UAAU,KAAK,IAAI,GAAGA,EAAU,WAAW,KAAK,IAAA,IAAQK,EAAU;AAAA,IAChF;AAAA,EACJ,GAAG,CAACV,GAAQD,GAAWF,EAAM,EAAE,CAAC;AAEhC,QAAMe,IAAOf,EAAM,YAAY,UAAUgB,IAAoBC;AAE7D;AAAA;AAAA,IAEI,gBAAAC;AAAA,MAAC;AAAA,MAAA;AAAA,QACG,KAAAZ;AAAA,QACA,eAAY;AAAA,QACZ,cAAYN,EAAM;AAAA,QAClB,SAAS,CAACmB,MAAU;AAEhB,UAAAA,EAAM,gBAAA,GACNjB,EAAUF,EAAM,EAAE;AAAA,QACtB;AAAA,QACA,WAAU;AAAA,QACV,OAAO,EAAE,cAAc,WAAA;AAAA,QAEvB,UAAA;AAAA,UAAA,gBAAAoB,EAACL,GAAA,EAAK,MAAM,IAAI,WAAW,qBAAqBjB,EAAWE,EAAM,OAAO,CAAC,GAAA,CAAI;AAAA,UAC7E,gBAAAoB,EAAC,QAAA,EAAM,UAAApB,EAAM,QAAA,CAAQ;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA;AAGjC;"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { jsxs as m, jsx as n } from "react/jsx-runtime";
|
|
2
|
+
import { useState as i, useRef as v, useCallback as u, useEffect as D, useMemo as E } from "react";
|
|
3
|
+
import _ from "./ToastHost.js";
|
|
4
|
+
import { ToastContext as x } from "./toastContext.js";
|
|
5
|
+
import { TOAST_ANNOUNCEMENT_LIFETIME_MS as I, TOAST_DEFAULT_DURATION_MS as M } from "./toastTypes.js";
|
|
6
|
+
const N = {
|
|
7
|
+
position: "absolute",
|
|
8
|
+
width: 1,
|
|
9
|
+
height: 1,
|
|
10
|
+
margin: -1,
|
|
11
|
+
padding: 0,
|
|
12
|
+
border: 0,
|
|
13
|
+
overflow: "hidden",
|
|
14
|
+
clip: "rect(0 0 0 0)",
|
|
15
|
+
clipPath: "inset(50%)",
|
|
16
|
+
whiteSpace: "nowrap"
|
|
17
|
+
}, C = ({
|
|
18
|
+
children: p,
|
|
19
|
+
duration: f = M
|
|
20
|
+
}) => {
|
|
21
|
+
const [h, r] = i([]), [a, c] = i(
|
|
22
|
+
[]
|
|
23
|
+
), [T, w] = i(!1), l = v(0), d = u(({ message: t, variant: s = "success" }) => {
|
|
24
|
+
l.current += 1;
|
|
25
|
+
const e = { id: l.current, message: t, variant: s };
|
|
26
|
+
r((o) => [...o, e].slice(-3)), c((o) => [...o, { ...e, announcedAt: Date.now() }]), w(!0);
|
|
27
|
+
}, []), A = u((t) => {
|
|
28
|
+
r((s) => s.filter((e) => e.id !== t));
|
|
29
|
+
}, []);
|
|
30
|
+
D(() => {
|
|
31
|
+
const t = a[0];
|
|
32
|
+
if (!t)
|
|
33
|
+
return;
|
|
34
|
+
const s = setTimeout(
|
|
35
|
+
() => c((e) => e.filter((o) => o.id !== t.id)),
|
|
36
|
+
Math.max(0, t.announcedAt + I - Date.now())
|
|
37
|
+
);
|
|
38
|
+
return () => clearTimeout(s);
|
|
39
|
+
}, [a]);
|
|
40
|
+
const S = E(() => ({ show: d }), [d]);
|
|
41
|
+
return /* @__PURE__ */ m(x.Provider, { value: S, children: [
|
|
42
|
+
p,
|
|
43
|
+
/* @__PURE__ */ m("div", { style: N, children: [
|
|
44
|
+
/* @__PURE__ */ n("span", { role: "status", "aria-atomic": "false", children: a.filter((t) => t.variant === "success").map((t) => /* @__PURE__ */ n("span", { children: t.message }, t.id)) }),
|
|
45
|
+
/* @__PURE__ */ n("span", { role: "alert", "aria-atomic": "false", children: a.filter((t) => t.variant === "error").map((t) => /* @__PURE__ */ n("span", { children: t.message }, t.id)) })
|
|
46
|
+
] }),
|
|
47
|
+
T && /* @__PURE__ */ n(_, { toasts: h, duration: f, onDismiss: A })
|
|
48
|
+
] });
|
|
49
|
+
};
|
|
50
|
+
export {
|
|
51
|
+
C as ToastProvider,
|
|
52
|
+
C as default
|
|
53
|
+
};
|
|
54
|
+
//# sourceMappingURL=ToastProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ToastProvider.js","sources":["../../src/components/ToastProvider.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport ToastHost from './ToastHost';\nimport { ToastContext } from './toastContext';\nimport {\n type QueuedToast,\n TOAST_ANNOUNCEMENT_LIFETIME_MS,\n TOAST_DEFAULT_DURATION_MS,\n TOAST_MAX_VISIBLE,\n type ToastOptions,\n} from './toastTypes';\n\n// Outside any shadow root, so Tailwind's sr-only is not available.\nconst VISUALLY_HIDDEN: React.CSSProperties = {\n position: 'absolute',\n width: 1,\n height: 1,\n margin: -1,\n padding: 0,\n border: 0,\n overflow: 'hidden',\n clip: 'rect(0 0 0 0)',\n clipPath: 'inset(50%)',\n whiteSpace: 'nowrap',\n};\n\nexport interface ToastProviderProps {\n children?: React.ReactNode;\n /** How long each toast stays, in ms. Defaults to 3000. */\n duration?: number;\n}\n\nconst ToastProvider: React.FC<ToastProviderProps> = ({\n children,\n duration = TOAST_DEFAULT_DURATION_MS,\n}) => {\n const [toasts, setToasts] = useState<QueuedToast[]>([]);\n const [announcements, setAnnouncements] = useState<(QueuedToast & { announcedAt: number })[]>(\n [],\n );\n const [hasShown, setHasShown] = useState(false);\n const nextId = useRef(0);\n\n const show = useCallback(({ message, variant = 'success' }: ToastOptions) => {\n nextId.current += 1;\n const toast: QueuedToast = { id: nextId.current, message, variant };\n setToasts((previous) => [...previous, toast].slice(-TOAST_MAX_VISIBLE));\n setAnnouncements((previous) => [...previous, { ...toast, announcedAt: Date.now() }]);\n setHasShown(true);\n }, []);\n\n const dismiss = useCallback((id: number) => {\n setToasts((previous) => previous.filter((toast) => toast.id !== id));\n }, []);\n\n useEffect(() => {\n const oldest = announcements[0];\n if (!oldest) {\n return;\n }\n const timeout = setTimeout(\n () =>\n setAnnouncements((previous) => previous.filter((entry) => entry.id !== oldest.id)),\n Math.max(0, oldest.announcedAt + TOAST_ANNOUNCEMENT_LIFETIME_MS - Date.now()),\n );\n return () => clearTimeout(timeout);\n }, [announcements]);\n\n const api = useMemo(() => ({ show }), [show]);\n\n return (\n <ToastContext.Provider value={api}>\n {children}\n {/* A region added with its text is not announced; status and alert default to atomic. */}\n <div style={VISUALLY_HIDDEN}>\n <span role=\"status\" aria-atomic=\"false\">\n {announcements\n .filter((entry) => entry.variant === 'success')\n .map((entry) => (\n <span key={entry.id}>{entry.message}</span>\n ))}\n </span>\n <span role=\"alert\" aria-atomic=\"false\">\n {announcements\n .filter((entry) => entry.variant === 'error')\n .map((entry) => (\n <span key={entry.id}>{entry.message}</span>\n ))}\n </span>\n </div>\n {hasShown && <ToastHost toasts={toasts} duration={duration} onDismiss={dismiss} />}\n </ToastContext.Provider>\n );\n};\n\nexport { ToastProvider };\nexport default ToastProvider;\n"],"names":["VISUALLY_HIDDEN","ToastProvider","children","duration","TOAST_DEFAULT_DURATION_MS","toasts","setToasts","useState","announcements","setAnnouncements","hasShown","setHasShown","nextId","useRef","show","useCallback","message","variant","toast","previous","dismiss","id","useEffect","oldest","timeout","entry","TOAST_ANNOUNCEMENT_LIFETIME_MS","api","useMemo","jsxs","ToastContext","jsx","ToastHost"],"mappings":";;;;;AAYA,MAAMA,IAAuC;AAAA,EACzC,UAAU;AAAA,EACV,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,MAAM;AAAA,EACN,UAAU;AAAA,EACV,YAAY;AAChB,GAQMC,IAA8C,CAAC;AAAA,EACjD,UAAAC;AAAA,EACA,UAAAC,IAAWC;AACf,MAAM;AACF,QAAM,CAACC,GAAQC,CAAS,IAAIC,EAAwB,CAAA,CAAE,GAChD,CAACC,GAAeC,CAAgB,IAAIF;AAAA,IACtC,CAAA;AAAA,EAAC,GAEC,CAACG,GAAUC,CAAW,IAAIJ,EAAS,EAAK,GACxCK,IAASC,EAAO,CAAC,GAEjBC,IAAOC,EAAY,CAAC,EAAE,SAAAC,GAAS,SAAAC,IAAU,gBAA8B;AACzE,IAAAL,EAAO,WAAW;AAClB,UAAMM,IAAqB,EAAE,IAAIN,EAAO,SAAS,SAAAI,GAAS,SAAAC,EAAA;AAC1D,IAAAX,EAAU,CAACa,MAAa,CAAC,GAAGA,GAAUD,CAAK,EAAE,MAAM,EAAkB,CAAC,GACtET,EAAiB,CAACU,MAAa,CAAC,GAAGA,GAAU,EAAE,GAAGD,GAAO,aAAa,KAAK,IAAA,EAAI,CAAG,CAAC,GACnFP,EAAY,EAAI;AAAA,EACpB,GAAG,CAAA,CAAE,GAECS,IAAUL,EAAY,CAACM,MAAe;AACxC,IAAAf,EAAU,CAACa,MAAaA,EAAS,OAAO,CAACD,MAAUA,EAAM,OAAOG,CAAE,CAAC;AAAA,EACvE,GAAG,CAAA,CAAE;AAEL,EAAAC,EAAU,MAAM;AACZ,UAAMC,IAASf,EAAc,CAAC;AAC9B,QAAI,CAACe;AACD;AAEJ,UAAMC,IAAU;AAAA,MACZ,MACIf,EAAiB,CAACU,MAAaA,EAAS,OAAO,CAACM,MAAUA,EAAM,OAAOF,EAAO,EAAE,CAAC;AAAA,MACrF,KAAK,IAAI,GAAGA,EAAO,cAAcG,IAAiC,KAAK,KAAK;AAAA,IAAA;AAEhF,WAAO,MAAM,aAAaF,CAAO;AAAA,EACrC,GAAG,CAAChB,CAAa,CAAC;AAElB,QAAMmB,IAAMC,EAAQ,OAAO,EAAE,MAAAd,MAAS,CAACA,CAAI,CAAC;AAE5C,SACI,gBAAAe,EAACC,EAAa,UAAb,EAAsB,OAAOH,GACzB,UAAA;AAAA,IAAAzB;AAAA,IAED,gBAAA2B,EAAC,OAAA,EAAI,OAAO7B,GACR,UAAA;AAAA,MAAA,gBAAA+B,EAAC,QAAA,EAAK,MAAK,UAAS,eAAY,SAC3B,UAAAvB,EACI,OAAO,CAACiB,MAAUA,EAAM,YAAY,SAAS,EAC7C,IAAI,CAACA,MACF,gBAAAM,EAAC,QAAA,EAAqB,YAAM,QAAA,GAAjBN,EAAM,EAAmB,CACvC,EAAA,CACT;AAAA,MACA,gBAAAM,EAAC,QAAA,EAAK,MAAK,SAAQ,eAAY,SAC1B,UAAAvB,EACI,OAAO,CAACiB,MAAUA,EAAM,YAAY,OAAO,EAC3C,IAAI,CAACA,MACF,gBAAAM,EAAC,QAAA,EAAqB,YAAM,QAAA,GAAjBN,EAAM,EAAmB,CACvC,EAAA,CACT;AAAA,IAAA,GACJ;AAAA,IACCf,KAAY,gBAAAqB,EAACC,GAAA,EAAU,QAAA3B,GAAgB,UAAAF,GAAoB,WAAWiB,EAAA,CAAS;AAAA,EAAA,GACpF;AAER;"}
|
|
@@ -1,119 +1,123 @@
|
|
|
1
1
|
import { useSyncExternalStore as b, useRef as f, useCallback as N, useEffect as E, useLayoutEffect as m } from "react";
|
|
2
|
-
import { getDeepActiveElement as
|
|
3
|
-
import { pushEscapeLayer as
|
|
4
|
-
import { FOCUS_RING as
|
|
5
|
-
import { nextLayerTicket as
|
|
6
|
-
import { useOwnedByPopover as
|
|
7
|
-
import { OVERLAY_Z_BASE as
|
|
8
|
-
import { lockBodyScroll as
|
|
9
|
-
import { leaveTopLayer as
|
|
10
|
-
const
|
|
11
|
-
const t = /* @__PURE__ */ new Map(), o = (
|
|
12
|
-
const
|
|
13
|
-
if (
|
|
14
|
-
return
|
|
15
|
-
const { display: a, visibility: r, contentVisibility: s } = getComputedStyle(
|
|
16
|
-
hidden:
|
|
2
|
+
import { getDeepActiveElement as R, containsComposed as B } from "./activeElement.js";
|
|
3
|
+
import { pushEscapeLayer as V } from "./escapeLayers.js";
|
|
4
|
+
import { FOCUS_RING as Y } from "./focusRing.js";
|
|
5
|
+
import { nextLayerTicket as j, popupLayerHolding as Z } from "./overlayLayers.js";
|
|
6
|
+
import { useOwnedByPopover as $ } from "./popoverTree.js";
|
|
7
|
+
import { OVERLAY_Z_BASE as _, ensureElevatedOverlayStyles as q } from "./portalOverlay.js";
|
|
8
|
+
import { lockBodyScroll as J } from "./scrollLock.js";
|
|
9
|
+
import { leaveTopLayer as G, raiseToTopLayer as M } from "./topLayer.js";
|
|
10
|
+
const Tt = `flex shrink-0 cursor-pointer items-center justify-center rounded-md border-0 bg-transparent p-[4px] text-[var(--malachite-text-secondary)] hover:text-[var(--malachite-text-primary)] transition-colors ${Y}`, Q = 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), summary, [tabindex]:not([tabindex="-1"])', X = (t) => t.assignedSlot ?? t.parentElement ?? (t.parentNode instanceof ShadowRoot ? t.parentNode.host : null), tt = (t) => Array.from(t.children).find((o) => o.tagName === "SUMMARY"), et = () => {
|
|
11
|
+
const t = /* @__PURE__ */ new Map(), o = (e) => {
|
|
12
|
+
const n = t.get(e);
|
|
13
|
+
if (n)
|
|
14
|
+
return n;
|
|
15
|
+
const { display: a, visibility: r, contentVisibility: s } = getComputedStyle(e), c = X(e), d = c ? o(c) : null, h = c instanceof HTMLDetailsElement && !c.open && tt(c) !== e, l = {
|
|
16
|
+
hidden: e.hasAttribute("inert") || a === "none" || h || !!(d && (d.hidden || d.hidesContent)),
|
|
17
17
|
invisible: r === "hidden" || r === "collapse",
|
|
18
18
|
hidesContent: s === "hidden"
|
|
19
19
|
};
|
|
20
|
-
return t.set(
|
|
20
|
+
return t.set(e, l), l;
|
|
21
21
|
};
|
|
22
22
|
return o;
|
|
23
23
|
}, nt = (t, o) => {
|
|
24
24
|
if (t.tabIndex < 0 || t.matches(":disabled"))
|
|
25
25
|
return !1;
|
|
26
|
-
const { hidden:
|
|
27
|
-
return !
|
|
28
|
-
},
|
|
29
|
-
if (!
|
|
26
|
+
const { hidden: e, invisible: n } = o(t);
|
|
27
|
+
return !e && !n;
|
|
28
|
+
}, v = (t) => t instanceof HTMLInputElement && t.type === "radio" && t.name !== "", ot = (t, o) => {
|
|
29
|
+
if (!v(t))
|
|
30
30
|
return !1;
|
|
31
|
-
const
|
|
32
|
-
(
|
|
31
|
+
const e = o.filter(
|
|
32
|
+
(n) => v(n) && n.name === t.name && n.form === t.form
|
|
33
33
|
);
|
|
34
|
-
return (
|
|
35
|
-
},
|
|
36
|
-
for (const
|
|
37
|
-
o.push(
|
|
34
|
+
return (e.find((n) => n.checked) ?? e[0]) !== t;
|
|
35
|
+
}, rt = (t, o) => t.map((e, n) => ({ element: e, index: n, tabIndex: o(e) })).sort((e, n) => e.tabIndex !== n.tabIndex ? e.tabIndex === 0 ? 1 : n.tabIndex === 0 ? -1 : e.tabIndex - n.tabIndex : e.index - n.index).map(({ element: e }) => e), x = (t) => t instanceof HTMLSlotElement && t.getRootNode() instanceof ShadowRoot, O = (t, o = []) => {
|
|
36
|
+
for (const e of t)
|
|
37
|
+
o.push(e), !e.shadowRoot && !x(e) && O(e.children, o);
|
|
38
38
|
return o;
|
|
39
39
|
}, L = (t, o) => {
|
|
40
|
-
const
|
|
41
|
-
(r) => r instanceof HTMLElement && r.matches(
|
|
42
|
-
),
|
|
43
|
-
|
|
40
|
+
const e = t.filter(
|
|
41
|
+
(r) => r instanceof HTMLElement && r.matches(Q) && nt(r, o)
|
|
42
|
+
), n = new Set(
|
|
43
|
+
e.filter((r) => !ot(r, e))
|
|
44
44
|
), a = t.filter(
|
|
45
|
-
(r) =>
|
|
45
|
+
(r) => n.has(r) || r.shadowRoot || x(r)
|
|
46
46
|
);
|
|
47
|
-
return
|
|
47
|
+
return rt(
|
|
48
48
|
a,
|
|
49
|
-
(r) =>
|
|
49
|
+
(r) => n.has(r) ? r.tabIndex : 0
|
|
50
50
|
).flatMap((r) => {
|
|
51
51
|
if (x(r))
|
|
52
|
-
return L(
|
|
52
|
+
return L(O(r.assignedElements({ flatten: !0 })), o);
|
|
53
53
|
const s = r.shadowRoot;
|
|
54
54
|
if (s && Number.parseInt(r.getAttribute("tabindex") ?? "", 10) < 0)
|
|
55
55
|
return [];
|
|
56
|
-
const c =
|
|
57
|
-
return s ? [...c, ...L(
|
|
56
|
+
const c = n.has(r) && !(s != null && s.delegatesFocus) ? [r] : [];
|
|
57
|
+
return s ? [...c, ...L(O(s.children), o)] : c;
|
|
58
58
|
});
|
|
59
|
-
}, C = (t) => L(
|
|
60
|
-
const
|
|
59
|
+
}, C = (t) => L(O(t.children), et()), st = (t, o) => {
|
|
60
|
+
const e = (r) => {
|
|
61
61
|
const s = [r];
|
|
62
62
|
for (let c = r.getRootNode(); c instanceof ShadowRoot; c = c.host.getRootNode())
|
|
63
63
|
s.push(c.host);
|
|
64
64
|
return s;
|
|
65
|
-
},
|
|
66
|
-
for (const r of
|
|
65
|
+
}, n = e(t), a = e(o);
|
|
66
|
+
for (const r of n) {
|
|
67
67
|
const s = a.find((c) => c.getRootNode() === r.getRootNode());
|
|
68
68
|
if (s)
|
|
69
69
|
return r !== s ? r.compareDocumentPosition(s) : r === t ? Node.DOCUMENT_POSITION_FOLLOWING : Node.DOCUMENT_POSITION_PRECEDING;
|
|
70
70
|
}
|
|
71
71
|
return Node.DOCUMENT_POSITION_DISCONNECTED;
|
|
72
|
-
},
|
|
72
|
+
}, ct = (t) => C(t)[0] ?? null, u = [], p = /* @__PURE__ */ new Set(), k = /* @__PURE__ */ new Map(), w = /* @__PURE__ */ new Map(), g = /* @__PURE__ */ new Set(), at = () => {
|
|
73
73
|
};
|
|
74
74
|
let y = [];
|
|
75
|
-
const
|
|
76
|
-
const t = p.size ? u.map((
|
|
77
|
-
var
|
|
78
|
-
return (
|
|
79
|
-
}).filter((
|
|
80
|
-
if (t.length === y.length && t.every((
|
|
75
|
+
const D = /* @__PURE__ */ new Set(), it = () => {
|
|
76
|
+
const t = p.size ? u.map((e) => {
|
|
77
|
+
var n;
|
|
78
|
+
return (n = k.get(e)) == null ? void 0 : n();
|
|
79
|
+
}).filter((e) => !!e) : [];
|
|
80
|
+
if (t.length === y.length && t.every((e, n) => e === y[n]))
|
|
81
81
|
return;
|
|
82
82
|
const o = new Set(t);
|
|
83
|
-
for (const
|
|
84
|
-
o.has(
|
|
85
|
-
for (const
|
|
86
|
-
|
|
83
|
+
for (const e of y)
|
|
84
|
+
o.has(e) || G(e);
|
|
85
|
+
for (const e of t)
|
|
86
|
+
M(e);
|
|
87
87
|
y = t;
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}, B = (t) => (D.add(t), () => {
|
|
88
|
+
for (const e of D)
|
|
89
|
+
M(e);
|
|
90
|
+
}, Nt = (t) => (D.add(t), () => {
|
|
92
91
|
D.delete(t);
|
|
93
|
-
}),
|
|
94
|
-
const
|
|
95
|
-
|
|
92
|
+
}), I = () => {
|
|
93
|
+
for (const t of g)
|
|
94
|
+
t();
|
|
95
|
+
}, P = (t) => (g.add(t), () => {
|
|
96
|
+
g.delete(t);
|
|
97
|
+
}), A = (t, o, e, n) => {
|
|
98
|
+
const a = n[0], r = n[n.length - 1], s = B(e, o);
|
|
99
|
+
if (o && s && o !== e && !n.includes(o)) {
|
|
96
100
|
const c = t.shiftKey ? Node.DOCUMENT_POSITION_PRECEDING : Node.DOCUMENT_POSITION_FOLLOWING;
|
|
97
|
-
|
|
101
|
+
n.some((d) => st(o, d) & c) || (t.preventDefault(), (t.shiftKey ? r : a).focus());
|
|
98
102
|
return;
|
|
99
103
|
}
|
|
100
|
-
t.shiftKey ? (!s || o === a || o ===
|
|
101
|
-
},
|
|
104
|
+
t.shiftKey ? (!s || o === a || o === e) && (t.preventDefault(), r.focus()) : (!s || o === r || o === e) && (t.preventDefault(), a.focus());
|
|
105
|
+
}, F = (t) => {
|
|
102
106
|
if (t.key !== "Tab" || t.defaultPrevented)
|
|
103
107
|
return;
|
|
104
|
-
let o = null,
|
|
108
|
+
let o = null, e = 0;
|
|
105
109
|
for (let s = u.length - 1; s >= 0 && !o; s -= 1)
|
|
106
|
-
o = u[s](), o && (
|
|
110
|
+
o = u[s](), o && (e = w.get(u[s]) ?? 0);
|
|
107
111
|
if (!o)
|
|
108
112
|
return;
|
|
109
|
-
const
|
|
110
|
-
if (
|
|
113
|
+
const n = R(), a = n ? Z(n) : null;
|
|
114
|
+
if (n && a && a.ticket > e) {
|
|
111
115
|
const s = a.popup.shadowRoot ?? a.popup, c = C(s);
|
|
112
116
|
if (c.length === 0) {
|
|
113
117
|
t.preventDefault();
|
|
114
118
|
return;
|
|
115
119
|
}
|
|
116
|
-
|
|
120
|
+
A(t, n, s, c);
|
|
117
121
|
return;
|
|
118
122
|
}
|
|
119
123
|
const r = C(o);
|
|
@@ -121,35 +125,35 @@ const at = () => {
|
|
|
121
125
|
t.preventDefault(), o.focus();
|
|
122
126
|
return;
|
|
123
127
|
}
|
|
124
|
-
|
|
125
|
-
},
|
|
126
|
-
const
|
|
127
|
-
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
}),
|
|
131
|
-
|
|
128
|
+
A(t, n, o, r);
|
|
129
|
+
}, ut = (t, o) => (u.length === 0 && document.addEventListener("keydown", F), u.push(t), k.set(t, o), w.set(t, j()), I(), () => {
|
|
130
|
+
const e = u.lastIndexOf(t);
|
|
131
|
+
e !== -1 && u.splice(e, 1), p.delete(t), k.delete(t), w.delete(t);
|
|
132
|
+
const n = o();
|
|
133
|
+
n && G(n), u.length === 0 && document.removeEventListener("keydown", F), I();
|
|
134
|
+
}), Et = () => b(
|
|
135
|
+
P,
|
|
132
136
|
() => u.length > 0,
|
|
133
137
|
() => !1
|
|
134
|
-
),
|
|
138
|
+
), U = (t, o) => {
|
|
135
139
|
if (o === "content") {
|
|
136
|
-
const
|
|
137
|
-
if (
|
|
140
|
+
const e = R();
|
|
141
|
+
if (B(t, e))
|
|
138
142
|
return;
|
|
139
|
-
(
|
|
143
|
+
(ct(t) ?? t).focus();
|
|
140
144
|
return;
|
|
141
145
|
}
|
|
142
146
|
t.focus();
|
|
143
|
-
},
|
|
147
|
+
}, mt = ({
|
|
144
148
|
open: t,
|
|
145
149
|
onClose: o,
|
|
146
|
-
elevated:
|
|
147
|
-
hostRef:
|
|
150
|
+
elevated: e = !1,
|
|
151
|
+
hostRef: n,
|
|
148
152
|
initialFocus: a = "panel"
|
|
149
153
|
}) => {
|
|
150
154
|
const r = f(null), s = f(() => r.current).current;
|
|
151
|
-
|
|
152
|
-
N(() => (
|
|
155
|
+
$(
|
|
156
|
+
N(() => (n == null ? void 0 : n.current) ?? r.current, [n]),
|
|
153
157
|
t
|
|
154
158
|
);
|
|
155
159
|
const c = f(null), d = f(null), h = f(a), l = f(o);
|
|
@@ -157,7 +161,7 @@ const at = () => {
|
|
|
157
161
|
l.current = o;
|
|
158
162
|
}, [o]), E(() => {
|
|
159
163
|
if (t)
|
|
160
|
-
return c.current =
|
|
164
|
+
return c.current = R(), () => {
|
|
161
165
|
const i = c.current;
|
|
162
166
|
c.current = null, i != null && i.isConnected && i.focus();
|
|
163
167
|
};
|
|
@@ -165,20 +169,20 @@ const at = () => {
|
|
|
165
169
|
if (!t)
|
|
166
170
|
return;
|
|
167
171
|
d.current = s;
|
|
168
|
-
const i =
|
|
169
|
-
return r.current &&
|
|
170
|
-
d.current = null,
|
|
172
|
+
const i = V(() => l.current()), K = J(), W = ut(s, () => (n == null ? void 0 : n.current) ?? null);
|
|
173
|
+
return r.current && U(r.current, h.current), () => {
|
|
174
|
+
d.current = null, W(), i(), K();
|
|
171
175
|
};
|
|
172
|
-
}, [t,
|
|
173
|
-
if (!(!t || !
|
|
174
|
-
return p.add(s),
|
|
175
|
-
p.delete(s),
|
|
176
|
+
}, [t, n, s]), m(() => {
|
|
177
|
+
if (!(!t || !e))
|
|
178
|
+
return p.add(s), I(), () => {
|
|
179
|
+
p.delete(s), I();
|
|
176
180
|
};
|
|
177
|
-
}, [t,
|
|
181
|
+
}, [t, e, s]);
|
|
178
182
|
const T = N(
|
|
179
|
-
(i) => t ?
|
|
183
|
+
(i) => t ? P(i) : at,
|
|
180
184
|
[t]
|
|
181
|
-
),
|
|
185
|
+
), H = b(
|
|
182
186
|
T,
|
|
183
187
|
// Gated on `open` so an overlay fading out stops claiming modal. Before it registers
|
|
184
188
|
// it is the one about to go on top, or aria-modal would drop for a frame on open.
|
|
@@ -186,29 +190,30 @@ const at = () => {
|
|
|
186
190
|
() => !0
|
|
187
191
|
), S = b(
|
|
188
192
|
T,
|
|
189
|
-
() => t && (
|
|
193
|
+
() => t && (e || p.size > 0),
|
|
190
194
|
() => !1
|
|
191
|
-
),
|
|
195
|
+
), z = b(
|
|
192
196
|
T,
|
|
193
197
|
() => {
|
|
194
198
|
const i = d.current;
|
|
195
|
-
return
|
|
199
|
+
return _ + (t && i ? Math.max(0, u.indexOf(i)) : 0);
|
|
196
200
|
},
|
|
197
|
-
() =>
|
|
201
|
+
() => _
|
|
198
202
|
);
|
|
199
203
|
return m(() => {
|
|
200
|
-
S &&
|
|
204
|
+
S && q();
|
|
201
205
|
}, [S]), m(() => {
|
|
202
|
-
|
|
206
|
+
it();
|
|
203
207
|
}), { ref: N((i) => {
|
|
204
|
-
r.current = i, i &&
|
|
205
|
-
}, []), isTopmost:
|
|
208
|
+
r.current = i, i && U(i, h.current);
|
|
209
|
+
}, []), isTopmost: H, zIndex: S ? void 0 : z, elevated: S };
|
|
206
210
|
};
|
|
207
211
|
export {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
212
|
+
Q as FOCUSABLE_SELECTOR,
|
|
213
|
+
Tt as OVERLAY_ICON_BUTTON_CLASSES,
|
|
214
|
+
ct as firstTabStopIn,
|
|
215
|
+
Nt as keepAboveOverlayStack,
|
|
216
|
+
Et as useHasOpenOverlay,
|
|
217
|
+
mt as useOverlayBehaviour
|
|
213
218
|
};
|
|
214
219
|
//# sourceMappingURL=overlayBehaviour.js.map
|