efficient-shell 0.0.0 → 4.126.3

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.
Files changed (121) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +758 -3
  3. package/dist/Browser-LM4RRZIL.js +478 -0
  4. package/dist/Browser-LM4RRZIL.js.map +1 -0
  5. package/dist/Calculator-HCKFTSJR.js +188 -0
  6. package/dist/Calculator-HCKFTSJR.js.map +1 -0
  7. package/dist/ConfirmDialog-LJXMB45A.js +3 -0
  8. package/dist/ConfirmDialog-LJXMB45A.js.map +1 -0
  9. package/dist/CurrencyConverter-BKKORN6K.js +232 -0
  10. package/dist/CurrencyConverter-BKKORN6K.js.map +1 -0
  11. package/dist/Documents-DD3QI5ER.js +437 -0
  12. package/dist/Documents-DD3QI5ER.js.map +1 -0
  13. package/dist/Files-BOPCPMJE.js +801 -0
  14. package/dist/Files-BOPCPMJE.js.map +1 -0
  15. package/dist/Notepad-KJOLF63O.js +406 -0
  16. package/dist/Notepad-KJOLF63O.js.map +1 -0
  17. package/dist/PdfViewer-LSP3YNFC.js +4 -0
  18. package/dist/PdfViewer-LSP3YNFC.js.map +1 -0
  19. package/dist/PomodoroTimer-SVJ62RXM.js +629 -0
  20. package/dist/PomodoroTimer-SVJ62RXM.js.map +1 -0
  21. package/dist/Preview-5UOC7ZRU.js +2955 -0
  22. package/dist/Preview-5UOC7ZRU.js.map +1 -0
  23. package/dist/Sidebar-J76PV4QF.js +290 -0
  24. package/dist/Sidebar-J76PV4QF.js.map +1 -0
  25. package/dist/Spreadsheet-J7BH7UHC.js +515 -0
  26. package/dist/Spreadsheet-J7BH7UHC.js.map +1 -0
  27. package/dist/Stock-CDUS4VCZ.js +154 -0
  28. package/dist/Stock-CDUS4VCZ.js.map +1 -0
  29. package/dist/Weather-EEDBWBPQ.js +427 -0
  30. package/dist/Weather-EEDBWBPQ.js.map +1 -0
  31. package/dist/WorldClock-FFFULVTJ.js +198 -0
  32. package/dist/WorldClock-FFFULVTJ.js.map +1 -0
  33. package/dist/apps/index.d.ts +267 -0
  34. package/dist/apps/index.js +147 -0
  35. package/dist/apps/index.js.map +1 -0
  36. package/dist/brand.css +2 -0
  37. package/dist/chunk-2VM2FRZJ.js +215 -0
  38. package/dist/chunk-2VM2FRZJ.js.map +1 -0
  39. package/dist/chunk-32W6VY2J.js +549 -0
  40. package/dist/chunk-32W6VY2J.js.map +1 -0
  41. package/dist/chunk-3CUSBZWG.js +59 -0
  42. package/dist/chunk-3CUSBZWG.js.map +1 -0
  43. package/dist/chunk-3L463T5H.js +26 -0
  44. package/dist/chunk-3L463T5H.js.map +1 -0
  45. package/dist/chunk-4TVV2BIU.js +13334 -0
  46. package/dist/chunk-4TVV2BIU.js.map +1 -0
  47. package/dist/chunk-6XQHH7D2.js +105 -0
  48. package/dist/chunk-6XQHH7D2.js.map +1 -0
  49. package/dist/chunk-7CCHEEYC.js +94 -0
  50. package/dist/chunk-7CCHEEYC.js.map +1 -0
  51. package/dist/chunk-7KIOEKHS.js +617 -0
  52. package/dist/chunk-7KIOEKHS.js.map +1 -0
  53. package/dist/chunk-AXWC3332.js +1103 -0
  54. package/dist/chunk-AXWC3332.js.map +1 -0
  55. package/dist/chunk-BFBWLCO6.js +16 -0
  56. package/dist/chunk-BFBWLCO6.js.map +1 -0
  57. package/dist/chunk-CT3HVZRZ.js +26 -0
  58. package/dist/chunk-CT3HVZRZ.js.map +1 -0
  59. package/dist/chunk-D7PYW2QS.js +265 -0
  60. package/dist/chunk-D7PYW2QS.js.map +1 -0
  61. package/dist/chunk-DMCFOWOJ.js +153 -0
  62. package/dist/chunk-DMCFOWOJ.js.map +1 -0
  63. package/dist/chunk-FQB24B42.js +416 -0
  64. package/dist/chunk-FQB24B42.js.map +1 -0
  65. package/dist/chunk-GA35NEND.js +56 -0
  66. package/dist/chunk-GA35NEND.js.map +1 -0
  67. package/dist/chunk-HNH7FOYB.js +69 -0
  68. package/dist/chunk-HNH7FOYB.js.map +1 -0
  69. package/dist/chunk-HYZ5QMVO.js +462 -0
  70. package/dist/chunk-HYZ5QMVO.js.map +1 -0
  71. package/dist/chunk-I464GYJJ.js +17 -0
  72. package/dist/chunk-I464GYJJ.js.map +1 -0
  73. package/dist/chunk-JFQGPY7W.js +819 -0
  74. package/dist/chunk-JFQGPY7W.js.map +1 -0
  75. package/dist/chunk-MGGY74RY.js +14 -0
  76. package/dist/chunk-MGGY74RY.js.map +1 -0
  77. package/dist/chunk-N3CG5HG5.js +144 -0
  78. package/dist/chunk-N3CG5HG5.js.map +1 -0
  79. package/dist/chunk-QRGFTK2X.js +79 -0
  80. package/dist/chunk-QRGFTK2X.js.map +1 -0
  81. package/dist/chunk-SZ4WMHUX.js +7 -0
  82. package/dist/chunk-SZ4WMHUX.js.map +1 -0
  83. package/dist/chunk-W6XTG23K.js +3708 -0
  84. package/dist/chunk-W6XTG23K.js.map +1 -0
  85. package/dist/chunk-YG45DAUT.js +96 -0
  86. package/dist/chunk-YG45DAUT.js.map +1 -0
  87. package/dist/chunk-YNGPTOL6.js +46 -0
  88. package/dist/chunk-YNGPTOL6.js.map +1 -0
  89. package/dist/chunk-YNHLQ24V.js +400 -0
  90. package/dist/chunk-YNHLQ24V.js.map +1 -0
  91. package/dist/chunk-YNKK7NE3.js +171 -0
  92. package/dist/chunk-YNKK7NE3.js.map +1 -0
  93. package/dist/chunk-YPO6RDMX.js +20 -0
  94. package/dist/chunk-YPO6RDMX.js.map +1 -0
  95. package/dist/file-intake/index.d.ts +87 -0
  96. package/dist/file-intake/index.js +3 -0
  97. package/dist/file-intake/index.js.map +1 -0
  98. package/dist/index-dQia6NpB.d.ts +5904 -0
  99. package/dist/index.d.ts +2495 -0
  100. package/dist/index.js +7460 -0
  101. package/dist/index.js.map +1 -0
  102. package/dist/markdown/index.d.ts +118 -0
  103. package/dist/markdown/index.js +184 -0
  104. package/dist/markdown/index.js.map +1 -0
  105. package/dist/markup/index.d.ts +235 -0
  106. package/dist/markup/index.js +135 -0
  107. package/dist/markup/index.js.map +1 -0
  108. package/dist/page-tabs/index.d.ts +154 -0
  109. package/dist/page-tabs/index.js +706 -0
  110. package/dist/page-tabs/index.js.map +1 -0
  111. package/dist/shell.css +105 -0
  112. package/dist/sounds-NT4DEZGD.js +3 -0
  113. package/dist/sounds-NT4DEZGD.js.map +1 -0
  114. package/dist/styles.css +22 -0
  115. package/dist/themes.css +249 -0
  116. package/dist/types-BOinJXUf.d.ts +118 -0
  117. package/dist/ui/index.d.ts +4 -0
  118. package/dist/ui/index.js +15 -0
  119. package/dist/ui/index.js.map +1 -0
  120. package/dist/ui.css +1518 -0
  121. package/package.json +172 -3
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/page-tabs/context.ts","../../src/page-tabs/tabsModel.ts","../../src/page-tabs/PageTabsProvider.tsx","../../src/page-tabs/PageTabsOutlet.tsx","../../src/page-tabs/PageTabBar.tsx","../../src/page-tabs/hooks.ts"],"names":["setTitle","setDirty","Activity","jsx","TabFrame","useRef","useLayoutEffect","useEffect","useMemo","useLocation","useContext","jsxs","Fragment","useNavigate","useCallback"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * The two contexts page tabs run on, in their own module so the provider, the\n * outlet, the strip and the page hooks can all import them without importing\n * each other.\n */\nimport { createContext, type ReactNode } from 'react';\nimport type { Location } from 'react-router-dom';\n\nimport type { PageTab, TabsState } from './tabsModel';\n\n/** What the consumer's route table says about an address. */\nexport interface PageTabRoute {\n /** The tab's name until the page names it (`usePageTabTitle`). */\n title: string;\n /** Identity; defaults to the pathname. Give two addresses the same key to\n * make them one tab. */\n key?: string;\n /** Drawn before the title in the strip. Never persisted — re-resolved from\n * the address, so a restored tab gets today's icon. */\n icon?: ReactNode;\n}\n\n/** The parts of a location a route decision may depend on. */\nexport type TabLocation = Pick<Location, 'pathname' | 'search' | 'hash'>;\n\n/** Return null for an address that is never a tab: a redirect on its way\n * somewhere, a page that must not stay open behind others. */\nexport type ResolvePageTab = (location: TabLocation) => PageTabRoute | null;\n\nexport interface CloseTabOptions {\n /** Go here instead of the neighbouring tab (a form that just created its\n * record goes to the record). */\n to?: string;\n /** Skip the unsaved-changes question — the page knows its work is saved. */\n force?: boolean;\n}\n\nexport interface PageTabsContextValue {\n enabled: boolean;\n state: TabsState;\n /** The tab the address is on right now, derived during render — a frame\n * must not wait an effect to learn it is the visible one. */\n currentKey: string | null;\n resolve: ResolvePageTab;\n keyFor: (location: TabLocation) => string | null;\n locationFor: (key: string) => Location | undefined;\n idFor: (key: string, part: 'tab' | 'panel') => string;\n activate: (key: string) => void;\n close: (key: string, options?: CloseTabOptions) => Promise<boolean>;\n closeMany: (scope: 'others' | 'right' | 'all', key: string | null) => Promise<void>;\n setTitle: (key: string, title: string) => void;\n setDirty: (key: string, dirty: boolean) => void;\n visibleTabs: PageTab[];\n}\n\nexport const PageTabsContext = createContext<PageTabsContextValue | null>(null);\n\n/** Which tab a subtree belongs to. `activeRef` is written in a layout effect,\n * which runs before a hidden subtree's passive effect clean-ups — so a\n * clean-up can tell \"my tab was hidden\" (keep my state) from \"my page was\n * replaced while on screen\" (drop it). */\nexport interface PageTabFrame {\n key: string;\n activeRef: { current: boolean };\n}\n\nexport const PageTabFrameContext = createContext<PageTabFrame | null>(null);\n","/**\n * The page-tabs state, as plain functions over plain data.\n *\n * Kept free of React and of the router so the rules that decide what a user\n * sees — which tab a click lands on, which one goes when there are too many,\n * what survives a reload — are tested directly rather than through a rendered\n * strip. `PageTabsProvider` holds a `TabsState` and calls these; nothing else\n * mutates one.\n *\n * A tab is an OPEN PAGE, identified by `key` (by default the page's pathname,\n * so `/orders?status=open` and `/orders?status=done` are the same tab showing\n * different filters, while `/orders/41` and `/orders/42` are two tabs — the\n * two windows the desktop used to give them). `path` is the full address the\n * tab was last at, which is where clicking it goes back to.\n */\n\nexport interface PageTab {\n /** Identity. Two addresses with the same key are the same tab. */\n key: string;\n /** Where the tab was last: pathname + search. Never the fragment — see\n * `pathOf` in PageTabsProvider. */\n path: string;\n /** What the strip shows. The route's name until the page supplies its own\n * (`usePageTabTitle`), after which navigation within the tab keeps it. */\n title: string;\n /** Who set `title`: the route table, or the page itself. */\n titleFrom: 'route' | 'page';\n /** Pinned tabs sit first and cannot be closed — a home page. */\n pinned: boolean;\n /** Recency, for choosing which tab to close when there are too many. A\n * counter rather than a clock, so it is deterministic under test. */\n lastActive: number;\n}\n\nexport interface TabsState {\n tabs: PageTab[];\n /** The tab on screen, or null while the address is not a tab at all (a\n * redirect on its way somewhere, a page the consumer keeps out of tabs). */\n activeKey: string | null;\n /** Tabs rendered at least once this session. A tab restored from storage is\n * not rendered until it is first opened — restoring ten tabs must not run\n * ten pages' worth of rendering and chunk loading behind the one in view. */\n mounted: string[];\n /** Unsaved changes, by tab. Never persisted: a reload loses them anyway. */\n dirty: string[];\n /** A tab whose close is waiting for navigation to leave it. Closing the tab\n * on screen is two updates — the state, and the address — and they do not\n * land in the same render; the tab stays mounted (but out of the strip)\n * until the address has moved, so the page never unmounts and remounts in\n * between. */\n closing: string | null;\n /** Monotonic counter feeding `lastActive`. */\n clock: number;\n}\n\nexport interface TabEntry {\n key: string;\n path: string;\n title: string;\n}\n\nexport const DEFAULT_MAX_TABS = 12;\n\nexport function emptyState(): TabsState {\n return { tabs: [], activeKey: null, mounted: [], dirty: [], closing: null, clock: 0 };\n}\n\nconst without = (list: string[], key: string) => list.filter((k) => k !== key);\nconst withKey = (list: string[], key: string) => (list.includes(key) ? list : [...list, key]);\n\n/** Pinned first, in pin order; then the rest in the order they were opened. */\nfunction orderPinned(tabs: PageTab[], pinnedKeys: string[]): PageTab[] {\n const pinned = pinnedKeys\n .map((key) => tabs.find((t) => t.key === key))\n .filter((t): t is PageTab => Boolean(t));\n return [...pinned, ...tabs.filter((t) => !pinnedKeys.includes(t.key))];\n}\n\n/**\n * The address moved to `entry`: activate its tab, opening one if needed.\n *\n * An existing tab takes the new address (a filter changed, a hash moved) and\n * keeps a title its page set. A new tab is appended — at the end, where the\n * strip's newest tab always is — and if that takes the count past `maxTabs`\n * the least recently used tab that can go does: not pinned, not on screen,\n * not holding unsaved changes. When nothing can go, the strip runs long\n * rather than throwing work away.\n */\nexport function visit(state: TabsState, entry: TabEntry, maxTabs = DEFAULT_MAX_TABS): TabsState {\n const clock = state.clock + 1;\n const existing = state.tabs.find((t) => t.key === entry.key);\n let tabs: PageTab[];\n if (existing) {\n tabs = state.tabs.map((t) =>\n t.key === entry.key\n ? {\n ...t,\n path: entry.path,\n title: t.titleFrom === 'page' ? t.title : entry.title || t.title,\n lastActive: clock,\n }\n : t,\n );\n } else {\n tabs = [\n ...state.tabs,\n { key: entry.key, path: entry.path, title: entry.title, titleFrom: 'route', pinned: false, lastActive: clock },\n ];\n }\n let next: TabsState = {\n ...state,\n tabs,\n activeKey: entry.key,\n mounted: withKey(state.mounted, entry.key),\n clock,\n };\n // A pending close completes once the address has left that tab.\n if (next.closing && next.closing !== entry.key) next = removeTab(next, next.closing);\n else if (next.closing === entry.key) next = { ...next, closing: null };\n return evictOverflow(next, maxTabs);\n}\n\n/** The address is not a tab (a redirect in flight, an excluded page). */\nexport function visitTransient(state: TabsState): TabsState {\n let next: TabsState = { ...state, activeKey: null };\n if (next.closing) next = removeTab(next, next.closing);\n return next;\n}\n\nfunction evictOverflow(state: TabsState, maxTabs: number): TabsState {\n let next = state;\n while (next.tabs.length > maxTabs) {\n const candidates = next.tabs\n .filter((t) => !t.pinned && t.key !== next.activeKey && !next.dirty.includes(t.key) && t.key !== next.closing)\n .sort((a, b) => a.lastActive - b.lastActive);\n if (candidates.length === 0) break;\n next = removeTab(next, candidates[0].key);\n }\n return next;\n}\n\n/** Drop a tab outright. Callers decide about unsaved changes first. */\nexport function removeTab(state: TabsState, key: string): TabsState {\n return {\n ...state,\n tabs: state.tabs.filter((t) => t.key !== key),\n mounted: without(state.mounted, key),\n dirty: without(state.dirty, key),\n activeKey: state.activeKey === key ? null : state.activeKey,\n closing: state.closing === key ? null : state.closing,\n };\n}\n\n/**\n * Where to go when the tab on screen closes: the tab to its right, else the\n * one to its left — the browser's rule, so the strip does not jump.\n */\nexport function neighbourOf(state: TabsState, key: string): PageTab | null {\n const visible = state.tabs.filter((t) => t.key !== state.closing || t.key === key);\n const i = visible.findIndex((t) => t.key === key);\n if (i < 0) return null;\n return visible[i + 1] ?? visible[i - 1] ?? null;\n}\n\n/** Mark the tab on screen as closing; it goes when the address moves on. */\nexport function beginClose(state: TabsState, key: string): TabsState {\n return { ...state, closing: key };\n}\n\n/** The keys a bulk close would take, before any unsaved-changes check. */\nexport function keysToClose(\n state: TabsState,\n scope: 'others' | 'right' | 'all',\n key: string | null,\n): string[] {\n const closable = state.tabs.filter((t) => !t.pinned);\n if (scope === 'all') return closable.map((t) => t.key);\n if (scope === 'others') return closable.filter((t) => t.key !== key).map((t) => t.key);\n const i = state.tabs.findIndex((t) => t.key === key);\n if (i < 0) return [];\n return state.tabs.slice(i + 1).filter((t) => !t.pinned).map((t) => t.key);\n}\n\nexport function setTitle(state: TabsState, key: string, title: string): TabsState {\n const tab = state.tabs.find((t) => t.key === key);\n if (!tab || !title || (tab.title === title && tab.titleFrom === 'page')) return state;\n return {\n ...state,\n tabs: state.tabs.map((t) => (t.key === key ? { ...t, title, titleFrom: 'page' } : t)),\n };\n}\n\nexport function setDirty(state: TabsState, key: string, dirty: boolean): TabsState {\n const has = state.dirty.includes(key);\n if (dirty === has) return state;\n return { ...state, dirty: dirty ? [...state.dirty, key] : without(state.dirty, key) };\n}\n\n/**\n * Make sure every pinned tab exists and they lead the strip.\n *\n * Runs on every start, so a home page added to `pinned` after a user's tabs\n * were saved still appears, and one removed from it stops being pinned (it\n * stays open as an ordinary tab rather than vanishing under the user).\n */\nexport function ensurePinned(state: TabsState, pinned: TabEntry[]): TabsState {\n const pinnedKeys = pinned.map((p) => p.key);\n let tabs = state.tabs.map((t) => ({ ...t, pinned: pinnedKeys.includes(t.key) }));\n for (const p of pinned) {\n if (!tabs.some((t) => t.key === p.key)) {\n tabs = [...tabs, { key: p.key, path: p.path, title: p.title, titleFrom: 'route', pinned: true, lastActive: 0 }];\n }\n }\n return { ...state, tabs: orderPinned(tabs, pinnedKeys) };\n}\n\n// ── Persistence ────────────────────────────────────────────────────────────\n\n/** What survives a reload: which pages were open, where, and what they were\n * called. Not the page state — that is the page's to restore. */\ninterface StoredTabs {\n v: 1;\n tabs: { key: string; path: string; title: string; titleFrom: 'route' | 'page' }[];\n}\n\nexport function serialize(state: TabsState): string {\n const stored: StoredTabs = {\n v: 1,\n tabs: state.tabs\n .filter((t) => t.key !== state.closing)\n .map(({ key, path, title, titleFrom }) => ({ key, path, title, titleFrom })),\n };\n return JSON.stringify(stored);\n}\n\n/**\n * Read saved tabs back, re-deciding each one against today's routes.\n *\n * `resolve` is the consumer's route table: a saved page that is no longer a\n * tab (retired, renamed, now excluded) is dropped, and one whose key rule\n * changed takes its new key. Anything unreadable yields no tabs — a corrupt\n * entry must not stop the portal from starting.\n */\nexport function restore(raw: string | null, resolve: (path: string) => TabEntry | null): PageTab[] {\n if (!raw) return [];\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n return [];\n }\n const stored = parsed as Partial<StoredTabs> | null;\n if (!stored || stored.v !== 1 || !Array.isArray(stored.tabs)) return [];\n const out: PageTab[] = [];\n for (const item of stored.tabs) {\n // An app path only. `//host/…` is protocol-relative: another origin.\n if (!item || typeof item.path !== 'string' || !item.path.startsWith('/') || item.path.startsWith('//')) continue;\n // A fragment is never kept (see `pathOf`); drop one a hand-edited or\n // foreign value carries on the way in.\n const hashAt = item.path.indexOf('#');\n const path = hashAt >= 0 ? item.path.slice(0, hashAt) : item.path;\n const entry = resolve(path);\n if (!entry || out.some((t) => t.key === entry.key)) continue;\n const pageTitle = item.titleFrom === 'page' && typeof item.title === 'string' && item.title;\n out.push({\n key: entry.key,\n path,\n title: pageTitle || entry.title,\n titleFrom: pageTitle ? 'page' : 'route',\n pinned: false,\n lastActive: 0,\n });\n }\n return out;\n}\n","/**\n * PageTabsProvider — keeps a strip of open pages in step with the router.\n *\n * A routed app shows one page at a time: open an order from a list and the\n * list is gone, with its filters, its scroll position and anything half typed.\n * The desktop shell answered that with windows; a portal that dropped the\n * desktop for plain pages lost it. Page tabs put it back the way admin\n * dashboards commonly do it: every page opened stays open as a tab under the\n * header, the pages behind the other tabs stay alive, and clicking a tab goes\n * back to exactly where it was.\n *\n * The address stays the source of truth. The provider never renders a page\n * the router did not route to: it watches the location, and a location its\n * `resolve` names becomes (or re-activates) a tab. Clicking a tab navigates to\n * that tab's last address, so Back, Forward, bookmarks and deep links behave\n * as they do without tabs. `PageTabsOutlet` does the keeping-alive and\n * `PageTabBar` draws the strip; this component is only the state between them.\n *\n * Mount it inside the router, once, keyed on the signed-in user:\n *\n * <PageTabsProvider key={user.id} storageKey={`tabs:u${user.id}`} resolve={…}>\n *\n * The key matters. The saved strip belongs to one user, and a provider that\n * outlived a sign-out would show the next user the last one's pages.\n *\n * Unsaved changes ask before a tab closes (`usePageTabDirty` marks them) and\n * hold the browser tab open while they exist. The question is asked through\n * the kit's `confirm`, so `ConfirmProvider` must be mounted — or pass\n * `confirmDiscard` to ask some other way.\n */\nimport {\n useCallback,\n useEffect,\n useId,\n useLayoutEffect,\n useMemo,\n useReducer,\n useRef,\n type ReactNode,\n} from 'react';\nimport { useLocation, useNavigate, type Location } from 'react-router-dom';\n\nimport { confirm } from '../shell/ConfirmDialog';\nimport { useShellStrings } from '../shell/strings';\nimport {\n PageTabsContext,\n type CloseTabOptions,\n type PageTabsContextValue,\n type ResolvePageTab,\n type TabLocation,\n} from './context';\nimport {\n DEFAULT_MAX_TABS,\n beginClose,\n emptyState,\n ensurePinned,\n keysToClose,\n neighbourOf,\n removeTab,\n restore,\n serialize,\n setDirty as setDirtyIn,\n setTitle as setTitleIn,\n visit,\n visitTransient,\n type PageTab,\n type TabEntry,\n type TabsState,\n} from './tabsModel';\n\nexport interface PageTabsProviderProps {\n children: ReactNode;\n /** The route table: whether an address is a tab, and what it is called. */\n resolve: ResolvePageTab;\n /** Addresses that are always open, first in the strip, and cannot be\n * closed — the portal's home page. */\n pinned?: string[];\n /** localStorage key for the open tabs. Scope it to the user. Omit to keep\n * tabs for the life of the page only. */\n storageKey?: string;\n /** Past this many, opening a page closes the least recently used tab that\n * has no unsaved changes. */\n maxTabs?: number;\n /** Off, there is no strip and no keeping-alive: the outlet renders the\n * current page alone. For phones, where a strip of tabs has no room. */\n enabled?: boolean;\n /** Ask before discarding unsaved changes. Defaults to the kit's `confirm`. */\n confirmDiscard?: (tabs: PageTab[]) => Promise<boolean>;\n}\n\ntype Action =\n | { type: 'visit'; entry: TabEntry; maxTabs: number }\n | { type: 'transient' }\n | { type: 'close'; keys: string[]; closing: string | null }\n | { type: 'title'; key: string; title: string }\n | { type: 'dirty'; key: string; dirty: boolean };\n\nfunction reducer(state: TabsState, action: Action): TabsState {\n switch (action.type) {\n case 'visit':\n return visit(state, action.entry, action.maxTabs);\n case 'transient':\n return visitTransient(state);\n case 'close': {\n let next = state;\n for (const key of action.keys) next = removeTab(next, key);\n return action.closing ? beginClose(next, action.closing) : next;\n }\n case 'title':\n return setTitleIn(state, action.key, action.title);\n case 'dirty':\n return setDirtyIn(state, action.key, action.dirty);\n }\n}\n\n/**\n * What a tab remembers of an address: the path and the query, never the\n * fragment. A fragment is where credentials travel precisely because it is\n * never sent to a server — an impersonation hand-off (`#_imp=<token>`), an\n * OAuth implicit grant. A tab that kept it would write the token into\n * localStorage and put it back in the address bar every time the tab was\n * clicked. An in-page anchor is the only thing lost, and a tab switch that\n * lands at the top of the section rather than on the anchor is a fair price.\n */\nconst pathOf = (location: TabLocation) => `${location.pathname}${location.search}`;\n\n/** A path back into the parts `resolve` reads. Relative to nothing: every\n * stored path starts with `/`. */\nexport function parseTabPath(path: string): TabLocation {\n const hashAt = path.indexOf('#');\n const hash = hashAt >= 0 ? path.slice(hashAt) : '';\n const rest = hashAt >= 0 ? path.slice(0, hashAt) : path;\n const searchAt = rest.indexOf('?');\n return {\n pathname: searchAt >= 0 ? rest.slice(0, searchAt) : rest,\n search: searchAt >= 0 ? rest.slice(searchAt) : '',\n hash,\n };\n}\n\nfunction readStorage(key: string | undefined): string | null {\n if (!key) return null;\n try {\n return localStorage.getItem(key);\n } catch {\n return null;\n }\n}\n\nexport default function PageTabsProvider({\n children,\n resolve,\n pinned = [],\n storageKey,\n maxTabs = DEFAULT_MAX_TABS,\n enabled = true,\n confirmDiscard,\n}: PageTabsProviderProps) {\n const location = useLocation();\n const navigate = useNavigate();\n const strings = useShellStrings().pageTabs;\n const idPrefix = useId();\n\n // `resolve` is usually an inline function; hold the latest in a ref so the\n // callbacks below stay stable without asking the consumer to memoise it.\n const resolveRef = useRef(resolve);\n resolveRef.current = resolve;\n\n const entryFor = useCallback((loc: TabLocation): TabEntry | null => {\n const route = resolveRef.current(loc);\n if (!route) return null;\n return { key: route.key ?? loc.pathname, path: pathOf(loc), title: route.title };\n }, []);\n\n const [state, dispatch] = useReducer(reducer, undefined, (): TabsState => {\n const restored = restore(readStorage(storageKey), (path) => entryFor(parseTabPath(path)));\n const pinnedEntries = pinned\n .map((path) => entryFor(parseTabPath(path)))\n .filter((e): e is TabEntry => Boolean(e));\n let initial = ensurePinned({ ...emptyState(), tabs: restored }, pinnedEntries);\n // The first address is visited here, not in an effect, so the first paint\n // already has its tab — no frame of \"no tab\" before the page appears.\n const entry = enabled ? entryFor(location) : null;\n initial = entry ? visit(initial, entry, maxTabs) : visitTransient(initial);\n return initial;\n });\n\n // The async handlers (close waits on a dialog) read the state as it is when\n // they resume, not as it was when they started.\n const stateRef = useRef(state);\n stateRef.current = state;\n\n // Each tab's last location, so a hidden tab keeps rendering the address it\n // was at (with its router state) rather than the current one.\n const locations = useRef(new Map<string, Location>());\n const current = enabled ? entryFor(location) : null;\n const currentKey = current?.key ?? null;\n\n useLayoutEffect(() => {\n if (!enabled) return;\n const entry = entryFor(location);\n if (entry) {\n locations.current.set(entry.key, location);\n dispatch({ type: 'visit', entry, maxTabs });\n } else {\n dispatch({ type: 'transient' });\n }\n }, [location, enabled, maxTabs, entryFor]);\n\n // Forget the locations of tabs that are gone.\n useEffect(() => {\n const open = new Set(state.tabs.map((t) => t.key));\n for (const key of locations.current.keys()) if (!open.has(key)) locations.current.delete(key);\n }, [state.tabs]);\n\n const serialized = useMemo(() => serialize(state), [state]);\n useEffect(() => {\n if (!storageKey) return;\n try {\n localStorage.setItem(storageKey, serialized);\n } catch {\n /* storage full or unavailable — the strip just won't survive a reload */\n }\n }, [serialized, storageKey]);\n\n // Unsaved work anywhere holds the browser tab, as a dirty window did.\n const anyDirty = state.dirty.length > 0;\n useEffect(() => {\n if (!anyDirty) return;\n const hold = (e: BeforeUnloadEvent) => {\n e.preventDefault();\n // Chrome still needs returnValue set to show the prompt.\n e.returnValue = '';\n };\n window.addEventListener('beforeunload', hold);\n return () => window.removeEventListener('beforeunload', hold);\n }, [anyDirty]);\n\n const ids = useRef(new Map<string, number>());\n const idFor = useCallback(\n (key: string, part: 'tab' | 'panel') => {\n let n = ids.current.get(key);\n if (n === undefined) {\n n = ids.current.size;\n ids.current.set(key, n);\n }\n return `${idPrefix}-page-${part}-${n}`;\n },\n [idPrefix],\n );\n\n const askDiscard = useCallback(\n (tabs: PageTab[]) => {\n if (confirmDiscard) return confirmDiscard(tabs);\n return confirm({\n title: strings.discardTitle,\n message: tabs.length === 1 ? strings.discardOne : `${tabs.length} ${strings.discardMany}`,\n confirmLabel: strings.discardConfirm,\n cancelLabel: strings.keepEditing,\n variant: 'warning',\n });\n },\n [confirmDiscard, strings],\n );\n\n const fallbackPath = useCallback(() => {\n const s = stateRef.current;\n return s.tabs.find((t) => t.pinned)?.path ?? '/';\n }, []);\n\n /**\n * Close `keys` now. If the tab on screen is among them it is not removed\n * here — it is marked closing and the address moves to `to` (or the\n * nearest surviving tab); `visit` drops it once the address has left.\n */\n const closeNow = useCallback(\n (keys: string[], to?: string, prefer?: string | null) => {\n const s = stateRef.current;\n const active = s.activeKey;\n if (!active || !keys.includes(active)) {\n dispatch({ type: 'close', keys, closing: null });\n return;\n }\n let target = to;\n if (!target) {\n const survivors = { ...s, tabs: s.tabs.filter((t) => t.key === active || !keys.includes(t.key)) };\n const preferred = prefer ? s.tabs.find((t) => t.key === prefer && !keys.includes(t.key)) : undefined;\n target = (preferred ?? neighbourOf(survivors, active))?.path ?? fallbackPath();\n }\n dispatch({ type: 'close', keys: keys.filter((k) => k !== active), closing: active });\n navigate(target);\n },\n [navigate, fallbackPath],\n );\n\n const close = useCallback(\n async (key: string, options: CloseTabOptions = {}) => {\n const tab = stateRef.current.tabs.find((t) => t.key === key);\n if (!tab || tab.pinned) {\n if (options.to) navigate(options.to);\n return false;\n }\n if (!options.force && stateRef.current.dirty.includes(key) && !(await askDiscard([tab]))) return false;\n // The dialog took time: the tab may have closed some other way.\n if (!stateRef.current.tabs.some((t) => t.key === key)) return false;\n closeNow([key], options.to);\n return true;\n },\n [askDiscard, closeNow, navigate],\n );\n\n const closeMany = useCallback(\n async (scope: 'others' | 'right' | 'all', key: string | null) => {\n let keys = keysToClose(stateRef.current, scope, key);\n const dirty = stateRef.current.tabs.filter(\n (t) => keys.includes(t.key) && stateRef.current.dirty.includes(t.key),\n );\n // One question for the lot. Declining keeps the unsaved ones and still\n // closes the rest — the user asked for fewer tabs, not for nothing.\n if (dirty.length && !(await askDiscard(dirty))) {\n keys = keys.filter((k) => !dirty.some((t) => t.key === k));\n }\n const open = new Set(stateRef.current.tabs.map((t) => t.key));\n keys = keys.filter((k) => open.has(k));\n if (keys.length) closeNow(keys, undefined, scope === 'all' ? null : key);\n },\n [askDiscard, closeNow],\n );\n\n const activate = useCallback(\n (key: string) => {\n const tab = stateRef.current.tabs.find((t) => t.key === key);\n if (!tab || key === stateRef.current.activeKey) return;\n navigate(tab.path);\n },\n [navigate],\n );\n\n const setTitle = useCallback((key: string, title: string) => dispatch({ type: 'title', key, title }), []);\n const setDirty = useCallback((key: string, dirty: boolean) => dispatch({ type: 'dirty', key, dirty }), []);\n const keyFor = useCallback((loc: TabLocation) => entryFor(loc)?.key ?? null, [entryFor]);\n const locationFor = useCallback((key: string) => locations.current.get(key), []);\n\n const visibleTabs = useMemo(\n () => (enabled ? state.tabs.filter((t) => t.key !== state.closing) : []),\n [enabled, state.tabs, state.closing],\n );\n\n const value = useMemo<PageTabsContextValue>(\n () => ({\n enabled,\n state,\n currentKey,\n resolve,\n keyFor,\n locationFor,\n idFor,\n activate,\n close,\n closeMany,\n setTitle,\n setDirty,\n visibleTabs,\n }),\n [enabled, state, currentKey, resolve, keyFor, locationFor, idFor, activate, close, closeMany, setTitle, setDirty, visibleTabs],\n );\n\n return <PageTabsContext.Provider value={value}>{children}</PageTabsContext.Provider>;\n}\n","/**\n * PageTabsOutlet — renders every open tab's page, and shows one.\n *\n * Each open tab gets a frame that renders the consumer's routes at THAT TAB'S\n * address (`children(location)`, typically `<Routes location={location}>`), so\n * a hidden tab keeps its page mounted — its query results, its filters, the\n * form half filled in — while a different page is on screen. The router's own\n * `<Routes location>` is what makes this possible: inside it, `useLocation`,\n * `useParams` and relative links all answer for the tab's address, not the\n * browser's.\n *\n * ## Hidden is not the same as paused\n *\n * On React 19.2+ each frame is wrapped in `<Activity>`. A hidden Activity keeps\n * its state but runs its effects' clean-ups, and runs them again when shown.\n * That is the behaviour a hidden page needs: a list stops polling, a form's\n * ⌘S handler stops listening (a keystroke in one tab must not submit another\n * tab's form), `document.title` is set again by whichever page comes forward.\n * React 18 has no Activity; there the frame is only hidden and its effects keep\n * running (`PAGE_TABS_PAUSE_HIDDEN` says which you got). The peer range is\n * still `react >=18`, so both are supported — but a portal whose pages bind\n * global listeners wants 19.2.\n *\n * ## Scroll\n *\n * A frame is the page's scroll container (give it `overflow-y-auto` through\n * `frameClassName`), and scrolling inside a hidden element is not something\n * browsers keep. The frame records scroll positions — its own and any\n * scrolling list inside it — while it is on screen, and puts them back when it\n * is shown again.\n */\nimport * as ReactModule from 'react';\nimport {\n memo,\n useContext,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n type ComponentType,\n type ReactNode,\n} from 'react';\nimport { useLocation, type Location } from 'react-router-dom';\n\nimport { PageTabFrameContext, PageTabsContext, type PageTabFrame } from './context';\n\n/** React 19.2's keep-alive primitive, or undefined on older Reacts. Read off\n * the namespace so this module still loads (and type-checks) on React 18. */\nconst Activity = (ReactModule as unknown as {\n Activity?: ComponentType<{ mode: 'visible' | 'hidden'; children?: ReactNode }>;\n}).Activity;\n\n/** True when hidden tabs are paused (`<Activity>`), false when they are only\n * hidden. Exported for the consumer that wants to know which it got. */\nexport const PAGE_TABS_PAUSE_HIDDEN = Boolean(Activity);\n\nfunction KeepAlive({ active, children }: { active: boolean; children: ReactNode }) {\n if (Activity) return <Activity mode={active ? 'visible' : 'hidden'}>{children}</Activity>;\n return <>{children}</>;\n}\n\ninterface FrameProps {\n tabKey: string;\n active: boolean;\n location: Location;\n render: (location: Location) => ReactNode;\n className?: string;\n panelId?: string;\n tabId?: string;\n}\n\n/**\n * A hidden frame re-renders only when its own address changes. Every\n * navigation re-renders the outlet, and without this each one would re-render\n * every open page behind the one in view — the outlet's `children` is a fresh\n * function each time, but it renders the same routes. Contexts the pages read\n * still reach them; this only stops the outlet's own re-render cascading.\n */\nconst sameFrame = (a: FrameProps, b: FrameProps) =>\n a.active === b.active &&\n a.location === b.location &&\n a.className === b.className &&\n a.panelId === b.panelId &&\n a.tabId === b.tabId &&\n (!b.active || a.render === b.render);\n\nconst TabFrame = memo(function TabFrame({ tabKey, active, location, render, className, panelId, tabId }: FrameProps) {\n const ref = useRef<HTMLDivElement>(null);\n const activeRef = useRef(active);\n const scrolls = useRef(new Map<Element, [number, number]>());\n\n // A layout effect, so `activeRef` is already false by the time a hiding\n // Activity runs its subtree's passive clean-ups (see PageTabFrame).\n useLayoutEffect(() => {\n const wasActive = activeRef.current;\n activeRef.current = active;\n if (!active || wasActive) return;\n for (const [el, [top, left]] of scrolls.current) {\n if (!el.isConnected) {\n scrolls.current.delete(el);\n continue;\n }\n el.scrollTop = top;\n el.scrollLeft = left;\n }\n }, [active]);\n\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n // `scroll` does not bubble, but it can be captured: one listener here\n // hears the frame and every scrolling element inside it.\n const onScroll = (e: Event) => {\n if (!activeRef.current) return;\n const target = e.target as Element | null;\n if (!target || typeof target.scrollTop !== 'number') return;\n scrolls.current.set(target, [target.scrollTop, target.scrollLeft]);\n };\n el.addEventListener('scroll', onScroll, true);\n return () => el.removeEventListener('scroll', onScroll, true);\n }, []);\n\n const frame = useMemo<PageTabFrame>(() => ({ key: tabKey, activeRef }), [tabKey]);\n\n return (\n <div\n ref={ref}\n role={panelId ? 'tabpanel' : undefined}\n id={panelId}\n aria-labelledby={tabId}\n hidden={!active}\n // Inline, not the `hidden` attribute alone: a `flex` or `block` class on\n // the frame would out-rank the user-agent rule and show it anyway.\n style={active ? undefined : { display: 'none' }}\n className={className}\n data-page-tab={tabKey}\n >\n <PageTabFrameContext.Provider value={frame}>\n <KeepAlive active={active}>{render(location)}</KeepAlive>\n </PageTabFrameContext.Provider>\n </div>\n );\n}, sameFrame);\n\nexport interface PageTabsOutletProps {\n /** Render the page at an address — usually `<Routes location={location}>`\n * with the app's content routes. Called once per open tab. */\n children: (location: Location) => ReactNode;\n /** Classes for each tab's frame. The frame is the page's scroll container,\n * so it wants a height and `overflow-y-auto`. */\n frameClassName?: string;\n}\n\nconst TRANSIENT = '\\u0000transient';\n\nexport default function PageTabsOutlet({ children, frameClassName }: PageTabsOutletProps) {\n const ctx = useContext(PageTabsContext);\n const location = useLocation();\n\n if (!ctx || !ctx.enabled) {\n return (\n <div className={frameClassName} key={TRANSIENT}>\n {children(location)}\n </div>\n );\n }\n\n const { state, currentKey, locationFor, idFor } = ctx;\n // Every tab rendered so far, in strip order, plus the one the address is on\n // if the state has not caught up with it yet. Keyed by tab, so a frame keeps\n // its place in the tree — and its page — however the strip is reordered.\n const keys = state.tabs.filter((t) => state.mounted.includes(t.key)).map((t) => t.key);\n if (currentKey && !keys.includes(currentKey)) keys.push(currentKey);\n\n return (\n <>\n {keys.map((key) => {\n const active = key === currentKey;\n const loc = active ? location : locationFor(key);\n // A tab never shown this session has no location to render at; it\n // waits until it is opened.\n if (!loc) return null;\n return (\n <TabFrame\n key={key}\n tabKey={key}\n active={active}\n location={loc}\n render={children}\n className={frameClassName}\n panelId={idFor(key, 'panel')}\n tabId={idFor(key, 'tab')}\n />\n );\n })}\n {!currentKey && (\n <TabFrame key={TRANSIENT} tabKey={TRANSIENT} active location={location} render={children} className={frameClassName} />\n )}\n </>\n );\n}\n","/**\n * PageTabBar — the strip of open pages.\n *\n * One tab per open page, newest on the right, pinned ones first. Click a tab to\n * go back to it; its × (or a middle-click, or Delete while it has focus) closes\n * it; right-click offers Close, Close other tabs, Close tabs to the right and\n * Close all. A tab with unsaved changes shows a dot where its × would be and\n * asks before it goes.\n *\n * Many tabs shrink rather than scroll, as a browser's do (see TAB_BASE).\n *\n * Keyboard: the strip is one tab stop and the arrow keys move along it (Home /\n * End to the ends) — the roving-tabindex tablist pattern the kit's `Tabs` uses.\n * Moving focus does not switch pages; Enter or Space does, because switching\n * navigates and a user arrowing past five tabs should not visit five pages.\n *\n * The strip can be an app's whole top bar: `end` puts controls at its right\n * (a connection light, a theme switch) that stay put while the tabs scroll.\n * The active tab takes the page's background and covers the strip's bottom\n * rule, so it reads as the top of the page below it — give `activeClassName`\n * the page's background if it is not `bg-gray-50`.\n *\n * Renders nothing when tabs are off (`enabled={false}` on the provider).\n */\nimport { Fragment, useContext, useEffect, useRef, useState, type KeyboardEvent, type MouseEvent, type ReactNode } from 'react';\n\nimport { PopupMenu, PopupMenuDivider, PopupMenuItem } from '../shell/PopupMenu';\nimport { useShellStrings } from '../shell/strings';\nimport { PageTabsContext } from './context';\nimport { parseTabPath } from './PageTabsProvider';\nimport type { PageTab } from './tabsModel';\n\nexport interface PageTabBarProps {\n /** Replaces the strip's own classes (height, background, padding). */\n className?: string;\n /** Replaces the active tab's colours — its background should be the\n * page's, so the tab and the page read as one surface. */\n activeClassName?: string;\n /** Controls at the right end of the strip. They do not scroll with the\n * tabs. */\n end?: ReactNode;\n}\n\nconst STRIP = 'relative flex h-10 shrink-0 items-end gap-3 bg-gray-100 px-3';\n\n/** The tabs sit in this. It scrolls sideways only once every tab is at its\n * narrowest; the scrollbar is hidden (a wheel or a trackpad still scrolls it,\n * and the active tab is kept in view). */\nconst TABLIST =\n 'flex min-w-0 flex-1 items-end overflow-x-auto overflow-y-hidden [scrollbar-width:none] [&::-webkit-scrollbar]:hidden';\n\n/**\n * Sizing, the way a browser's tab strip does it. Every tab asks for 15rem and\n * all of them shrink evenly as more open (`flex: 0 1 15rem`), so a strip of\n * twelve tabs fits where it used to scroll. Each tab is a size container\n * (`@container`) and gives detail up as it narrows: its title fades at the\n * edge, then an idle tab's × steps aside until the pointer is over the tab,\n * then its title goes, until only the icon is left. The tab on screen keeps\n * its × however narrow it gets, and hovering any tab shows its × — closing a\n * page is always one click. Pinned tabs are icon-only.\n */\nconst TAB_BASE =\n 'group @container relative flex h-9 flex-[0_1_15rem] items-center rounded-t-md border border-b-0 text-[13px] transition-colors';\n/** Floors: an icon for an idle tab; an icon and its × for the active one. */\nconst TAB_FLOOR_IDLE = 'min-w-[2.75rem]';\nconst TAB_FLOOR_ACTIVE = 'min-w-[4.25rem]';\nconst TAB_PINNED =\n 'group relative flex h-9 flex-none items-center justify-center rounded-t-md border border-b-0 transition-colors';\nconst TAB_ACTIVE = 'z-[1] border-gray-200 bg-gray-50 text-gray-900';\nconst TAB_IDLE = 'border-transparent text-gray-600 hover:bg-gray-200/70 hover:text-gray-900';\n\n/** A title that runs out of room fades rather than ending in \"…\" — the\n * browser's treatment, and it reads more of the word. */\nconst TITLE =\n 'min-w-0 flex-1 overflow-hidden whitespace-nowrap [mask-image:linear-gradient(to_right,#000_calc(100%-1rem),transparent)]';\n\nconst ICON_WRAP = 'relative flex size-4 shrink-0 items-center justify-center text-gray-500 [&>svg]:size-4';\nconst FOCUS_RING = 'outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-blue-500';\n\nfunction CloseIcon() {\n return (\n <svg viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\" className=\"size-3.5\">\n <path d=\"M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z\" />\n </svg>\n );\n}\n\ninterface MenuState {\n x: number;\n y: number;\n key: string;\n}\n\nexport default function PageTabBar({ className, activeClassName, end }: PageTabBarProps) {\n const ctx = useContext(PageTabsContext);\n const strings = useShellStrings().pageTabs;\n const stripRef = useRef<HTMLDivElement>(null);\n const [menu, setMenu] = useState<MenuState | null>(null);\n const activeKey = ctx?.currentKey ?? null;\n\n // Keep the tab on screen in view — a page opened from the menu lands at the\n // far right of a strip that may be scrolled the other way.\n useEffect(() => {\n if (!ctx || !activeKey) return;\n const el = document.getElementById(ctx.idFor(activeKey, 'tab'));\n el?.scrollIntoView?.({ block: 'nearest', inline: 'nearest' });\n }, [ctx, activeKey]);\n\n if (!ctx || !ctx.enabled) return null;\n const { visibleTabs: tabs, state, idFor, activate, close, closeMany, resolve } = ctx;\n const focusKey = tabs.some((t) => t.key === activeKey) ? activeKey : tabs[0]?.key;\n\n const focusTab = (index: number) => {\n const tab = tabs[(index + tabs.length) % tabs.length];\n if (tab) document.getElementById(idFor(tab.key, 'tab'))?.focus();\n };\n\n const onKeyDown = (e: KeyboardEvent<HTMLDivElement>) => {\n const i = tabs.findIndex((t) => document.getElementById(idFor(t.key, 'tab')) === e.target);\n if (i < 0) return;\n if (e.key === 'ArrowRight') focusTab(i + 1);\n else if (e.key === 'ArrowLeft') focusTab(i - 1);\n else if (e.key === 'Home') focusTab(0);\n else if (e.key === 'End') focusTab(tabs.length - 1);\n else if (e.key === 'Delete' && !tabs[i].pinned) void close(tabs[i].key);\n else return;\n e.preventDefault();\n };\n\n const onContextMenu = (e: MouseEvent, tab: PageTab) => {\n // Claimed, so the shell's global menu stands down (see ShellContextMenu).\n e.preventDefault();\n setMenu({ x: e.clientX, y: e.clientY, key: tab.key });\n };\n\n const onAuxClick = (e: MouseEvent, tab: PageTab) => {\n if (e.button !== 1 || tab.pinned) return;\n e.preventDefault();\n void close(tab.key);\n };\n\n const menuTab = menu ? tabs.find((t) => t.key === menu.key) : undefined;\n const menuIndex = menuTab ? tabs.indexOf(menuTab) : -1;\n const closable = (list: PageTab[]) => list.some((t) => !t.pinned);\n const run = (fn: () => unknown) => () => {\n setMenu(null);\n void fn();\n };\n\n return (\n <div className={className ?? STRIP}>\n {/* The strip's bottom rule, drawn as its own layer so the active tab —\n stacked above it — can cover it. A border on the scrolling list\n could not be covered: the list clips anything that reaches past it. */}\n <div aria-hidden=\"true\" className=\"pointer-events-none absolute inset-x-0 bottom-0 h-px bg-gray-200\" />\n <div\n ref={stripRef}\n role=\"tablist\"\n aria-label={strings.label}\n onKeyDown={onKeyDown}\n className={TABLIST}\n >\n {tabs.map((tab, i) => {\n const active = tab.key === activeKey;\n const dirty = state.dirty.includes(tab.key);\n const icon = resolve(parseTabPath(tab.path))?.icon;\n const colours = active ? (activeClassName ?? TAB_ACTIVE) : TAB_IDLE;\n // A hairline between two idle tabs, as the browser draws; none\n // beside the active tab, whose own edges already separate it.\n const divider = i > 0 && !active && tabs[i - 1].key !== activeKey;\n const tabButton = {\n type: 'button' as const,\n role: 'tab',\n id: idFor(tab.key, 'tab'),\n 'aria-selected': active,\n 'aria-controls': state.mounted.includes(tab.key) ? idFor(tab.key, 'panel') : undefined,\n tabIndex: tab.key === focusKey ? 0 : -1,\n title: tab.title,\n onClick: () => activate(tab.key),\n };\n const handlers = {\n onContextMenu: (e: MouseEvent) => onContextMenu(e, tab),\n onAuxClick: (e: MouseEvent) => onAuxClick(e, tab),\n // A middle-press would otherwise start the browser's autoscroll.\n onMouseDown: (e: MouseEvent) => {\n if (e.button === 1) e.preventDefault();\n },\n };\n const iconEl = icon && (\n // The consumer's nav icons, whatever size they were drawn at for\n // the sidebar, sit at the strip's size here.\n <span className={ICON_WRAP} aria-hidden=\"true\">\n {icon}\n {dirty && !active && !tab.pinned && (\n // Unsaved work on a tab too narrow for its × slot: the dot\n // moves onto the icon.\n <span className=\"absolute -right-1 -top-1 hidden size-2 rounded-full bg-gray-500 ring-2 ring-gray-100 @max-[6.5rem]:block @max-[6.5rem]:group-hover:hidden\" />\n )}\n </span>\n );\n\n if (tab.pinned) {\n return (\n <div key={tab.key} role=\"presentation\" className={`${TAB_PINNED} ${icon ? 'w-10' : ''} ${colours}`} {...handlers}>\n <button {...tabButton} className={`flex h-full items-center justify-center rounded-t-md ${icon ? 'w-full' : 'px-3'} ${FOCUS_RING}`}>\n {iconEl}\n <span className={icon ? 'sr-only' : 'whitespace-nowrap text-[13px]'}>{tab.title}</span>\n </button>\n </div>\n );\n }\n\n return (\n <Fragment key={tab.key}>\n {/* A border, not a fill: `border-gray-300` is the line every\n theme remaps (dark to --line-strong), and `bg-gray-300` has\n no dark remap, so it drew a light bar on the dark strip. */}\n {divider && <span aria-hidden=\"true\" className=\"mb-2.5 h-4 w-px shrink-0 self-end border-l border-gray-300\" />}\n <div\n role=\"presentation\"\n className={`${TAB_BASE} ${active ? TAB_FLOOR_ACTIVE : TAB_FLOOR_IDLE} ${colours}`}\n {...handlers}\n >\n <button\n {...tabButton}\n className={`flex h-full min-w-0 flex-1 items-center gap-2 rounded-t-md pl-3 pr-1 text-left ${FOCUS_RING} ${\n active\n ? '@max-[5rem]:pl-2.5'\n : '@max-[6.5rem]:pr-3 @max-[6.5rem]:group-hover:pr-1 @max-[4.5rem]:justify-center @max-[4.5rem]:px-0 @max-[4.5rem]:group-hover:pl-1.5'\n }`}\n >\n {iconEl}\n <span className={`${TITLE} ${icon ? (active ? '@max-[5rem]:sr-only' : '@max-[4.5rem]:sr-only') : ''}`}>\n {tab.title}\n </span>\n </button>\n <span\n className={`mr-1.5 flex size-5 shrink-0 items-center justify-center ${\n active ? '' : '@max-[6.5rem]:hidden @max-[6.5rem]:group-hover:flex'\n }`}\n >\n {dirty && (\n <span\n role=\"img\"\n aria-label={strings.unsaved}\n className=\"size-2 rounded-full bg-gray-500 group-hover:hidden\"\n />\n )}\n <button\n type=\"button\"\n tabIndex={-1}\n aria-label={`${strings.close} ${tab.title}`}\n onClick={() => void close(tab.key)}\n className={`size-5 items-center justify-center rounded text-gray-400 hover:bg-gray-200 hover:text-gray-700 ${\n dirty ? 'hidden group-hover:flex' : active ? 'flex' : 'flex opacity-0 group-hover:opacity-100 focus-visible:opacity-100'\n }`}\n >\n <CloseIcon />\n </button>\n </span>\n </div>\n </Fragment>\n );\n })}\n </div>\n {end && <div className=\"flex shrink-0 items-center gap-2 self-center\">{end}</div>}\n\n {menu && menuTab && (\n <PopupMenu portal style={{ left: menu.x, top: menu.y }} onClose={() => setMenu(null)}>\n <PopupMenuItem disabled={menuTab.pinned} onClick={run(() => close(menuTab.key))}>\n {strings.close}\n </PopupMenuItem>\n <PopupMenuDivider />\n <PopupMenuItem\n disabled={!closable(tabs.filter((t) => t.key !== menuTab.key))}\n onClick={run(() => closeMany('others', menuTab.key))}\n >\n {strings.closeOthers}\n </PopupMenuItem>\n <PopupMenuItem\n disabled={!closable(tabs.slice(menuIndex + 1))}\n onClick={run(() => closeMany('right', menuTab.key))}\n >\n {strings.closeRight}\n </PopupMenuItem>\n <PopupMenuItem disabled={!closable(tabs)} onClick={run(() => closeMany('all', null))}>\n {strings.closeAll}\n </PopupMenuItem>\n </PopupMenu>\n )}\n </div>\n );\n}\n","/**\n * What a page asks of the tab it is in — and what the rest of the app asks of\n * the strip.\n *\n * Every hook here is safe outside a tab: with no provider, or with tabs turned\n * off (a phone), they do nothing, and `usePageTab().close` still honours `to`.\n * A page written for tabs therefore works unchanged without them.\n */\nimport { useCallback, useContext, useEffect } from 'react';\nimport { useNavigate } from 'react-router-dom';\n\nimport { PageTabFrameContext, PageTabsContext, type CloseTabOptions } from './context';\nimport type { PageTab } from './tabsModel';\n\nexport interface PageTabsApi {\n enabled: boolean;\n tabs: PageTab[];\n activeKey: string | null;\n activate: (key: string) => void;\n close: (key: string, options?: CloseTabOptions) => Promise<boolean>;\n closeOthers: (key: string) => Promise<void>;\n closeRight: (key: string) => Promise<void>;\n closeAll: () => Promise<void>;\n}\n\nconst NO_TABS: PageTabsApi = {\n enabled: false,\n tabs: [],\n activeKey: null,\n activate: () => {},\n close: async () => false,\n closeOthers: async () => {},\n closeRight: async () => {},\n closeAll: async () => {},\n};\n\n/** The strip, for code outside any one page (a keyboard shortcut, a menu). */\nexport function usePageTabs(): PageTabsApi {\n const ctx = useContext(PageTabsContext);\n if (!ctx || !ctx.enabled) return NO_TABS;\n return {\n enabled: true,\n tabs: ctx.visibleTabs,\n activeKey: ctx.currentKey,\n activate: ctx.activate,\n close: ctx.close,\n closeOthers: (key) => ctx.closeMany('others', key),\n closeRight: (key) => ctx.closeMany('right', key),\n closeAll: () => ctx.closeMany('all', null),\n };\n}\n\nexport interface PageTabHandle {\n /** This page's tab, or null outside one. */\n key: string | null;\n /**\n * Close this page's tab. Unsaved changes are asked about unless `force`.\n * Outside a tab it only navigates to `to`, if given. Resolves true when the\n * tab closed.\n */\n close: (options?: CloseTabOptions) => Promise<boolean>;\n}\n\n/** The tab this page is in. */\nexport function usePageTab(): PageTabHandle {\n const ctx = useContext(PageTabsContext);\n const frame = useContext(PageTabFrameContext);\n const navigate = useNavigate();\n const key = ctx?.enabled && frame ? frame.key : null;\n const close = useCallback(\n async (options: CloseTabOptions = {}) => {\n if (ctx?.enabled && frame && ctx.state.tabs.some((t) => t.key === frame.key)) {\n return ctx.close(frame.key, options);\n }\n if (options.to) navigate(options.to);\n return false;\n },\n [ctx, frame, navigate],\n );\n return { key, close };\n}\n\n/**\n * Name this page's tab — a record's number once it has loaded, say. Empty\n * strings are ignored, so a page can pass its title before the data arrives.\n * The name sticks: moving within the tab (a filter, a hash) keeps it.\n */\nexport function usePageTabTitle(title: string | null | undefined): void {\n const ctx = useContext(PageTabsContext);\n const frame = useContext(PageTabFrameContext);\n const setTitle = ctx?.enabled ? ctx.setTitle : undefined;\n const key = frame?.key;\n useEffect(() => {\n if (setTitle && key && title) setTitle(key, title);\n }, [setTitle, key, title]);\n}\n\n/**\n * Mark this page's tab as holding unsaved changes. Closing it then asks\n * first, and the browser tab asks before a reload.\n *\n * The flag survives the tab being hidden. A hidden tab's effects are cleaned\n * up (see PageTabsOutlet), and clearing the flag in that clean-up would let a\n * hidden form close silently; so the clean-up only clears it when the page\n * went away while its tab was on screen (the tab moved to another page). A\n * closed tab's flag goes with the tab.\n */\nexport function usePageTabDirty(dirty: boolean): void {\n const ctx = useContext(PageTabsContext);\n const frame = useContext(PageTabFrameContext);\n const setDirty = ctx?.enabled ? ctx.setDirty : undefined;\n useEffect(() => {\n if (!setDirty || !frame) return;\n setDirty(frame.key, dirty);\n return () => {\n if (frame.activeRef.current) setDirty(frame.key, false);\n };\n }, [setDirty, frame, dirty]);\n}\n"]}
package/dist/shell.css ADDED
@@ -0,0 +1,105 @@
1
+ /**
2
+ * react-os-shell/shell.css — the window chrome half of the stylesheet.
3
+ *
4
+ * NOT a public subpath: it is reached only through `styles.css`, which imports
5
+ * it by relative path. Consumers take `styles.css` (shell + kit) or
6
+ * `ui.css` (kit alone).
7
+ *
8
+ * A rule lives here only if its selector is scoped to DOM the shell alone
9
+ * produces — [data-sticky-id], .glass-input-bg, .docs-editor — or if it
10
+ * declares a --window-* / --taskbar-* custom property. Everything whose
11
+ * selector is a bare utility class stays in ui.css, even where a comment
12
+ * mentions the taskbar: the cascade does not read comments, and a rule that
13
+ * names .text-gray-600 applies to every button in every app.
14
+ */
15
+
16
+ /* Glass input field — used by the start-menu search and any consumer that
17
+ * imports GLASS_INPUT_BG. Adapts to dark mode so the tile blends with the
18
+ * dark glass gradient instead of reading as a bright white panel that
19
+ * mismatches its frame. */
20
+ .glass-input-bg {
21
+ background-color: rgba(255, 255, 255, 0.15);
22
+ }
23
+ [data-theme="dark"] .glass-input-bg {
24
+ background-color: rgba(255, 255, 255, 0.06);
25
+ }
26
+
27
+ /* Base theme colors for transparent windows.
28
+ *
29
+ * --window-accent-rgb (SG#00372) is deliberately NOT defined here: it is a
30
+ * per-window property, set inline on the panel element by Modal when the
31
+ * consumer passes `accentRgb` (see WindowManagerProvider's
32
+ * `windowAccentForRoute`). It paints only the thin accent stripe between the
33
+ * title bar and the body, and only when the user has switched that stripe on
34
+ * (the `window_accent_stripe` preference) — the header colours below and the
35
+ * user's custom header colour are never overridden by it. */
36
+ :root {
37
+ --window-header-rgb: 243 244 246;
38
+ --window-footer-rgb: 249 250 251;
39
+ --window-content-rgb: 255 255 255;
40
+ }
41
+ [data-theme="pink"] {
42
+ --window-header-rgb: 252 231 243;
43
+ --window-footer-rgb: 253 242 248;
44
+ --window-content-rgb: 255 245 249;
45
+ }
46
+ [data-theme="green"] {
47
+ --window-header-rgb: 220 252 231;
48
+ --window-footer-rgb: 236 253 245;
49
+ --window-content-rgb: 245 254 247;
50
+ }
51
+ [data-theme="grey"] {
52
+ --window-header-rgb: 229 231 235;
53
+ --window-footer-rgb: 243 244 246;
54
+ --window-content-rgb: 249 250 251;
55
+ }
56
+ [data-theme="blue"] {
57
+ --window-header-rgb: 219 234 254;
58
+ --window-footer-rgb: 239 246 255;
59
+ --window-content-rgb: 245 249 255;
60
+ }
61
+ [data-theme="dark"] {
62
+ --window-header-rgb: 49 50 68;
63
+ --window-footer-rgb: 24 24 37;
64
+ --window-content-rgb: 30 30 46;
65
+ }
66
+
67
+ /* Sticky notes — keep a solid coloured "paper" in dark mode. The bare .bg-*-100
68
+ overrides above mute these to a faint 18% status-pill tint (washed out) and
69
+ the note's black ink then can't be read. The [data-sticky-id] selector wins
70
+ on specificity: give each colour a muted dark paper and flip the ink to a
71
+ light tone. */
72
+ [data-theme="dark"] [data-sticky-id].bg-yellow-100 { background-color: #514a1f !important; border-color: #6e6330 !important; }
73
+ [data-theme="dark"] [data-sticky-id].bg-blue-100 { background-color: #1e3553 !important; border-color: #2f4d72 !important; }
74
+ [data-theme="dark"] [data-sticky-id].bg-green-100 { background-color: #1f4030 !important; border-color: #2f5c45 !important; }
75
+ [data-theme="dark"] [data-sticky-id].bg-pink-100 { background-color: #4d2339 !important; border-color: #6e3654 !important; }
76
+ [data-theme="dark"] [data-sticky-id].bg-purple-100 { background-color: #392555 !important; border-color: #4f3873 !important; }
77
+ [data-theme="dark"] [data-sticky-id].bg-orange-100 { background-color: #533619 !important; border-color: #6e4b27 !important; }
78
+ [data-theme="dark"] [data-sticky-id] .text-black\/70 { color: rgba(230, 233, 245, 0.92) !important; }
79
+ [data-theme="dark"] [data-sticky-id] .text-black\/30 { color: rgba(230, 233, 245, 0.45) !important; }
80
+ [data-theme="dark"] [data-sticky-id] .text-black\/20 { color: rgba(230, 233, 245, 0.42) !important; }
81
+ [data-theme="dark"] [data-sticky-id] .text-black\/15 { color: rgba(230, 233, 245, 0.35) !important; }
82
+ [data-theme="dark"] [data-sticky-id] .hover\:text-black\/50:hover { color: rgba(230, 233, 245, 0.70) !important; }
83
+ [data-theme="dark"] [data-sticky-id] .placeholder\:text-black\/30::placeholder { color: rgba(230, 233, 245, 0.45) !important; }
84
+ [data-theme="dark"] [data-sticky-id] .bg-black\/10 { background-color: rgba(230, 233, 245, 0.16) !important; }
85
+ [data-theme="dark"] [data-sticky-id] .hover\:bg-black\/20:hover { background-color: rgba(230, 233, 245, 0.26) !important; }
86
+
87
+ /* Window title colors — read by Modal.tsx */
88
+ [data-theme="dark"] {
89
+ --window-title-active: #cdd6f4;
90
+ --window-title-inactive: #6c7086;
91
+ --taskbar-bg-rgb: 24 24 37; /* Catppuccin mantle */
92
+ --taskbar-border-color: #313244;
93
+ }
94
+
95
+ /* Documents app — page content styling. The editor is a bare contenteditable
96
+ and Tailwind's preflight strips list markers and element margins, so
97
+ restore them for anything typed into or imported from a document; images
98
+ are click-to-resize (menu) and never overflow the page. */
99
+ .docs-editor ul { list-style: disc; padding-left: 1.5rem; margin: 0.25rem 0; }
100
+ .docs-editor ul ul { list-style: circle; }
101
+ .docs-editor ol { list-style: decimal; padding-left: 1.5rem; margin: 0.25rem 0; }
102
+ .docs-editor li { margin: 0.125rem 0; }
103
+ .docs-editor p { margin: 0 0 0.5rem; }
104
+ .docs-editor img { max-width: 100%; height: auto; cursor: pointer; }
105
+ .docs-editor img:hover { outline: 2px solid rgba(59, 130, 246, 0.45); outline-offset: 1px; }
@@ -0,0 +1,3 @@
1
+ export { SOUND_PACKS, SOUND_PACK_KEYS, SOUND_TYPES, SOUND_TYPE_LABELS, getSoundConfig, playClick, playError, playLogout, playNotification, playStartup, playSuccess, playTimerDone, previewSound, setAllSounds, setSoundForType, soundsEnabled, toggleSounds } from './chunk-D7PYW2QS.js';
2
+ //# sourceMappingURL=sounds-NT4DEZGD.js.map
3
+ //# sourceMappingURL=sounds-NT4DEZGD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"sounds-NT4DEZGD.js"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * react-os-shell base styles — the full stylesheet: UI kit + window chrome.
3
+ *
4
+ * Consumers import this once near their app entry:
5
+ *
6
+ * import "react-os-shell/styles.css";
7
+ *
8
+ * Since 4.16.0 this is an umbrella over two halves, so a consumer taking
9
+ * `react-os-shell/ui` can load `ui.css` alone and skip the window, taskbar,
10
+ * desktop and sticky-note rules it will never render. The rules, their order,
11
+ * and the resulting cascade are unchanged — no selector appears in both halves,
12
+ * so the split is order-independent (asserted by tests/cssSplit.test.ts).
13
+ *
14
+ * Import EXACTLY ONE of this and ui.css. Taking both doubles every rule.
15
+ *
16
+ * themes.css is imported by ui.css, and is also exported standalone
17
+ * ("react-os-shell/themes.css") for consumers that build their CSS granularly.
18
+ */
19
+
20
+ @import "tailwindcss";
21
+ @import "./ui.css";
22
+ @import "./shell.css";
@@ -0,0 +1,249 @@
1
+ /**
2
+ * react-os-shell theme variants — accent + surface-tint remaps for the
3
+ * pink / green / grey / blue themes and the user-picked custom accent.
4
+ *
5
+ * useTheme() stamps `data-theme="<name>"` on <html> and, when the user
6
+ * picks a custom accent color, `data-custom-accent` plus the --accent-*
7
+ * shade scale. This file turns those attributes into looks by remapping
8
+ * the blue accent utilities (bg-blue-600 buttons, text-blue-700 links,
9
+ * focus rings, checkbox accents) and tinting the neutral gray surfaces.
10
+ *
11
+ * styles.css imports this file, so plain `import 'react-os-shell/styles.css'`
12
+ * already includes it. It is exported standalone ("react-os-shell/themes.css")
13
+ * only for consumers that build their CSS granularly.
14
+ *
15
+ * Dark-theme remaps are NOT here — they live in styles.css, because dark
16
+ * is a readability baseline rather than an accent variant.
17
+ *
18
+ * Upstreamed 2026-06-13 from the admin portal's index.css so all three
19
+ * EFFICIENT portals + the demo share one source of truth.
20
+ */
21
+
22
+ /* ═══════════════════════════════════════════════════
23
+ Theme: Pink
24
+ Swaps the blue accent to pink/rose throughout
25
+ ═══════════════════════════════════════════════════ */
26
+
27
+ /* Accent backgrounds */
28
+ [data-theme="pink"] .bg-blue-600 { background-color: #db2777 !important; }
29
+ [data-theme="pink"] .bg-blue-700 { background-color: #be185d !important; }
30
+ [data-theme="pink"] .bg-blue-500 { background-color: #ec4899 !important; }
31
+ [data-theme="pink"] .bg-blue-100 { background-color: #fce7f3 !important; }
32
+ [data-theme="pink"] .bg-blue-50 { background-color: #fdf2f8 !important; }
33
+
34
+ /* Accent text */
35
+ [data-theme="pink"] .text-blue-600 { color: #db2777 !important; }
36
+ [data-theme="pink"] .text-blue-700 { color: #be185d !important; }
37
+ [data-theme="pink"] .text-blue-800 { color: #9d174d !important; }
38
+ [data-theme="pink"] .text-blue-500 { color: #ec4899 !important; }
39
+
40
+ /* Accent borders */
41
+ [data-theme="pink"] .border-blue-600 { border-color: #db2777 !important; }
42
+ [data-theme="pink"] .border-blue-500 { border-color: #ec4899 !important; }
43
+ [data-theme="pink"] .border-blue-400 { border-color: #f472b6 !important; }
44
+ [data-theme="pink"] .border-blue-300 { border-color: #f9a8d4 !important; }
45
+ [data-theme="pink"] .border-blue-200 { border-color: #fbcfe8 !important; }
46
+
47
+ /* Accent hover */
48
+ [data-theme="pink"] .hover\:bg-blue-700:hover { background-color: #be185d !important; }
49
+ [data-theme="pink"] .hover\:bg-blue-100:hover { background-color: #fce7f3 !important; }
50
+ [data-theme="pink"] .hover\:bg-blue-50:hover { background-color: #fdf2f8 !important; }
51
+ [data-theme="pink"] .hover\:text-blue-800:hover { color: #9d174d !important; }
52
+ [data-theme="pink"] .hover\:border-blue-300:hover { border-color: #f9a8d4 !important; }
53
+
54
+ /* Focus rings */
55
+ [data-theme="pink"] .focus\:border-blue-500:focus { border-color: #ec4899 !important; }
56
+ [data-theme="pink"] .focus\:ring-blue-500:focus { --tw-ring-color: #ec4899 !important; }
57
+
58
+ /* Checkbox accent */
59
+ [data-theme="pink"] input[type="checkbox"].text-blue-600 { accent-color: #db2777; }
60
+ [data-theme="pink"] input[type="range"].accent-blue-600 { accent-color: #db2777; }
61
+
62
+ /* Ring colors */
63
+ [data-theme="pink"] .ring-blue-300 { --tw-ring-color: #f9a8d4 !important; }
64
+
65
+ /* Pink tint on backgrounds */
66
+ [data-theme="pink"] .bg-white { background-color: #fff5f9 !important; }
67
+ [data-theme="pink"] .bg-gray-100 { background-color: #fce7f3 !important; }
68
+ [data-theme="pink"] .bg-gray-50 { background-color: #fdf2f8 !important; }
69
+ [data-theme="pink"] .bg-gray-200 { background-color: #fbcfe8 !important; }
70
+
71
+ /* Pink tint on borders — kept light to distinguish from accent */
72
+ [data-theme="pink"] .border-gray-200 { border-color: #fce7f3 !important; }
73
+ [data-theme="pink"] .border-gray-300 { border-color: #fbcfe8 !important; }
74
+ [data-theme="pink"] .border-gray-100 { border-color: #fdf2f8 !important; }
75
+ [data-theme="pink"] .divide-gray-200 > :not(:last-child) { border-color: #fce7f3 !important; }
76
+ [data-theme="pink"] .divide-gray-100 > :not(:last-child) { border-color: #fdf2f8 !important; }
77
+
78
+ /* Pink hover states */
79
+ [data-theme="pink"] .hover\:bg-gray-50:hover { background-color: #fdf2f8 !important; }
80
+ [data-theme="pink"] .hover\:bg-gray-100:hover { background-color: #fce7f3 !important; }
81
+ [data-theme="pink"] .hover\:bg-gray-200:hover { background-color: #fbcfe8 !important; }
82
+
83
+
84
+ /* ═══════════════════════════════════════════════════
85
+ Theme: Green
86
+ Swaps the blue accent to green/emerald throughout
87
+ ═══════════════════════════════════════════════════ */
88
+
89
+ /* Accent backgrounds */
90
+ [data-theme="green"] .bg-blue-600 { background-color: #059669 !important; }
91
+ [data-theme="green"] .bg-blue-700 { background-color: #047857 !important; }
92
+ [data-theme="green"] .bg-blue-500 { background-color: #10b981 !important; }
93
+ [data-theme="green"] .bg-blue-100 { background-color: #d1fae5 !important; }
94
+ [data-theme="green"] .bg-blue-50 { background-color: #ecfdf5 !important; }
95
+
96
+ /* Accent text */
97
+ [data-theme="green"] .text-blue-600 { color: #059669 !important; }
98
+ [data-theme="green"] .text-blue-700 { color: #047857 !important; }
99
+ [data-theme="green"] .text-blue-800 { color: #065f46 !important; }
100
+ [data-theme="green"] .text-blue-500 { color: #10b981 !important; }
101
+
102
+ /* Accent borders */
103
+ [data-theme="green"] .border-blue-600 { border-color: #059669 !important; }
104
+ [data-theme="green"] .border-blue-500 { border-color: #10b981 !important; }
105
+ [data-theme="green"] .border-blue-400 { border-color: #34d399 !important; }
106
+ [data-theme="green"] .border-blue-300 { border-color: #6ee7b7 !important; }
107
+ [data-theme="green"] .border-blue-200 { border-color: #a7f3d0 !important; }
108
+
109
+ /* Accent hover */
110
+ [data-theme="green"] .hover\:bg-blue-700:hover { background-color: #047857 !important; }
111
+ [data-theme="green"] .hover\:bg-blue-100:hover { background-color: #d1fae5 !important; }
112
+ [data-theme="green"] .hover\:bg-blue-50:hover { background-color: #ecfdf5 !important; }
113
+ [data-theme="green"] .hover\:text-blue-800:hover { color: #065f46 !important; }
114
+ [data-theme="green"] .hover\:border-blue-300:hover { border-color: #6ee7b7 !important; }
115
+
116
+ /* Focus rings */
117
+ [data-theme="green"] .focus\:border-blue-500:focus { border-color: #10b981 !important; }
118
+ [data-theme="green"] .focus\:ring-blue-500:focus { --tw-ring-color: #10b981 !important; }
119
+
120
+ /* Checkbox accent */
121
+ [data-theme="green"] input[type="checkbox"].text-blue-600 { accent-color: #059669; }
122
+ [data-theme="green"] input[type="range"].accent-blue-600 { accent-color: #059669; }
123
+
124
+ /* Ring colors */
125
+ [data-theme="green"] .ring-blue-300 { --tw-ring-color: #6ee7b7 !important; }
126
+
127
+ /* Green tint on backgrounds */
128
+ [data-theme="green"] .bg-white { background-color: #f5fef7 !important; }
129
+ [data-theme="green"] .bg-gray-100 { background-color: #dcfce7 !important; }
130
+ [data-theme="green"] .bg-gray-50 { background-color: #ecfdf5 !important; }
131
+ [data-theme="green"] .bg-gray-200 { background-color: #bbf7d0 !important; }
132
+
133
+ /* Green tint on borders — kept light to distinguish from accent */
134
+ [data-theme="green"] .border-gray-200 { border-color: #dcfce7 !important; }
135
+ [data-theme="green"] .border-gray-300 { border-color: #bbf7d0 !important; }
136
+ [data-theme="green"] .border-gray-100 { border-color: #ecfdf5 !important; }
137
+ [data-theme="green"] .divide-gray-200 > :not(:last-child) { border-color: #dcfce7 !important; }
138
+ [data-theme="green"] .divide-gray-100 > :not(:last-child) { border-color: #ecfdf5 !important; }
139
+
140
+ /* Green hover states */
141
+ [data-theme="green"] .hover\:bg-gray-50:hover { background-color: #ecfdf5 !important; }
142
+ [data-theme="green"] .hover\:bg-gray-100:hover { background-color: #dcfce7 !important; }
143
+ [data-theme="green"] .hover\:bg-gray-200:hover { background-color: #bbf7d0 !important; }
144
+
145
+
146
+ /* ═══════════════════════════════════════════════════
147
+ Theme: Grey
148
+ A darker, more contrasty neutral theme
149
+ ═══════════════════════════════════════════════════ */
150
+
151
+ /* Grey tint on backgrounds */
152
+ [data-theme="grey"] .bg-white { background-color: #f3f4f6 !important; }
153
+ [data-theme="grey"] .bg-gray-100 { background-color: #e5e7eb !important; }
154
+ [data-theme="grey"] .bg-gray-50 { background-color: #f3f4f6 !important; }
155
+ [data-theme="grey"] .bg-gray-200 { background-color: #d1d5db !important; }
156
+
157
+ /* Grey tint on borders */
158
+ [data-theme="grey"] .border-gray-200 { border-color: #d1d5db !important; }
159
+ [data-theme="grey"] .border-gray-300 { border-color: #9ca3af !important; }
160
+ [data-theme="grey"] .border-gray-100 { border-color: #e5e7eb !important; }
161
+ [data-theme="grey"] .divide-gray-200 > :not(:last-child) { border-color: #d1d5db !important; }
162
+ [data-theme="grey"] .divide-gray-100 > :not(:last-child) { border-color: #e5e7eb !important; }
163
+
164
+ /* Grey hover states */
165
+ [data-theme="grey"] .hover\:bg-gray-50:hover { background-color: #e5e7eb !important; }
166
+ [data-theme="grey"] .hover\:bg-gray-100:hover { background-color: #d1d5db !important; }
167
+ [data-theme="grey"] .hover\:bg-gray-200:hover { background-color: #9ca3af !important; }
168
+
169
+ /* Grey accent — dark gray buttons */
170
+ [data-theme="grey"] .bg-blue-600 { background-color: #374151 !important; }
171
+ [data-theme="grey"] .bg-blue-700 { background-color: #1f2937 !important; }
172
+ [data-theme="grey"] .bg-blue-500 { background-color: #4b5563 !important; }
173
+ [data-theme="grey"] .bg-blue-100 { background-color: #e5e7eb !important; }
174
+ [data-theme="grey"] .bg-blue-50 { background-color: #f3f4f6 !important; }
175
+ [data-theme="grey"] .text-blue-600 { color: #374151 !important; }
176
+ [data-theme="grey"] .text-blue-700 { color: #1f2937 !important; }
177
+ [data-theme="grey"] .text-blue-800 { color: #111827 !important; }
178
+ [data-theme="grey"] .text-blue-500 { color: #4b5563 !important; }
179
+ [data-theme="grey"] .border-blue-600 { border-color: #374151 !important; }
180
+ [data-theme="grey"] .border-blue-500 { border-color: #4b5563 !important; }
181
+ [data-theme="grey"] .border-blue-400 { border-color: #6b7280 !important; }
182
+ [data-theme="grey"] .border-blue-300 { border-color: #9ca3af !important; }
183
+ [data-theme="grey"] .border-blue-200 { border-color: #d1d5db !important; }
184
+ [data-theme="grey"] .hover\:bg-blue-700:hover { background-color: #1f2937 !important; }
185
+ [data-theme="grey"] .hover\:bg-blue-100:hover { background-color: #e5e7eb !important; }
186
+ [data-theme="grey"] .hover\:bg-blue-50:hover { background-color: #f3f4f6 !important; }
187
+ [data-theme="grey"] .focus\:border-blue-500:focus { border-color: #4b5563 !important; }
188
+ [data-theme="grey"] .focus\:ring-blue-500:focus { --tw-ring-color: #4b5563 !important; }
189
+ [data-theme="grey"] input[type="checkbox"].text-blue-600 { accent-color: #374151; }
190
+ [data-theme="grey"] input[type="range"].accent-blue-600 { accent-color: #374151; }
191
+ [data-theme="grey"] .ring-blue-300 { --tw-ring-color: #9ca3af !important; }
192
+
193
+
194
+ /* ═══════════════════════════════════════════════════
195
+ Theme: Blue
196
+ Swaps the blue accent to a deeper blue, tints UI blue
197
+ ═══════════════════════════════════════════════════ */
198
+
199
+ /* Blue tint on backgrounds */
200
+ [data-theme="blue"] .bg-white { background-color: #f0f6ff !important; }
201
+ [data-theme="blue"] .bg-gray-100 { background-color: #dbeafe !important; }
202
+ [data-theme="blue"] .bg-gray-50 { background-color: #eff6ff !important; }
203
+ [data-theme="blue"] .bg-gray-200 { background-color: #bfdbfe !important; }
204
+
205
+ /* Blue tint on borders — kept light to distinguish from accent */
206
+ [data-theme="blue"] .border-gray-200 { border-color: #dbeafe !important; }
207
+ [data-theme="blue"] .border-gray-300 { border-color: #bfdbfe !important; }
208
+ [data-theme="blue"] .border-gray-100 { border-color: #eff6ff !important; }
209
+ [data-theme="blue"] .divide-gray-200 > :not(:last-child) { border-color: #dbeafe !important; }
210
+ [data-theme="blue"] .divide-gray-100 > :not(:last-child) { border-color: #eff6ff !important; }
211
+
212
+ /* Blue hover states */
213
+ [data-theme="blue"] .hover\:bg-gray-50:hover { background-color: #eff6ff !important; }
214
+ [data-theme="blue"] .hover\:bg-gray-100:hover { background-color: #dbeafe !important; }
215
+ [data-theme="blue"] .hover\:bg-gray-200:hover { background-color: #bfdbfe !important; }
216
+
217
+
218
+ /* ═══════════════════════════════════════════════════
219
+ Custom Accent Color
220
+ Overrides the blue accent when user picks a custom color.
221
+ useTheme() sets data-custom-accent + the --accent-* scale.
222
+ ═══════════════════════════════════════════════════ */
223
+ [data-custom-accent] .bg-blue-600 { background-color: var(--accent-600) !important; }
224
+ [data-custom-accent] .bg-blue-700 { background-color: var(--accent-700) !important; }
225
+ [data-custom-accent] .bg-blue-500 { background-color: var(--accent-500) !important; }
226
+ [data-custom-accent] .bg-blue-100 { background-color: var(--accent-100) !important; }
227
+ [data-custom-accent] .bg-blue-50 { background-color: var(--accent-50) !important; }
228
+ [data-custom-accent] .text-blue-600 { color: var(--accent-600) !important; }
229
+ [data-custom-accent] .text-blue-700 { color: var(--accent-700) !important; }
230
+ [data-custom-accent] .text-blue-800 { color: var(--accent-700) !important; }
231
+ [data-custom-accent] .text-blue-500 { color: var(--accent-500) !important; }
232
+ [data-custom-accent] .border-blue-600 { border-color: var(--accent-600) !important; }
233
+ [data-custom-accent] .border-blue-500 { border-color: var(--accent-500) !important; }
234
+ [data-custom-accent] .border-blue-400 { border-color: var(--accent-400) !important; }
235
+ [data-custom-accent] .border-blue-300 { border-color: var(--accent-300) !important; }
236
+ [data-custom-accent] .border-blue-200 { border-color: var(--accent-200) !important; }
237
+ [data-custom-accent] .hover\:bg-blue-700:hover { background-color: var(--accent-700) !important; }
238
+ /* The hover steps of the 600 ink and the 600 border. Without these a control
239
+ whose RESTING state follows the accent jumps back to literal blue under the
240
+ pointer — the timeline's Play pill is the one that showed it. */
241
+ [data-custom-accent] .hover\:text-blue-600:hover { color: var(--accent-600) !important; }
242
+ [data-custom-accent] .hover\:border-blue-600:hover { border-color: var(--accent-600) !important; }
243
+ [data-custom-accent] .hover\:bg-blue-100:hover { background-color: var(--accent-100) !important; }
244
+ [data-custom-accent] .hover\:bg-blue-50:hover { background-color: var(--accent-50) !important; }
245
+ [data-custom-accent] .focus\:border-blue-500:focus { border-color: var(--accent-500) !important; }
246
+ [data-custom-accent] .focus\:ring-blue-500:focus { --tw-ring-color: var(--accent-500) !important; }
247
+ [data-custom-accent] input[type="checkbox"].text-blue-600 { accent-color: var(--accent-600); }
248
+ [data-custom-accent] input[type="range"].accent-blue-600 { accent-color: var(--accent-600); }
249
+ [data-custom-accent] .ring-blue-300 { --tw-ring-color: var(--accent-300) !important; }