efficient-shell 4.127.0 → 4.132.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 +938 -5
- package/dist/{Browser-F5TKMP4K.js → Browser-XPVJ2K7B.js} +13 -10
- package/dist/Browser-XPVJ2K7B.js.map +1 -0
- package/dist/{Calculator-T3XG7S73.js → Calculator-ZXJPXG7F.js} +12 -9
- package/dist/Calculator-ZXJPXG7F.js.map +1 -0
- package/dist/ConfirmDialog-MTC7QMUJ.js +4 -0
- package/dist/{ConfirmDialog-LJXMB45A.js.map → ConfirmDialog-MTC7QMUJ.js.map} +1 -1
- package/dist/{CurrencyConverter-CASQMKLO.js → CurrencyConverter-WSJ2BBSX.js} +12 -9
- package/dist/CurrencyConverter-WSJ2BBSX.js.map +1 -0
- package/dist/{Documents-YX67YTZS.js → Documents-ONGSXUJI.js} +14 -11
- package/dist/Documents-ONGSXUJI.js.map +1 -0
- package/dist/{Files-QB63GO6J.js → Files-GQZMFWXQ.js} +17 -14
- package/dist/Files-GQZMFWXQ.js.map +1 -0
- package/dist/{Notepad-3SUD5XUE.js → Notepad-HM73XAM4.js} +15 -12
- package/dist/Notepad-HM73XAM4.js.map +1 -0
- package/dist/PdfViewer-M2YGZIYX.js +5 -0
- package/dist/{PdfViewer-LSP3YNFC.js.map → PdfViewer-M2YGZIYX.js.map} +1 -1
- package/dist/{PomodoroTimer-4EHD2QC4.js → PomodoroTimer-DG3LI5CX.js} +14 -11
- package/dist/PomodoroTimer-DG3LI5CX.js.map +1 -0
- package/dist/{Preview-4ZHR4SKP.js → Preview-TUSV4UMO.js} +16 -13
- package/dist/Preview-TUSV4UMO.js.map +1 -0
- package/dist/{Sidebar-J76PV4QF.js → Sidebar-BPU7RCZP.js} +5 -4
- package/dist/Sidebar-BPU7RCZP.js.map +1 -0
- package/dist/{Spreadsheet-G3SC7XJ5.js → Spreadsheet-3WTXCHYQ.js} +14 -11
- package/dist/Spreadsheet-3WTXCHYQ.js.map +1 -0
- package/dist/{Stock-TLT4VN2R.js → Stock-YMPOMUAW.js} +12 -9
- package/dist/Stock-YMPOMUAW.js.map +1 -0
- package/dist/{Weather-FRKX3DAK.js → Weather-NZO3CWLH.js} +12 -9
- package/dist/Weather-NZO3CWLH.js.map +1 -0
- package/dist/{WorldClock-GKCITO3M.js → WorldClock-HUC6D3AD.js} +12 -9
- package/dist/WorldClock-HUC6D3AD.js.map +1 -0
- package/dist/apps/index.js +26 -22
- package/dist/apps/index.js.map +1 -1
- package/dist/brand.css +1 -1
- package/dist/chunk-7IN7YZAL.js +547 -0
- package/dist/chunk-7IN7YZAL.js.map +1 -0
- package/dist/{chunk-YNGPTOL6.js → chunk-7MA5XBWD.js} +3 -3
- package/dist/{chunk-YNGPTOL6.js.map → chunk-7MA5XBWD.js.map} +1 -1
- package/dist/{chunk-WK7FV7VV.js → chunk-BJ34QOR3.js} +827 -625
- package/dist/chunk-BJ34QOR3.js.map +1 -0
- package/dist/{chunk-HNH7FOYB.js → chunk-CGXMWHQW.js} +7 -6
- package/dist/chunk-CGXMWHQW.js.map +1 -0
- package/dist/{chunk-XUCIYMN7.js → chunk-CJYO4RVV.js} +4 -4
- package/dist/{chunk-XUCIYMN7.js.map → chunk-CJYO4RVV.js.map} +1 -1
- package/dist/{chunk-N3CG5HG5.js → chunk-CLGNTGC5.js} +12 -11
- package/dist/chunk-CLGNTGC5.js.map +1 -0
- package/dist/chunk-D276EMXS.js +57 -0
- package/dist/chunk-D276EMXS.js.map +1 -0
- package/dist/{chunk-7KIOEKHS.js → chunk-E3TWIN7Z.js} +21 -135
- package/dist/chunk-E3TWIN7Z.js.map +1 -0
- package/dist/{chunk-2VM2FRZJ.js → chunk-EENVXIVU.js} +47 -67
- package/dist/chunk-EENVXIVU.js.map +1 -0
- package/dist/{chunk-YG45DAUT.js → chunk-FONEQRBH.js} +17 -11
- package/dist/chunk-FONEQRBH.js.map +1 -0
- package/dist/chunk-IPXN646P.js +14 -0
- package/dist/chunk-IPXN646P.js.map +1 -0
- package/dist/chunk-IRWSRJ4K.js +48 -0
- package/dist/chunk-IRWSRJ4K.js.map +1 -0
- package/dist/chunk-JMKYYPOF.js +7 -0
- package/dist/{chunk-CJZXR7MG.js.map → chunk-JMKYYPOF.js.map} +1 -1
- package/dist/{chunk-JFQGPY7W.js → chunk-KWEX4ZAF.js} +20 -17
- package/dist/chunk-KWEX4ZAF.js.map +1 -0
- package/dist/{chunk-OKEFO6TI.js → chunk-LQTVTOSY.js} +10 -10
- package/dist/chunk-LQTVTOSY.js.map +1 -0
- package/dist/{chunk-G4KA3SAX.js → chunk-MQPX6ERJ.js} +4 -4
- package/dist/{chunk-G4KA3SAX.js.map → chunk-MQPX6ERJ.js.map} +1 -1
- package/dist/{chunk-FQB24B42.js → chunk-SEWF4O3H.js} +3 -3
- package/dist/{chunk-FQB24B42.js.map → chunk-SEWF4O3H.js.map} +1 -1
- package/dist/{chunk-AXWC3332.js → chunk-TFXJRHJV.js} +3 -3
- package/dist/{chunk-AXWC3332.js.map → chunk-TFXJRHJV.js.map} +1 -1
- package/dist/{chunk-G3HQLQYZ.js → chunk-TQURTLK2.js} +59 -34
- package/dist/chunk-TQURTLK2.js.map +1 -0
- package/dist/{chunk-6XQHH7D2.js → chunk-TRCWINHF.js} +5 -5
- package/dist/{chunk-6XQHH7D2.js.map → chunk-TRCWINHF.js.map} +1 -1
- package/dist/{chunk-NPJCMM6V.js → chunk-VWZIGZFF.js} +4 -4
- package/dist/{chunk-NPJCMM6V.js.map → chunk-VWZIGZFF.js.map} +1 -1
- package/dist/{chunk-HYZ5QMVO.js → chunk-XH3ELPQZ.js} +22 -19
- package/dist/chunk-XH3ELPQZ.js.map +1 -0
- package/dist/{chunk-PPUZJFCI.js → chunk-ZKHD4J73.js} +8 -7
- package/dist/chunk-ZKHD4J73.js.map +1 -0
- package/dist/file-intake/index.js +3 -1
- package/dist/file-intake/index.js.map +1 -1
- package/dist/{index-dQia6NpB.d.ts → index-COwksV6G.d.ts} +699 -199
- package/dist/index.d.ts +2 -2
- package/dist/index.js +37 -32
- package/dist/index.js.map +1 -1
- package/dist/map/index.js +5 -3
- package/dist/map/index.js.map +1 -1
- package/dist/markdown/index.js +4 -3
- package/dist/markdown/index.js.map +1 -1
- package/dist/page-tabs/index.js +12 -8
- package/dist/page-tabs/index.js.map +1 -1
- package/dist/shell.css +17 -17
- package/dist/themes.css +15 -0
- package/dist/ui/index.d.ts +1 -1
- package/dist/ui/index.js +17 -13
- package/dist/ui/index.js.map +1 -1
- package/dist/ui.css +691 -283
- package/package.json +1 -1
- package/dist/Browser-F5TKMP4K.js.map +0 -1
- package/dist/Calculator-T3XG7S73.js.map +0 -1
- package/dist/ConfirmDialog-LJXMB45A.js +0 -3
- package/dist/CurrencyConverter-CASQMKLO.js.map +0 -1
- package/dist/Documents-YX67YTZS.js.map +0 -1
- package/dist/Files-QB63GO6J.js.map +0 -1
- package/dist/Notepad-3SUD5XUE.js.map +0 -1
- package/dist/PdfViewer-LSP3YNFC.js +0 -4
- package/dist/PomodoroTimer-4EHD2QC4.js.map +0 -1
- package/dist/Preview-4ZHR4SKP.js.map +0 -1
- package/dist/Sidebar-J76PV4QF.js.map +0 -1
- package/dist/Spreadsheet-G3SC7XJ5.js.map +0 -1
- package/dist/Stock-TLT4VN2R.js.map +0 -1
- package/dist/Weather-FRKX3DAK.js.map +0 -1
- package/dist/WorldClock-GKCITO3M.js.map +0 -1
- package/dist/chunk-2VM2FRZJ.js.map +0 -1
- package/dist/chunk-3CUSBZWG.js +0 -59
- package/dist/chunk-3CUSBZWG.js.map +0 -1
- package/dist/chunk-7KIOEKHS.js.map +0 -1
- package/dist/chunk-CJZXR7MG.js +0 -7
- package/dist/chunk-G3HQLQYZ.js.map +0 -1
- package/dist/chunk-HNH7FOYB.js.map +0 -1
- package/dist/chunk-HYZ5QMVO.js.map +0 -1
- package/dist/chunk-JFQGPY7W.js.map +0 -1
- package/dist/chunk-N3CG5HG5.js.map +0 -1
- package/dist/chunk-OKEFO6TI.js.map +0 -1
- package/dist/chunk-PPUZJFCI.js.map +0 -1
- package/dist/chunk-WK7FV7VV.js.map +0 -1
- package/dist/chunk-YG45DAUT.js.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { useShellStrings } from './chunk-7IN7YZAL.js';
|
|
1
2
|
import { Fragment } from 'react';
|
|
2
3
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
3
4
|
|
|
4
|
-
// src/shell/Breadcrumbs.tsx
|
|
5
5
|
var DEFAULT_SEPARATOR = /* @__PURE__ */ jsx("svg", { className: "h-3.5 w-3.5 shrink-0 text-gray-300", viewBox: "0 0 20 20", fill: "currentColor", "aria-hidden": true, children: /* @__PURE__ */ jsx(
|
|
6
6
|
"path",
|
|
7
7
|
{
|
|
@@ -10,8 +10,9 @@ var DEFAULT_SEPARATOR = /* @__PURE__ */ jsx("svg", { className: "h-3.5 w-3.5 shr
|
|
|
10
10
|
clipRule: "evenodd"
|
|
11
11
|
}
|
|
12
12
|
) });
|
|
13
|
-
var CRUMB_LINK = "inline-flex min-w-0 items-center gap-1 truncate rounded px-1 -mx-1 text-gray-500 transition-colors hover:text-gray-900 hover:underline focus
|
|
13
|
+
var CRUMB_LINK = "inline-flex min-w-0 items-center gap-1 truncate rounded px-1 -mx-1 text-gray-500 transition-colors hover:text-gray-900 hover:underline rosh-focus-ring focus-visible:ring-2 focus-visible:ring-[color:var(--rosh-focus-ring-solid)]";
|
|
14
14
|
function Breadcrumbs({ items, separator, maxItems = 0, className }) {
|
|
15
|
+
const strings = useShellStrings().breadcrumbs;
|
|
15
16
|
if (items.length === 0) return null;
|
|
16
17
|
const sep = separator ?? DEFAULT_SEPARATOR;
|
|
17
18
|
const crumbs = [];
|
|
@@ -26,9 +27,9 @@ function Breadcrumbs({ items, separator, maxItems = 0, className }) {
|
|
|
26
27
|
} else {
|
|
27
28
|
items.forEach((item, i) => crumbs.push({ kind: "item", item, isLast: i === lastIndex }));
|
|
28
29
|
}
|
|
29
|
-
return /* @__PURE__ */ jsx("nav", { "aria-label":
|
|
30
|
+
return /* @__PURE__ */ jsx("nav", { "aria-label": strings.label, className: `min-w-0 ${className ?? ""}`, children: /* @__PURE__ */ jsx("ol", { className: "flex items-center gap-1.5 text-sm", children: crumbs.map((crumb, i) => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
30
31
|
i > 0 && /* @__PURE__ */ jsx("li", { "aria-hidden": true, className: "flex items-center", children: sep }),
|
|
31
|
-
/* @__PURE__ */ jsx("li", { className: "flex min-w-0 items-center", children: crumb.kind === "ellipsis" ? /* @__PURE__ */ jsx("span", { className: "px-0.5 text-gray-400 select-none", "aria-label":
|
|
32
|
+
/* @__PURE__ */ jsx("li", { className: "flex min-w-0 items-center", children: crumb.kind === "ellipsis" ? /* @__PURE__ */ jsx("span", { className: "px-0.5 text-gray-400 select-none", "aria-label": strings.hidden, children: "\u2026" }) : crumb.isLast || !(crumb.item.href || crumb.item.onClick) ? /* @__PURE__ */ jsxs(
|
|
32
33
|
"span",
|
|
33
34
|
{
|
|
34
35
|
"aria-current": crumb.isLast ? "page" : void 0,
|
|
@@ -65,5 +66,5 @@ function Breadcrumbs({ items, separator, maxItems = 0, className }) {
|
|
|
65
66
|
}
|
|
66
67
|
|
|
67
68
|
export { Breadcrumbs };
|
|
68
|
-
//# sourceMappingURL=chunk-
|
|
69
|
-
//# sourceMappingURL=chunk-
|
|
69
|
+
//# sourceMappingURL=chunk-CGXMWHQW.js.map
|
|
70
|
+
//# sourceMappingURL=chunk-CGXMWHQW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shell/Breadcrumbs.tsx"],"names":[],"mappings":"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","file":"chunk-CGXMWHQW.js","sourcesContent":["import { Fragment } from 'react';\nimport type { MouseEvent, ReactNode } from 'react';\nimport { useShellStrings } from './strings';\n\n/**\n * Generic breadcrumb trail. Self-contained and styled with the same Tailwind\n * utilities the shell already ships, so consumers get it for free.\n *\n * Pass an ordered list of `items` from root → current. Every crumb except the\n * last renders as a button when it has an `onClick`; the last crumb is treated\n * as the current location — rendered inert with `aria-current=\"page\"`. When the\n * trail is long, set `maxItems` to collapse the middle into an ellipsis\n * (`first … last-n` ), keeping the first and the tail visible.\n */\nexport interface BreadcrumbItem {\n /** Visible label. */\n label: ReactNode;\n /** Optional leading icon (typically a 3.5×3.5 svg). */\n icon?: ReactNode;\n /**\n * Navigate to this crumb. Omitted on the current (last) crumb.\n *\n * Receives the event, which is what makes `href` usable from a routed app:\n * the handler calls `preventDefault()` on a plain click and hands the\n * navigation to its router, while ctrl/middle/right clicks fall through to\n * the browser untouched. Without the argument an anchor could only ever do a\n * full page load, which is the thing a single-page app is avoiding.\n */\n onClick?: (event: MouseEvent<HTMLAnchorElement | HTMLButtonElement>) => void;\n /**\n * Where this crumb goes, when it is a real destination.\n *\n * A routed app needs this rather than `onClick` alone: an `<a href>` can be\n * middle-clicked into a new tab, copied, and read off the status bar before\n * committing to it — none of which a button offers, however well it behaves\n * once pressed. Given both, the anchor still calls `onClick`, so a client-side\n * router can intercept the plain-click case and leave the rest to the browser.\n */\n href?: string;\n}\n\nexport interface BreadcrumbsProps {\n items: BreadcrumbItem[];\n /** Node rendered between crumbs. Defaults to a chevron. */\n separator?: ReactNode;\n /** Collapse the middle to an ellipsis when there are more than this many\n * crumbs. `0` (default) never collapses. */\n maxItems?: number;\n className?: string;\n}\n\nconst DEFAULT_SEPARATOR = (\n <svg className=\"h-3.5 w-3.5 shrink-0 text-gray-300\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden>\n <path\n fillRule=\"evenodd\"\n d=\"M7.21 14.77a.75.75 0 0 1 .02-1.06L11.168 10 7.23 6.29a.75.75 0 1 1 1.04-1.08l4.5 4.25a.75.75 0 0 1 0 1.08l-4.5 4.25a.75.75 0 0 1-1.06-.02Z\"\n clipRule=\"evenodd\"\n />\n </svg>\n);\n\n/** Shared by the anchor and the button forms so the two cannot drift apart. */\nconst CRUMB_LINK =\n 'inline-flex min-w-0 items-center gap-1 truncate rounded px-1 -mx-1 text-gray-500 ' +\n 'transition-colors hover:text-gray-900 hover:underline rosh-focus-ring focus-visible:ring-2 focus-visible:ring-[color:var(--rosh-focus-ring-solid)]';\n\ntype Crumb = { kind: 'item'; item: BreadcrumbItem; isLast: boolean } | { kind: 'ellipsis' };\n\nexport default function Breadcrumbs({ items, separator, maxItems = 0, className }: BreadcrumbsProps) {\n const strings = useShellStrings().breadcrumbs;\n if (items.length === 0) return null;\n const sep = separator ?? DEFAULT_SEPARATOR;\n\n // Build the display list, collapsing the middle if `maxItems` is exceeded.\n const crumbs: Crumb[] = [];\n const lastIndex = items.length - 1;\n if (maxItems > 0 && items.length > maxItems && maxItems >= 2) {\n const tailCount = Math.max(1, maxItems - 1); // keep the first + this many from the end\n crumbs.push({ kind: 'item', item: items[0], isLast: false });\n crumbs.push({ kind: 'ellipsis' });\n for (let i = items.length - tailCount; i <= lastIndex; i++) {\n crumbs.push({ kind: 'item', item: items[i], isLast: i === lastIndex });\n }\n } else {\n items.forEach((item, i) => crumbs.push({ kind: 'item', item, isLast: i === lastIndex }));\n }\n\n return (\n <nav aria-label={strings.label} className={`min-w-0 ${className ?? ''}`}>\n <ol className=\"flex items-center gap-1.5 text-sm\">\n {crumbs.map((crumb, i) => (\n <Fragment key={i}>\n {i > 0 && <li aria-hidden className=\"flex items-center\">{sep}</li>}\n <li className=\"flex min-w-0 items-center\">\n {crumb.kind === 'ellipsis' ? (\n <span className=\"px-0.5 text-gray-400 select-none\" aria-label={strings.hidden}>…</span>\n ) : crumb.isLast || !(crumb.item.href || crumb.item.onClick) ? (\n <span\n aria-current={crumb.isLast ? 'page' : undefined}\n className={`inline-flex min-w-0 items-center gap-1 truncate ${\n crumb.isLast ? 'font-medium text-gray-900' : 'text-gray-500'\n }`}\n >\n {crumb.item.icon}\n <span className=\"truncate\">{crumb.item.label}</span>\n </span>\n ) : crumb.item.href ? (\n <a\n href={crumb.item.href}\n onClick={crumb.item.onClick}\n className={CRUMB_LINK}\n >\n {crumb.item.icon}\n <span className=\"truncate\">{crumb.item.label}</span>\n </a>\n ) : (\n <button\n type=\"button\"\n onClick={crumb.item.onClick}\n className={CRUMB_LINK}\n >\n {crumb.item.icon}\n <span className=\"truncate\">{crumb.item.label}</span>\n </button>\n )}\n </li>\n </Fragment>\n ))}\n </ol>\n </nav>\n );\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { useWindowMenuItem, Modal } from './chunk-
|
|
1
|
+
import { useWindowMenuItem, Modal } from './chunk-ZKHD4J73.js';
|
|
2
2
|
import { navIcons } from './chunk-GA35NEND.js';
|
|
3
|
-
import { VERSION } from './chunk-
|
|
3
|
+
import { VERSION } from './chunk-JMKYYPOF.js';
|
|
4
4
|
import { useState, useCallback, isValidElement, cloneElement } from 'react';
|
|
5
5
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
6
6
|
|
|
@@ -75,5 +75,5 @@ function AboutApp({ app }) {
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
export { AboutApp, BUILTIN_APP_INFO };
|
|
78
|
-
//# sourceMappingURL=chunk-
|
|
79
|
-
//# sourceMappingURL=chunk-
|
|
78
|
+
//# sourceMappingURL=chunk-CJYO4RVV.js.map
|
|
79
|
+
//# sourceMappingURL=chunk-CJYO4RVV.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/apps/_about.tsx"],"names":[],"mappings":";;;;;;AA4BO,IAAM,gBAAA,GAAmB;AAAA,EAC9B,WAAA,EAAa;AAAA,IACX,IAAA,EAAM,cAAA;AAAA,IACN,OAAA,EAAS,OAAA;AAAA,IACT,KAAA,EAAO,cAAA;AAAA,IACP,WAAA,EAAa;AAAA,GACf;AAAA,EACA,OAAA,EAAS;AAAA,IACP,IAAA,EAAM,SAAA;AAAA,IACN,OAAA,EAAS,OAAA;AAAA,IACT,KAAA,EAAO,UAAA;AAAA,IACP,WAAA,EAAa;AAAA,GACf;AAAA,EACA,SAAA,EAAW;AAAA,IACT,IAAA,EAAM,WAAA;AAAA,IACN,OAAA,EAAS,OAAA;AAAA,IACT,KAAA,EAAO,YAAA;AAAA,IACP,WAAA,EAAa;AAAA,GACf;AAAA,EACA,OAAA,EAAS;AAAA,IACP,IAAA,EAAM,SAAA;AAAA,IACN,OAAA,EAAS,OAAA;AAAA,IACT,KAAA,EAAO,UAAA;AAAA,IACP,WAAA,EAAa;AAAA,GACf;AAAA,EACA,KAAA,EAAO;AAAA,IACL,IAAA,EAAM,OAAA;AAAA,IACN,OAAA,EAAS,OAAA;AAAA,IACT,KAAA,EAAO,QAAA;AAAA,IACP,WAAA,EAAa;AAAA,GACf;AAAA,EACA,OAAA,EAAS;AAAA,IACP,IAAA,EAAM,SAAA;AAAA,IACN,OAAA,EAAS,OAAA;AAAA,IACT,KAAA,EAAO,UAAA;AAAA,IACP,WAAA,EAAa;AAAA;AAEjB;AAIA,IAAM,eAAA,uBACH,KAAA,EAAA,EAAI,SAAA,EAAU,yBAAwB,IAAA,EAAK,MAAA,EAAO,SAAQ,WAAA,EAAY,MAAA,EAAO,gBAAe,WAAA,EAAa,GAAA,EACxG,8BAAC,MAAA,EAAA,EAAK,aAAA,EAAc,SAAQ,cAAA,EAAe,OAAA,EAAQ,CAAA,EAAE,oJAAA,EAAqJ,CAAA,EAC5M,CAAA;AAKF,IAAM,iBAAA,uBACH,KAAA,EAAA,EAAI,SAAA,EAAU,WAAU,IAAA,EAAK,MAAA,EAAO,SAAQ,WAAA,EAAY,MAAA,EAAO,gBAAe,WAAA,EAAa,GAAA,EAC1F,8BAAC,MAAA,EAAA,EAAK,aAAA,EAAc,SAAQ,cAAA,EAAe,OAAA,EAAQ,CAAA,EAAE,oIAAA,EAAqI,CAAA,EAC5L,CAAA;AAKa,SAAR,QAAA,CAA0B,EAAE,GAAA,EAAI,EAA0B;AAC/D,EAAA,MAAM,IAAA,GAAO,iBAAiB,GAAG,CAAA;AACjC,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,SAAS,KAAK,CAAA;AACtC,EAAA,MAAM,aAAa,WAAA,CAAY,MAAM,QAAQ,IAAI,CAAA,EAAG,EAAE,CAAA;AACtD,EAAA,iBAAA,CAAkB,CAAA,MAAA,EAAS,IAAA,CAAK,IAAI,CAAA,CAAA,EAAI,YAAY,eAAe,CAAA;AAEnE,EAAA,IAAI,CAAC,MAAM,OAAO,IAAA;AAElB,EAAA,MAAM,UAAA,GAAa,QAAA,CAAS,IAAA,CAAK,KAAK,CAAA;AACtC,EAAA,MAAM,OAAA,GAAU,cAAA,CAAe,UAAU,CAAA,GACrC,YAAA,CAAa,YAA4B,EAAE,SAAA,EAAW,SAAA,EAAkB,CAAA,GACxE,iBAAA;AAEJ,EAAA,uBACE,GAAA,CAAC,KAAA,EAAA,EAAM,IAAA,EAAI,IAAA,EAAC,OAAA,EAAS,MAAM,OAAA,CAAQ,KAAK,CAAA,EAAG,KAAA,EAAO,CAAA,MAAA,EAAS,IAAA,CAAK,IAAI,CAAA,CAAA,EAAI,IAAA,EAAK,IAAA,EAAK,OAAA,EAAO,IAAA,EAAC,UAAA,EAAY,KAAA,EAAO,UAAA,EAAU,IAAA,EAAC,UAAA,EAAY,CAAC,GAAA,EAAK,GAAG,CAAA,EAC3I,QAAA,kBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,uDAAA,EACb,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,2FAAA,EACZ,QAAA,EAAA,OAAA,EACH,CAAA;AAAA,oBACA,GAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,sCAAA,EAAwC,eAAK,IAAA,EAAK,CAAA;AAAA,oBAChE,IAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,qCAAA,EAAsC,QAAA,EAAA;AAAA,MAAA,UAAA;AAAA,MAAS,IAAA,CAAK;AAAA,KAAA,EAAQ,CAAA;AAAA,oBACzE,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,4CAAA,EAA8C,eAAK,WAAA,EAAY,CAAA;AAAA,oBAC5E,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,2CAAA,EACb,QAAA,EAAA;AAAA,sBAAA,IAAA,CAAC,GAAA,EAAA,EAAE,WAAU,2BAAA,EAA4B,QAAA,EAAA;AAAA,QAAA,cAAA;AAAA,wBAC3B,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,2BAAA,EAA4B,QAAA,EAAA,gBAAA,EAAc,CAAA;AAAA,QAAO;AAAA,OAAA,EAC/E,CAAA;AAAA,MACC,OAAA,oBAAW,IAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,4CAAA,EAA6C,QAAA,EAAA;AAAA,QAAA,SAAA;AAAA,QAAQ;AAAA,OAAA,EAAQ;AAAA,KAAA,EACxF;AAAA,GAAA,EACF,CAAA,EACF,CAAA;AAEJ","file":"chunk-
|
|
1
|
+
{"version":3,"sources":["../src/apps/_about.tsx"],"names":[],"mappings":"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","file":"chunk-CJYO4RVV.js","sourcesContent":["/**\n * Shared \"About\" dialog for the bundled apps.\n *\n * Each bundled app carries its own version (independent of the package\n * version) so app-level changes can be tracked without bumping every app at\n * once. `<AboutApp app=\"…\" />` registers an \"About <Name>\" item in the\n * window title menu and renders the dialog: app icon, name, app version and\n * the react-os-shell attribution + shell version.\n *\n * Bump an app's version in `BUILTIN_APP_INFO` whenever that app's behaviour\n * changes, alongside the package-level CHANGELOG entry.\n */\nimport { useCallback, useState, isValidElement, cloneElement, type ReactElement } from 'react';\nimport Modal, { useWindowMenuItem } from '../shell/Modal';\nimport { navIcons } from '../shell-config/nav';\nimport { VERSION } from '../version';\n\nexport interface BuiltinAppInfo {\n /** Display name — matches the window-registry label. */\n name: string;\n /** App version, independent of the package version. */\n version: string;\n /** One-line summary shown in the About dialog. */\n description: string;\n /** Registry route — used to look up the consumer-registered nav icon. */\n route: string;\n}\n\nexport const BUILTIN_APP_INFO = {\n spreadsheet: {\n name: 'Spreadsheets',\n version: '1.1.3',\n route: '/spreadsheet',\n description: 'Multi-sheet spreadsheet editor with CSV / TSV import and export.',\n },\n notepad: {\n name: 'Notepad',\n version: '1.0.0',\n route: '/notepad',\n description: 'Color-coded notes with checklists, desktop stickies and entity autolinking.',\n },\n documents: {\n name: 'Documents',\n version: '1.1.0',\n route: '/documents',\n description: 'Letter-page editor for Word documents and plain-text files — images, lists, alignment.',\n },\n preview: {\n name: 'Preview',\n version: '1.3.2',\n route: '/preview',\n description: 'Viewer for PDF documents, images, DXF drawings and 3D models — CAD-style measuring with object snap and an AutoCAD-like command bar.',\n },\n files: {\n name: 'Files',\n version: '1.1.0',\n route: '/files',\n description: 'Personal file manager with folders, uploads, quota, trash and desktop shortcut folders.',\n },\n browser: {\n name: 'Browser',\n version: '1.0.1',\n route: '/browser',\n description: 'Minimal web browser with bookmarks, history and navigation bar.',\n },\n} satisfies Record<string, BuiltinAppInfo>;\n\nexport type BuiltinAppId = keyof typeof BUILTIN_APP_INFO;\n\nconst ABOUT_MENU_ICON = (\n <svg className=\"h-4 w-4 text-gray-400\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.5}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z\" />\n </svg>\n);\n\n// Generic window glyph shown when the consumer hasn't registered a nav icon\n// for the app's route (same fallback shape as the Modal title bar).\nconst FALLBACK_APP_ICON = (\n <svg className=\"h-9 w-9\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.5}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M3.75 6.75A2.25 2.25 0 016 4.5h12a2.25 2.25 0 012.25 2.25v10.5A2.25 2.25 0 0118 19.5H6a2.25 2.25 0 01-2.25-2.25V6.75z M3.75 9h16.5\" />\n </svg>\n);\n\n/** Registers \"About <Name>\" in the window title menu and renders the dialog.\n * Render anywhere inside the app's window. */\nexport default function AboutApp({ app }: { app: BuiltinAppId }) {\n const info = BUILTIN_APP_INFO[app];\n const [open, setOpen] = useState(false);\n const openDialog = useCallback(() => setOpen(true), []);\n useWindowMenuItem(`About ${info.name}`, openDialog, ABOUT_MENU_ICON);\n\n if (!open) return null;\n\n const registered = navIcons[info.route];\n const appIcon = isValidElement(registered)\n ? cloneElement(registered as ReactElement, { className: 'h-9 w-9' } as any)\n : FALLBACK_APP_ICON;\n\n return (\n <Modal open onClose={() => setOpen(false)} title={`About ${info.name}`} size=\"sm\" compact bodyScroll={false} autoHeight dimensions={[320, 320]}>\n <div className=\"flex flex-col items-center text-center px-5 pt-5 pb-4\">\n <div className=\"flex h-16 w-16 items-center justify-center rounded-2xl bg-gray-100 text-gray-600 shrink-0\">\n {appIcon}\n </div>\n <h2 className=\"mt-3 text-lg font-bold text-gray-900\">{info.name}</h2>\n <p className=\"text-[11px] font-mono text-gray-400\">Version {info.version}</p>\n <p className=\"mt-2 text-xs text-gray-500 leading-relaxed\">{info.description}</p>\n <div className=\"mt-4 pt-3 border-t border-gray-200 w-full\">\n <p className=\"text-[11px] text-gray-500\">\n Part of the <span className=\"font-medium text-gray-700\">react-os-shell</span> desktop environment\n </p>\n {VERSION && <p className=\"mt-0.5 text-[10px] font-mono text-gray-400\">shell v{VERSION}</p>}\n </div>\n </div>\n </Modal>\n );\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { DEFAULT_SHELL_STRINGS, useShellStrings } from './chunk-7IN7YZAL.js';
|
|
1
2
|
import { useRef, useState, useCallback } from 'react';
|
|
2
3
|
import { jsx } from 'react/jsx-runtime';
|
|
3
4
|
|
|
4
|
-
// src/forms/useFileIntake.tsx
|
|
5
5
|
function acceptsFile(file, accept) {
|
|
6
6
|
const rules = (accept ?? "").split(",").map((rule) => rule.trim().toLocaleLowerCase()).filter(Boolean);
|
|
7
7
|
if (rules.length === 0 || rules.includes("*") || rules.includes("*/*")) return true;
|
|
@@ -13,10 +13,10 @@ function acceptsFile(file, accept) {
|
|
|
13
13
|
return fileType === rule;
|
|
14
14
|
});
|
|
15
15
|
}
|
|
16
|
-
var humanSize = (bytes) => {
|
|
17
|
-
if (bytes < 1024) return
|
|
18
|
-
if (bytes < 1024 * 1024) return
|
|
19
|
-
return
|
|
16
|
+
var humanSize = (bytes, strings = DEFAULT_SHELL_STRINGS.files) => {
|
|
17
|
+
if (bytes < 1024) return strings.bytes(bytes);
|
|
18
|
+
if (bytes < 1024 * 1024) return strings.kilobytes(Math.round(bytes / 1024));
|
|
19
|
+
return strings.megabytes(bytes / (1024 * 1024));
|
|
20
20
|
};
|
|
21
21
|
var isFileDrag = (e) => Array.from(e.dataTransfer?.types ?? []).includes("Files");
|
|
22
22
|
function pastedFiles(e) {
|
|
@@ -42,6 +42,7 @@ function useFileIntake({
|
|
|
42
42
|
acceptHint,
|
|
43
43
|
disabled = false
|
|
44
44
|
}) {
|
|
45
|
+
const strings = useShellStrings().files;
|
|
45
46
|
const inputRef = useRef(null);
|
|
46
47
|
const [dragOver, setDragOver] = useState(false);
|
|
47
48
|
const [rejections, setRejections] = useState([]);
|
|
@@ -58,7 +59,7 @@ function useFileIntake({
|
|
|
58
59
|
rejected.push({
|
|
59
60
|
file,
|
|
60
61
|
reason: "type",
|
|
61
|
-
message:
|
|
62
|
+
message: strings.notAccepted(file.name, hintText)
|
|
62
63
|
});
|
|
63
64
|
continue;
|
|
64
65
|
}
|
|
@@ -66,7 +67,7 @@ function useFileIntake({
|
|
|
66
67
|
rejected.push({
|
|
67
68
|
file,
|
|
68
69
|
reason: "size",
|
|
69
|
-
message:
|
|
70
|
+
message: strings.tooLarge(file.name, humanSize(file.size, strings), humanSize(maxSizeBytes, strings))
|
|
70
71
|
});
|
|
71
72
|
continue;
|
|
72
73
|
}
|
|
@@ -74,7 +75,7 @@ function useFileIntake({
|
|
|
74
75
|
rejected.push({
|
|
75
76
|
file,
|
|
76
77
|
reason: "count",
|
|
77
|
-
message:
|
|
78
|
+
message: strings.tooMany(file.name, maxFiles)
|
|
78
79
|
});
|
|
79
80
|
continue;
|
|
80
81
|
}
|
|
@@ -83,7 +84,7 @@ function useFileIntake({
|
|
|
83
84
|
setRejections(rejected);
|
|
84
85
|
if (accepted.length) onAccept(accepted);
|
|
85
86
|
if (inputRef.current) inputRef.current.value = "";
|
|
86
|
-
}, [disabled, multiple, accept, hintText, maxSizeBytes, maxFiles, currentCount, onAccept]);
|
|
87
|
+
}, [disabled, multiple, accept, hintText, maxSizeBytes, maxFiles, currentCount, onAccept, strings]);
|
|
87
88
|
const open = useCallback(() => {
|
|
88
89
|
if (!disabled) inputRef.current?.click();
|
|
89
90
|
}, [disabled]);
|
|
@@ -140,5 +141,5 @@ function FileIntakeAlert({ rejections, className = "mt-2" }) {
|
|
|
140
141
|
}
|
|
141
142
|
|
|
142
143
|
export { FileIntakeAlert, acceptsFile, humanSize, useFileIntake };
|
|
143
|
-
//# sourceMappingURL=chunk-
|
|
144
|
-
//# sourceMappingURL=chunk-
|
|
144
|
+
//# sourceMappingURL=chunk-CLGNTGC5.js.map
|
|
145
|
+
//# sourceMappingURL=chunk-CLGNTGC5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/forms/useFileIntake.tsx"],"names":[],"mappings":"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","file":"chunk-CLGNTGC5.js","sourcesContent":["/**\n * useFileIntake — the one way a file gets INTO a kit primitive.\n *\n * Every upload surface in the kit (`FilePicker`, `MediaUploadField`,\n * `MediaUploadGrid`, `BrandAssetEditor`, `BulkImportGrid`) takes files through\n * this hook, so the three gestures — the native file dialog, a drop onto the\n * zone, a paste into a composer — share ONE intake path and ONE set of checks.\n *\n * Before this each primitive owned its own hidden `<input type=file>`, its own\n * drag-over state and its own idea of what to check: `accept` reached the\n * native dialog only, so a file dropped onto the zone bypassed it entirely;\n * a multi-file drop onto a gallery kept the first file and lost the rest\n * without a word; and a rejected file was listed in plain red text that no\n * screen reader announced. The portals then copied the hidden-input block\n * nineteen more times. This hook is the fix at the narrowest layer that can\n * hold it (harness UI-15 / PAT-10).\n *\n * The hook validates and hands back `File[]`. It never uploads — transport\n * belongs to the consumer, for the reasons `FilePicker`'s header gives.\n *\n * Its rejection sentences and size units are the catalog's `files` section, so\n * a translated app says why a file was refused in the reader's language. The\n * catalog module imports nothing but React, which keeps this entry React-only.\n */\nimport {\n useCallback, useRef, useState,\n type ChangeEvent, type ClipboardEvent, type DragEvent, type ReactNode,\n} from 'react';\nimport { DEFAULT_SHELL_STRINGS, useShellStrings, type ShellStrings } from '../shell/strings';\n\nexport type FileRejectionReason = 'type' | 'size' | 'count';\n\nexport interface FileRejection {\n file: File;\n reason: FileRejectionReason;\n /** Human sentence naming the file and the rule it broke. */\n message: string;\n}\n\nexport interface FileIntakeLimits {\n /**\n * Native `accept` string — `image/*`, `.pdf,application/pdf`, … Enforced on\n * EVERY gesture, not only the dialog: a dropped or pasted file that fails it\n * is rejected with a reason. Empty or `*` accepts anything.\n */\n accept?: string;\n /** Rejected above this many bytes, with the reason shown. */\n maxSizeBytes?: number;\n /** Rejected once this many files are held in total (see `currentCount`). */\n maxFiles?: number;\n}\n\nexport interface FileIntakeOptions extends FileIntakeLimits {\n /** Receives the files that passed every check. Never called with an empty list. */\n onAccept: (files: File[]) => void;\n /** `false` takes the first candidate only — a single slot. Default `true`. */\n multiple?: boolean;\n /** Files the surface already holds, so `maxFiles` counts the total. Default 0. */\n currentCount?: number;\n /** Short kind hint for the type-rejection sentence, e.g. \"PNG · JPG\". */\n acceptHint?: ReactNode;\n disabled?: boolean;\n}\n\n/**\n * Does `file` satisfy a native `accept` string? Extension rules match the\n * name, `type/*` rules match the MIME prefix, anything else is an exact MIME.\n * A browser reports several media types for one `.ico` file and sometimes\n * none at all, which is why an extension rule exists at all.\n */\nexport function acceptsFile(file: File, accept?: string): boolean {\n const rules = (accept ?? '').split(',').map(rule => rule.trim().toLocaleLowerCase()).filter(Boolean);\n if (rules.length === 0 || rules.includes('*') || rules.includes('*/*')) return true;\n const fileName = file.name.toLocaleLowerCase();\n const fileType = file.type.toLocaleLowerCase();\n return rules.some(rule => {\n if (rule.startsWith('.')) return fileName.endsWith(rule);\n if (rule.endsWith('/*')) return fileType.startsWith(rule.slice(0, -1));\n return fileType === rule;\n });\n}\n\n/** `812 B`, `14 KB`, `6.2 MB` — the units, and their digits, from the catalog. */\nexport const humanSize = (bytes: number, strings: ShellStrings['files'] = DEFAULT_SHELL_STRINGS.files): string => {\n if (bytes < 1024) return strings.bytes(bytes);\n if (bytes < 1024 * 1024) return strings.kilobytes(Math.round(bytes / 1024));\n return strings.megabytes(bytes / (1024 * 1024));\n};\n\n/** Is this drag carrying files (as opposed to text, a URL, or an in-page reorder)? */\nexport const isFileDrag = (e: DragEvent): boolean =>\n Array.from(e.dataTransfer?.types ?? []).includes('Files');\n\n/** Files on a clipboard event, if the paste carried any. */\nexport function pastedFiles(e: ClipboardEvent): File[] {\n const data = e.clipboardData;\n if (!data) return [];\n if (data.files && data.files.length > 0) return Array.from(data.files);\n const out: File[] = [];\n for (const item of Array.from(data.items ?? [])) {\n if (item.kind === 'file') {\n const file = item.getAsFile();\n if (file) out.push(file);\n }\n }\n return out;\n}\n\nexport function useFileIntake({\n onAccept, accept, maxSizeBytes, maxFiles, multiple = true, currentCount = 0,\n acceptHint, disabled = false,\n}: FileIntakeOptions) {\n const strings = useShellStrings().files;\n const inputRef = useRef<HTMLInputElement>(null);\n const [dragOver, setDragOver] = useState(false);\n const [rejections, setRejections] = useState<FileRejection[]>([]);\n // A drag passes over every child of the zone, firing leave/enter pairs; a\n // depth counter is what keeps the highlight steady across them.\n const depthRef = useRef(0);\n\n const hintText = typeof acceptHint === 'string' ? acceptHint : '';\n\n /** Run every candidate through the checks; deliver the survivors. */\n const take = useCallback((incoming: FileList | File[] | null | undefined) => {\n if (disabled || !incoming) return;\n const candidates = Array.from(incoming);\n if (candidates.length === 0) return;\n const accepted: File[] = [];\n const rejected: FileRejection[] = [];\n for (const file of multiple ? candidates : candidates.slice(0, 1)) {\n if (!acceptsFile(file, accept)) {\n rejected.push({\n file, reason: 'type',\n message: strings.notAccepted(file.name, hintText),\n });\n continue;\n }\n if (maxSizeBytes != null && file.size > maxSizeBytes) {\n rejected.push({\n file, reason: 'size',\n message: strings.tooLarge(file.name, humanSize(file.size, strings), humanSize(maxSizeBytes, strings)),\n });\n continue;\n }\n if (multiple && maxFiles != null && currentCount + accepted.length >= maxFiles) {\n rejected.push({\n file, reason: 'count',\n message: strings.tooMany(file.name, maxFiles),\n });\n continue;\n }\n accepted.push(file);\n }\n setRejections(rejected);\n if (accepted.length) onAccept(accepted);\n // Reset the native input so re-picking the SAME file fires change again —\n // without this, removing a file and re-adding it appears to do nothing.\n if (inputRef.current) inputRef.current.value = '';\n }, [disabled, multiple, accept, hintText, maxSizeBytes, maxFiles, currentCount, onAccept, strings]);\n\n const open = useCallback(() => {\n if (!disabled) inputRef.current?.click();\n }, [disabled]);\n\n const clearRejections = useCallback(() => setRejections([]), []);\n\n /** Spread onto the hidden native input. It is never a tab stop and never the visible control. */\n const inputProps = {\n ref: inputRef,\n type: 'file' as const,\n accept: accept || undefined,\n multiple,\n disabled,\n tabIndex: -1,\n 'aria-hidden': true as const,\n className: 'hidden',\n onChange: (e: ChangeEvent<HTMLInputElement>) => take(e.target.files),\n };\n\n /** Spread onto the drop target. Only a drag carrying files lights it up. */\n const zoneProps = disabled\n ? {}\n : {\n onDragEnter: (e: DragEvent) => {\n if (!isFileDrag(e)) return;\n e.preventDefault();\n depthRef.current += 1;\n setDragOver(true);\n },\n onDragOver: (e: DragEvent) => {\n if (!isFileDrag(e)) return;\n e.preventDefault();\n if (!dragOver) setDragOver(true);\n },\n onDragLeave: (e: DragEvent) => {\n if (!isFileDrag(e)) return;\n depthRef.current = Math.max(0, depthRef.current - 1);\n if (depthRef.current === 0) setDragOver(false);\n },\n onDrop: (e: DragEvent) => {\n if (!isFileDrag(e)) return;\n e.preventDefault();\n depthRef.current = 0;\n setDragOver(false);\n take(e.dataTransfer.files);\n },\n };\n\n /** Spread onto a composer's text area: a paste that carries files is taken, one of text is left alone. */\n const pasteProps = disabled\n ? {}\n : {\n onPaste: (e: ClipboardEvent) => {\n const files = pastedFiles(e);\n if (files.length === 0) return;\n e.preventDefault();\n take(files);\n },\n };\n\n return { inputRef, inputProps, zoneProps, pasteProps, open, take, dragOver, rejections, clearRejections };\n}\n\n/**\n * The rejection list, announced. `role=\"alert\"` is what tells a screen-reader\n * user why the drop did nothing; the sighted user sees the same sentences.\n * Renders nothing while there is nothing to say.\n */\nexport function FileIntakeAlert({ rejections, className = 'mt-2' }: { rejections: FileRejection[]; className?: string }) {\n if (rejections.length === 0) return null;\n return (\n <ul role=\"alert\" className={`${className} flex flex-col gap-0.5`}>\n {rejections.map(({ file, message }, i) => (\n <li key={`${file.name}-${i}`} className=\"text-xs text-red-600\">{message}</li>\n ))}\n </ul>\n );\n}\n"]}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { rootIsDark } from './chunk-IPXN646P.js';
|
|
2
|
+
|
|
3
|
+
// src/utils/glass.ts
|
|
4
|
+
function getMenuOpacity() {
|
|
5
|
+
try {
|
|
6
|
+
const val = getComputedStyle(document.documentElement).getPropertyValue("--menu-opacity")?.trim();
|
|
7
|
+
if (val) return parseFloat(val);
|
|
8
|
+
} catch {
|
|
9
|
+
}
|
|
10
|
+
return 0.95;
|
|
11
|
+
}
|
|
12
|
+
var isDarkTheme = rootIsDark;
|
|
13
|
+
function reduceTransparency() {
|
|
14
|
+
try {
|
|
15
|
+
return document.documentElement.classList.contains("rosh-reduce-transparency");
|
|
16
|
+
} catch {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function tint(colour, alpha) {
|
|
21
|
+
const steps = Math.round(Math.min(1, Math.max(0, alpha)) * 255);
|
|
22
|
+
return `color-mix(in srgb, ${colour} ${+(steps / 255 * 100).toFixed(4)}%, transparent)`;
|
|
23
|
+
}
|
|
24
|
+
function glassStyle(opacity) {
|
|
25
|
+
const o = opacity ?? getMenuOpacity();
|
|
26
|
+
if (reduceTransparency()) {
|
|
27
|
+
return {
|
|
28
|
+
background: "var(--rosh-glass-surface)",
|
|
29
|
+
border: "1px solid var(--rosh-glass-solid-border)",
|
|
30
|
+
boxShadow: "var(--rosh-glass-solid-shadow)"
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
const surface = "var(--rosh-glass-surface)";
|
|
34
|
+
const mid = "var(--rosh-glass-surface-mid)";
|
|
35
|
+
if (isDarkTheme()) {
|
|
36
|
+
return {
|
|
37
|
+
background: `linear-gradient(135deg in srgb, ${tint(surface, o * 0.85)} 0%, ${tint(mid, o * 0.75)} 50%, ${tint(surface, o * 0.85)} 100%)`,
|
|
38
|
+
backdropFilter: "blur(40px) saturate(1.6)",
|
|
39
|
+
WebkitBackdropFilter: "blur(40px) saturate(1.6)",
|
|
40
|
+
border: "1px solid var(--rosh-glass-border)",
|
|
41
|
+
boxShadow: "var(--rosh-glass-shadow)"
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
background: `linear-gradient(135deg in srgb, ${tint(surface, o * 0.85)} 0%, ${tint(mid, o * 0.65)} 50%, ${tint(surface, o * 0.75)} 100%)`,
|
|
46
|
+
backdropFilter: "blur(40px) saturate(1.8)",
|
|
47
|
+
WebkitBackdropFilter: "blur(40px) saturate(1.8)",
|
|
48
|
+
border: "1px solid var(--rosh-glass-border)",
|
|
49
|
+
boxShadow: "var(--rosh-glass-shadow)"
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
var GLASS_DIVIDER = "border-white/20";
|
|
53
|
+
var GLASS_INPUT_BG = "glass-input-bg";
|
|
54
|
+
|
|
55
|
+
export { GLASS_DIVIDER, GLASS_INPUT_BG, glassStyle };
|
|
56
|
+
//# sourceMappingURL=chunk-D276EMXS.js.map
|
|
57
|
+
//# sourceMappingURL=chunk-D276EMXS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/glass.ts"],"names":[],"mappings":";;;AAIA,SAAS,cAAA,GAAyB;AAChC,EAAA,IAAI;AACF,IAAA,MAAM,GAAA,GAAM,iBAAiB,QAAA,CAAS,eAAe,EAAE,gBAAA,CAAiB,gBAAgB,GAAG,IAAA,EAAK;AAChG,IAAA,IAAI,GAAA,EAAK,OAAO,UAAA,CAAW,GAAG,CAAA;AAAA,EAChC,CAAA,CAAA,MAAQ;AAAA,EAAC;AACT,EAAA,OAAO,IAAA;AACT;AAGA,IAAM,WAAA,GAAc,UAAA;AAKpB,SAAS,kBAAA,GAA8B;AACrC,EAAA,IAAI;AACF,IAAA,OAAO,QAAA,CAAS,eAAA,CAAgB,SAAA,CAAU,QAAA,CAAS,0BAA0B,CAAA;AAAA,EAC/E,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,KAAA;AAAA,EACT;AACF;AAgBA,SAAS,IAAA,CAAK,QAAgB,KAAA,EAAuB;AACnD,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,KAAK,CAAC,CAAA,GAAI,GAAG,CAAA;AAC9D,EAAA,OAAO,CAAA,mBAAA,EAAsB,MAAM,CAAA,CAAA,EAAI,CAAA,CAAG,QAAQ,GAAA,GAAO,GAAA,EAAK,OAAA,CAAQ,CAAC,CAAC,CAAA,eAAA,CAAA;AAC1E;AAgBO,SAAS,WAAW,OAAA,EAAiC;AAC1D,EAAA,MAAM,CAAA,GAAI,WAAW,cAAA,EAAe;AACpC,EAAA,IAAI,oBAAmB,EAAG;AAQxB,IAAA,OAAO;AAAA,MACL,UAAA,EAAY,2BAAA;AAAA,MACZ,MAAA,EAAQ,0CAAA;AAAA,MACR,SAAA,EAAW;AAAA,KACb;AAAA,EACF;AAIA,EAAA,MAAM,OAAA,GAAU,2BAAA;AAChB,EAAA,MAAM,GAAA,GAAM,+BAAA;AACZ,EAAA,IAAI,aAAY,EAAG;AAIjB,IAAA,OAAO;AAAA,MACL,YAAY,CAAA,gCAAA,EAAmC,IAAA,CAAK,SAAS,CAAA,GAAI,IAAI,CAAC,CAAA,KAAA,EAAQ,IAAA,CAAK,GAAA,EAAK,CAAA,GAAI,IAAI,CAAC,CAAA,MAAA,EAAS,KAAK,OAAA,EAAS,CAAA,GAAI,IAAI,CAAC,CAAA,MAAA,CAAA;AAAA,MACjI,cAAA,EAAgB,0BAAA;AAAA,MAChB,oBAAA,EAAsB,0BAAA;AAAA,MACtB,MAAA,EAAQ,oCAAA;AAAA,MACR,SAAA,EAAW;AAAA,KACb;AAAA,EACF;AACA,EAAA,OAAO;AAAA,IACL,YAAY,CAAA,gCAAA,EAAmC,IAAA,CAAK,SAAS,CAAA,GAAI,IAAI,CAAC,CAAA,KAAA,EAAQ,IAAA,CAAK,GAAA,EAAK,CAAA,GAAI,IAAI,CAAC,CAAA,MAAA,EAAS,KAAK,OAAA,EAAS,CAAA,GAAI,IAAI,CAAC,CAAA,MAAA,CAAA;AAAA,IACjI,cAAA,EAAgB,0BAAA;AAAA,IAChB,oBAAA,EAAsB,0BAAA;AAAA,IACtB,MAAA,EAAQ,oCAAA;AAAA,IACR,SAAA,EAAW;AAAA,GACb;AACF;AAGO,IAAM,aAAA,GAAgB;AAKtB,IAAM,cAAA,GAAiB","file":"chunk-D276EMXS.js","sourcesContent":["import type { CSSProperties } from 'react';\nimport { rootIsDark } from './rootTheme';\n\n/** Read the system menu opacity from CSS custom property set by Layout */\nfunction getMenuOpacity(): number {\n try {\n const val = getComputedStyle(document.documentElement).getPropertyValue('--menu-opacity')?.trim();\n if (val) return parseFloat(val);\n } catch {}\n return 0.95;\n}\n\n// `data-theme=\"dark\"` or a `dark` class on <html>, as ui.css reads it.\nconst isDarkTheme = rootIsDark;\n\n/** Whether the \"Reduce transparency\" preference is active (root class set by\n * Layout). When on, glass surfaces render solid + blur-free — the blur is the\n * GPU-expensive part, and dropping it is the point of the setting. */\nfunction reduceTransparency(): boolean {\n try {\n return document.documentElement.classList.contains('rosh-reduce-transparency');\n } catch {\n return false;\n }\n}\n\n/**\n * `colour` at `alpha` (0–1) of its own opacity — what `rgba(r,g,b,alpha)` was,\n * for a colour that is a token rather than three channels. `rgba()` cannot take\n * a variable for its channels; `color-mix()` with `transparent` can, and in\n * sRGB it is exactly that colour at that alpha (the mix is premultiplied, so\n * the channels come back unchanged).\n *\n * The alpha is rounded to a 255th first. An `rgba()` is a legacy colour, which\n * the engine stores with an 8-bit alpha; a `color-mix()` result keeps a float\n * one, and across a gradient the two land a rounding step apart on a few\n * percent of pixels. Rounding here puts the stops where the `rgba()` ones were,\n * and the gradient is pixel-identical to the one this replaced — measured in\n * Chromium against the previous release's output, light and dark.\n */\nfunction tint(colour: string, alpha: number): string {\n const steps = Math.round(Math.min(1, Math.max(0, alpha)) * 255);\n return `color-mix(in srgb, ${colour} ${+((steps / 255) * 100).toFixed(4)}%, transparent)`;\n}\n\n/** Frosted glass style — shared across all menus, popups, and glass UI elements.\n * Reads --menu-opacity CSS variable set by the theme system, and adapts the\n * base tint to dark mode so menus don't stay light-cream when text is light.\n *\n * Every colour is a token from ui.css (\"Kit colours\" there), so a host can\n * restyle the popups without forking this: the surface they are tinted from\n * (`--rosh-glass-surface`, which reads `--surface`), the stop across the middle,\n * the edge and the depth. Each token's default is the literal this function\n * used to write, in both themes. The numbers stay here — the alphas follow\n * `--menu-opacity`, which is read per call, and the blur differs by theme.\n *\n * To make every popup SOLID in the host's own surface colour, put\n * `rosh-reduce-transparency` on <html>: the branch below then paints one opaque\n * `--rosh-glass-surface`, and the stylesheet drops every backdrop blur. */\nexport function glassStyle(opacity?: number): CSSProperties {\n const o = opacity ?? getMenuOpacity();\n if (reduceTransparency()) {\n // Reduce-transparency: a fully opaque, blur-free surface. No\n // backdrop-filter (the expensive part on low-end GPUs) and a solid\n // background so menus/popups stay legible over any wallpaper. The global\n // stylesheet rule also strips backdrop-filter, but returning a solid\n // background here is what keeps the surface from reading as washed-out\n // translucent glass with the blur gone. One branch for both themes: the\n // tokens carry the dark values themselves.\n return {\n background: 'var(--rosh-glass-surface)',\n border: '1px solid var(--rosh-glass-solid-border)',\n boxShadow: 'var(--rosh-glass-solid-shadow)',\n };\n }\n // `in srgb` on both gradients: once any stop is a non-legacy colour — and a\n // `color-mix()` result is one — a gradient interpolates in Oklab by default,\n // where the `rgba()` stops it replaced were interpolated in sRGB.\n const surface = 'var(--rosh-glass-surface)';\n const mid = 'var(--rosh-glass-surface-mid)';\n if (isDarkTheme()) {\n // Dark frosted glass — the dark `--surface` (Catppuccin's #1e1e2e) with\n // `--surface-sunken` across the middle, a subtle gradient and a lighter\n // inner highlight.\n return {\n background: `linear-gradient(135deg in srgb, ${tint(surface, o * 0.85)} 0%, ${tint(mid, o * 0.75)} 50%, ${tint(surface, o * 0.85)} 100%)`,\n backdropFilter: 'blur(40px) saturate(1.6)',\n WebkitBackdropFilter: 'blur(40px) saturate(1.6)',\n border: '1px solid var(--rosh-glass-border)',\n boxShadow: 'var(--rosh-glass-shadow)',\n };\n }\n return {\n background: `linear-gradient(135deg in srgb, ${tint(surface, o * 0.85)} 0%, ${tint(mid, o * 0.65)} 50%, ${tint(surface, o * 0.75)} 100%)`,\n backdropFilter: 'blur(40px) saturate(1.8)',\n WebkitBackdropFilter: 'blur(40px) saturate(1.8)',\n border: '1px solid var(--rosh-glass-border)',\n boxShadow: 'var(--rosh-glass-shadow)',\n };\n}\n\n/** Glass divider border color */\nexport const GLASS_DIVIDER = 'border-white/20';\n\n/** Glass input/search bar background — declared in styles.css so it can adapt\n * to dark mode (a flat `bg-white/15` reads as a too-bright tile on the dark\n * glass gradient). */\nexport const GLASS_INPUT_BG = 'glass-input-bg';\n"]}
|
|
@@ -1,122 +1,9 @@
|
|
|
1
|
-
import { onOverlayOpen, Z_LAYERS, registerModalEscapeInterceptor } from './chunk-
|
|
2
|
-
import { glassStyle, GLASS_DIVIDER } from './chunk-
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { onOverlayOpen, Z_LAYERS, registerModalEscapeInterceptor } from './chunk-XH3ELPQZ.js';
|
|
2
|
+
import { glassStyle, GLASS_DIVIDER } from './chunk-D276EMXS.js';
|
|
3
|
+
import { useHydrated, useBrowserLayoutEffect } from './chunk-IRWSRJ4K.js';
|
|
4
|
+
import { createContext, forwardRef, useContext, useRef, useId, useState, useEffect, useMemo, useCallback } from 'react';
|
|
5
5
|
import { createPortal } from 'react-dom';
|
|
6
|
-
|
|
7
|
-
var DEFAULT_SHELL_STRINGS = {
|
|
8
|
-
window: {
|
|
9
|
-
minimize: "Minimize",
|
|
10
|
-
restore: "Restore",
|
|
11
|
-
maximize: "Maximize",
|
|
12
|
-
windowed: "Windowed",
|
|
13
|
-
pinOnTop: "Pin on top",
|
|
14
|
-
unpin: "Unpin from top",
|
|
15
|
-
close: "Close",
|
|
16
|
-
windowSuffix: "window",
|
|
17
|
-
prev: "Prev",
|
|
18
|
-
next: "Next",
|
|
19
|
-
snapLayouts: "Snap layouts",
|
|
20
|
-
snapLeft: "Snap left half",
|
|
21
|
-
snapRight: "Snap right half",
|
|
22
|
-
snapTopLeft: "Snap top-left quarter",
|
|
23
|
-
snapTopRight: "Snap top-right quarter",
|
|
24
|
-
snapBottomLeft: "Snap bottom-left quarter",
|
|
25
|
-
snapBottomRight: "Snap bottom-right quarter"
|
|
26
|
-
},
|
|
27
|
-
taskbar: {
|
|
28
|
-
closeWindow: "Close window",
|
|
29
|
-
offscreenHint: "This window is off screen \u2014 click to bring it back",
|
|
30
|
-
offscreenDot: "Off screen \u2014 click to bring this window back",
|
|
31
|
-
expose: "Expos\xE9 \u2014 show all open windows as thumbnails",
|
|
32
|
-
addToDesktop: "Add to desktop",
|
|
33
|
-
removeFromDesktop: "Remove from desktop",
|
|
34
|
-
minimizeAllWindows: "Minimize all",
|
|
35
|
-
restoreAllWindows: "Restore all",
|
|
36
|
-
closeAllWindows: "Close all"
|
|
37
|
-
},
|
|
38
|
-
logout: {
|
|
39
|
-
goodbye: "Goodbye",
|
|
40
|
-
seeYou: "See you next time"
|
|
41
|
-
},
|
|
42
|
-
about: {
|
|
43
|
-
aboutPrefix: "About",
|
|
44
|
-
thisApp: "this app",
|
|
45
|
-
openSourceLicenses: "Open Source Licenses",
|
|
46
|
-
whatsNew: "What's New",
|
|
47
|
-
noChangelog: "No changelog available."
|
|
48
|
-
},
|
|
49
|
-
table: {
|
|
50
|
-
empty: "Nothing to show",
|
|
51
|
-
loading: "Loading",
|
|
52
|
-
selectAll: "Select all rows",
|
|
53
|
-
selectRow: "Select row"
|
|
54
|
-
},
|
|
55
|
-
select: {
|
|
56
|
-
none: "\u2014 None \u2014",
|
|
57
|
-
noMatches: "No matches",
|
|
58
|
-
allSelected: "All options selected",
|
|
59
|
-
clear: "Clear selection",
|
|
60
|
-
remove: "Remove"
|
|
61
|
-
},
|
|
62
|
-
notifications: {
|
|
63
|
-
title: "Notifications",
|
|
64
|
-
markAllRead: "Mark all read",
|
|
65
|
-
dnd: "Do not disturb",
|
|
66
|
-
dndOn: "Do not disturb is on",
|
|
67
|
-
caughtUp: "All caught up",
|
|
68
|
-
empty: "No notifications yet",
|
|
69
|
-
viewAll: "View all notifications",
|
|
70
|
-
cardLabel: "Notification",
|
|
71
|
-
dismiss: "Dismiss notification"
|
|
72
|
-
},
|
|
73
|
-
form: {
|
|
74
|
-
errorSummaryTitle: "There is a problem"
|
|
75
|
-
},
|
|
76
|
-
help: {
|
|
77
|
-
title: "Help",
|
|
78
|
-
searchPlaceholder: "Search help\u2026",
|
|
79
|
-
empty: "No help articles yet.",
|
|
80
|
-
noResults: "No articles match your search.",
|
|
81
|
-
loading: "Loading\u2026",
|
|
82
|
-
pickArticle: "Pick a help article from the left.",
|
|
83
|
-
noBody: "This article has no body yet.",
|
|
84
|
-
draft: "Draft",
|
|
85
|
-
newArticle: "+ New",
|
|
86
|
-
edit: "Edit"
|
|
87
|
-
},
|
|
88
|
-
update: {
|
|
89
|
-
available: "A new version is available.",
|
|
90
|
-
refreshNow: "Refresh now"
|
|
91
|
-
},
|
|
92
|
-
pageTabs: {
|
|
93
|
-
label: "Open pages",
|
|
94
|
-
close: "Close",
|
|
95
|
-
closeOthers: "Close other tabs",
|
|
96
|
-
closeRight: "Close tabs to the right",
|
|
97
|
-
closeAll: "Close all tabs",
|
|
98
|
-
unsaved: "Unsaved changes",
|
|
99
|
-
discardTitle: "Discard unsaved changes?",
|
|
100
|
-
discardOne: "This page has changes that have not been saved. Close it anyway?",
|
|
101
|
-
discardMany: "pages have changes that have not been saved. Close them anyway?",
|
|
102
|
-
discardConfirm: "Discard and close",
|
|
103
|
-
keepEditing: "Keep editing"
|
|
104
|
-
}
|
|
105
|
-
};
|
|
106
|
-
var ShellStringsContext = createContext(DEFAULT_SHELL_STRINGS);
|
|
107
|
-
function ShellStringsProvider({ value, children }) {
|
|
108
|
-
const merged = useMemo(() => {
|
|
109
|
-
const out = {};
|
|
110
|
-
for (const key of Object.keys(DEFAULT_SHELL_STRINGS)) {
|
|
111
|
-
out[key] = { ...DEFAULT_SHELL_STRINGS[key], ...value[key] ?? {} };
|
|
112
|
-
}
|
|
113
|
-
return out;
|
|
114
|
-
}, [value]);
|
|
115
|
-
return /* @__PURE__ */ jsx(ShellStringsContext.Provider, { value: merged, children });
|
|
116
|
-
}
|
|
117
|
-
function useShellStrings() {
|
|
118
|
-
return useContext(ShellStringsContext);
|
|
119
|
-
}
|
|
6
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
120
7
|
|
|
121
8
|
// src/shell/contextMenuTarget.ts
|
|
122
9
|
var TEXT_INPUT_TYPES = /* @__PURE__ */ new Set([
|
|
@@ -219,7 +106,11 @@ function menuPanelLeft(ownerLeft, ownerRight, width, viewportW, gap, preferLeft
|
|
|
219
106
|
return preferLeft ? { left: margin, flipped: true } : { left: Math.max(margin, viewportW - margin - width), flipped: false };
|
|
220
107
|
}
|
|
221
108
|
function getDensity() {
|
|
222
|
-
|
|
109
|
+
try {
|
|
110
|
+
return getComputedStyle(document.documentElement).getPropertyValue("--menu-density")?.trim() || "normal";
|
|
111
|
+
} catch {
|
|
112
|
+
return "normal";
|
|
113
|
+
}
|
|
223
114
|
}
|
|
224
115
|
var SUBMENU_CLOSE_DELAY = 200;
|
|
225
116
|
var SUBMENU_OPEN_DELAY = 120;
|
|
@@ -231,6 +122,7 @@ function PopupMenu({ children, style, className = "", onClose, minWidth = 180, p
|
|
|
231
122
|
const [path, setPath] = useState([]);
|
|
232
123
|
const closeTimer = useRef();
|
|
233
124
|
useEffect(() => () => clearTimeout(closeTimer.current), []);
|
|
125
|
+
const hydrated = useHydrated();
|
|
234
126
|
const tree = useMemo(() => {
|
|
235
127
|
const cancelClose = () => clearTimeout(closeTimer.current);
|
|
236
128
|
return {
|
|
@@ -319,7 +211,7 @@ function PopupMenu({ children, style, className = "", onClose, minWidth = 180, p
|
|
|
319
211
|
});
|
|
320
212
|
const density = getDensity();
|
|
321
213
|
const ownsZ = /(^|[\s:])!?z-/.test(className);
|
|
322
|
-
const menu = /* @__PURE__ */
|
|
214
|
+
const menu = /* @__PURE__ */ jsx(
|
|
323
215
|
"div",
|
|
324
216
|
{
|
|
325
217
|
ref,
|
|
@@ -329,13 +221,11 @@ function PopupMenu({ children, style, className = "", onClose, minWidth = 180, p
|
|
|
329
221
|
if (!keepsNativeMenu(e.target)) e.preventDefault();
|
|
330
222
|
},
|
|
331
223
|
style: { ...ownsZ ? {} : { zIndex: Z_LAYERS.menu }, minWidth, animation: "popup-in 0.12s ease-out", ...glassStyle(), ...style },
|
|
332
|
-
children:
|
|
333
|
-
/* @__PURE__ */ jsx(MenuTreeContext.Provider, { value: tree, children }),
|
|
334
|
-
/* @__PURE__ */ jsx("style", { children: `@keyframes popup-in { from { opacity: 0; transform: scale(0.96); } to { opacity: 1; transform: scale(1); } }` })
|
|
335
|
-
]
|
|
224
|
+
children: /* @__PURE__ */ jsx(MenuTreeContext.Provider, { value: tree, children })
|
|
336
225
|
}
|
|
337
226
|
);
|
|
338
|
-
|
|
227
|
+
if (!portal) return menu;
|
|
228
|
+
return hydrated ? createPortal(menu, document.body) : null;
|
|
339
229
|
}
|
|
340
230
|
function itemLook(danger, disabled, className, highlighted = false) {
|
|
341
231
|
const density = getDensity();
|
|
@@ -442,7 +332,7 @@ function PopupSubmenu({ label, icon, children, disabled, className = "", minWidt
|
|
|
442
332
|
return true;
|
|
443
333
|
});
|
|
444
334
|
});
|
|
445
|
-
|
|
335
|
+
useBrowserLayoutEffect(() => {
|
|
446
336
|
if (!isOpen || !anchor) return;
|
|
447
337
|
const place = () => {
|
|
448
338
|
const panel = panelRef.current;
|
|
@@ -547,7 +437,7 @@ function PopupSubmenu({ label, icon, children, disabled, className = "", minWidt
|
|
|
547
437
|
}
|
|
548
438
|
),
|
|
549
439
|
isOpen && createPortal(
|
|
550
|
-
/* @__PURE__ */
|
|
440
|
+
/* @__PURE__ */ jsx(
|
|
551
441
|
"div",
|
|
552
442
|
{
|
|
553
443
|
ref: panelRef,
|
|
@@ -576,11 +466,7 @@ function PopupSubmenu({ label, icon, children, disabled, className = "", minWidt
|
|
|
576
466
|
onContextMenu: (e) => {
|
|
577
467
|
if (!keepsNativeMenu(e.target)) e.preventDefault();
|
|
578
468
|
},
|
|
579
|
-
children:
|
|
580
|
-
/* @__PURE__ */ jsx(MenuTreeContext.Provider, { value: childTree, children }),
|
|
581
|
-
/* @__PURE__ */ jsx("style", { children: `@keyframes popup-submenu-in { from { opacity: 0; transform: translateX(-4px); } to { opacity: 1; transform: translateX(0); } }
|
|
582
|
-
@keyframes popup-submenu-in-left { from { opacity: 0; transform: translateX(4px); } to { opacity: 1; transform: translateX(0); } }` })
|
|
583
|
-
]
|
|
469
|
+
children: /* @__PURE__ */ jsx(MenuTreeContext.Provider, { value: childTree, children })
|
|
584
470
|
}
|
|
585
471
|
),
|
|
586
472
|
document.body
|
|
@@ -612,6 +498,6 @@ function MenuIcon({ d, className = "h-4 w-4 text-gray-400" }) {
|
|
|
612
498
|
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 }) });
|
|
613
499
|
}
|
|
614
500
|
|
|
615
|
-
export {
|
|
616
|
-
//# sourceMappingURL=chunk-
|
|
617
|
-
//# sourceMappingURL=chunk-
|
|
501
|
+
export { MenuIcon, NATIVE_MENU_ATTR, PopupMenu, PopupMenuDivider, PopupMenuItem, PopupMenuLabel, PopupSubmenu, clampMenuTop, closeMenuBelow, describeContextTarget, keepsNativeMenu, menuPanelLeft, openMenuLevel, resolveMenuLevels };
|
|
502
|
+
//# sourceMappingURL=chunk-E3TWIN7Z.js.map
|
|
503
|
+
//# sourceMappingURL=chunk-E3TWIN7Z.js.map
|