efficient-shell 4.137.0 → 4.137.1
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/LICENSE +6 -17
- package/README.md +3 -1
- package/dist/Browser-ZX5OTOKK.js +43 -0
- package/dist/Calculator-4SQGOQFQ.js +29 -0
- package/dist/ConfirmDialog-NPKW2XHM.js +1 -0
- package/dist/CurrencyConverter-2KOM7L6V.js +21 -0
- package/dist/Documents-IZTIQYPG.js +52 -0
- package/dist/Files-B63KKXGZ.js +89 -0
- package/dist/Notepad-WA77V45J.js +25 -0
- package/dist/PdfViewer-RBRGEKWF.js +1 -0
- package/dist/PomodoroTimer-SDUBKXUS.js +99 -0
- package/dist/Preview-D4KOA4OI.js +187 -0
- package/dist/Sidebar-Y57LYXXI.js +23 -0
- package/dist/Spreadsheet-JX5E6WH6.js +37 -0
- package/dist/Stock-XAQ5WMUZ.js +16 -0
- package/dist/Weather-HLAGJ5LV.js +60 -0
- package/dist/WorldClock-IRI4VCTA.js +32 -0
- package/dist/apps/index.js +1 -151
- package/dist/chunk-3A46NCXK.js +29 -0
- package/dist/chunk-44UO7FYU.js +11 -0
- package/dist/chunk-466CM2TJ.js +1 -0
- package/dist/chunk-57MIENLJ.js +1 -0
- package/dist/chunk-5CRAF2AD.js +2 -0
- package/dist/chunk-A2OQLLYK.js +6 -0
- package/dist/chunk-B43AGQET.js +4 -0
- package/dist/chunk-BR22X7E5.js +1 -0
- package/dist/chunk-BUTSU7FO.js +1 -0
- package/dist/chunk-D65T4H6J.js +1 -0
- package/dist/chunk-ESL5TDNA.js +1 -0
- package/dist/chunk-FBDZGO3V.js +1 -0
- package/dist/chunk-FHTLC7HH.js +1 -0
- package/dist/chunk-FQLMX3IE.js +948 -0
- package/dist/chunk-H562R4GX.js +34 -0
- package/dist/chunk-JN4WXTWJ.js +106 -0
- package/dist/chunk-LVDRBRYU.js +1 -0
- package/dist/chunk-LWLCNQY7.js +1 -0
- package/dist/chunk-MAIHBBWT.js +1 -0
- package/dist/chunk-NPJH5MD7.js +13 -0
- package/dist/chunk-OCSOMMY2.js +1 -0
- package/dist/chunk-OQDWLHZI.js +1 -0
- package/dist/chunk-OWSAMA3I.js +23 -0
- package/dist/chunk-PH3PRIFP.js +5 -0
- package/dist/chunk-TAWKWSPN.js +9 -0
- package/dist/chunk-U4GTZPXP.js +1 -0
- package/dist/chunk-UB4JIOLD.js +2 -0
- package/dist/chunk-UZAJ5BF6.js +9 -0
- package/dist/chunk-VEGMDXT4.js +1 -0
- package/dist/chunk-VTVSMRFX.js +1 -0
- package/dist/chunk-VVAGSKW7.js +1 -0
- package/dist/chunk-XO43FJRM.js +19 -0
- package/dist/chunk-Y7BOLDRM.js +69 -0
- package/dist/file-intake/index.js +1 -4
- package/dist/index.js +639 -7473
- package/dist/map/index.js +20 -540
- package/dist/markdown/index.js +6 -184
- package/dist/markup/index.js +1 -135
- package/dist/page-tabs/index.js +21 -709
- package/dist/sounds-OMHXVVQ4.js +1 -0
- package/dist/ui/index.js +1 -19
- package/package.json +4 -3
- package/dist/Browser-ZNX4WFUH.js +0 -482
- package/dist/Browser-ZNX4WFUH.js.map +0 -1
- package/dist/Calculator-6FGNKOXU.js +0 -192
- package/dist/Calculator-6FGNKOXU.js.map +0 -1
- package/dist/ConfirmDialog-NPQMIGUR.js +0 -4
- package/dist/ConfirmDialog-NPQMIGUR.js.map +0 -1
- package/dist/CurrencyConverter-FF7EXRYL.js +0 -236
- package/dist/CurrencyConverter-FF7EXRYL.js.map +0 -1
- package/dist/Documents-H3R7XSBH.js +0 -441
- package/dist/Documents-H3R7XSBH.js.map +0 -1
- package/dist/Files-ZHJIAUC2.js +0 -805
- package/dist/Files-ZHJIAUC2.js.map +0 -1
- package/dist/Notepad-VE7ISWRQ.js +0 -410
- package/dist/Notepad-VE7ISWRQ.js.map +0 -1
- package/dist/PdfViewer-SQBFYAGW.js +0 -5
- package/dist/PdfViewer-SQBFYAGW.js.map +0 -1
- package/dist/PomodoroTimer-IR3WREED.js +0 -633
- package/dist/PomodoroTimer-IR3WREED.js.map +0 -1
- package/dist/Preview-DAQGRNRM.js +0 -2959
- package/dist/Preview-DAQGRNRM.js.map +0 -1
- package/dist/Sidebar-YW6H4NDJ.js +0 -291
- package/dist/Sidebar-YW6H4NDJ.js.map +0 -1
- package/dist/Spreadsheet-HOCPHJOC.js +0 -519
- package/dist/Spreadsheet-HOCPHJOC.js.map +0 -1
- package/dist/Stock-LVRQPURG.js +0 -158
- package/dist/Stock-LVRQPURG.js.map +0 -1
- package/dist/Weather-LZQGVDJL.js +0 -431
- package/dist/Weather-LZQGVDJL.js.map +0 -1
- package/dist/WorldClock-XPD7WOZT.js +0 -202
- package/dist/WorldClock-XPD7WOZT.js.map +0 -1
- package/dist/apps/index.js.map +0 -1
- package/dist/chunk-5O42JXQE.js +0 -26
- package/dist/chunk-5O42JXQE.js.map +0 -1
- package/dist/chunk-5RPTS3BT.js +0 -70
- package/dist/chunk-5RPTS3BT.js.map +0 -1
- package/dist/chunk-6XJEJWNJ.js +0 -61
- package/dist/chunk-6XJEJWNJ.js.map +0 -1
- package/dist/chunk-7CCHEEYC.js +0 -94
- package/dist/chunk-7CCHEEYC.js.map +0 -1
- package/dist/chunk-BE7FZOFU.js +0 -17
- package/dist/chunk-BE7FZOFU.js.map +0 -1
- package/dist/chunk-COWYSHG2.js +0 -79
- package/dist/chunk-COWYSHG2.js.map +0 -1
- package/dist/chunk-D7PYW2QS.js +0 -265
- package/dist/chunk-D7PYW2QS.js.map +0 -1
- package/dist/chunk-DVZWYWSD.js +0 -26
- package/dist/chunk-DVZWYWSD.js.map +0 -1
- package/dist/chunk-E7TB6WD2.js +0 -153
- package/dist/chunk-E7TB6WD2.js.map +0 -1
- package/dist/chunk-FIHOGVUP.js +0 -416
- package/dist/chunk-FIHOGVUP.js.map +0 -1
- package/dist/chunk-GA35NEND.js +0 -56
- package/dist/chunk-GA35NEND.js.map +0 -1
- package/dist/chunk-HUBJAUGG.js +0 -316
- package/dist/chunk-HUBJAUGG.js.map +0 -1
- package/dist/chunk-I2TAAJHS.js +0 -465
- package/dist/chunk-I2TAAJHS.js.map +0 -1
- package/dist/chunk-ICTRCKUE.js +0 -3710
- package/dist/chunk-ICTRCKUE.js.map +0 -1
- package/dist/chunk-IPXN646P.js +0 -14
- package/dist/chunk-IPXN646P.js.map +0 -1
- package/dist/chunk-IRWSRJ4K.js +0 -48
- package/dist/chunk-IRWSRJ4K.js.map +0 -1
- package/dist/chunk-JOPU6WPY.js +0 -504
- package/dist/chunk-JOPU6WPY.js.map +0 -1
- package/dist/chunk-MGGY74RY.js +0 -14
- package/dist/chunk-MGGY74RY.js.map +0 -1
- package/dist/chunk-PVPPAWVM.js +0 -46
- package/dist/chunk-PVPPAWVM.js.map +0 -1
- package/dist/chunk-R7QGMK6N.js +0 -102
- package/dist/chunk-R7QGMK6N.js.map +0 -1
- package/dist/chunk-RT6DSB5Y.js +0 -143
- package/dist/chunk-RT6DSB5Y.js.map +0 -1
- package/dist/chunk-TRCWINHF.js +0 -105
- package/dist/chunk-TRCWINHF.js.map +0 -1
- package/dist/chunk-TW7LPMVR.js +0 -16
- package/dist/chunk-TW7LPMVR.js.map +0 -1
- package/dist/chunk-UTYKLGGT.js +0 -195
- package/dist/chunk-UTYKLGGT.js.map +0 -1
- package/dist/chunk-VNJJCH5A.js +0 -822
- package/dist/chunk-VNJJCH5A.js.map +0 -1
- package/dist/chunk-XJHZWSKV.js +0 -1103
- package/dist/chunk-XJHZWSKV.js.map +0 -1
- package/dist/chunk-Y3GYJ7YR.js +0 -549
- package/dist/chunk-Y3GYJ7YR.js.map +0 -1
- package/dist/chunk-YA4EE7ST.js +0 -14107
- package/dist/chunk-YA4EE7ST.js.map +0 -1
- package/dist/chunk-YDHXWCCJ.js +0 -145
- package/dist/chunk-YDHXWCCJ.js.map +0 -1
- package/dist/chunk-YE6GUDGP.js +0 -548
- package/dist/chunk-YE6GUDGP.js.map +0 -1
- package/dist/chunk-YNKK7NE3.js +0 -171
- package/dist/chunk-YNKK7NE3.js.map +0 -1
- package/dist/chunk-YPO6RDMX.js +0 -20
- package/dist/chunk-YPO6RDMX.js.map +0 -1
- package/dist/chunk-ZS7PMGUW.js +0 -7
- package/dist/chunk-ZS7PMGUW.js.map +0 -1
- package/dist/file-intake/index.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/map/index.js.map +0 -1
- package/dist/markdown/index.js.map +0 -1
- package/dist/markup/index.js.map +0 -1
- package/dist/page-tabs/index.js.map +0 -1
- package/dist/sounds-NT4DEZGD.js +0 -3
- package/dist/sounds-NT4DEZGD.js.map +0 -1
- package/dist/ui/index.js.map +0 -1
package/dist/chunk-IPXN646P.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
// src/utils/rootTheme.ts
|
|
2
|
-
function rootIsDark() {
|
|
3
|
-
try {
|
|
4
|
-
const root = document.documentElement;
|
|
5
|
-
return root.getAttribute("data-theme") === "dark" || root.classList.contains("dark");
|
|
6
|
-
} catch {
|
|
7
|
-
return false;
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
var ROOT_THEME_ATTRIBUTES = ["data-theme", "class"];
|
|
11
|
-
|
|
12
|
-
export { ROOT_THEME_ATTRIBUTES, rootIsDark };
|
|
13
|
-
//# sourceMappingURL=chunk-IPXN646P.js.map
|
|
14
|
-
//# sourceMappingURL=chunk-IPXN646P.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/rootTheme.ts"],"names":[],"mappings":";AAYO,SAAS,UAAA,GAAsB;AACpC,EAAA,IAAI;AACF,IAAA,MAAM,OAAO,QAAA,CAAS,eAAA;AACtB,IAAA,OAAO,IAAA,CAAK,aAAa,YAAY,CAAA,KAAM,UAAU,IAAA,CAAK,SAAA,CAAU,SAAS,MAAM,CAAA;AAAA,EACrF,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,KAAA;AAAA,EACT;AACF;AAGO,IAAM,qBAAA,GAAwB,CAAC,YAAA,EAAc,OAAO","file":"chunk-IPXN646P.js","sourcesContent":["/**\n * Whether the document is in its dark theme, read off `<html>` the same way\n * ui.css reads it: `data-theme=\"dark\"` (what `useTheme()` stamps, and what the\n * EFFICIENT portals' own toggles stamp) OR a `dark` class (next-themes,\n * shadcn/ui, Tailwind's class strategy). Every dark rule in the stylesheet is\n * scoped by `:is([data-theme=\"dark\"], .dark)`; a component that decides in\n * script — a canvas, an inline glass tint — must agree with it, or it paints\n * light inside a page the stylesheet has already turned dark.\n *\n * Never throws: a document without a root (a server render, a detached test)\n * is light, which is also what the stylesheet would say.\n */\nexport function rootIsDark(): boolean {\n try {\n const root = document.documentElement;\n return root.getAttribute('data-theme') === 'dark' || root.classList.contains('dark');\n } catch {\n return false;\n }\n}\n\n/** The `<html>` attributes a theme change can arrive on — for a MutationObserver's `attributeFilter`. */\nexport const ROOT_THEME_ATTRIBUTES = ['data-theme', 'class'];\n"]}
|
package/dist/chunk-IRWSRJ4K.js
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { useLayoutEffect, useEffect, useSyncExternalStore, useRef, useState, useCallback } from 'react';
|
|
2
|
-
|
|
3
|
-
// src/shell/hydration.ts
|
|
4
|
-
var IN_BROWSER = typeof window !== "undefined" && typeof document !== "undefined";
|
|
5
|
-
var useBrowserLayoutEffect = IN_BROWSER ? useLayoutEffect : useEffect;
|
|
6
|
-
var NO_SUBSCRIPTION = () => () => {
|
|
7
|
-
};
|
|
8
|
-
var ALWAYS = () => true;
|
|
9
|
-
var NEVER = () => false;
|
|
10
|
-
function useHydrated() {
|
|
11
|
-
return useSyncExternalStore(NO_SUBSCRIPTION, ALWAYS, NEVER);
|
|
12
|
-
}
|
|
13
|
-
function useBrowserValue(read, serverValue, subscribe = NO_SUBSCRIPTION) {
|
|
14
|
-
return useSyncExternalStore(subscribe, read, () => serverValue);
|
|
15
|
-
}
|
|
16
|
-
function useBrowserValueOnce(read, serverValue) {
|
|
17
|
-
const held = useRef(null);
|
|
18
|
-
return useSyncExternalStore(
|
|
19
|
-
NO_SUBSCRIPTION,
|
|
20
|
-
() => (held.current ??= { value: read() }).value,
|
|
21
|
-
() => serverValue
|
|
22
|
-
);
|
|
23
|
-
}
|
|
24
|
-
function useBrowserState(read, serverValue) {
|
|
25
|
-
const hydrated = useHydrated();
|
|
26
|
-
const [value, setValue] = useState(() => hydrated ? read() : serverValue);
|
|
27
|
-
const restored = useRef(hydrated);
|
|
28
|
-
const latestRead = useRef(read);
|
|
29
|
-
latestRead.current = read;
|
|
30
|
-
useBrowserLayoutEffect(() => {
|
|
31
|
-
if (!hydrated || restored.current) return;
|
|
32
|
-
restored.current = true;
|
|
33
|
-
setValue(latestRead.current());
|
|
34
|
-
}, [hydrated]);
|
|
35
|
-
const set = useCallback((next) => {
|
|
36
|
-
if (restored.current) {
|
|
37
|
-
setValue(next);
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
restored.current = true;
|
|
41
|
-
setValue(typeof next === "function" ? next(latestRead.current()) : next);
|
|
42
|
-
}, []);
|
|
43
|
-
return [value, set];
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export { useBrowserLayoutEffect, useBrowserState, useBrowserValue, useBrowserValueOnce, useHydrated };
|
|
47
|
-
//# sourceMappingURL=chunk-IRWSRJ4K.js.map
|
|
48
|
-
//# sourceMappingURL=chunk-IRWSRJ4K.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/shell/hydration.ts"],"names":[],"mappings":";;;AAyCO,IAAM,UAAA,GAAa,OAAO,MAAA,KAAW,WAAA,IAAe,OAAO,QAAA,KAAa,WAAA;AASxE,IAAM,sBAAA,GAAyB,aAAa,eAAA,GAAkB;AAGrE,IAAM,eAAA,GAAkB,MAAM,MAAM;AAAC,CAAA;AACrC,IAAM,SAAS,MAAM,IAAA;AACrB,IAAM,QAAQ,MAAM,KAAA;AAOb,SAAS,WAAA,GAAuB;AACrC,EAAA,OAAO,oBAAA,CAAqB,eAAA,EAAiB,MAAA,EAAQ,KAAK,CAAA;AAC5D;AAYO,SAAS,eAAA,CACd,IAAA,EACA,WAAA,EACA,SAAA,GAAkD,eAAA,EAC/C;AACH,EAAA,OAAO,oBAAA,CAAqB,SAAA,EAAW,IAAA,EAAM,MAAM,WAAW,CAAA;AAChE;AAYO,SAAS,mBAAA,CAAuB,MAAe,WAAA,EAAmB;AACvE,EAAA,MAAM,IAAA,GAAO,OAA4B,IAAI,CAAA;AAC7C,EAAA,OAAO,oBAAA;AAAA,IACL,eAAA;AAAA,IACA,OAAO,IAAA,CAAK,OAAA,KAAY,EAAE,KAAA,EAAO,IAAA,IAAO,EAAG,KAAA;AAAA,IAC3C,MAAM;AAAA,GACR;AACF;AAiBO,SAAS,eAAA,CAAmB,MAAe,WAAA,EAAkD;AAClG,EAAA,MAAM,WAAW,WAAA,EAAY;AAC7B,EAAA,MAAM,CAAC,OAAO,QAAQ,CAAA,GAAI,SAAY,MAAO,QAAA,GAAW,IAAA,EAAK,GAAI,WAAY,CAAA;AAG7E,EAAA,MAAM,QAAA,GAAW,OAAO,QAAQ,CAAA;AAChC,EAAA,MAAM,UAAA,GAAa,OAAO,IAAI,CAAA;AAC9B,EAAA,UAAA,CAAW,OAAA,GAAU,IAAA;AAErB,EAAA,sBAAA,CAAuB,MAAM;AAC3B,IAAA,IAAI,CAAC,QAAA,IAAY,QAAA,CAAS,OAAA,EAAS;AACnC,IAAA,QAAA,CAAS,OAAA,GAAU,IAAA;AACnB,IAAA,QAAA,CAAS,UAAA,CAAW,SAAS,CAAA;AAAA,EAC/B,CAAA,EAAG,CAAC,QAAQ,CAAC,CAAA;AAEb,EAAA,MAAM,GAAA,GAAM,WAAA,CAAyC,CAAC,IAAA,KAAS;AAC7D,IAAA,IAAI,SAAS,OAAA,EAAS;AACpB,MAAA,QAAA,CAAS,IAAI,CAAA;AACb,MAAA;AAAA,IACF;AACA,IAAA,QAAA,CAAS,OAAA,GAAU,IAAA;AACnB,IAAA,QAAA,CAAS,OAAO,SAAS,UAAA,GAAc,IAAA,CAAwB,WAAW,OAAA,EAAS,IAAI,IAAI,CAAA;AAAA,EAC7F,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,OAAO,CAAC,OAAO,GAAG,CAAA;AACpB","file":"chunk-IRWSRJ4K.js","sourcesContent":["/**\n * Rendering on a server, and hydrating what it sent.\n *\n * Every consumer this package had until now mounted it in the browser and\n * nowhere else — the portals are static exports that load the app behind\n * `dynamic(…, { ssr: false })`, so the first render always ran with a window, a\n * clock and the reader's storage in reach. A Next.js App Router consumer renders\n * on a SERVER first and then hydrates that HTML in the browser, and hydration\n * has one rule nothing here ever had to keep: the browser's first render must\n * produce exactly the HTML the server did. A component that reads the platform,\n * a stored width, today's date or a media query while it renders draws one thing\n * on the server and another in the browser, and React either logs a mismatch\n * and leaves the wrong attribute in place, or throws the server HTML away.\n *\n * So the rule for anything only a browser knows: the server — and the hydration\n * pass that has to agree with it — renders a fixed SERVER value, and the\n * browser's value arrives in the render after. The other half matters as much,\n * because the browser-only consumers are the ones this package has: a root that\n * was NOT server-rendered (`createRoot`, a dialog mounted later, a client-only\n * page) reads the browser's value on its very first render, exactly as before,\n * with no frame of the server value and no extra render.\n *\n * `useSyncExternalStore` is what tells the two apart. React calls its\n * `getServerSnapshot` on the server AND while hydrating, and `getSnapshot`\n * everywhere else, then re-renders with `getSnapshot` once hydration commits if\n * the two disagree. That is the whole mechanism; the hooks below are that one\n * call shaped for the three ways the kit needs it.\n */\nimport {\n useCallback, useEffect, useLayoutEffect, useRef, useState, useSyncExternalStore,\n type Dispatch, type SetStateAction,\n} from 'react';\n\n/**\n * A browser, as opposed to a server. Read once, at module scope, because it\n * cannot change for the life of the module: a server never turns into a browser.\n *\n * `window` rather than `navigator`: Node has had a global `navigator` since 21,\n * and its `platform` is the SERVER's — a guard on it reads a Mac build machine\n * as a Mac reader.\n */\nexport const IN_BROWSER = typeof window !== 'undefined' && typeof document !== 'undefined';\n\n/**\n * `useLayoutEffect` in a browser, `useEffect` where there is no DOM.\n *\n * Neither runs on a server, but React 18's server renderer warns about every\n * `useLayoutEffect` it meets, once per component per render. Chosen at module\n * scope, so the hook order is the same on every render either way.\n */\nexport const useBrowserLayoutEffect = IN_BROWSER ? useLayoutEffect : useEffect;\n\n/** Nothing to subscribe to: the value is read again on the next render. */\nconst NO_SUBSCRIPTION = () => () => {};\nconst ALWAYS = () => true;\nconst NEVER = () => false;\n\n/**\n * False while React renders on a server or hydrates the HTML it sent; true\n * otherwise — including the very FIRST render of a root that was never\n * server-rendered, which is what keeps a client-only consumer exactly as it was.\n */\nexport function useHydrated(): boolean {\n return useSyncExternalStore(NO_SUBSCRIPTION, ALWAYS, NEVER);\n}\n\n/**\n * A value only the browser knows, read on every render, with `serverValue` in\n * its place on a server and while hydrating.\n *\n * `read` must return the same value for the same state of the world — a\n * primitive, or a cached object — because React compares consecutive reads to\n * decide whether anything changed. Pass `subscribe` to re-render when it does\n * (a media query); without one the value is simply read again on the next\n * render, which is what the code this replaced did by calling it inline.\n */\nexport function useBrowserValue<T>(\n read: () => T,\n serverValue: T,\n subscribe: (onChange: () => void) => () => void = NO_SUBSCRIPTION,\n): T {\n return useSyncExternalStore(subscribe, read, () => serverValue);\n}\n\n/**\n * A browser value read ONCE per mounted component — the moment it mounted, or\n * the moment hydration ended — and held for its lifetime.\n *\n * For what the kit used to capture with `useState(() => Date.now())`: \"now\" as\n * a timeline's coordinate, which must not drift while the reader looks at it.\n * The state initialiser runs during hydration as well, so it put the browser's\n * clock into a render that had to match the server's; this holds the server\n * value until hydration ends and reads the clock then.\n */\nexport function useBrowserValueOnce<T>(read: () => T, serverValue: T): T {\n const held = useRef<{ value: T } | null>(null);\n return useSyncExternalStore(\n NO_SUBSCRIPTION,\n () => (held.current ??= { value: read() }).value,\n () => serverValue,\n );\n}\n\n/**\n * `useState` whose initial value comes from the browser — a stored width, the\n * saved prefs — and starts as `serverValue` when the HTML came from a server.\n *\n * A client-only root reads the browser on its first render, as the\n * `useState(() => localStorage…)` this replaces did, so nothing about it\n * changes. A hydrating root renders `serverValue`, then reads the browser in a\n * layout effect the moment hydration ends — before that render is painted.\n *\n * An update made in between is applied to the BROWSER's value, not to the\n * placeholder, and counts as the restore. The window is real: the children's\n * effects run when hydration commits, before the restore, and a `save(patch)`\n * from one of them would otherwise merge the patch into the defaults and write\n * that over everything the reader had stored.\n */\nexport function useBrowserState<T>(read: () => T, serverValue: T): [T, Dispatch<SetStateAction<T>>] {\n const hydrated = useHydrated();\n const [value, setValue] = useState<T>(() => (hydrated ? read() : serverValue));\n // True once the state holds the browser's value: from the start on a\n // client-only root, after the restore below on a hydrated one.\n const restored = useRef(hydrated);\n const latestRead = useRef(read);\n latestRead.current = read;\n\n useBrowserLayoutEffect(() => {\n if (!hydrated || restored.current) return;\n restored.current = true;\n setValue(latestRead.current());\n }, [hydrated]);\n\n const set = useCallback<Dispatch<SetStateAction<T>>>((next) => {\n if (restored.current) {\n setValue(next);\n return;\n }\n restored.current = true;\n setValue(typeof next === 'function' ? (next as (prev: T) => T)(latestRead.current()) : next);\n }, []);\n\n return [value, set];\n}\n"]}
|
package/dist/chunk-JOPU6WPY.js
DELETED
|
@@ -1,504 +0,0 @@
|
|
|
1
|
-
import { onOverlayOpen, Z_LAYERS, registerModalEscapeInterceptor } from './chunk-I2TAAJHS.js';
|
|
2
|
-
import { glassStyle, GLASS_DIVIDER } from './chunk-6XJEJWNJ.js';
|
|
3
|
-
import { useHydrated, useBrowserLayoutEffect } from './chunk-IRWSRJ4K.js';
|
|
4
|
-
import { createContext, forwardRef, useContext, useRef, useId, useState, useEffect, useMemo, useCallback } from 'react';
|
|
5
|
-
import { createPortal } from 'react-dom';
|
|
6
|
-
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
7
|
-
|
|
8
|
-
// src/shell/contextMenuTarget.ts
|
|
9
|
-
var TEXT_INPUT_TYPES = /* @__PURE__ */ new Set([
|
|
10
|
-
"text",
|
|
11
|
-
"search",
|
|
12
|
-
"url",
|
|
13
|
-
"tel",
|
|
14
|
-
"email",
|
|
15
|
-
"password",
|
|
16
|
-
"number",
|
|
17
|
-
"date",
|
|
18
|
-
"datetime-local",
|
|
19
|
-
"month",
|
|
20
|
-
"week",
|
|
21
|
-
"time"
|
|
22
|
-
]);
|
|
23
|
-
var NATIVE_MEDIA = "img, picture, canvas, video, audio";
|
|
24
|
-
var NATIVE_MENU_ATTR = "data-native-context-menu";
|
|
25
|
-
function closest(el, selector) {
|
|
26
|
-
if (!el || typeof el.closest !== "function") return null;
|
|
27
|
-
return el.closest(selector);
|
|
28
|
-
}
|
|
29
|
-
function keepsNativeMenu(target) {
|
|
30
|
-
const el = target;
|
|
31
|
-
if (!el || typeof el.closest !== "function") return false;
|
|
32
|
-
if (closest(el, `[${NATIVE_MENU_ATTR}]`)) return true;
|
|
33
|
-
if (closest(el, "textarea")) return true;
|
|
34
|
-
if (closest(el, NATIVE_MEDIA)) return true;
|
|
35
|
-
const input = closest(el, "input");
|
|
36
|
-
if (input) {
|
|
37
|
-
const type = (input.type || "text").toLowerCase();
|
|
38
|
-
if (TEXT_INPUT_TYPES.has(type)) return true;
|
|
39
|
-
}
|
|
40
|
-
const editable = closest(el, "[contenteditable]");
|
|
41
|
-
if (editable) {
|
|
42
|
-
const value = (editable.getAttribute("contenteditable") || "").toLowerCase();
|
|
43
|
-
if (value === "" || value === "true" || value === "plaintext-only") return true;
|
|
44
|
-
}
|
|
45
|
-
return false;
|
|
46
|
-
}
|
|
47
|
-
var LINK_SCHEMES = /* @__PURE__ */ new Set(["http:", "https:", "mailto:", "tel:", "blob:"]);
|
|
48
|
-
function linkAddress(href, base) {
|
|
49
|
-
if (!href || href === "#") return void 0;
|
|
50
|
-
try {
|
|
51
|
-
const url = new URL(href, base ?? (typeof document !== "undefined" ? document.baseURI : void 0));
|
|
52
|
-
return LINK_SCHEMES.has(url.protocol) ? url.href : void 0;
|
|
53
|
-
} catch {
|
|
54
|
-
return void 0;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
function describeContextTarget(target, selectionText, baseUrl) {
|
|
58
|
-
const el = target;
|
|
59
|
-
const link = closest(el, "a[href]");
|
|
60
|
-
const text = (selectionText || "").trim();
|
|
61
|
-
const linkUrl = linkAddress(link?.getAttribute("href"), baseUrl);
|
|
62
|
-
const kind = text ? "selection" : linkUrl ? "link" : "default";
|
|
63
|
-
return {
|
|
64
|
-
kind,
|
|
65
|
-
...text ? { selectionText: text } : {},
|
|
66
|
-
...linkUrl ? { linkUrl } : {}
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// src/shell/menuPath.ts
|
|
71
|
-
function openMenuLevel(path, depth, anchor) {
|
|
72
|
-
if (path.length === depth + 1 && path[depth].key === anchor.key) return path;
|
|
73
|
-
return [...path.slice(0, depth), anchor];
|
|
74
|
-
}
|
|
75
|
-
function closeMenuBelow(path, depth) {
|
|
76
|
-
const keep = Math.max(0, depth);
|
|
77
|
-
return path.length > keep ? path.slice(0, keep) : path;
|
|
78
|
-
}
|
|
79
|
-
function resolveMenuLevels(rootItems, path, childrenOf) {
|
|
80
|
-
if (path.length === 0 || rootItems.length === 0) return [];
|
|
81
|
-
const levels = [rootItems];
|
|
82
|
-
for (let i = 1; i < path.length; i++) {
|
|
83
|
-
const parent = levels[i - 1].find((item) => item.to === path[i].key);
|
|
84
|
-
const kids = parent ? childrenOf(parent) : [];
|
|
85
|
-
if (kids.length === 0) break;
|
|
86
|
-
levels.push(kids);
|
|
87
|
-
}
|
|
88
|
-
return levels;
|
|
89
|
-
}
|
|
90
|
-
function clampMenuTop(anchorY, height, minTop, maxBottom) {
|
|
91
|
-
const span = Math.max(0, maxBottom - minTop);
|
|
92
|
-
const h = Math.min(height, span);
|
|
93
|
-
const top = anchorY - h / 2;
|
|
94
|
-
if (top < minTop) return minTop;
|
|
95
|
-
if (top + h > maxBottom) return Math.max(minTop, maxBottom - h);
|
|
96
|
-
return top;
|
|
97
|
-
}
|
|
98
|
-
function menuPanelLeft(ownerLeft, ownerRight, width, viewportW, gap, preferLeft = false, margin = 8) {
|
|
99
|
-
const onRight = ownerRight + gap;
|
|
100
|
-
const onLeft = ownerLeft - gap - width;
|
|
101
|
-
const rightFits = onRight + width <= viewportW - margin;
|
|
102
|
-
const leftFits = onLeft >= margin;
|
|
103
|
-
if (preferLeft && leftFits) return { left: onLeft, flipped: true };
|
|
104
|
-
if (rightFits) return { left: onRight, flipped: false };
|
|
105
|
-
if (leftFits) return { left: onLeft, flipped: true };
|
|
106
|
-
return preferLeft ? { left: margin, flipped: true } : { left: Math.max(margin, viewportW - margin - width), flipped: false };
|
|
107
|
-
}
|
|
108
|
-
function getDensity() {
|
|
109
|
-
try {
|
|
110
|
-
return getComputedStyle(document.documentElement).getPropertyValue("--menu-density")?.trim() || "normal";
|
|
111
|
-
} catch {
|
|
112
|
-
return "normal";
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
var SUBMENU_CLOSE_DELAY = 200;
|
|
116
|
-
var SUBMENU_OPEN_DELAY = 120;
|
|
117
|
-
var SUBMENU_GAP = 4;
|
|
118
|
-
var MenuTreeContext = createContext(null);
|
|
119
|
-
function PopupMenu({ children, style, className = "", onClose, minWidth = 180, portal = false }) {
|
|
120
|
-
const ref = useRef(null);
|
|
121
|
-
const treeId = useId();
|
|
122
|
-
const [path, setPath] = useState([]);
|
|
123
|
-
const closeTimer = useRef();
|
|
124
|
-
useEffect(() => () => clearTimeout(closeTimer.current), []);
|
|
125
|
-
const hydrated = useHydrated();
|
|
126
|
-
const tree = useMemo(() => {
|
|
127
|
-
const cancelClose = () => clearTimeout(closeTimer.current);
|
|
128
|
-
return {
|
|
129
|
-
id: treeId,
|
|
130
|
-
depth: 0,
|
|
131
|
-
path,
|
|
132
|
-
open: (depth, anchor) => {
|
|
133
|
-
cancelClose();
|
|
134
|
-
setPath((prev) => openMenuLevel(prev, depth, anchor));
|
|
135
|
-
},
|
|
136
|
-
scheduleClose: (depth) => {
|
|
137
|
-
cancelClose();
|
|
138
|
-
closeTimer.current = setTimeout(() => setPath((prev) => closeMenuBelow(prev, depth)), SUBMENU_CLOSE_DELAY);
|
|
139
|
-
},
|
|
140
|
-
closeBelow: (depth) => {
|
|
141
|
-
cancelClose();
|
|
142
|
-
setPath((prev) => closeMenuBelow(prev, depth));
|
|
143
|
-
},
|
|
144
|
-
cancelClose,
|
|
145
|
-
closeTree: () => {
|
|
146
|
-
cancelClose();
|
|
147
|
-
setPath([]);
|
|
148
|
-
onClose?.();
|
|
149
|
-
},
|
|
150
|
-
root: ref
|
|
151
|
-
};
|
|
152
|
-
}, [treeId, path, onClose]);
|
|
153
|
-
useEffect(() => {
|
|
154
|
-
if (!onClose) return;
|
|
155
|
-
const handleClick = (e) => {
|
|
156
|
-
if (e.target.closest("[data-menu-toggle]")) return;
|
|
157
|
-
if (e.target.closest?.(`[data-popup-menu-tree="${treeId}"]`)) return;
|
|
158
|
-
if (ref.current && !ref.current.contains(e.target)) onClose();
|
|
159
|
-
};
|
|
160
|
-
const handleKey = (e) => {
|
|
161
|
-
if (e.key === "Escape") onClose();
|
|
162
|
-
};
|
|
163
|
-
window.addEventListener("pointerdown", handleClick);
|
|
164
|
-
window.addEventListener("keydown", handleKey);
|
|
165
|
-
const offOverlay = onOverlayOpen(onClose);
|
|
166
|
-
return () => {
|
|
167
|
-
window.removeEventListener("pointerdown", handleClick);
|
|
168
|
-
window.removeEventListener("keydown", handleKey);
|
|
169
|
-
offOverlay();
|
|
170
|
-
};
|
|
171
|
-
}, [onClose, treeId]);
|
|
172
|
-
useEffect(() => {
|
|
173
|
-
const el = ref.current;
|
|
174
|
-
if (!el) return;
|
|
175
|
-
requestAnimationFrame(() => {
|
|
176
|
-
const rect = el.getBoundingClientRect();
|
|
177
|
-
const margin = 8;
|
|
178
|
-
if (rect.right > window.innerWidth - margin) {
|
|
179
|
-
const overflow = rect.right - window.innerWidth + margin;
|
|
180
|
-
if (el.style.left) {
|
|
181
|
-
el.style.left = `${parseFloat(el.style.left) - overflow}px`;
|
|
182
|
-
} else if (!el.style.right) {
|
|
183
|
-
el.style.left = `${rect.left - overflow}px`;
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
if (rect.left < margin) {
|
|
187
|
-
if (el.style.left) {
|
|
188
|
-
el.style.left = `${margin}px`;
|
|
189
|
-
} else if (el.style.right) {
|
|
190
|
-
el.style.right = `${window.innerWidth - rect.width - margin}px`;
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
if (rect.bottom > window.innerHeight - margin) {
|
|
194
|
-
const overflow = rect.bottom - window.innerHeight + margin;
|
|
195
|
-
if (el.style.top) {
|
|
196
|
-
el.style.top = `${parseFloat(el.style.top) - overflow}px`;
|
|
197
|
-
} else if (el.style.bottom) {
|
|
198
|
-
el.style.bottom = `${margin}px`;
|
|
199
|
-
} else {
|
|
200
|
-
el.style.top = `${rect.top - overflow}px`;
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
if (rect.top < margin) {
|
|
204
|
-
if (el.style.top) {
|
|
205
|
-
el.style.top = `${margin}px`;
|
|
206
|
-
} else if (el.style.bottom) {
|
|
207
|
-
el.style.bottom = `${window.innerHeight - rect.height - margin}px`;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
});
|
|
211
|
-
});
|
|
212
|
-
const density = getDensity();
|
|
213
|
-
const ownsZ = /(^|[\s:])!?z-/.test(className);
|
|
214
|
-
const menu = /* @__PURE__ */ jsx(
|
|
215
|
-
"div",
|
|
216
|
-
{
|
|
217
|
-
ref,
|
|
218
|
-
"data-popup-menu-tree": treeId,
|
|
219
|
-
className: `fixed rounded-2xl ${density === "tight" ? "py-1" : density === "large" ? "py-2" : "py-1.5"} ${className}`,
|
|
220
|
-
onContextMenu: (e) => {
|
|
221
|
-
if (!keepsNativeMenu(e.target)) e.preventDefault();
|
|
222
|
-
},
|
|
223
|
-
style: { ...ownsZ ? {} : { zIndex: Z_LAYERS.menu }, minWidth, animation: "popup-in 0.12s ease-out", ...glassStyle(), ...style },
|
|
224
|
-
children: /* @__PURE__ */ jsx(MenuTreeContext.Provider, { value: tree, children })
|
|
225
|
-
}
|
|
226
|
-
);
|
|
227
|
-
if (!portal) return menu;
|
|
228
|
-
return hydrated ? createPortal(menu, document.body) : null;
|
|
229
|
-
}
|
|
230
|
-
function itemLook(danger, disabled, className, highlighted = false) {
|
|
231
|
-
const density = getDensity();
|
|
232
|
-
const itemPadY = density === "tight" ? "0.25rem" : density === "large" ? "0.6rem" : "max(0.25rem, calc(var(--menu-padding-y, 0.5rem) - 0.1rem))";
|
|
233
|
-
const tone = danger ? "text-red-600 hover:bg-red-50" : highlighted ? "bg-blue-50 text-blue-700" : "text-gray-700 hover:bg-blue-50 hover:text-blue-700";
|
|
234
|
-
return {
|
|
235
|
-
className: `w-full flex items-center gap-2 text-left transition-colors rounded-lg mx-auto
|
|
236
|
-
${tone}
|
|
237
|
-
${disabled ? "opacity-40 cursor-not-allowed" : ""}
|
|
238
|
-
${className}`,
|
|
239
|
-
style: {
|
|
240
|
-
width: "calc(100% - 8px)",
|
|
241
|
-
marginLeft: 4,
|
|
242
|
-
marginRight: 4,
|
|
243
|
-
fontSize: "var(--menu-font-size, 14px)",
|
|
244
|
-
paddingLeft: "var(--menu-padding-x, 1rem)",
|
|
245
|
-
paddingRight: "var(--menu-padding-x, 1rem)",
|
|
246
|
-
paddingTop: itemPadY,
|
|
247
|
-
paddingBottom: itemPadY
|
|
248
|
-
}
|
|
249
|
-
};
|
|
250
|
-
}
|
|
251
|
-
var PopupMenuItem = forwardRef(function PopupMenuItem2({
|
|
252
|
-
onClick,
|
|
253
|
-
children,
|
|
254
|
-
className = "",
|
|
255
|
-
danger,
|
|
256
|
-
disabled,
|
|
257
|
-
role,
|
|
258
|
-
tabIndex,
|
|
259
|
-
id,
|
|
260
|
-
onMouseEnter
|
|
261
|
-
}, ref) {
|
|
262
|
-
const tree = useContext(MenuTreeContext);
|
|
263
|
-
const look = itemLook(danger, disabled, className);
|
|
264
|
-
return /* @__PURE__ */ jsx(
|
|
265
|
-
"button",
|
|
266
|
-
{
|
|
267
|
-
ref,
|
|
268
|
-
id,
|
|
269
|
-
role,
|
|
270
|
-
tabIndex,
|
|
271
|
-
onClick: () => {
|
|
272
|
-
onClick?.();
|
|
273
|
-
if (tree && tree.depth > 0) tree.closeTree();
|
|
274
|
-
},
|
|
275
|
-
onMouseEnter: () => {
|
|
276
|
-
tree?.scheduleClose(tree.depth);
|
|
277
|
-
onMouseEnter?.();
|
|
278
|
-
},
|
|
279
|
-
disabled,
|
|
280
|
-
className: look.className,
|
|
281
|
-
style: look.style,
|
|
282
|
-
children
|
|
283
|
-
}
|
|
284
|
-
);
|
|
285
|
-
});
|
|
286
|
-
var chevron = /* @__PURE__ */ jsx("svg", { "aria-hidden": true, className: "h-3.5 w-3.5 shrink-0 ml-auto text-gray-500", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8.25 4.5l7.5 7.5-7.5 7.5" }) });
|
|
287
|
-
function layerOf(el) {
|
|
288
|
-
let z = Z_LAYERS.menu;
|
|
289
|
-
for (let node = el; node && node !== document.body; node = node.parentElement) {
|
|
290
|
-
const value = parseInt(getComputedStyle(node).zIndex, 10);
|
|
291
|
-
if (!Number.isNaN(value)) z = value;
|
|
292
|
-
}
|
|
293
|
-
return z;
|
|
294
|
-
}
|
|
295
|
-
function focusables(panel) {
|
|
296
|
-
if (!panel) return [];
|
|
297
|
-
return [...panel.querySelectorAll("button:not([disabled])")].filter((b) => b.closest("[data-popup-submenu-panel]") === panel);
|
|
298
|
-
}
|
|
299
|
-
function PopupSubmenu({ label, icon, children, disabled, className = "", minWidth = 180, maxHeight }) {
|
|
300
|
-
const tree = useContext(MenuTreeContext);
|
|
301
|
-
const key = useId();
|
|
302
|
-
const rowRef = useRef(null);
|
|
303
|
-
const panelRef = useRef(null);
|
|
304
|
-
const openTimer = useRef();
|
|
305
|
-
const focusOnOpen = useRef(false);
|
|
306
|
-
const panelId = `${key}-menu`;
|
|
307
|
-
useEffect(() => () => clearTimeout(openTimer.current), []);
|
|
308
|
-
const depth = tree?.depth ?? 0;
|
|
309
|
-
const anchor = tree?.path[depth];
|
|
310
|
-
const isOpen = !!anchor && anchor.key === key && !disabled;
|
|
311
|
-
const openNow = useCallback((withFocus) => {
|
|
312
|
-
if (!tree || disabled || !rowRef.current) return;
|
|
313
|
-
clearTimeout(openTimer.current);
|
|
314
|
-
focusOnOpen.current = withFocus;
|
|
315
|
-
const row = rowRef.current.getBoundingClientRect();
|
|
316
|
-
const owner = rowRef.current.closest("[data-popup-submenu-panel]") ?? rowRef.current.closest("[data-popup-menu-tree]");
|
|
317
|
-
const ownerRect = owner?.getBoundingClientRect() ?? row;
|
|
318
|
-
const preferLeft = depth > 0 && (tree.path[depth - 1]?.flipped ?? false);
|
|
319
|
-
const place = menuPanelLeft(ownerRect.left, ownerRect.right, minWidth, window.innerWidth, SUBMENU_GAP, preferLeft);
|
|
320
|
-
tree.open(depth, { key, y: row.top, ...place });
|
|
321
|
-
}, [tree, disabled, depth, key, minWidth]);
|
|
322
|
-
const closeSelf = (restoreFocus) => {
|
|
323
|
-
tree?.closeBelow(depth);
|
|
324
|
-
rowRef.current?.focus();
|
|
325
|
-
};
|
|
326
|
-
useEffect(() => {
|
|
327
|
-
if (!isOpen) return;
|
|
328
|
-
return registerModalEscapeInterceptor((e) => {
|
|
329
|
-
if (e.key !== "Escape") return false;
|
|
330
|
-
if (tree && tree.path.length > depth + 1) return false;
|
|
331
|
-
closeSelf();
|
|
332
|
-
return true;
|
|
333
|
-
});
|
|
334
|
-
});
|
|
335
|
-
useBrowserLayoutEffect(() => {
|
|
336
|
-
if (!isOpen || !anchor) return;
|
|
337
|
-
const place = () => {
|
|
338
|
-
const panel = panelRef.current;
|
|
339
|
-
if (!panel || !rowRef.current) return;
|
|
340
|
-
const margin = 8;
|
|
341
|
-
const owner = rowRef.current.closest("[data-popup-submenu-panel]") ?? rowRef.current.closest("[data-popup-menu-tree]");
|
|
342
|
-
const ownerRect = owner?.getBoundingClientRect() ?? rowRef.current.getBoundingClientRect();
|
|
343
|
-
const preferLeft = depth > 0 && (tree?.path[depth - 1]?.flipped ?? false);
|
|
344
|
-
const width = panel.offsetWidth || minWidth;
|
|
345
|
-
const spot = menuPanelLeft(ownerRect.left, ownerRect.right, width, window.innerWidth, SUBMENU_GAP, preferLeft, margin);
|
|
346
|
-
const height = panel.offsetHeight;
|
|
347
|
-
const rowTop = rowRef.current.getBoundingClientRect().top;
|
|
348
|
-
const top = clampMenuTop(rowTop + height / 2, height, margin, window.innerHeight - margin);
|
|
349
|
-
panel.style.left = `${spot.left}px`;
|
|
350
|
-
panel.style.top = `${top}px`;
|
|
351
|
-
panel.dataset.flipped = String(spot.flipped);
|
|
352
|
-
};
|
|
353
|
-
place();
|
|
354
|
-
let second = 0;
|
|
355
|
-
const first = requestAnimationFrame(() => {
|
|
356
|
-
second = requestAnimationFrame(place);
|
|
357
|
-
});
|
|
358
|
-
return () => {
|
|
359
|
-
cancelAnimationFrame(first);
|
|
360
|
-
cancelAnimationFrame(second);
|
|
361
|
-
};
|
|
362
|
-
});
|
|
363
|
-
useEffect(() => {
|
|
364
|
-
if (!isOpen || !focusOnOpen.current) return;
|
|
365
|
-
focusOnOpen.current = false;
|
|
366
|
-
focusables(panelRef.current)[0]?.focus();
|
|
367
|
-
}, [isOpen]);
|
|
368
|
-
const childTree = useMemo(() => tree && { ...tree, depth: depth + 1 }, [tree, depth]);
|
|
369
|
-
if (!tree) throw new Error("PopupSubmenu must be rendered inside a PopupMenu");
|
|
370
|
-
const onRowKeyDown = (e) => {
|
|
371
|
-
if (e.key === "ArrowRight") {
|
|
372
|
-
e.preventDefault();
|
|
373
|
-
e.stopPropagation();
|
|
374
|
-
openNow(true);
|
|
375
|
-
}
|
|
376
|
-
};
|
|
377
|
-
const onPanelKeyDown = (e) => {
|
|
378
|
-
if (e.target.closest("[data-popup-submenu-panel]") !== e.currentTarget) return;
|
|
379
|
-
const items = focusables(panelRef.current);
|
|
380
|
-
const at = items.indexOf(document.activeElement);
|
|
381
|
-
const move = (to) => {
|
|
382
|
-
e.preventDefault();
|
|
383
|
-
e.stopPropagation();
|
|
384
|
-
items[(to + items.length) % items.length]?.focus();
|
|
385
|
-
};
|
|
386
|
-
if (e.key === "ArrowDown") move(at + 1);
|
|
387
|
-
else if (e.key === "ArrowUp") move(at < 0 ? items.length - 1 : at - 1);
|
|
388
|
-
else if (e.key === "Home") move(0);
|
|
389
|
-
else if (e.key === "End") move(items.length - 1);
|
|
390
|
-
else if (e.key === "ArrowLeft") {
|
|
391
|
-
e.preventDefault();
|
|
392
|
-
e.stopPropagation();
|
|
393
|
-
closeSelf();
|
|
394
|
-
}
|
|
395
|
-
};
|
|
396
|
-
const look = itemLook(false, disabled, className, isOpen);
|
|
397
|
-
const density = getDensity();
|
|
398
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
399
|
-
/* @__PURE__ */ jsxs(
|
|
400
|
-
"button",
|
|
401
|
-
{
|
|
402
|
-
ref: rowRef,
|
|
403
|
-
type: "button",
|
|
404
|
-
role: "menuitem",
|
|
405
|
-
"aria-haspopup": "menu",
|
|
406
|
-
"aria-expanded": isOpen,
|
|
407
|
-
"aria-controls": isOpen ? panelId : void 0,
|
|
408
|
-
disabled,
|
|
409
|
-
"data-popup-submenu-row": true,
|
|
410
|
-
className: look.className,
|
|
411
|
-
style: look.style,
|
|
412
|
-
onClick: (e) => {
|
|
413
|
-
const byKey = e.detail === 0;
|
|
414
|
-
if (!isOpen) openNow(byKey);
|
|
415
|
-
else if (byKey) focusables(panelRef.current)[0]?.focus();
|
|
416
|
-
},
|
|
417
|
-
onKeyDown: onRowKeyDown,
|
|
418
|
-
onMouseEnter: () => {
|
|
419
|
-
if (disabled) return;
|
|
420
|
-
tree.cancelClose();
|
|
421
|
-
if (isOpen) {
|
|
422
|
-
tree.closeBelow(depth + 1);
|
|
423
|
-
return;
|
|
424
|
-
}
|
|
425
|
-
clearTimeout(openTimer.current);
|
|
426
|
-
openTimer.current = setTimeout(() => openNow(false), SUBMENU_OPEN_DELAY);
|
|
427
|
-
},
|
|
428
|
-
onMouseLeave: () => {
|
|
429
|
-
clearTimeout(openTimer.current);
|
|
430
|
-
tree.scheduleClose(depth);
|
|
431
|
-
},
|
|
432
|
-
children: [
|
|
433
|
-
icon,
|
|
434
|
-
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: label }),
|
|
435
|
-
chevron
|
|
436
|
-
]
|
|
437
|
-
}
|
|
438
|
-
),
|
|
439
|
-
isOpen && createPortal(
|
|
440
|
-
/* @__PURE__ */ jsx(
|
|
441
|
-
"div",
|
|
442
|
-
{
|
|
443
|
-
ref: panelRef,
|
|
444
|
-
id: panelId,
|
|
445
|
-
role: "menu",
|
|
446
|
-
"data-popup-menu-tree": tree.id,
|
|
447
|
-
"data-popup-submenu-panel": true,
|
|
448
|
-
className: `fixed rounded-2xl overflow-x-hidden overflow-y-auto overscroll-contain ${density === "tight" ? "py-1" : density === "large" ? "py-2" : "py-1.5"}`,
|
|
449
|
-
style: {
|
|
450
|
-
left: anchor.left,
|
|
451
|
-
top: anchor.y,
|
|
452
|
-
minWidth,
|
|
453
|
-
// The viewport cap always applies, so a long list scrolls rather
|
|
454
|
-
// than running off the screen even when no maxHeight is passed.
|
|
455
|
-
maxHeight: maxHeight === void 0 ? "calc(100vh - 16px)" : `min(${typeof maxHeight === "number" ? `${maxHeight}px` : maxHeight}, calc(100vh - 16px))`,
|
|
456
|
-
zIndex: layerOf(tree.root.current) + depth + 1,
|
|
457
|
-
animation: `${anchor.flipped ? "popup-submenu-in-left" : "popup-submenu-in"} 0.1s ease-out`,
|
|
458
|
-
...glassStyle()
|
|
459
|
-
},
|
|
460
|
-
onKeyDown: onPanelKeyDown,
|
|
461
|
-
onMouseEnter: () => {
|
|
462
|
-
tree.cancelClose();
|
|
463
|
-
clearTimeout(openTimer.current);
|
|
464
|
-
},
|
|
465
|
-
onMouseLeave: () => tree.scheduleClose(depth + 1),
|
|
466
|
-
onContextMenu: (e) => {
|
|
467
|
-
if (!keepsNativeMenu(e.target)) e.preventDefault();
|
|
468
|
-
},
|
|
469
|
-
children: /* @__PURE__ */ jsx(MenuTreeContext.Provider, { value: childTree, children })
|
|
470
|
-
}
|
|
471
|
-
),
|
|
472
|
-
document.body
|
|
473
|
-
)
|
|
474
|
-
] });
|
|
475
|
-
}
|
|
476
|
-
function PopupMenuDivider() {
|
|
477
|
-
const density = getDensity();
|
|
478
|
-
return /* @__PURE__ */ jsx("div", { className: `border-t ${GLASS_DIVIDER} ${density === "tight" ? "my-0.5" : density === "large" ? "my-1.5" : "my-1"} mx-3` });
|
|
479
|
-
}
|
|
480
|
-
function PopupMenuLabel({ children }) {
|
|
481
|
-
const density = getDensity();
|
|
482
|
-
const labelPadY = density === "tight" ? "0.125rem" : density === "large" ? "0.375rem" : "0.25rem";
|
|
483
|
-
return /* @__PURE__ */ jsx(
|
|
484
|
-
"div",
|
|
485
|
-
{
|
|
486
|
-
className: "text-xs font-medium uppercase tracking-wide",
|
|
487
|
-
style: {
|
|
488
|
-
color: "var(--ink-muted)",
|
|
489
|
-
paddingLeft: "var(--menu-padding-x, 1rem)",
|
|
490
|
-
paddingRight: "var(--menu-padding-x, 1rem)",
|
|
491
|
-
paddingTop: labelPadY,
|
|
492
|
-
paddingBottom: labelPadY
|
|
493
|
-
},
|
|
494
|
-
children
|
|
495
|
-
}
|
|
496
|
-
);
|
|
497
|
-
}
|
|
498
|
-
function MenuIcon({ d, className = "h-4 w-4 text-gray-400" }) {
|
|
499
|
-
return /* @__PURE__ */ jsx("svg", { className, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d }) });
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
export { MenuIcon, NATIVE_MENU_ATTR, PopupMenu, PopupMenuDivider, PopupMenuItem, PopupMenuLabel, PopupSubmenu, clampMenuTop, closeMenuBelow, describeContextTarget, itemLook, keepsNativeMenu, menuPanelLeft, openMenuLevel, resolveMenuLevels };
|
|
503
|
-
//# sourceMappingURL=chunk-JOPU6WPY.js.map
|
|
504
|
-
//# sourceMappingURL=chunk-JOPU6WPY.js.map
|