@powerhousedao/connect-core 6.2.3-dev.70 → 6.2.3-dev.72

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 (88) hide show
  1. package/dist/connect-router-11uRIT3z.d.ts.map +1 -1
  2. package/dist/{index-CL4fj0Pl.d.ts → index-Cm8rYUhs.d.ts} +17 -2
  3. package/dist/index-Cm8rYUhs.d.ts.map +1 -0
  4. package/dist/{index-DP1NfCUn.d.ts → index-DQ0nbYne.d.ts} +3 -2
  5. package/dist/{index-DP1NfCUn.d.ts.map → index-DQ0nbYne.d.ts.map} +1 -1
  6. package/dist/index-PjlUqG36.d.ts +2023 -0
  7. package/dist/index-PjlUqG36.d.ts.map +1 -0
  8. package/dist/index.d.ts +3 -3
  9. package/dist/index.js +9 -9
  10. package/dist/{plugin-host-DVwFg7-D.js → plugin-host-BSFfhXpz.js} +2 -2
  11. package/dist/{plugin-host-DVwFg7-D.js.map → plugin-host-BSFfhXpz.js.map} +1 -1
  12. package/dist/{plugin-ui-Br91idOH.js → plugin-ui-sO7AJLHj.js} +4 -4
  13. package/dist/{plugin-ui-Br91idOH.js.map → plugin-ui-sO7AJLHj.js.map} +1 -1
  14. package/dist/plugins.js +2 -2
  15. package/dist/{route-tree-91OurkPS.js → route-tree-D0aszMrk.js} +3 -6
  16. package/dist/route-tree-D0aszMrk.js.map +1 -0
  17. package/dist/route-tree.d.ts +36 -2088
  18. package/dist/route-tree.d.ts.map +1 -1
  19. package/dist/route-tree.js +18 -106
  20. package/dist/route-tree.js.map +1 -1
  21. package/dist/{router-uK9fOfed.js → router-8pekwJsk.js} +6 -6
  22. package/dist/router-8pekwJsk.js.map +1 -0
  23. package/dist/router.d.ts +2 -2
  24. package/dist/router.js +5 -5
  25. package/dist/routes/__root.d.ts +25 -0
  26. package/dist/routes/__root.d.ts.map +1 -0
  27. package/dist/routes/__root.js +17 -0
  28. package/dist/routes/__root.js.map +1 -0
  29. package/dist/routes/_app/$.d.ts +20 -0
  30. package/dist/routes/_app/$.d.ts.map +1 -0
  31. package/dist/routes/_app/$.js +17 -0
  32. package/dist/routes/_app/$.js.map +1 -0
  33. package/dist/routes/_app/d/$driveSlug/{-$nodeSlug}.d.ts +40 -0
  34. package/dist/routes/_app/d/$driveSlug/{-$nodeSlug}.d.ts.map +1 -0
  35. package/dist/routes/_app/d/$driveSlug/{-$nodeSlug}.js +26 -0
  36. package/dist/routes/_app/d/$driveSlug/{-$nodeSlug}.js.map +1 -0
  37. package/dist/routes/_app/d/$driveSlug.d.ts +28 -0
  38. package/dist/routes/_app/d/$driveSlug.d.ts.map +1 -0
  39. package/dist/routes/_app/d/$driveSlug.js +24 -0
  40. package/dist/routes/_app/d/$driveSlug.js.map +1 -0
  41. package/dist/routes/_app/index.d.ts +8 -0
  42. package/dist/routes/_app/index.d.ts.map +1 -0
  43. package/dist/routes/_app/index.js +14 -0
  44. package/dist/routes/_app/index.js.map +1 -0
  45. package/dist/routes/_app/settings/appearance.d.ts +15 -0
  46. package/dist/routes/_app/settings/appearance.d.ts.map +1 -0
  47. package/dist/routes/_app/settings/appearance.js +17 -0
  48. package/dist/routes/_app/settings/appearance.js.map +1 -0
  49. package/dist/routes/_app/settings/packages.d.ts +15 -0
  50. package/dist/routes/_app/settings/packages.d.ts.map +1 -0
  51. package/dist/routes/_app/settings/packages.js +17 -0
  52. package/dist/routes/_app/settings/packages.js.map +1 -0
  53. package/dist/routes/_app/settings.d.ts +25 -0
  54. package/dist/routes/_app/settings.d.ts.map +1 -0
  55. package/dist/routes/_app/settings.js +18 -0
  56. package/dist/routes/_app/settings.js.map +1 -0
  57. package/dist/routes/_app.d.ts +8 -0
  58. package/dist/routes/_app.d.ts.map +1 -0
  59. package/dist/routes/_app.js +14 -0
  60. package/dist/routes/_app.js.map +1 -0
  61. package/dist/{runtime-CYADuBKe.js → runtime-Y9B9UJK1.js} +2 -2
  62. package/dist/{runtime-CYADuBKe.js.map → runtime-Y9B9UJK1.js.map} +1 -1
  63. package/dist/runtime-config-D3YPhYyj.d.ts.map +1 -1
  64. package/dist/runtime-config.js +5 -5
  65. package/dist/runtime-config.js.map +1 -1
  66. package/dist/{runtime-flag-JJ_8aMvi.js → runtime-flag-CJWngtxE.js} +2 -2
  67. package/dist/{runtime-flag-JJ_8aMvi.js.map → runtime-flag-CJWngtxE.js.map} +1 -1
  68. package/dist/runtime.js +2 -2
  69. package/dist/{sidebar-C0RvssAJ.js → sidebar-DVQCwBYR.js} +22 -4
  70. package/dist/sidebar-DVQCwBYR.js.map +1 -0
  71. package/dist/{views-BOajEGgQ.js → views-CAbBIFzO.js} +40 -13
  72. package/dist/views-CAbBIFzO.js.map +1 -0
  73. package/dist/views.d.ts +1 -1
  74. package/dist/views.js +1 -1
  75. package/package.json +13 -9
  76. package/src/router/app-router.ts +1 -1
  77. package/src/router/create-target.ts +33 -0
  78. package/src/router/index.ts +2 -0
  79. package/src/router/modal-frame.tsx +2 -1
  80. package/src/router/perf-marks.ts +1 -1
  81. package/src/router/route-tree.ts +2 -5
  82. package/src/runtime/runtime-config.ts +2 -1
  83. package/src/views/modals.tsx +41 -5
  84. package/dist/index-CL4fj0Pl.d.ts.map +0 -1
  85. package/dist/route-tree-91OurkPS.js.map +0 -1
  86. package/dist/router-uK9fOfed.js.map +0 -1
  87. package/dist/sidebar-C0RvssAJ.js.map +0 -1
  88. package/dist/views-BOajEGgQ.js.map +0 -1
@@ -5,6 +5,8 @@ import {
5
5
  deleteNode,
6
6
  exportFile,
7
7
  getDocumentUpgradePreview,
8
+ getDriveName,
9
+ getNodeTarget,
8
10
  logout,
9
11
  openRenown,
10
12
  openTarget,
@@ -27,6 +29,7 @@ import type { ReactNode } from "react";
27
29
  import { createElement, useEffect, useId, useState } from "react";
28
30
  import type { ModalFrameProps } from "../router/modal-frame.js";
29
31
  import { ModalDialog, useModalFrame } from "../router/modal-frame.js";
32
+ import { useCreateDocumentTarget } from "../router/create-target.js";
30
33
  import { useDriveRouteData } from "../router/route-data.js";
31
34
 
32
35
  const buttonClass =
@@ -89,14 +92,17 @@ function useModal<T extends PHModal["type"]>(type: T) {
89
92
  : undefined;
90
93
  }
91
94
 
92
- /** A new document of the modal's type, in the open drive and folder. */
95
+ /** A new document of the modal's type: in its `driveId`, else the open drive
96
+ * and folder, else a drive picked here. */
93
97
  export function CreateDocumentModal() {
94
98
  const modal = useModal("createDocument");
95
99
  const module = useDocumentModelModuleById(
96
100
  modal?.documentType,
97
101
  modal?.documentModelVersion,
98
102
  );
99
- const { drive, folder } = useDriveRouteData();
103
+ const { folder } = useDriveRouteData();
104
+ const target = useCreateDocumentTarget(modal?.driveId);
105
+ const { drive } = target;
100
106
  const [name, setName] = useState("");
101
107
  const typeName = module?.documentModel.global.name ?? modal?.documentType;
102
108
  const create = async () => {
@@ -106,13 +112,14 @@ export function CreateDocumentModal() {
106
112
  drive.header.id,
107
113
  name.trim() || `New ${typeName}`,
108
114
  module.documentModel.global.id,
109
- folder?.id,
115
+ target.isOpenDrive ? folder?.id : undefined,
110
116
  undefined,
111
117
  undefined,
112
118
  undefined,
113
119
  modal.documentModelVersion,
114
120
  );
115
- setSelectedNode(node);
121
+ // Opens it in its drive, wherever the modal was opened.
122
+ openTarget(getNodeTarget(node, drive));
116
123
  };
117
124
  return (
118
125
  <Dialog
@@ -133,6 +140,7 @@ export function CreateDocumentModal() {
133
140
  >
134
141
  <form
135
142
  id="create-document"
143
+ className="flex flex-col gap-2"
136
144
  onSubmit={(event) => {
137
145
  event.preventDefault();
138
146
  void create();
@@ -148,8 +156,36 @@ export function CreateDocumentModal() {
148
156
  className="rounded border border-core-border bg-core-bg px-2 py-1"
149
157
  />
150
158
  </label>
159
+ {!!target.choices?.length && (
160
+ <label className="flex flex-col gap-1">
161
+ Drive
162
+ <select
163
+ value={drive?.header.id ?? ""}
164
+ onChange={(event) => target.pick(event.target.value)}
165
+ className="rounded border border-core-border bg-core-bg px-2 py-1"
166
+ >
167
+ {!drive && <option value="">Choose a drive</option>}
168
+ {target.choices.map((choice) => (
169
+ <option key={choice.header.id} value={choice.header.id}>
170
+ {getDriveName(choice)}
171
+ </option>
172
+ ))}
173
+ </select>
174
+ </label>
175
+ )}
151
176
  </form>
152
- {!drive && <p className="text-core-muted">Open a drive first.</p>}
177
+ {target.choices?.length === 0 && (
178
+ <p className="text-core-muted">
179
+ There's no drive to create it in.{" "}
180
+ <button
181
+ type="button"
182
+ className="underline"
183
+ onClick={() => showPHModal({ type: "addDrive" })}
184
+ >
185
+ Add a drive
186
+ </button>
187
+ </p>
188
+ )}
153
189
  </Dialog>
154
190
  );
155
191
  }
@@ -1 +0,0 @@
1
- {"version":3,"file":"index-CL4fj0Pl.d.ts","names":[],"sources":["../src/router/cold-start.ts","../src/router/app-router.ts","../src/router/navigation.ts","../src/router/perf-marks.ts","../src/router/core-views.tsx","../src/router/core-app.tsx","../src/router/modal-frame.tsx","../src/router/scroll.ts","../src/router/search.ts","../src/router/sidebar.ts","../src/router/settings.ts","../src/router/titles.ts"],"mappings":";;;;;;;iBAGgB;;;KCQJ,0BAA0B,KACpC;;;iBAMc,oBACd,OAAO,SACP,eAAe,0BACd;;iBA8Ba;;;;;iBClBA,wBACd,eAAe,sBACd;EAAiB;;;;;cChCP;;cAGA;;WAEX;;WAEA;;WAEA;;WAEA;;;iBAYc,kBAAkB;;iBAalB;;iBAYA,sBACd,QAAQ,KAAK,yBACb;;;cCvCI,aAAK;;iBAKK,SAAS,YAAY,QAAQ,kBAAkB,UAGvD;;iBAIQ,WAAW;;iBAaX,eAAe,QAAQ,QAAQ,kDAAmB,IAAA;;cASrD,WAA0C;;cAG1C,YAAY;;;;iBC3CT,eAAe;EAC7B,OAAO;EACP,WAAW;EACX;EACA,gBAAgB,KAAK;gCACtB,IAAA;;;;KCRW;EACV;;EAEA;EACA,SAAS;EACT,UAAU;;;YAIA;;IAER,aAAa,cAAc;;;;iBASf,iBAAa,cAAA;;;iBAMb,YAAY;EAC1B;EACA;EACA,UAAU;gCACX,IAAA;;;KC7BI,eAAe,KAAK;EACvB,SAAS;;;;iBAQK,+BAAwB;EAGL,UAAU;;;iBAO7B,kBAAkB,QAAQ,cAAc;;;;KCV5C,gBAAgB;;cAgBf,0BAA0B,iBAAiB;;iBAMxC,sBACd,QAAQ,0BACP;;iBAKa,mBAAmB,oBAAoB;;iBAKvC,uBAAuB,QAAQ;;;iBAY/B,oBACd,QAAQ,0BACP;;iBAYa,cAAc,iBAAiB;;;;KCnEnC;EACV;EACA,OAAO;IAAgB;IAAe;;;EAEtC;;;KAIU;;YAGA;IACR,MAAM;IACN,UAAU;;;KAIF,gBAAgB;EAAmB;EAAiB;;;iBAGhD,UAAU,QAAQ,YAAY;iBAe9B,gBAAY;;iBAOZ,kBAAkB;;;;KC/BtB;EACV;;EAEA;EACA,OAAO;IAAgB;IAAe;;;EAEtC;;EAEA,WAAW,SAAS;;;YAIV;IACR,WAAW;;;;cAKF;KAGR;EAAkB;EAAiB,YAAY;;;KAGxC,mBAAmB;EAC7B;EACA;EACA;;;iBAIc,eACd,eAAe,UACf,SAAS,uBACR;;iBAoBa,aAAa,QAAQ,YAAY;iBAWjC,mBAAe;;iBAOf,iBACd,kBAAkB,iBAClB,SAAS;;iBAUK,iBAAiB,QAAQ;;iBAKzB,wBACd,SACA;EAEA,kBAAkB;EAClB,SAAS;;;iBAYK,cAAc,8BAA8B;;;iBAM5C,qCAA2B;;iBAc3B,eAAe,gBAE0B;;;;iBC3IzC,SAAS;;iBAKT,cAAc;;iBAKd,WACd,OAAO,SACP,MAAM,4BACN"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"route-tree-91OurkPS.js","names":[],"sources":["../src/router/modal-frame.tsx","../src/router/modals.tsx","../src/router/route-tree.ts"],"sourcesContent":["import { closePHModal } from \"@powerhousedao/reactor-browser\";\nimport type { ComponentType, ReactNode } from \"react\";\nimport { createContext, useContext, useEffect, useRef } from \"react\";\n\n/** What a modal frame lays out: the modal's title, its content and its buttons. */\nexport type ModalFrameProps = {\n title: string;\n /** The title element's id, for the dialog's `aria-labelledby`. */\n titleId: string;\n actions: ReactNode;\n children: ReactNode;\n};\n\ndeclare module \"@tanstack/react-router\" {\n interface StaticDataRouteOption {\n /** Frames every core modal while the route matches; the deepest wins. */\n modalFrame?: ComponentType<ModalFrameProps>;\n }\n}\n\nexport const ModalFrameContext = createContext<\n ComponentType<ModalFrameProps> | undefined\n>(undefined);\n\n/** The frame the matched routes set, if any. */\nexport function useModalFrame() {\n return useContext(ModalFrameContext);\n}\n\n/** A modal `<dialog>`: it opens as a modal, and Escape or a click on the\n * backdrop closes the open modal. */\nexport function ModalDialog(props: {\n labelledBy: string;\n className?: string;\n children: ReactNode;\n}) {\n const ref = useRef<HTMLDialogElement>(null);\n useEffect(() => {\n const dialog = ref.current;\n if (dialog && !dialog.open) dialog.showModal();\n }, []);\n return (\n <dialog\n ref={ref}\n aria-labelledby={props.labelledBy}\n onCancel={(event) => {\n event.preventDefault();\n closePHModal();\n }}\n onClick={(event) => {\n if (event.target === event.currentTarget) closePHModal();\n }}\n className={props.className}\n >\n {props.children}\n </dialog>\n );\n}\n","import type { PHModal } from \"@powerhousedao/reactor-browser\";\nimport { usePHModal } from \"@powerhousedao/reactor-browser\";\nimport { useMatches } from \"@tanstack/react-router\";\nimport type { ComponentType, ErrorInfo, ReactNode } from \"react\";\nimport { Component, createElement, Suspense } from \"react\";\nimport type * as ModalViews from \"../views/modals.js\";\nimport type { ModalFrameProps } from \"./modal-frame.js\";\nimport { ModalFrameContext } from \"./modal-frame.js\";\n\n/** Modal views by modal type. Each reads the open modal with `usePHModal()`. */\nexport type ConnectModals = Partial<Record<PHModal[\"type\"], ComponentType>>;\n\ndeclare module \"@tanstack/react-router\" {\n interface StaticDataRouteOption {\n /** Replaces the host's view of these modals while the route matches. */\n modals?: ConnectModals;\n }\n}\n\n/** Core's modals: the ones editors, drive apps and the reactor open, so every\n * host has them. Each names its view in `@powerhousedao/connect-core/views`. */\nexport const CORE_MODAL_VIEWS = {\n createDocument: \"CreateDocumentModal\",\n login: \"LoginModal\",\n deleteItem: \"DeleteItemModal\",\n confirmDocumentUpgrade: \"ConfirmDocumentUpgradeModal\",\n downloadDocumentWithErrors: \"DownloadDocumentWithErrorsModal\",\n documentVersionUnsupported: \"DocumentVersionUnsupportedModal\",\n driveAuthRequired: \"DriveAuthRequiredModal\",\n} as const satisfies Partial<Record<PHModal[\"type\"], keyof typeof ModalViews>>;\n\ntype BoundaryProps = { modal: string; children: ReactNode };\n\n// A broken modal closes quietly instead of taking the page down; keyed by\n// modal, so the next one gets a fresh try.\nclass ModalErrorBoundary extends Component<BoundaryProps, { failed: boolean }> {\n state = { failed: false };\n\n static getDerivedStateFromError() {\n return { failed: true };\n }\n\n componentDidCatch(error: unknown, info: ErrorInfo) {\n console.error(\n `[connect] the ${this.props.modal} modal failed:`,\n error,\n info,\n );\n }\n\n render() {\n return this.state.failed ? null : this.props.children;\n }\n}\n\n/** The open modal's view: the deepest matched route's `staticData.modals`\n * entry for it, else `modals`', in the deepest `staticData.modalFrame`. */\nexport function ModalOutlet({ modals }: { modals: ConnectModals }) {\n const type = usePHModal()?.type;\n const routed = useMatches({\n select: (matches) =>\n type &&\n matches.reduce<ComponentType | undefined>(\n (found, match) => match.staticData.modals?.[type] ?? found,\n undefined,\n ),\n });\n const frame = useMatches({\n select: (matches) =>\n matches.reduce<ComponentType<ModalFrameProps> | undefined>(\n (found, match) => match.staticData.modalFrame ?? found,\n undefined,\n ),\n });\n const View = routed || (type && modals[type]);\n if (!type || !View) return null;\n return (\n <ModalErrorBoundary key={type} modal={type}>\n <ModalFrameContext.Provider value={frame}>\n <Suspense name=\"Modal\" fallback={null}>\n {/* A registered view, not one made here. */}\n {createElement(View)}\n </Suspense>\n </ModalFrameContext.Provider>\n </ModalErrorBoundary>\n );\n}\n","// The app's route tree: core's own, or a project's generated one when its\n// tsconfig maps this specifier to the tree.\nimport type { AnyRoute } from \"@tanstack/react-router\";\nimport { useRouter } from \"@tanstack/react-router\";\nimport { useSyncExternalStore } from \"react\";\nimport type {\n FileRoutesById,\n routeTree as appRouteTree,\n} from \"@powerhousedao/connect-core/route-tree\";\nimport type {\n ConnectRouteEntry,\n ConnectRouteRegistration,\n} from \"../registry.js\";\nimport {\n getConnectRegistry,\n notifyConnectRegistry,\n subscribeConnectRegistry,\n} from \"../registry.js\";\nimport type { DRIVE_ROUTE_ID, NODE_ROUTE_ID } from \"./route-data.js\";\n\nexport { DRIVE_PENDING_MS } from \"./route-components.js\";\nexport type { ConnectRouteRegistration } from \"../registry.js\";\n\n/** The home route's id; a tree change that moves it is a type error here. */\nexport const HOME_ROUTE_ID = \"/_app/\" satisfies keyof FileRoutesById;\n/** The `_app` layout's id; a project's _app/ routes nest in it. */\nexport const APP_ROUTE_ID = \"/_app\";\nconst SETTINGS_ROUTE_ID = \"/_app/settings\";\n\ntype RouteOptions = { id?: string; path?: string };\n\n// Generated routes carry their full id only once a router initialises them.\nfunction findChild(parent: AnyRoute, idOrPath: string) {\n const children = (parent.children ?? []) as AnyRoute[];\n const child = children.find((route) => {\n const options = route.options as RouteOptions;\n return options.id === idOrPath || options.path === idOrPath;\n });\n if (!child) throw new Error(`Connect's route tree lacks ${idOrPath}`);\n return child;\n}\n\n// Named, so declarations name the tree instead of inlining its type.\nexport type ConnectRootRoute = typeof appRouteTree;\nexport type ConnectRoutes = {\n routeTree: ConnectRootRoute;\n rootRoute: ConnectRootRoute;\n appRoute: FileRoutesById[typeof APP_ROUTE_ID];\n homeRoute: FileRoutesById[typeof HOME_ROUTE_ID];\n /** The drive layout, around the node route. */\n driveRoute: FileRoutesById[typeof DRIVE_ROUTE_ID];\n /** The open folder or document; the drive's root without a node. */\n nodeRoute: FileRoutesById[typeof NODE_ROUTE_ID];\n settingsRoute: FileRoutesById[typeof SETTINGS_ROUTE_ID];\n};\n\n/** Connect's routes in `routeTree`, core's or a project's generated one, which\n * holds the same routes. Deployment routes attach to these. */\nexport function connectRoutes(routeTree: AnyRoute): ConnectRoutes {\n const appRoute = findChild(routeTree, APP_ROUTE_ID);\n const driveRoute = findChild(appRoute, \"/d/$driveSlug\");\n return {\n routeTree: routeTree as ConnectRootRoute,\n rootRoute: routeTree as ConnectRootRoute,\n appRoute: appRoute as ConnectRoutes[\"appRoute\"],\n homeRoute: findChild(appRoute, \"/\") as ConnectRoutes[\"homeRoute\"],\n driveRoute: driveRoute as ConnectRoutes[\"driveRoute\"],\n nodeRoute: findChild(\n driveRoute,\n \"/{-$nodeSlug}\",\n ) as ConnectRoutes[\"nodeRoute\"],\n settingsRoute: findChild(\n appRoute,\n \"/settings\",\n ) as ConnectRoutes[\"settingsRoute\"],\n };\n}\n\n/** Code routes, e.g. `createRoute({ getParentRoute: () => rootRoute })`, join\n * their parent's file routes; an embedding app without the router plugin adds routes so. */\nexport function addConnectRoutes(routes: readonly AnyRoute[]) {\n for (const route of routes) {\n const parent = route.options.getParentRoute() as AnyRoute | undefined;\n if (!parent) throw new Error(\"A Connect route needs getParentRoute\");\n const children = (parent.children ?? []) as AnyRoute[];\n if (children.includes(route)) continue;\n // A project's file route keeps its path; the code route steps aside.\n const path = (route.options as RouteOptions).path;\n if (path && children.some((child) => samePath(child, path))) {\n console.warn(`[connect] a route already serves \"${path}\"; skipping`);\n continue;\n }\n parent.addChildren([...children, route]);\n }\n}\n\nconst trimSlashes = (path: string) => path.replace(/^\\/+|\\/+$/g, \"\");\n\nfunction samePath(route: AnyRoute, path: string) {\n const own = (route.options as RouteOptions).path;\n return own !== undefined && trimSlashes(own) === trimSlashes(path);\n}\n\n/** Takes `routes` out of their parents, e.g. when the module that made them is replaced. */\nexport function removeConnectRoutes(routes: readonly AnyRoute[]) {\n for (const route of routes) {\n const parent = route.options.getParentRoute() as AnyRoute | undefined;\n const children = (parent?.children ?? []) as AnyRoute[];\n if (children.includes(route)) {\n parent?.addChildren(children.filter((child) => child !== route));\n }\n }\n}\n\n/** The routes `registration` gives for `tree`'s core routes. */\nexport function resolveConnectRoutes(\n registration: ConnectRouteRegistration,\n tree: AnyRoute,\n): readonly AnyRoute[] {\n return typeof registration === \"function\"\n ? registration(connectRoutes(tree))\n : registration;\n}\n\n/** Adds code routes to the app's router, e.g. a package's settings tab below\n * `settingsRoute`; a running router takes them in. Returns the unregister. */\nexport function registerConnectRoutes(\n registration: ConnectRouteRegistration,\n): () => void {\n const registry = getConnectRegistry();\n const entry: ConnectRouteEntry = { registration, added: [] };\n registry.routes = [...registry.routes, entry];\n const bound = registry.app;\n if (bound) {\n const tree = bound.bundle.router.routeTree;\n entry.added = [...resolveConnectRoutes(registration, tree)];\n addConnectRoutes(entry.added);\n rebuildRoutes(bound.bundle.router);\n }\n return () => {\n registry.routes = registry.routes.filter((other) => other !== entry);\n const router = registry.app?.bundle.router;\n const ids = new Set<string>(entry.added.map((route) => route.id as string));\n const remove = () => {\n // The router reads a cached match's route later; those go with them.\n router?.clearCache({ filter: (match) => ids.has(match.routeId) });\n removeConnectRoutes(entry.added);\n if (router) rebuildRoutes(router);\n };\n // Leaving a route needs it: from one of these, go home before they go.\n const open = router?.state.matches.some((match) => ids.has(match.routeId));\n if (router && open) {\n void router.navigate({ to: \"/\", replace: true }).then(remove);\n } else {\n remove();\n }\n };\n}\n\n/** A file route a package offers to other Connects; `ph build` generates the\n * list from its hosts/connect/routes, parents before children. */\nexport type PackageRoute = {\n route: AnyRoute;\n /** The route's full id, e.g. `/_app/reports`. */\n id: string;\n /** Its path below its parent, e.g. `/reports`; none for a pathless layout. */\n path?: string;\n /** Its parent's full id: a Connect route's, or one of the package's. */\n parentId: string;\n};\n\nconst ROOT_ID = \"__root__\";\n\n// Before a router initialises a tree, its ids are only in the routes' options.\nfunction findRouteById(tree: AnyRoute, id: string): AnyRoute | undefined {\n if (id === ROOT_ID) return tree;\n const walk = (route: AnyRoute, routeId: string): AnyRoute | undefined => {\n for (const child of (route.children ?? []) as AnyRoute[]) {\n const options = child.options as RouteOptions;\n const own = options.id ?? options.path ?? \"\";\n const childId = `${routeId}${own.startsWith(\"/\") ? \"\" : \"/\"}${own}`;\n if (childId === id) return child;\n if (id.startsWith(childId)) {\n const found = walk(child, childId);\n if (found) return found;\n }\n }\n return undefined;\n };\n return walk(tree, \"\");\n}\n\nfunction routeHolds() {\n const registry = getConnectRegistry();\n registry.routeHolds ??= { count: 0, settled: new Set() };\n return registry.routeHolds;\n}\n\n/** Marks routes as still loading, e.g. a package's; unknown paths wait for\n * them before showing not found. Returns the release. */\nexport function holdConnectRoutes() {\n const holds = routeHolds();\n holds.count++;\n let released = false;\n return () => {\n if (released) return;\n released = true;\n holds.count--;\n if (holds.count > 0) return;\n for (const settle of holds.settled) settle();\n holds.settled.clear();\n };\n}\n\n/** Resolves once no routes are loading, or after `timeoutMs`. */\nexport function connectRoutesSettled(timeoutMs = 10_000) {\n const holds = routeHolds();\n if (holds.count === 0) return Promise.resolve();\n return new Promise<void>((resolve) => {\n const settle = () => {\n clearTimeout(timer);\n holds.settled.delete(settle);\n resolve();\n };\n const timer = setTimeout(settle, timeoutMs);\n holds.settled.add(settle);\n });\n}\n\n/** Adds a package's file routes below the app's routes with the same ids; a\n * route whose id the app already serves is skipped. Returns the unregister. */\nexport function registerPackageRoutes(routes: readonly PackageRoute[]) {\n return registerConnectRoutes(({ routeTree }) => {\n const own = new Map<string, AnyRoute>();\n for (const entry of routes) {\n const parent =\n own.get(entry.parentId) ?? findRouteById(routeTree, entry.parentId);\n if (!parent) {\n console.warn(\n `[connect] no route \"${entry.parentId}\" for \"${entry.id}\"`,\n );\n continue;\n }\n if (findRouteById(routeTree, entry.id)) {\n console.warn(\n `[connect] a route already serves \"${entry.id}\"; skipping`,\n );\n continue;\n }\n const relativeId = entry.path ?? entry.id.slice(entry.parentId.length);\n entry.route.update({\n id: relativeId,\n path: entry.path,\n getParentRoute: () => parent,\n } as never);\n own.set(entry.id, entry.route);\n }\n return [...own.values()];\n });\n}\n\ntype RebuildableRouter = {\n buildRouteTree(): unknown;\n setRoutes(caches: never): void;\n invalidate(): Promise<unknown>;\n};\n\nfunction rebuildRoutes(router: RebuildableRouter) {\n router.setRoutes(router.buildRouteTree() as never);\n void router.invalidate();\n // For views that list routes, e.g. the nav and the settings tabs.\n notifyConnectRegistry();\n}\n\n/** The router's routes by id, read again when routes are added or removed. */\nexport function useRoutesById() {\n const router = useRouter();\n const routesById = () => router.routesById;\n // The server snapshot too: the loading shell is prerendered.\n return useSyncExternalStore(subscribeConnectRegistry, routesById, routesById);\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"router-uK9fOfed.js","names":[],"sources":["../src/router/perf-marks.ts","../src/router/scroll.ts","../src/router/search.ts","../src/router/navigation.ts","../src/router/connect-router.ts","../src/router/app-router.ts","../src/router/core-app.tsx"],"sourcesContent":["import type { AnyRouter } from \"@tanstack/react-router\";\n\n/** `localStorage[PERF_STORAGE_KEY] = \"1\"` or `?perf=1` turns the marks on in production. */\nexport const PERF_STORAGE_KEY = \"ph:perf\";\n\n/** The measures each navigation writes, as the bench reads them. */\nexport const ROUTER_MEASURES = {\n /** `navigation.open` to the router starting the navigation. */\n click: \"nav click\",\n /** Route loaders, until the router commits the matches. */\n loader: \"nav loader\",\n /** The commit until React has rendered it. */\n commit: \"nav commit\",\n /** The click (or the navigation's start) to the next frame after render. */\n total: \"nav total\",\n} as const;\n\n// Chrome's Performance panel shows these as \"Connect › Router\".\nconst DETAIL = {\n devtools: { dataType: \"track-entry\", track: \"Router\", trackGroup: \"Connect\" },\n} as const;\n\nlet marking = 0;\nlet clickedAt: number | undefined;\n\n/** On in dev builds; elsewhere only with the runtime flag. */\nexport function routerPerfEnabled(dev: boolean = import.meta.env.DEV) {\n if (dev) return true;\n try {\n return (\n new URLSearchParams(location.search).get(\"perf\") === \"1\" ||\n localStorage.getItem(PERF_STORAGE_KEY) === \"1\"\n );\n } catch {\n return false;\n }\n}\n\n/** Marks a navigation's click; a no-op unless a router is being marked. */\nexport function markNavigationClick() {\n if (!marking) return;\n clickedAt = performance.now();\n performance.mark(\"nav:click\", { detail: DETAIL });\n}\n\nfunction measure(name: string, start: number | undefined, end: number) {\n if (start === undefined) return;\n performance.measure(name, { start, end, detail: DETAIL });\n}\n\n/** Writes each navigation's phases as performance measures; returns the unsubscribe. */\nexport function markRouterNavigations(\n router: Pick<AnyRouter, \"subscribe\">,\n enabled = routerPerfEnabled(),\n) {\n if (!enabled) return () => {};\n marking++;\n let generation = 0;\n let clicked: number | undefined;\n let navigated: number | undefined;\n let loading: number | undefined;\n let loaded: number | undefined;\n const unsubscribes = [\n router.subscribe(\"onBeforeNavigate\", () => {\n generation++;\n navigated = performance.now();\n clicked = clickedAt;\n clickedAt = undefined;\n measure(ROUTER_MEASURES.click, clicked, navigated);\n loading = loaded = undefined;\n }),\n router.subscribe(\"onBeforeLoad\", () => {\n loading = performance.now();\n }),\n router.subscribe(\"onLoad\", () => {\n loaded = performance.now();\n measure(ROUTER_MEASURES.loader, loading, loaded);\n }),\n router.subscribe(\"onRendered\", () => {\n measure(ROUTER_MEASURES.commit, loaded, performance.now());\n const current = generation;\n const start = clicked ?? navigated;\n // The frame after render, as close to paint as a script sees.\n requestAnimationFrame(() =>\n setTimeout(() => {\n if (current === generation) {\n measure(ROUTER_MEASURES.total, start, performance.now());\n }\n }),\n );\n }),\n ];\n return () => {\n marking--;\n for (const unsubscribe of unsubscribes) unsubscribe();\n };\n}\n","import type {\n AnyRouter,\n ParsedLocation,\n RouterHistory,\n} from \"@tanstack/react-router\";\n\ntype ScrollRouter = Pick<AnyRouter, \"subscribe\" | \"_scroll\" | \"options\"> & {\n history: RouterHistory;\n};\n\nconst TRAVERSALS = new Set([\"BACK\", \"FORWARD\", \"GO\"]);\nconst traversals = new WeakMap<object, { traversal: boolean }>();\n\n/** The router's `scrollRestoration`: on for back/forward only; other\n * navigations reset the content view in `bindConnectScroll`. */\nexport function connectScrollRestoration() {\n // The first load restores a reloaded page's scroll.\n const state = { traversal: true };\n const restore = ({ location }: { location: ParsedLocation }) =>\n state.traversal || !!location.hash;\n traversals.set(restore, state);\n return restore;\n}\n\n/** Tracks history actions, and resets a scrolled content view on new views. */\nexport function bindConnectScroll(router: ScrollRouter, contentViewId: string) {\n const state = traversals.get(router.options.scrollRestoration as object);\n if (!state) return () => {};\n const unsubscribeHistory = router.history.subscribe(({ action }) => {\n state.traversal = TRAVERSALS.has(action.type);\n });\n if (typeof document === \"undefined\") return unsubscribeHistory;\n\n // Read in the scroll event, where layout is clean, not at navigation.\n let scrolledView: Element | undefined;\n let windowScrolled = false;\n const onScroll = (event: Event) => {\n const target = event.target;\n if (target === document) {\n windowScrolled = window.scrollY > 0 || window.scrollX > 0;\n } else if (target instanceof Element && target.id === contentViewId) {\n scrolledView = target.scrollTop > 0 ? target : undefined;\n }\n };\n document.addEventListener(\"scroll\", onScroll, {\n capture: true,\n passive: true,\n });\n\n let resetScroll = true;\n const unsubscribes = [\n unsubscribeHistory,\n // The navigation's `resetScroll`, before the router clears it on render.\n router.subscribe(\"onBeforeRouteMount\", () => {\n resetScroll = router._scroll.n;\n }),\n router.subscribe(\"onRendered\", ({ toLocation }) => {\n if (state.traversal || toLocation.hash || !resetScroll) return;\n if (scrolledView?.isConnected) scrolledView.scrollTo(0, 0);\n if (windowScrolled) window.scrollTo(0, 0);\n scrolledView = undefined;\n windowScrolled = false;\n }),\n ];\n return () => {\n document.removeEventListener(\"scroll\", onScroll, { capture: true });\n for (const unsubscribe of unsubscribes) unsubscribe();\n };\n}\n","import {\n FEATURE_FLAG_PARAM_PREFIX,\n GLOBAL_SEARCH_PARAMS,\n parseRevisionHistoryPage,\n REVISION_HISTORY_PAGE_PARAM,\n REVISION_HISTORY_PARAM,\n searchParamsToString,\n} from \"@powerhousedao/reactor-browser\";\nimport type { SearchMiddleware } from \"@tanstack/react-router\";\nimport { retainSearchParams } from \"@tanstack/react-router\";\n\n// Shared with reactor-browser's fallback navigation.\nexport { FEATURE_FLAG_PARAM_PREFIX, GLOBAL_SEARCH_PARAMS };\n\n/** Connect's query params: plain strings, as in the URL. */\nexport type ConnectSearch = Record<string, string | undefined>;\n\nconst retainFeatureFlags: SearchMiddleware<ConnectSearch> = ({\n search,\n next,\n}) => {\n const result = { ...next(search) };\n for (const [key, value] of Object.entries(search)) {\n if (key.startsWith(FEATURE_FLAG_PARAM_PREFIX) && !(key in result)) {\n result[key] = value;\n }\n }\n return result;\n};\n\n/** The root route's middlewares; they apply to every navigation and redirect. */\nexport const connectSearchMiddlewares: SearchMiddleware<ConnectSearch>[] = [\n retainSearchParams<ConnectSearch>([...GLOBAL_SEARCH_PARAMS]),\n retainFeatureFlags,\n];\n\n/** Lets every param through; routes add none of their own. */\nexport function validateConnectSearch(\n search: Record<string, unknown>,\n): ConnectSearch {\n return search as ConnectSearch;\n}\n\n/** Parses a query string into plain string values, unlike the JSON default. */\nexport function parseConnectSearch(searchStr: string): ConnectSearch {\n return Object.fromEntries(new URLSearchParams(searchStr));\n}\n\n/** Writes plain `key=value` pairs, so other readers of the URL see strings. */\nexport function stringifyConnectSearch(search: Record<string, unknown>) {\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(search)) {\n if (value === undefined || value === null) continue;\n params.set(key, typeof value === \"string\" ? value : JSON.stringify(value));\n }\n const searchStr = searchParamsToString(params);\n return searchStr ? `?${searchStr}` : \"\";\n}\n\n/** The drive route's params: `?history` opens the document's revision history,\n * and `historyPage` (a positive integer; 1 is dropped) pages it. */\nexport function validateDriveSearch(\n search: Record<string, unknown>,\n): ConnectSearch {\n const result = { ...search } as ConnectSearch;\n if (result[REVISION_HISTORY_PARAM] === undefined) return result;\n result[REVISION_HISTORY_PARAM] = \"\";\n const page = parseRevisionHistoryPage(result[REVISION_HISTORY_PAGE_PARAM]);\n if (page > 1) result[REVISION_HISTORY_PAGE_PARAM] = String(page);\n // Undefined, not deleted: a route's search is merged over its parent's.\n else result[REVISION_HISTORY_PAGE_PARAM] = undefined;\n return result;\n}\n\n/** The defined values of `search`, for callers that take plain records. */\nexport function definedSearch(search: object): Record<string, string> {\n const record: Record<string, string> = {};\n for (const [key, value] of Object.entries(search)) {\n if (typeof value === \"string\") record[key] = value;\n else if (value !== undefined && value !== null) {\n record[key] = JSON.stringify(value);\n }\n }\n return record;\n}\n","import type {\n PHDriveTarget,\n PHNavigation,\n PHNavigationTarget,\n PHSettingsTarget,\n SetSearchParams,\n} from \"@powerhousedao/reactor-browser\";\nimport {\n applySearchUpdate,\n findDriveBySlugOrId,\n isSettingsTarget,\n makeDriveSlug,\n OPENED_FROM_STATE_KEY,\n openedFromIndex,\n resolveSearchUpdate,\n} from \"@powerhousedao/reactor-browser\";\nimport type {\n AnyRouter,\n HistoryState,\n MakeRouteMatchUnion,\n} from \"@tanstack/react-router\";\nimport { useRouterState } from \"@tanstack/react-router\";\nimport { useMemo } from \"react\";\nimport type { ConnectRouterBundle } from \"./connect-router.js\";\nimport { markNavigationClick } from \"./perf-marks.js\";\nimport { definedSearch } from \"./search.js\";\nimport { keepOpenedFrom, settingsTabs } from \"./settings.js\";\n\n// Hover intent: a pointer passing over cards doesn't preload each of them.\nconst PRELOAD_DELAY_MS = 50;\n\n/** The PH navigation backed by `router`; its hooks take the router directly,\n * so they work outside the RouterProvider. */\nexport function createConnectNavigation(\n connectRouter: ConnectRouterBundle,\n): PHNavigation & { dispose(): void } {\n const { router, homeRoute, nodeRoute, settingsRoute } = connectRouter;\n // Settings tabs can come from a project's routes, unknown to Connect's types.\n const anyRouter = router as unknown as AnyRouter;\n\n // A listed drive is addressed by its canonical slug, whatever form came in.\n const driveParams = (target: PHDriveTarget) => {\n const drive = findDriveBySlugOrId(\n router.options.context.store,\n target.driveSlug,\n );\n return {\n driveSlug: drive ? makeDriveSlug(drive) : target.driveSlug,\n nodeSlug: target.nodeSlug || undefined,\n };\n };\n\n // `true` is the first tab, so the URL names a tab without a redirect.\n const settingsPath = ({ settings }: PHSettingsTarget) => {\n const tab =\n settings === true ? settingsTabs(anyRouter).at(0)?.id : settings;\n return tab ? `${settingsRoute.fullPath}/${tab}` : settingsRoute.fullPath;\n };\n\n // In-document writes keep the entry's state, so its opened-from index too.\n const setSearch: PHNavigation[\"setSearch\"] = (update, options) => {\n void router.navigate({\n to: \".\",\n search: (prev) => applySearchUpdate({}, update(definedSearch(prev))),\n state: true,\n replace: options?.replace,\n resetScroll: false,\n });\n };\n\n const showsSettings = () =>\n router.state.matches.some((match) => match.routeId === settingsRoute.id);\n\n // A push remembers the entry it leaves; a replace keeps what that one had,\n // as does a move between settings tabs.\n const openedFromState = (\n replace: boolean | undefined,\n target: PHNavigationTarget | undefined,\n ) => {\n const { state } = router.history.location;\n const next =\n replace || (isSettingsTarget(target) && showsSettings())\n ? keepOpenedFrom(state)\n : ({\n [OPENED_FROM_STATE_KEY]: state.__TSR_index,\n } as unknown as HistoryState);\n return () => next;\n };\n\n const targetKey = (target: PHNavigationTarget | undefined) => {\n if (!target) return homeRoute.id;\n if (isSettingsTarget(target)) return settingsPath(target);\n const { driveSlug, nodeSlug } = driveParams(target);\n return JSON.stringify([driveSlug, nodeSlug ?? \"\"]);\n };\n let keyedMatches: readonly MakeRouteMatchUnion[] | undefined;\n let matchesKey: string | undefined;\n const currentKey = (matches: readonly MakeRouteMatchUnion[]) => {\n if (matches === keyedMatches) return matchesKey;\n keyedMatches = matches;\n const drive = matches.find((match) => match.routeId === nodeRoute.id);\n const settings = matches.some(\n (match) => match.routeId === settingsRoute.id,\n );\n if (drive) {\n matchesKey = targetKey(drive.params as PHDriveTarget);\n } else if (settings) {\n // A tab's key is its path, as settingsPath builds it.\n matchesKey = matches.at(-1)?.fullPath.replace(/\\/$/, \"\");\n } else {\n matchesKey = matches.find(\n (match) => match.routeId === homeRoute.id,\n )?.routeId;\n }\n return matchesKey;\n };\n\n // Hrefs depend only on the target and the global params of the current search.\n const hrefs = new Map<string, string>();\n let hrefsSearch: string | undefined;\n\n const setSearchParams: SetSearchParams = (update, options) =>\n setSearch((prev) => resolveSearchUpdate(prev, update), options);\n\n let preloadTimer: ReturnType<typeof setTimeout> | undefined;\n return {\n location: () => router.history.location,\n // The root route's middlewares add the global params to `search`.\n open: (target, options) => {\n markNavigationClick();\n const search = applySearchUpdate({}, options?.search ?? {});\n const replace = options?.replace;\n const state = openedFromState(replace, target);\n if (!target) {\n void router.navigate({\n to: homeRoute.fullPath,\n search,\n replace,\n state,\n });\n return;\n }\n if (isSettingsTarget(target)) {\n void anyRouter.navigate({\n to: settingsPath(target),\n search,\n replace,\n state,\n });\n return;\n }\n void router.navigate({\n to: nodeRoute.fullPath,\n params: driveParams(target),\n search,\n replace,\n state,\n });\n },\n // The public href, base path included; global params as `open` keeps them.\n hrefFor: (target) => {\n const { searchStr } = router.latestLocation;\n if (searchStr !== hrefsSearch) {\n hrefs.clear();\n hrefsSearch = searchStr;\n }\n const key = targetKey(target);\n let href = hrefs.get(key);\n if (href === undefined) {\n const location = !target\n ? router.buildLocation({ to: homeRoute.fullPath, search: {} })\n : isSettingsTarget(target)\n ? anyRouter.buildLocation({ to: settingsPath(target), search: {} })\n : router.buildLocation({\n to: nodeRoute.fullPath,\n params: driveParams(target),\n search: {},\n });\n href = location.publicHref;\n hrefs.set(key, href);\n }\n return href;\n },\n // One key per shown matches, so each link's selector is a string compare.\n useIsCurrent: (target) => {\n // The settings page itself is current on any of its tabs.\n const anyTab = isSettingsTarget(target) && target.settings === true;\n const key = anyTab ? `${settingsRoute.fullPath}/` : targetKey(target);\n return useRouterState({\n router,\n select: (state) => {\n const current = currentKey(state.matches);\n return anyTab ? !!current?.startsWith(key) : current === key;\n },\n });\n },\n preload: (target) => {\n clearTimeout(preloadTimer);\n if (!target) return;\n preloadTimer = setTimeout(() => {\n const preloading = isSettingsTarget(target)\n ? anyRouter.preloadRoute({ to: settingsPath(target) })\n : router.preloadRoute({\n to: nodeRoute.fullPath,\n params: driveParams(target),\n });\n preloading.catch(() => undefined);\n }, PRELOAD_DELAY_MS);\n },\n setSearch,\n // The presented matches' params, else the location's.\n useSearchParams() {\n const search = useRouterState({\n router,\n select: (state) =>\n state.matches.at(-1)?.search ?? state.location.search,\n });\n return useMemo(() => definedSearch(search), [search]);\n },\n useSetSearchParams: () => setSearchParams,\n closeOpened: () => {\n const { state } = router.history.location;\n const from = openedFromIndex(state, state.__TSR_index);\n if (from === undefined) return false;\n router.history.go(from - state.__TSR_index);\n return true;\n },\n dispose: () => clearTimeout(preloadTimer),\n };\n}\n","import type { DriveArrivals, PHStore } from \"@powerhousedao/reactor-browser\";\nimport {\n getPHStoreSubscribe,\n isRoutedModal,\n modalFromSearch,\n} from \"@powerhousedao/reactor-browser\";\nimport type {\n AnyRoute,\n ErrorRouteComponent,\n NotFoundRouteComponent,\n RouteComponent,\n Router,\n RouterHistory,\n} from \"@tanstack/react-router\";\nimport { createRouter } from \"@tanstack/react-router\";\nimport type { ErrorInfo, PropsWithChildren, ReactElement } from \"react\";\nimport type { ConnectPluginUiSet } from \"../plugins/plugin-ui.js\";\nimport { applyConnectPluginUi } from \"../plugins/plugin-ui.js\";\nimport { markRouterNavigations } from \"./perf-marks.js\";\nimport { bindConnectScroll, connectScrollRestoration } from \"./scroll.js\";\nimport type { DriveRouteData } from \"./drive-route-loader.js\";\nimport type { ConnectRootRoute, ConnectRoutes } from \"./route-tree.js\";\nimport { createConnectNavigation } from \"./navigation.js\";\nimport { CoreError, CoreNotFound } from \"./core-views.js\";\nimport { CONTENT_VIEW_ID } from \"./route-components.js\";\nimport { addConnectRoutes, connectRoutes } from \"./route-tree.js\";\nimport { setSettingsRoute } from \"./settings.js\";\nimport { parseConnectSearch, stringifyConnectSearch } from \"./search.js\";\nimport { driveTitle } from \"./titles.js\";\n\nexport type ConnectRouterOptions = {\n store: PHStore;\n arrivals?: DriveArrivals;\n basepath?: string;\n history?: RouterHistory;\n InnerWrap?: (props: PropsWithChildren) => ReactElement;\n /** Shown while a route's loader or chunks are pending, after the router's `pendingMs`. */\n pendingComponent?: RouteComponent;\n /** Any route's loader or render error; the plugins', else core's error view. */\n errorComponent?: ErrorRouteComponent;\n /** The active plugins' UI, set on the routes that show core's views. */\n pluginUi?: ConnectPluginUiSet;\n /** Loaders' notFound(), e.g. a missing drive's; core's page by default. */\n notFoundComponent?: NotFoundRouteComponent;\n /** The tree to route with: `@powerhousedao/connect/route-tree`, core's or a project's. */\n routeTree: AnyRoute;\n /** Code routes added to the file routes; see `addConnectRoutes`. A function\n * receives the tree's core routes to attach to. */\n routes?:\n | readonly AnyRoute[]\n | ((routes: ConnectRoutes) => readonly AnyRoute[]);\n /** Reports a route's loader or render error; logged by default. */\n onCatch?: (error: unknown, info?: ErrorInfo) => void;\n /** Ends every document title; \"Connect\" without one. */\n appName?: string;\n /** Renders the loading shell: layouts show their pendingComponent, not their page. */\n shell?: boolean;\n};\n\nfunction reportRouteError(error: unknown, info?: ErrorInfo) {\n console.error(error, info?.componentStack ?? \"\");\n}\n\n/** The router over `TRouteTree`; a project's generated tree registers its own. */\nexport type ConnectRouterFor<TRouteTree extends AnyRoute> = Router<\n TRouteTree,\n \"never\",\n false,\n RouterHistory,\n Record<string, any>\n>;\n// Written out, not inferred; see ConnectRootRoute.\nexport type ConnectRouter = ConnectRouterFor<ConnectRootRoute>;\nexport type ConnectRouterBundle = Pick<\n ConnectRoutes,\n \"homeRoute\" | \"driveRoute\" | \"nodeRoute\" | \"settingsRoute\"\n> & { router: ConnectRouter };\n\nexport function createConnectRouter(\n options: ConnectRouterOptions,\n): ConnectRouterBundle {\n const { routeTree, homeRoute, driveRoute, nodeRoute, settingsRoute } =\n connectRoutes(options.routeTree);\n if (options.pluginUi) applyConnectPluginUi(routeTree, options.pluginUi);\n if (options.routes) {\n addConnectRoutes(\n typeof options.routes === \"function\"\n ? options.routes(connectRoutes(routeTree))\n : options.routes,\n );\n }\n setSettingsRoute(settingsRoute);\n const router = createRouter({\n routeTree,\n basepath: options.basepath,\n history: options.history,\n context: {\n store: options.store,\n arrivals: options.arrivals,\n appName: options.appName,\n shell: options.shell,\n },\n parseSearch: parseConnectSearch,\n stringifySearch: stringifyConnectSearch,\n scrollRestoration: connectScrollRestoration(),\n scrollToTopSelectors: [`#${CONTENT_VIEW_ID}`],\n InnerWrap: options.InnerWrap,\n defaultPendingComponent: options.pendingComponent,\n defaultErrorComponent:\n options.errorComponent ?? options.pluginUi?.errorComponent ?? CoreError,\n // Not per route: a route's notFoundComponent mounts a boundary that\n // re-renders on every navigation.\n defaultNotFoundComponent: options.notFoundComponent ?? CoreNotFound,\n defaultOnCatch: options.onCatch ?? reportRouteError,\n });\n return { router, homeRoute, driveRoute, nodeRoute, settingsRoute };\n}\n\nfunction writeSelection(store: PHStore, data: DriveRouteData | undefined) {\n // Drive first: a new drive resets the node.\n store.selectedDriveId = data?.driveId;\n store.selectedNodeId = data?.nodeId;\n}\n\n/** Makes `router` the store's navigation and writes the selection it commits. */\nexport function bindConnectRouter(\n connectRouter: ConnectRouterBundle,\n store: PHStore,\n) {\n const { router, nodeRoute } = connectRouter;\n\n // Only committed matches select; pending ones keep the open view.\n const commitSelection = () => {\n const matches = router.state.matches;\n const drive = matches.find((match) => match.routeId === nodeRoute.id);\n if (drive) {\n if (drive.status === \"success\" && drive.loaderData) {\n writeSelection(store, drive.loaderData);\n } else if (matches.some((match) => match.status === \"notFound\")) {\n // The drive's 404 page shows no drive.\n writeSelection(store, undefined);\n }\n return;\n }\n // Any other page (home, settings, a project's, a 404) shows no drive.\n const shown = matches.at(-1)?.status;\n if (shown === \"success\" || shown === \"notFound\") {\n writeSelection(store, undefined);\n }\n };\n\n // A routed modal is the URL's: the store holds what the location names,\n // unless a confirmation is open over it.\n const syncModal = () => {\n const routed = modalFromSearch(router.state.location.search);\n if (store.modal && !isRoutedModal(store.modal)) return;\n if (routed) {\n if (JSON.stringify(store.modal) !== JSON.stringify(routed)) {\n store.modal = routed;\n }\n } else if (isRoutedModal(store.modal)) {\n store.modal = undefined;\n }\n };\n\n // Set once, before the first render; selection setters navigate from the start.\n const navigation = createConnectNavigation(connectRouter);\n store.navigation = navigation;\n\n // The node route's head reads names from the store; a rename re-runs it.\n const shownTitle = () => {\n const node = router.state.matches.find((m) => m.routeId === nodeRoute.id);\n return driveTitle(store, node?.loaderData, router.options.context.appName);\n };\n let title = shownTitle();\n const retitle = () => {\n const next = shownTitle();\n if (next === title) return;\n title = next;\n void router.invalidate({ filter: (m) => m.routeId === nodeRoute.id });\n };\n\n // Before mount, so the view and scroll restoration see the new selection.\n const unsubscribes = [\n router.subscribe(\"onBeforeRouteMount\", commitSelection),\n router.subscribe(\"onResolved\", commitSelection),\n router.subscribe(\"onResolved\", () => {\n title = shownTitle();\n }),\n router.subscribe(\"onResolved\", syncModal),\n getPHStoreSubscribe(store, \"drives\")(retitle),\n markRouterNavigations(router),\n ];\n const unbindScroll = bindConnectScroll(router, CONTENT_VIEW_ID);\n commitSelection();\n syncModal();\n\n return () => {\n navigation.dispose();\n unbindScroll();\n for (const unsubscribe of unsubscribes) unsubscribe();\n if (store.navigation === navigation) store.navigation = undefined;\n };\n}\n","import type { PHStore } from \"@powerhousedao/reactor-browser\";\nimport { createDriveArrivals } from \"@powerhousedao/reactor-browser\";\nimport { getConnectPluginUi } from \"../plugins/plugin-ui.js\";\nimport { getConnectRegistry } from \"../registry.js\";\nimport type {\n ConnectRouterBundle,\n ConnectRouterOptions,\n} from \"./connect-router.js\";\nimport { bindConnectRouter, createConnectRouter } from \"./connect-router.js\";\nimport { resolveConnectRoutes } from \"./route-tree.js\";\n\nexport type ConnectAppRouterOptions = Omit<\n ConnectRouterOptions,\n \"store\" | \"arrivals\"\n>;\n\n/** The app's one router over `store`; created, and made the store's navigation,\n * on first use. Registered routes join `options.routes`. */\nexport function getConnectAppRouter(\n store: PHStore,\n options: () => ConnectAppRouterOptions,\n): ConnectRouterBundle {\n const registry = getConnectRegistry();\n const current = registry.app;\n if (current) {\n if (import.meta.env.DEV && current.store !== store) {\n throw new Error(\"Connect's router is already bound to another PH store\");\n }\n return current.bundle;\n }\n const { routes, ...rest } = options();\n const bundle = createConnectRouter({\n store,\n arrivals: createDriveArrivals(store),\n pluginUi: getConnectPluginUi(),\n ...rest,\n routes: (tree) => [\n ...(routes ? resolveConnectRoutes(routes, tree.routeTree) : []),\n ...registry.routes.flatMap((entry) => {\n entry.added = [\n ...resolveConnectRoutes(entry.registration, tree.routeTree),\n ];\n return entry.added;\n }),\n ],\n });\n registry.app = { store, bundle, unbind: bindConnectRouter(bundle, store) };\n return bundle;\n}\n\n/** Stops the app's router writing the selection, e.g. on HMR. */\nexport function disposeConnectAppRouter() {\n const registry = getConnectRegistry();\n registry.app?.unbind();\n registry.app = undefined;\n}\n","import type { PHStore } from \"@powerhousedao/reactor-browser\";\nimport { PHStoreProvider } from \"@powerhousedao/reactor-browser\";\nimport type { AnyRoute } from \"@tanstack/react-router\";\nimport { RouterProvider } from \"@tanstack/react-router\";\nimport type { ConnectAppRouterOptions } from \"./app-router.js\";\nimport { getConnectAppRouter } from \"./app-router.js\";\n\n/** A core-only app: `routeTree`'s views over `store`. */\nexport function ConnectCoreApp(props: {\n store: PHStore;\n routeTree: AnyRoute;\n basepath?: string;\n options?: () => Omit<ConnectAppRouterOptions, \"routeTree\">;\n}) {\n const { router } = getConnectAppRouter(props.store, () => ({\n basepath: props.basepath,\n ...props.options?.(),\n routeTree: props.routeTree,\n }));\n return (\n <PHStoreProvider store={props.store}>\n <RouterProvider router={router} />\n </PHStoreProvider>\n );\n}\n"],"mappings":";;;;;;;;;;AAGA,MAAa,mBAAmB;;AAGhC,MAAa,kBAAkB;;CAE7B,OAAO;;CAEP,QAAQ;;CAER,QAAQ;;CAER,OAAO;AACT;AAGA,MAAM,SAAS,EACb,UAAU;CAAE,UAAU;CAAe,OAAO;CAAU,YAAY;AAAU,EAC9E;AAEA,IAAI,UAAU;AACd,IAAI;;AAGJ,SAAgB,kBAAkB,MAAe,YAAY,IAAI,KAAK;CACpE,IAAI,KAAK,OAAO;CAChB,IAAI;EACF,OACE,IAAI,gBAAgB,SAAS,MAAM,CAAC,CAAC,IAAI,MAAM,MAAM,OACrD,aAAa,QAAA,SAAwB,MAAM;CAE/C,QAAQ;EACN,OAAO;CACT;AACF;;AAGA,SAAgB,sBAAsB;CACpC,IAAI,CAAC,SAAS;CACd,YAAY,YAAY,IAAI;CAC5B,YAAY,KAAK,aAAa,EAAE,QAAQ,OAAO,CAAC;AAClD;AAEA,SAAS,QAAQ,MAAc,OAA2B,KAAa;CACrE,IAAI,UAAU,KAAA,GAAW;CACzB,YAAY,QAAQ,MAAM;EAAE;EAAO;EAAK,QAAQ;CAAO,CAAC;AAC1D;;AAGA,SAAgB,sBACd,QACA,UAAU,kBAAkB,GAC5B;CACA,IAAI,CAAC,SAAS,aAAa,CAAC;CAC5B;CACA,IAAI,aAAa;CACjB,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,MAAM,eAAe;EACnB,OAAO,UAAU,0BAA0B;GACzC;GACA,YAAY,YAAY,IAAI;GAC5B,UAAU;GACV,YAAY,KAAA;GACZ,QAAQ,gBAAgB,OAAO,SAAS,SAAS;GACjD,UAAU,SAAS,KAAA;EACrB,CAAC;EACD,OAAO,UAAU,sBAAsB;GACrC,UAAU,YAAY,IAAI;EAC5B,CAAC;EACD,OAAO,UAAU,gBAAgB;GAC/B,SAAS,YAAY,IAAI;GACzB,QAAQ,gBAAgB,QAAQ,SAAS,MAAM;EACjD,CAAC;EACD,OAAO,UAAU,oBAAoB;GACnC,QAAQ,gBAAgB,QAAQ,QAAQ,YAAY,IAAI,CAAC;GACzD,MAAM,UAAU;GAChB,MAAM,QAAQ,WAAW;GAEzB,4BACE,iBAAiB;IACf,IAAI,YAAY,YACd,QAAQ,gBAAgB,OAAO,OAAO,YAAY,IAAI,CAAC;GAE3D,CAAC,CACH;EACF,CAAC;CACH;CACA,aAAa;EACX;EACA,KAAK,MAAM,eAAe,cAAc,YAAY;CACtD;AACF;;;ACtFA,MAAM,6BAAa,IAAI,IAAI;CAAC;CAAQ;CAAW;AAAI,CAAC;AACpD,MAAM,6BAAa,IAAI,QAAwC;;;AAI/D,SAAgB,2BAA2B;CAEzC,MAAM,QAAQ,EAAE,WAAW,KAAK;CAChC,MAAM,WAAW,EAAE,eACjB,MAAM,aAAa,CAAC,CAAC,SAAS;CAChC,WAAW,IAAI,SAAS,KAAK;CAC7B,OAAO;AACT;;AAGA,SAAgB,kBAAkB,QAAsB,eAAuB;CAC7E,MAAM,QAAQ,WAAW,IAAI,OAAO,QAAQ,iBAA2B;CACvE,IAAI,CAAC,OAAO,aAAa,CAAC;CAC1B,MAAM,qBAAqB,OAAO,QAAQ,WAAW,EAAE,aAAa;EAClE,MAAM,YAAY,WAAW,IAAI,OAAO,IAAI;CAC9C,CAAC;CACD,IAAI,OAAO,aAAa,aAAa,OAAO;CAG5C,IAAI;CACJ,IAAI,iBAAiB;CACrB,MAAM,YAAY,UAAiB;EACjC,MAAM,SAAS,MAAM;EACrB,IAAI,WAAW,UACb,iBAAiB,OAAO,UAAU,KAAK,OAAO,UAAU;OACnD,IAAI,kBAAkB,WAAW,OAAO,OAAO,eACpD,eAAe,OAAO,YAAY,IAAI,SAAS,KAAA;CAEnD;CACA,SAAS,iBAAiB,UAAU,UAAU;EAC5C,SAAS;EACT,SAAS;CACX,CAAC;CAED,IAAI,cAAc;CAClB,MAAM,eAAe;EACnB;EAEA,OAAO,UAAU,4BAA4B;GAC3C,cAAc,OAAO,QAAQ;EAC/B,CAAC;EACD,OAAO,UAAU,eAAe,EAAE,iBAAiB;GACjD,IAAI,MAAM,aAAa,WAAW,QAAQ,CAAC,aAAa;GACxD,IAAI,cAAc,aAAa,aAAa,SAAS,GAAG,CAAC;GACzD,IAAI,gBAAgB,OAAO,SAAS,GAAG,CAAC;GACxC,eAAe,KAAA;GACf,iBAAiB;EACnB,CAAC;CACH;CACA,aAAa;EACX,SAAS,oBAAoB,UAAU,UAAU,EAAE,SAAS,KAAK,CAAC;EAClE,KAAK,MAAM,eAAe,cAAc,YAAY;CACtD;AACF;;;ACnDA,MAAM,sBAAuD,EAC3D,QACA,WACI;CACJ,MAAM,SAAS,EAAE,GAAG,KAAK,MAAM,EAAE;CACjC,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,MAAM,GAC9C,IAAI,IAAI,WAAW,yBAAyB,KAAK,EAAE,OAAO,SACxD,OAAO,OAAO;CAGlB,OAAO;AACT;;AAGA,MAAa,2BAA8D,CACzE,mBAAkC,CAAC,GAAG,oBAAoB,CAAC,GAC3D,kBACF;;AAGA,SAAgB,sBACd,QACe;CACf,OAAO;AACT;;AAGA,SAAgB,mBAAmB,WAAkC;CACnE,OAAO,OAAO,YAAY,IAAI,gBAAgB,SAAS,CAAC;AAC1D;;AAGA,SAAgB,uBAAuB,QAAiC;CACtE,MAAM,SAAS,IAAI,gBAAgB;CACnC,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,MAAM,GAAG;EACjD,IAAI,UAAU,KAAA,KAAa,UAAU,MAAM;EAC3C,OAAO,IAAI,KAAK,OAAO,UAAU,WAAW,QAAQ,KAAK,UAAU,KAAK,CAAC;CAC3E;CACA,MAAM,YAAY,qBAAqB,MAAM;CAC7C,OAAO,YAAY,IAAI,cAAc;AACvC;;;AAIA,SAAgB,oBACd,QACe;CACf,MAAM,SAAS,EAAE,GAAG,OAAO;CAC3B,IAAI,OAAO,4BAA4B,KAAA,GAAW,OAAO;CACzD,OAAO,0BAA0B;CACjC,MAAM,OAAO,yBAAyB,OAAO,4BAA4B;CACzE,IAAI,OAAO,GAAG,OAAO,+BAA+B,OAAO,IAAI;MAE1D,OAAO,+BAA+B,KAAA;CAC3C,OAAO;AACT;;AAGA,SAAgB,cAAc,QAAwC;CACpE,MAAM,SAAiC,CAAC;CACxC,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,MAAM,GAC9C,IAAI,OAAO,UAAU,UAAU,OAAO,OAAO;MACxC,IAAI,UAAU,KAAA,KAAa,UAAU,MACxC,OAAO,OAAO,KAAK,UAAU,KAAK;CAGtC,OAAO;AACT;;;ACvDA,MAAM,mBAAmB;;;AAIzB,SAAgB,wBACd,eACoC;CACpC,MAAM,EAAE,QAAQ,WAAW,WAAW,kBAAkB;CAExD,MAAM,YAAY;CAGlB,MAAM,eAAe,WAA0B;EAC7C,MAAM,QAAQ,oBACZ,OAAO,QAAQ,QAAQ,OACvB,OAAO,SACT;EACA,OAAO;GACL,WAAW,QAAQ,cAAc,KAAK,IAAI,OAAO;GACjD,UAAU,OAAO,YAAY,KAAA;EAC/B;CACF;CAGA,MAAM,gBAAgB,EAAE,eAAiC;EACvD,MAAM,MACJ,aAAa,OAAO,aAAa,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK;EAC1D,OAAO,MAAM,GAAG,cAAc,SAAS,GAAG,QAAQ,cAAc;CAClE;CAGA,MAAM,aAAwC,QAAQ,YAAY;EAChE,OAAY,SAAS;GACnB,IAAI;GACJ,SAAS,SAAS,kBAAkB,CAAC,GAAG,OAAO,cAAc,IAAI,CAAC,CAAC;GACnE,OAAO;GACP,SAAS,SAAS;GAClB,aAAa;EACf,CAAC;CACH;CAEA,MAAM,sBACJ,OAAO,MAAM,QAAQ,MAAM,UAAU,MAAM,YAAY,cAAc,EAAE;CAIzE,MAAM,mBACJ,SACA,WACG;EACH,MAAM,EAAE,UAAU,OAAO,QAAQ;EACjC,MAAM,OACJ,WAAY,iBAAiB,MAAM,KAAK,cAAc,IAClD,eAAe,KAAK,IACnB,GACE,wBAAwB,MAAM,YACjC;EACN,aAAa;CACf;CAEA,MAAM,aAAa,WAA2C;EAC5D,IAAI,CAAC,QAAQ,OAAO,UAAU;EAC9B,IAAI,iBAAiB,MAAM,GAAG,OAAO,aAAa,MAAM;EACxD,MAAM,EAAE,WAAW,aAAa,YAAY,MAAM;EAClD,OAAO,KAAK,UAAU,CAAC,WAAW,YAAY,EAAE,CAAC;CACnD;CACA,IAAI;CACJ,IAAI;CACJ,MAAM,cAAc,YAA4C;EAC9D,IAAI,YAAY,cAAc,OAAO;EACrC,eAAe;EACf,MAAM,QAAQ,QAAQ,MAAM,UAAU,MAAM,YAAY,UAAU,EAAE;EACpE,MAAM,WAAW,QAAQ,MACtB,UAAU,MAAM,YAAY,cAAc,EAC7C;EACA,IAAI,OACF,aAAa,UAAU,MAAM,MAAuB;OAC/C,IAAI,UAET,aAAa,QAAQ,GAAG,EAAE,CAAC,EAAE,SAAS,QAAQ,OAAO,EAAE;OAEvD,aAAa,QAAQ,MAClB,UAAU,MAAM,YAAY,UAAU,EACzC,CAAC,EAAE;EAEL,OAAO;CACT;CAGA,MAAM,wBAAQ,IAAI,IAAoB;CACtC,IAAI;CAEJ,MAAM,mBAAoC,QAAQ,YAChD,WAAW,SAAS,oBAAoB,MAAM,MAAM,GAAG,OAAO;CAEhE,IAAI;CACJ,OAAO;EACL,gBAAgB,OAAO,QAAQ;EAE/B,OAAO,QAAQ,YAAY;GACzB,oBAAoB;GACpB,MAAM,SAAS,kBAAkB,CAAC,GAAG,SAAS,UAAU,CAAC,CAAC;GAC1D,MAAM,UAAU,SAAS;GACzB,MAAM,QAAQ,gBAAgB,SAAS,MAAM;GAC7C,IAAI,CAAC,QAAQ;IACX,OAAY,SAAS;KACnB,IAAI,UAAU;KACd;KACA;KACA;IACF,CAAC;IACD;GACF;GACA,IAAI,iBAAiB,MAAM,GAAG;IAC5B,UAAe,SAAS;KACtB,IAAI,aAAa,MAAM;KACvB;KACA;KACA;IACF,CAAC;IACD;GACF;GACA,OAAY,SAAS;IACnB,IAAI,UAAU;IACd,QAAQ,YAAY,MAAM;IAC1B;IACA;IACA;GACF,CAAC;EACH;EAEA,UAAU,WAAW;GACnB,MAAM,EAAE,cAAc,OAAO;GAC7B,IAAI,cAAc,aAAa;IAC7B,MAAM,MAAM;IACZ,cAAc;GAChB;GACA,MAAM,MAAM,UAAU,MAAM;GAC5B,IAAI,OAAO,MAAM,IAAI,GAAG;GACxB,IAAI,SAAS,KAAA,GAAW;IAUtB,QATiB,CAAC,SACd,OAAO,cAAc;KAAE,IAAI,UAAU;KAAU,QAAQ,CAAC;IAAE,CAAC,IAC3D,iBAAiB,MAAM,IACrB,UAAU,cAAc;KAAE,IAAI,aAAa,MAAM;KAAG,QAAQ,CAAC;IAAE,CAAC,IAChE,OAAO,cAAc;KACnB,IAAI,UAAU;KACd,QAAQ,YAAY,MAAM;KAC1B,QAAQ,CAAC;IACX,CAAC,EAAA,CACS;IAChB,MAAM,IAAI,KAAK,IAAI;GACrB;GACA,OAAO;EACT;EAEA,eAAe,WAAW;GAExB,MAAM,SAAS,iBAAiB,MAAM,KAAK,OAAO,aAAa;GAC/D,MAAM,MAAM,SAAS,GAAG,cAAc,SAAS,KAAK,UAAU,MAAM;GACpE,OAAO,eAAe;IACpB;IACA,SAAS,UAAU;KACjB,MAAM,UAAU,WAAW,MAAM,OAAO;KACxC,OAAO,SAAS,CAAC,CAAC,SAAS,WAAW,GAAG,IAAI,YAAY;IAC3D;GACF,CAAC;EACH;EACA,UAAU,WAAW;GACnB,aAAa,YAAY;GACzB,IAAI,CAAC,QAAQ;GACb,eAAe,iBAAiB;IAO9B,CANmB,iBAAiB,MAAM,IACtC,UAAU,aAAa,EAAE,IAAI,aAAa,MAAM,EAAE,CAAC,IACnD,OAAO,aAAa;KAClB,IAAI,UAAU;KACd,QAAQ,YAAY,MAAM;IAC5B,CAAC,EAAA,CACM,YAAY,KAAA,CAAS;GAClC,GAAG,gBAAgB;EACrB;EACA;EAEA,kBAAkB;GAChB,MAAM,SAAS,eAAe;IAC5B;IACA,SAAS,UACP,MAAM,QAAQ,GAAG,EAAE,CAAC,EAAE,UAAU,MAAM,SAAS;GACnD,CAAC;GACD,OAAO,cAAc,cAAc,MAAM,GAAG,CAAC,MAAM,CAAC;EACtD;EACA,0BAA0B;EAC1B,mBAAmB;GACjB,MAAM,EAAE,UAAU,OAAO,QAAQ;GACjC,MAAM,OAAO,gBAAgB,OAAO,MAAM,WAAW;GACrD,IAAI,SAAS,KAAA,GAAW,OAAO;GAC/B,OAAO,QAAQ,GAAG,OAAO,MAAM,WAAW;GAC1C,OAAO;EACT;EACA,eAAe,aAAa,YAAY;CAC1C;AACF;;;AC1KA,SAAS,iBAAiB,OAAgB,MAAkB;CAC1D,QAAQ,MAAM,OAAO,MAAM,kBAAkB,EAAE;AACjD;AAiBA,SAAgB,oBACd,SACqB;CACrB,MAAM,EAAE,WAAW,WAAW,YAAY,WAAW,kBACnD,cAAc,QAAQ,SAAS;CACjC,IAAI,QAAQ,UAAU,qBAAqB,WAAW,QAAQ,QAAQ;CACtE,IAAI,QAAQ,QACV,iBACE,OAAO,QAAQ,WAAW,aACtB,QAAQ,OAAO,cAAc,SAAS,CAAC,IACvC,QAAQ,MACd;CAEF,iBAAiB,aAAa;CAwB9B,OAAO;EAAE,QAvBM,aAAa;GAC1B;GACA,UAAU,QAAQ;GAClB,SAAS,QAAQ;GACjB,SAAS;IACP,OAAO,QAAQ;IACf,UAAU,QAAQ;IAClB,SAAS,QAAQ;IACjB,OAAO,QAAQ;GACjB;GACA,aAAa;GACb,iBAAiB;GACjB,mBAAmB,yBAAyB;GAC5C,sBAAsB,CAAC,IAAI,iBAAiB;GAC5C,WAAW,QAAQ;GACnB,yBAAyB,QAAQ;GACjC,uBACE,QAAQ,kBAAkB,QAAQ,UAAU,kBAAkB;GAGhE,0BAA0B,QAAQ,qBAAqB;GACvD,gBAAgB,QAAQ,WAAW;EACrC,CACc;EAAG;EAAW;EAAY;EAAW;CAAc;AACnE;AAEA,SAAS,eAAe,OAAgB,MAAkC;CAExE,MAAM,kBAAkB,MAAM;CAC9B,MAAM,iBAAiB,MAAM;AAC/B;;AAGA,SAAgB,kBACd,eACA,OACA;CACA,MAAM,EAAE,QAAQ,cAAc;CAG9B,MAAM,wBAAwB;EAC5B,MAAM,UAAU,OAAO,MAAM;EAC7B,MAAM,QAAQ,QAAQ,MAAM,UAAU,MAAM,YAAY,UAAU,EAAE;EACpE,IAAI,OAAO;GACT,IAAI,MAAM,WAAW,aAAa,MAAM,YACtC,eAAe,OAAO,MAAM,UAAU;QACjC,IAAI,QAAQ,MAAM,UAAU,MAAM,WAAW,UAAU,GAE5D,eAAe,OAAO,KAAA,CAAS;GAEjC;EACF;EAEA,MAAM,QAAQ,QAAQ,GAAG,EAAE,CAAC,EAAE;EAC9B,IAAI,UAAU,aAAa,UAAU,YACnC,eAAe,OAAO,KAAA,CAAS;CAEnC;CAIA,MAAM,kBAAkB;EACtB,MAAM,SAAS,gBAAgB,OAAO,MAAM,SAAS,MAAM;EAC3D,IAAI,MAAM,SAAS,CAAC,cAAc,MAAM,KAAK,GAAG;EAChD,IAAI,QACE;OAAA,KAAK,UAAU,MAAM,KAAK,MAAM,KAAK,UAAU,MAAM,GACvD,MAAM,QAAQ;EAAA,OAEX,IAAI,cAAc,MAAM,KAAK,GAClC,MAAM,QAAQ,KAAA;CAElB;CAGA,MAAM,aAAa,wBAAwB,aAAa;CACxD,MAAM,aAAa;CAGnB,MAAM,mBAAmB;EACvB,MAAM,OAAO,OAAO,MAAM,QAAQ,MAAM,MAAM,EAAE,YAAY,UAAU,EAAE;EACxE,OAAO,WAAW,OAAO,MAAM,YAAY,OAAO,QAAQ,QAAQ,OAAO;CAC3E;CACA,IAAI,QAAQ,WAAW;CACvB,MAAM,gBAAgB;EACpB,MAAM,OAAO,WAAW;EACxB,IAAI,SAAS,OAAO;EACpB,QAAQ;EACR,OAAY,WAAW,EAAE,SAAS,MAAM,EAAE,YAAY,UAAU,GAAG,CAAC;CACtE;CAGA,MAAM,eAAe;EACnB,OAAO,UAAU,sBAAsB,eAAe;EACtD,OAAO,UAAU,cAAc,eAAe;EAC9C,OAAO,UAAU,oBAAoB;GACnC,QAAQ,WAAW;EACrB,CAAC;EACD,OAAO,UAAU,cAAc,SAAS;EACxC,oBAAoB,OAAO,QAAQ,CAAC,CAAC,OAAO;EAC5C,sBAAsB,MAAM;CAC9B;CACA,MAAM,eAAe,kBAAkB,QAAQ,eAAe;CAC9D,gBAAgB;CAChB,UAAU;CAEV,aAAa;EACX,WAAW,QAAQ;EACnB,aAAa;EACb,KAAK,MAAM,eAAe,cAAc,YAAY;EACpD,IAAI,MAAM,eAAe,YAAY,MAAM,aAAa,KAAA;CAC1D;AACF;;;;;ACzLA,SAAgB,oBACd,OACA,SACqB;CACrB,MAAM,WAAW,mBAAmB;CACpC,MAAM,UAAU,SAAS;CACzB,IAAI,SAAS;EACX,IAAI,YAAY,IAAI,OAAO,QAAQ,UAAU,OAC3C,MAAM,IAAI,MAAM,uDAAuD;EAEzE,OAAO,QAAQ;CACjB;CACA,MAAM,EAAE,QAAQ,GAAG,SAAS,QAAQ;CACpC,MAAM,SAAS,oBAAoB;EACjC;EACA,UAAU,oBAAoB,KAAK;EACnC,UAAU,mBAAmB;EAC7B,GAAG;EACH,SAAS,SAAS,CAChB,GAAI,SAAS,qBAAqB,QAAQ,KAAK,SAAS,IAAI,CAAC,GAC7D,GAAG,SAAS,OAAO,SAAS,UAAU;GACpC,MAAM,QAAQ,CACZ,GAAG,qBAAqB,MAAM,cAAc,KAAK,SAAS,CAC5D;GACA,OAAO,MAAM;EACf,CAAC,CACH;CACF,CAAC;CACD,SAAS,MAAM;EAAE;EAAO;EAAQ,QAAQ,kBAAkB,QAAQ,KAAK;CAAE;CACzE,OAAO;AACT;;AAGA,SAAgB,0BAA0B;CACxC,MAAM,WAAW,mBAAmB;CACpC,SAAS,KAAK,OAAO;CACrB,SAAS,MAAM,KAAA;AACjB;;;;AC/CA,SAAgB,eAAe,OAK5B;CACD,MAAM,EAAE,WAAW,oBAAoB,MAAM,cAAc;EACzD,UAAU,MAAM;EAChB,GAAG,MAAM,UAAU;EACnB,WAAW,MAAM;CACnB,EAAE;CACF,OACE,oBAAC,iBAAD;EAAiB,OAAO,MAAM;EAC5B,UAAA,oBAAC,gBAAD,EAAwB,OAAS,CAAA;CAClB,CAAA;AAErB"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"sidebar-C0RvssAJ.js","names":[],"sources":["../src/router/cold-start.ts","../src/router/route-components.tsx","../src/router/titles.ts","../src/router/settings.ts","../src/router/route-data.ts","../src/router/sidebar.ts"],"sourcesContent":["import { useRouterState } from \"@tanstack/react-router\";\n\n/** True until the router has resolved its first location. */\nexport function useIsColdStart() {\n return useRouterState({ select: (state) => !state.resolvedLocation });\n}\n","import type {\n AnyRoute,\n AnyRouter,\n RouteComponent,\n} from \"@tanstack/react-router\";\nimport { Outlet, useMatch, useRouter } from \"@tanstack/react-router\";\nimport type { ReactNode } from \"react\";\nimport type {\n DocumentDriveDocument,\n FolderNode,\n} from \"@powerhousedao/shared/document-drive\";\nimport type { PHDocument } from \"@powerhousedao/shared/document-model\";\nimport { useIsColdStart } from \"./cold-start.js\";\n\n/** A drive view's props: drive apps and core's directory listing get the same. */\nexport type DriveViewProps = {\n drive: DocumentDriveDocument;\n /** The open folder; undefined at the drive's root. */\n folder?: FolderNode;\n /** The open document's view, when one is open. */\n children?: ReactNode;\n};\n\n/** A document view's props, e.g. core's JSON view or revision history. */\nexport type DocumentViewProps = { document: PHDocument };\n\n// Open views stay while a navigation loads; the pending view only after this.\nexport const DRIVE_PENDING_MS = 200;\n\n/** The scroll container of the content view. */\nexport const CONTENT_VIEW_ID = \"content-view\";\n\n/** A layout's content area: the matched route, in the container whose scroll\n * Connect resets on new views and restores on back and forward. */\nexport function ContentOutlet(props: { className?: string }) {\n return (\n <div\n className={props.className ?? \"flex h-full flex-col overflow-auto\"}\n id={CONTENT_VIEW_ID}\n data-scroll-restoration-id={CONTENT_VIEW_ID}\n >\n {useRouter().options.context.shell ? <LayoutPending /> : <Outlet />}\n </div>\n );\n}\n\n// The loading shell: the layout's own pendingComponent stands in for its page.\nfunction LayoutPending() {\n const router = useRouter<AnyRouter>();\n const routeId = useMatch({ strict: false, select: (match) => match.routeId });\n const routesById = router.routesById as Partial<Record<string, AnyRoute>>;\n const route = routeId ? routesById[routeId] : undefined;\n const Pending = route?.options.pendingComponent as RouteComponent | undefined;\n return Pending ? <Pending /> : null;\n}\n\n/** A note on a cold start; otherwise the open view stays while loading. */\nexport function DrivePending() {\n const isColdStart = useIsColdStart();\n if (!isColdStart) return null;\n return (\n <p role=\"status\" className=\"p-6 text-core-muted\">\n Loading drive…\n </p>\n );\n}\n","// Document titles for Connect's routes; route heads set them through <HeadContent />.\nimport type { PHStore } from \"@powerhousedao/reactor-browser\";\nimport { getDriveName } from \"@powerhousedao/reactor-browser\";\nimport type { DriveRouteData } from \"./drive-route-loader.js\";\n\nconst DEFAULT_APP_NAME = \"Connect\";\n\n/** The configured app name, else \"Connect\". */\nexport function appTitle(appName?: string) {\n return appName || DEFAULT_APP_NAME;\n}\n\n/** `Not found · <app>`. */\nexport function notFoundTitle(appName?: string) {\n return `Not found · ${appTitle(appName)}`;\n}\n\n/** `<node> · <drive> · <app>`, from the store so renames show. */\nexport function driveTitle(\n store: PHStore,\n data: DriveRouteData | undefined,\n appName?: string,\n) {\n const drive = data && store.drives?.find((d) => d.header.id === data.driveId);\n if (!drive) return appTitle(appName);\n const node = data.nodeId\n ? drive.state.global.nodes.find((n) => n.id === data.nodeId)\n : undefined;\n return [node?.name, getDriveName(drive)]\n .filter(Boolean)\n .concat(appTitle(appName))\n .join(\" · \");\n}\n","// The settings page: its tabs are the /settings route's children with `staticData.settings`.\nimport {\n OPENED_FROM_STATE_KEY,\n SETTINGS_PATH,\n} from \"@powerhousedao/reactor-browser\";\nimport type {\n AnyRoute,\n AnyRouter,\n HistoryState,\n StaticDataRouteOption,\n} from \"@tanstack/react-router\";\nimport { notFound, redirect, useRouter } from \"@tanstack/react-router\";\nimport type { ComponentType } from \"react\";\nimport { useMemo } from \"react\";\nimport { useRoutesById } from \"./route-tree.js\";\nimport type { ConnectRouterContext } from \"./drive-route-loader.js\";\nimport { appTitle } from \"./titles.js\";\n\n/** A settings tab, as a child route of /settings declares it in `staticData`. */\nexport type ConnectSettingsTab = {\n label: string;\n /** Ascending; Connect's own tabs use multiples of 10. */\n order: number;\n icon?: ComponentType<{ size?: number; className?: string }>;\n /** Marks the tab as destructive, e.g. the danger zone. */\n destructive?: boolean;\n /** Hidden, and redirected away from, when this returns false. */\n enabled?: (context: ConnectRouterContext) => boolean;\n};\n\ndeclare module \"@tanstack/react-router\" {\n interface StaticDataRouteOption {\n settings?: ConnectSettingsTab;\n }\n}\n\n/** The settings layout route's id. */\nexport const SETTINGS_ROUTE_ID = `/_app${SETTINGS_PATH}`;\n\n// Structural, not the router's match union: route options typed with it are circular.\ntype SettingsMatch = { routeId: string; staticData: StaticDataRouteOption };\n\n/** A listed tab: its id is its path below /settings. */\nexport type SettingsTabEntry = ConnectSettingsTab & {\n id: string;\n routeId: string;\n to: string;\n};\n\n/** The enabled tabs below `settingsRoute`, in order. */\nexport function settingsTabsOf(\n settingsRoute: AnyRoute,\n context: ConnectRouterContext,\n): SettingsTabEntry[] {\n const children = (settingsRoute.children ?? []) as AnyRoute[];\n const prefix = `${settingsRoute.fullPath}/`;\n return children\n .flatMap((route) => {\n const tab = (\n route.options as { staticData?: { settings?: ConnectSettingsTab } }\n ).staticData?.settings;\n if (!tab || tab.enabled?.(context) === false) return [];\n const { id: routeId, fullPath } = route as {\n id: string;\n fullPath: string;\n };\n const to = fullPath.replace(/\\/$/, \"\");\n return [{ ...tab, id: to.slice(prefix.length), routeId, to }];\n })\n .sort((a, b) => a.order - b.order || a.label.localeCompare(b.label));\n}\n\n/** The settings tabs of `router`'s tree; empty without a settings route. */\nexport function settingsTabs(router: AnyRouter): SettingsTabEntry[] {\n const settingsRoute = router.routesById[SETTINGS_ROUTE_ID] as\n | AnyRoute\n | undefined;\n if (!settingsRoute) return [];\n return settingsTabsOf(\n settingsRoute,\n router.options.context as ConnectRouterContext,\n );\n}\n\nexport function useSettingsTabs() {\n const router = useRouter();\n const routesById = useRoutesById();\n return useMemo(() => settingsTabs(router), [router, routesById]);\n}\n\n/** Whether `matches` show a tab that may stay: not bare /settings, not a disabled tab. */\nexport function showsSettingsTab(\n matches: readonly SettingsMatch[],\n context: ConnectRouterContext,\n) {\n const leaf = matches.at(-1);\n if (!leaf || leaf.routeId === SETTINGS_ROUTE_ID) return false;\n return leaf.staticData.settings?.enabled?.(context) !== false;\n}\n\nlet routerSettingsRoute: AnyRoute | undefined;\n\n/** The router's settings route: core's, or a project's override of it. */\nexport function setSettingsRoute(route?: AnyRoute) {\n routerSettingsRoute = route;\n}\n\n/** Sends bare /settings and a disabled tab to the first tab. */\nexport function redirectToSettingsTab({\n matches,\n context,\n}: {\n matches: readonly SettingsMatch[];\n context: ConnectRouterContext;\n}): void {\n if (showsSettingsTab(matches, context)) return;\n const first =\n routerSettingsRoute && settingsTabsOf(routerSettingsRoute, context).at(0);\n // oxlint-disable-next-line typescript/only-throw-error -- router control flow\n if (!first) throw notFound();\n // oxlint-disable-next-line typescript/only-throw-error -- router control flow\n throw redirect<AnyRouter>({ to: first.to, replace: true, state: true });\n}\n\n/** `Settings · <tab> · <app>`. */\nexport function settingsTitle(tabLabel: string | undefined, appName?: string) {\n return [\"Settings\", tabLabel, appTitle(appName)].filter(Boolean).join(\" · \");\n}\n\n/** Makes closing settings go home, not back to an entry that may be gone,\n * e.g. a deleted drive. */\nexport function useForgetSettingsOpenedFrom() {\n const router = useRouter();\n return () =>\n router.navigate({\n to: \".\",\n search: true,\n replace: true,\n resetScroll: false,\n state: (prev) =>\n ({ ...prev, [OPENED_FROM_STATE_KEY]: undefined }) as HistoryState,\n });\n}\n\n/** History state that keeps where the settings page was opened from. */\nexport function keepOpenedFrom(state: object) {\n const from: unknown = Reflect.get(state, OPENED_FROM_STATE_KEY);\n return { [OPENED_FROM_STATE_KEY]: from } as unknown as HistoryState;\n}\n","import { useDrives } from \"@powerhousedao/reactor-browser\";\nimport type {\n DocumentDriveDocument,\n FolderNode,\n} from \"@powerhousedao/shared/document-drive\";\nimport { useRouterState } from \"@tanstack/react-router\";\nimport type { DriveRouteData } from \"./drive-route-loader.js\";\n\n/** The drive layout route's id. */\nexport const DRIVE_ROUTE_ID = \"/_app/d/$driveSlug\";\n/** The node route's id: below the drive layout, with an optional node. */\nexport const NODE_ROUTE_ID = \"/_app/d/$driveSlug/{-$nodeSlug}\";\n\n/** The open drive, folder and document, from the node route's loader data.\n * Live: a drive's edits re-render the caller. */\nexport type DriveRouteView = {\n drive: DocumentDriveDocument | undefined;\n /** The open folder; undefined at the drive's root or on a document. */\n folder: FolderNode | undefined;\n /** The open document's id; undefined on a folder or the drive's root. */\n documentId: string | undefined;\n};\n\n/** The ids the node route resolved, or undefined outside a drive. */\nexport function useDriveRouteIds(): DriveRouteData | undefined {\n return useRouterState({\n select: (state) =>\n state.matches.find((match) => match.routeId === NODE_ROUTE_ID)\n ?.loaderData as DriveRouteData | undefined,\n });\n}\n\n/** What the drive routes show: the drive, and the folder or document open in it. */\nexport function useDriveRouteData(): DriveRouteView {\n const ids = useDriveRouteIds();\n const drives = useDrives();\n const drive = ids && drives?.find((d) => d.header.id === ids.driveId);\n const node = ids?.nodeId\n ? drive?.state.global.nodes.find((n) => n.id === ids.nodeId)\n : undefined;\n const folder = node?.kind === \"folder\" ? node : undefined;\n // A node the listed drive doesn't have yet was a document the loader fetched.\n return { drive, folder, documentId: folder ? undefined : ids?.nodeId };\n}\n","// What routes tell the sidebar layout: nav items and whether to show the sidebar.\nimport type { AnyRoute, AnyRouter } from \"@tanstack/react-router\";\nimport { useMatches, useRouter } from \"@tanstack/react-router\";\nimport type { ComponentType } from \"react\";\nimport { useMemo } from \"react\";\nimport { useRoutesById } from \"./route-tree.js\";\n\n/** A sidebar link to the route that declares it in `staticData.nav`. */\nexport type ConnectNavItem = {\n label: string;\n icon?: ComponentType<{ size?: number; className?: string }>;\n /** Ascending, after the drives. */\n order: number;\n};\n\n/** \"hidden\" drops the sidebar; \"collapsed\" keeps only its header and footer. */\nexport type SidebarMode = \"hidden\" | \"collapsed\";\n\ndeclare module \"@tanstack/react-router\" {\n interface StaticDataRouteOption {\n nav?: ConnectNavItem;\n sidebar?: SidebarMode;\n }\n}\n\nexport type NavRouteEntry = ConnectNavItem & { routeId: string; to: string };\n\n/** The routes with `staticData.nav`, in order; routes with params can't be listed. */\nexport function navRoutes(router: AnyRouter): NavRouteEntry[] {\n return Object.values(router.routesById as Record<string, AnyRoute>)\n .flatMap((route) => {\n const nav = (route.options as { staticData?: { nav?: ConnectNavItem } })\n .staticData?.nav;\n const { id: routeId, fullPath } = route as {\n id: string;\n fullPath: string;\n };\n if (!nav || fullPath.includes(\"$\")) return [];\n return [{ ...nav, routeId, to: fullPath.replace(/(.)\\/$/, \"$1\") }];\n })\n .sort((a, b) => a.order - b.order || a.label.localeCompare(b.label));\n}\n\nexport function useNavRoutes() {\n const router = useRouter();\n const routesById = useRoutesById();\n return useMemo(() => navRoutes(router), [router, routesById]);\n}\n\n/** The deepest match's `staticData.sidebar`, if any declares one. */\nexport function useSidebarMode(): SidebarMode | undefined {\n return useMatches({\n select: (matches) =>\n matches.findLast((match) => match.staticData.sidebar !== undefined)\n ?.staticData.sidebar,\n });\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"views-BOajEGgQ.js","names":["modalViews"],"sources":["../src/views/index-table.tsx","../src/views/directory-listing.tsx","../src/views/document-history.tsx","../src/views/document-json.tsx","../src/views/editor-host.tsx","../src/views/content.tsx","../src/views/home.tsx","../src/views/theme-toggle.tsx","../src/views/modals.tsx","../src/views/layout.tsx","../src/views/not-found-page.tsx","../src/views/route-views.tsx","../src/views/settings.tsx","../src/views/settings-packages.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\n\n/** `YYYY-MM-DD HH:mm` in UTC, as a server index lists it; \"-\" when unknown. */\nexport function formatModified(iso: string | undefined) {\n if (!iso) return \"-\";\n const date = new Date(iso);\n if (Number.isNaN(date.getTime())) return \"-\";\n return date.toISOString().slice(0, 16).replace(\"T\", \" \");\n}\n\n/** An \"Index of\" page: a title above a name / type / last modified table. */\nexport function IndexTable(props: {\n title: ReactNode;\n label: string;\n children: ReactNode;\n}) {\n return (\n <div className=\"p-6 font-mono text-sm text-core-fg\">\n <h1 className=\"mb-4 text-xl font-semibold\">{props.title}</h1>\n <table aria-label={props.label} className=\"w-full border-collapse\">\n <thead>\n <tr className=\"border-b border-core-border text-left text-core-muted\">\n <th className=\"py-1 pr-6 font-normal\">Name</th>\n <th className=\"py-1 pr-6 font-normal\">Type</th>\n <th className=\"py-1 font-normal\">Last modified</th>\n </tr>\n </thead>\n <tbody>{props.children}</tbody>\n </table>\n </div>\n );\n}\n\nexport function IndexRow(props: {\n name: ReactNode;\n type: ReactNode;\n modified: ReactNode;\n}) {\n return (\n <tr className=\"border-b border-core-border/50 hover:bg-core-hover\">\n <td className=\"py-1 pr-6\">{props.name}</td>\n <td className=\"py-1 pr-6 text-core-muted\">{props.type}</td>\n <td className=\"py-1 whitespace-nowrap text-core-muted\">\n {props.modified}\n </td>\n </tr>\n );\n}\n\nexport const linkClass = \"text-core-link underline-offset-2 hover:underline\";\n","import {\n getDriveName,\n makeDriveSlug,\n makeNodeSlug,\n useDocumentById,\n useLinkProps,\n} from \"@powerhousedao/reactor-browser\";\nimport type {\n DocumentDriveDocument,\n FolderNode,\n Node,\n} from \"@powerhousedao/shared/document-drive\";\nimport { isFileNode } from \"@powerhousedao/shared/document-drive\";\nimport type { ReactNode } from \"react\";\nimport { Component, Fragment, Suspense } from \"react\";\nimport type { DriveViewProps } from \"../router/route-components.js\";\nimport {\n formatModified,\n IndexRow,\n IndexTable,\n linkClass,\n} from \"./index-table.js\";\n\nfunction NodeLink(props: {\n drive: DocumentDriveDocument;\n node: Node | undefined;\n children: ReactNode;\n}) {\n const link = useLinkProps({\n driveSlug: makeDriveSlug(props.drive),\n nodeSlug: props.node ? makeNodeSlug(props.node) : undefined,\n });\n return (\n <a {...link} className={linkClass}>\n {props.children}\n </a>\n );\n}\n\nfunction HomeLink(props: { children: ReactNode }) {\n const link = useLinkProps(undefined);\n return (\n <a {...link} className={linkClass}>\n {props.children}\n </a>\n );\n}\n\n// A row's date is a nicety: it shows \"-\" when the document can't load.\nclass Quiet extends Component<{ children: ReactNode }, { failed: boolean }> {\n state = { failed: false };\n static getDerivedStateFromError() {\n return { failed: true };\n }\n render() {\n return this.state.failed ? \"-\" : this.props.children;\n }\n}\n\nfunction DocumentModified({ id }: { id: string }) {\n const [document] = useDocumentById(id);\n return formatModified(document?.header.lastModifiedAtUtcIso);\n}\n\n/** The folders from the drive's root down to `folder`. */\nfunction folderPath(nodes: readonly Node[], folder: FolderNode | undefined) {\n const path: Node[] = [];\n for (let node: Node | undefined = folder; node;) {\n path.unshift(node);\n const parentId: string | null | undefined = node.parentFolder;\n node = parentId ? nodes.find((n) => n.id === parentId) : undefined;\n }\n return path;\n}\n\nconst byKindThenName = (a: Node, b: Node) =>\n a.kind === b.kind\n ? a.name.localeCompare(b.name)\n : a.kind === \"folder\"\n ? -1\n : 1;\n\n/** Core's drive fallback: a listing of the open folder; an open document shows instead. */\nexport function DirectoryListing({ drive, folder, children }: DriveViewProps) {\n if (children) return children;\n const nodes = drive.state.global.nodes;\n const path = folderPath(nodes, folder);\n const parent = path.at(-2);\n const entries = nodes\n .filter((node) => (node.parentFolder ?? null) === (folder?.id ?? null))\n .sort(byKindThenName);\n const title = (\n <>\n Index of /\n <NodeLink drive={drive} node={undefined}>\n {getDriveName(drive)}\n </NodeLink>\n /\n {path.map((node) => (\n <Fragment key={node.id}>\n <NodeLink drive={drive} node={node}>\n {node.name}\n </NodeLink>\n /\n </Fragment>\n ))}\n </>\n );\n return (\n <IndexTable title={title} label=\"Directory listing\">\n <IndexRow\n name={\n folder ? (\n <NodeLink drive={drive} node={parent}>\n Parent Directory\n </NodeLink>\n ) : (\n <HomeLink>Parent Directory</HomeLink>\n )\n }\n type=\"-\"\n modified=\"-\"\n />\n {entries.map((node) => (\n <IndexRow\n key={node.id}\n name={\n <NodeLink drive={drive} node={node}>\n {node.kind === \"folder\" ? `${node.name}/` : node.name}\n </NodeLink>\n }\n type={isFileNode(node) ? node.documentType : \"Folder\"}\n modified={\n node.kind === \"folder\" ? (\n \"-\"\n ) : (\n <Quiet>\n <Suspense fallback=\"…\">\n <DocumentModified id={node.id} />\n </Suspense>\n </Quiet>\n )\n }\n />\n ))}\n </IndexTable>\n );\n}\n","import {\n hideRevisionHistory,\n setRevisionHistoryPage,\n useReactorClient,\n useRevisionHistoryPage,\n} from \"@powerhousedao/reactor-browser\";\nimport type { Operation } from \"@powerhousedao/shared/document-model\";\nimport { useEffect, useState } from \"react\";\nimport type { DocumentViewProps } from \"../router/route-components.js\";\nimport { formatModified, linkClass } from \"./index-table.js\";\n\nconst pagerClass = `${linkClass} disabled:text-core-muted disabled:no-underline`;\n\n/** Operations per scope on a history page. */\nexport const HISTORY_PAGE_SIZE = 50;\n\n/** Page `page`'s index range of a scope with `count` operations, newest first. */\nexport function historyPageRange(count: number, page: number) {\n const end = Math.max(count - (page - 1) * HISTORY_PAGE_SIZE, 0);\n return { start: Math.max(end - HISTORY_PAGE_SIZE, 0), end };\n}\n\ntype PageState =\n | { status: \"loading\" }\n | { status: \"ready\"; operations: Operation[] }\n | { status: \"error\"; error: Error };\n\n// Fetches only the page's range: `sinceRevision` and a limit of the page size.\nfunction useScopePage(\n documentId: string,\n scope: string,\n start: number,\n end: number,\n) {\n const client = useReactorClient();\n // Each result is kept with its request; a newer request reads as loading.\n const key = `${documentId}:${scope}:${start}:${end}`;\n const [result, setResult] = useState<{ key: string; state: PageState }>();\n const empty = !client || end <= start;\n useEffect(() => {\n if (empty) return;\n const controller = new AbortController();\n const setState = (state: PageState) => setResult({ key, state });\n client\n .getOperations(\n documentId,\n { scopes: [scope] },\n { sinceRevision: start },\n { cursor: \"\", limit: end - start },\n controller.signal,\n )\n .then(\n (page) => {\n const operations = page.results\n .filter((operation) => operation.index < end)\n .sort((a, b) => b.index - a.index);\n setState({ status: \"ready\", operations });\n },\n (reason: unknown) => {\n if (controller.signal.aborted) return;\n setState({\n status: \"error\",\n error: reason instanceof Error ? reason : new Error(String(reason)),\n });\n },\n );\n return () => controller.abort();\n }, [client, empty, key, documentId, scope, start, end]);\n if (empty) return { status: \"ready\", operations: [] } as const;\n return result?.key === key ? result.state : ({ status: \"loading\" } as const);\n}\n\nfunction ScopeOperations(props: {\n documentId: string;\n scope: string;\n count: number;\n page: number;\n}) {\n const { start, end } = historyPageRange(props.count, props.page);\n const state = useScopePage(props.documentId, props.scope, start, end);\n return (\n <section className=\"mb-6\">\n <h2 className=\"mb-2 font-semibold\">\n {props.scope}{\" \"}\n <span className=\"font-normal text-core-muted\">\n {end > start\n ? `${end - start} of ${props.count}, ${start}-${end - 1}`\n : `0 of ${props.count}`}\n </span>\n </h2>\n {state.status === \"error\" ? (\n <p className=\"text-core-danger\">{state.error.message}</p>\n ) : state.status === \"loading\" ? (\n <p className=\"text-core-muted\">Loading…</p>\n ) : state.operations.length === 0 ? (\n <p className=\"text-core-muted\">No operations on this page.</p>\n ) : (\n <table\n aria-label={`${props.scope} operations`}\n className=\"w-full border-collapse\"\n >\n <thead>\n <tr className=\"border-b border-core-border text-left text-core-muted\">\n <th className=\"py-1 pr-6 font-normal\">Index</th>\n <th className=\"py-1 pr-6 font-normal\">Action</th>\n <th className=\"py-1 font-normal\">Timestamp</th>\n </tr>\n </thead>\n <tbody>\n {state.operations.map((operation) => (\n <tr\n key={operation.index}\n className=\"border-b border-core-border/50 hover:bg-core-hover\"\n >\n <td className=\"py-1 pr-6\">{operation.index}</td>\n <td className=\"py-1 pr-6\">{operation.action.type}</td>\n <td className=\"py-1\">\n {formatModified(operation.timestampUtcMs)}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n )}\n </section>\n );\n}\n\n/** Core's revision history: each scope's operations, newest first, a page at a time. */\nexport function DocumentHistory({ document }: DocumentViewProps) {\n const page = useRevisionHistoryPage();\n const { header } = document;\n const scopes = Object.entries(header.revision);\n const pageCount = Math.max(\n 1,\n ...scopes.map(([, count]) => Math.ceil(count / HISTORY_PAGE_SIZE)),\n );\n const pager = (\n <nav aria-label=\"History pages\" className=\"flex items-center gap-4\">\n <button\n type=\"button\"\n className={pagerClass}\n disabled={page <= 1}\n onClick={() => setRevisionHistoryPage(page - 1)}\n >\n Newer\n </button>\n <span className=\"text-core-muted\">\n Page {page} of {pageCount}\n </span>\n <button\n type=\"button\"\n className={pagerClass}\n disabled={page >= pageCount}\n onClick={() => setRevisionHistoryPage(page + 1)}\n >\n Older\n </button>\n </nav>\n );\n return (\n <div className=\"p-6 font-mono text-sm text-core-fg\">\n <div className=\"mb-4 flex items-baseline justify-between\">\n <h1 className=\"text-xl font-semibold\">\n History of {header.name || header.id}\n </h1>\n <button\n type=\"button\"\n className={linkClass}\n onClick={hideRevisionHistory}\n >\n Close\n </button>\n </div>\n <div className=\"mb-4\">{pager}</div>\n {scopes.length === 0 ? (\n <p className=\"text-core-muted\">No operations yet.</p>\n ) : (\n scopes.map(([scope, count]) => (\n <ScopeOperations\n key={scope}\n documentId={header.id}\n scope={scope}\n count={count}\n page={page}\n />\n ))\n )}\n </div>\n );\n}\n","import type { ReactNode } from \"react\";\nimport type { DocumentViewProps } from \"../router/route-components.js\";\nimport { formatModified } from \"./index-table.js\";\n\nfunction Leaf({ value }: { value: unknown }) {\n if (value === null) return <span className=\"text-core-muted\">null</span>;\n if (typeof value === \"string\") {\n return <span className=\"text-core-string\">{JSON.stringify(value)}</span>;\n }\n return <span className=\"text-core-number\">{JSON.stringify(value)}</span>;\n}\n\nfunction JsonNode(props: { name: ReactNode; value: unknown; open?: boolean }) {\n const { name, value } = props;\n if (value === null || typeof value !== \"object\") {\n return (\n <div className=\"pl-4\">\n <span className=\"text-core-muted\">{name}: </span>\n <Leaf value={value} />\n </div>\n );\n }\n const entries = Object.entries(value as Record<string, unknown>);\n const isArray = Array.isArray(value);\n const summary = isArray ? `[${entries.length}]` : `{${entries.length}}`;\n return (\n <details open={props.open} className=\"pl-4\">\n <summary className=\"cursor-pointer select-none\">\n <span className=\"text-core-muted\">{name}: </span>\n <span className=\"text-core-muted\">{summary}</span>\n </summary>\n {entries.map(([key, child]) => (\n <JsonNode key={key} name={key} value={child} />\n ))}\n </details>\n );\n}\n\n/** Core's document fallback: the document's state, read-only, as a JSON tree. */\nexport function DocumentJson({ document }: DocumentViewProps) {\n const { header } = document;\n const revisions = Object.entries(header.revision);\n const operations = revisions.reduce((sum, [, count]) => sum + count, 0);\n const state = document.state as Record<string, unknown>;\n const scopes = [\"global\", \"local\"].filter((scope) => scope in state);\n return (\n <div className=\"p-6 font-mono text-sm text-core-fg\">\n <h1 className=\"mb-1 text-xl font-semibold\">{header.name || header.id}</h1>\n <dl className=\"mb-4 grid grid-cols-[max-content_1fr] gap-x-4 text-core-muted\">\n <dt>Type</dt>\n <dd>{header.documentType}</dd>\n <dt>Id</dt>\n <dd>{header.id}</dd>\n <dt>Last modified</dt>\n <dd>{formatModified(header.lastModifiedAtUtcIso)}</dd>\n <dt>Operations</dt>\n <dd data-testid=\"operation-count\">\n {operations}\n {revisions.length > 0 &&\n ` (${revisions.map(([scope, count]) => `${scope} ${count}`).join(\", \")})`}\n </dd>\n </dl>\n <p className=\"mb-2 text-core-muted\">\n No editor is installed for this document type; its state is shown\n read-only.\n </p>\n <div aria-label=\"Document state\" className=\"-ml-4\">\n {scopes.map((scope) => (\n <JsonNode key={scope} name={scope} value={state[scope]} open />\n ))}\n </div>\n </div>\n );\n}\n","import type { EditorProps } from \"@powerhousedao/shared/document-model\";\nimport type { ErrorInfo, ReactNode } from \"react\";\nimport { Component, Suspense } from \"react\";\n\n/** What core passes a document editor; drive apps get `DriveViewProps`. */\nexport type DocumentEditorProps = EditorProps & {\n documentId: string;\n context?: { readMode?: boolean; selectedTimelineRevision?: number };\n};\n\ntype BoundaryProps = {\n resetKeys: readonly unknown[];\n label: string;\n children: ReactNode;\n};\ntype BoundaryState = { error?: unknown; keys: readonly unknown[] };\n\nclass EditorErrorBoundary extends Component<BoundaryProps, BoundaryState> {\n state: BoundaryState = { keys: this.props.resetKeys };\n\n static getDerivedStateFromError(error: unknown): Partial<BoundaryState> {\n return { error };\n }\n\n // A new document or drive gets a fresh try.\n static getDerivedStateFromProps(\n props: BoundaryProps,\n state: BoundaryState,\n ): Partial<BoundaryState> | null {\n const changed =\n props.resetKeys.length !== state.keys.length ||\n props.resetKeys.some((key, i) => !Object.is(key, state.keys[i]));\n return changed ? { error: undefined, keys: props.resetKeys } : null;\n }\n\n componentDidCatch(error: unknown, info: ErrorInfo) {\n console.error(`[connect] ${this.props.label} failed:`, error, info);\n }\n\n render() {\n const { error } = this.state;\n if (error === undefined) return this.props.children;\n return (\n <div role=\"alert\" className=\"p-6 text-core-fg\">\n <h2 className=\"font-semibold\">The {this.props.label} failed</h2>\n <pre className=\"mt-2 overflow-x-auto text-sm text-core-muted\">\n {error instanceof Error ? error.message : JSON.stringify(error)}\n </pre>\n </div>\n );\n }\n}\n\nexport type EditorHostProps = {\n /** A change shows the editor again after an error. */\n resetKeys?: readonly unknown[];\n /** Names what failed, e.g. \"editor\" or \"drive app\". */\n label?: string;\n children: ReactNode;\n};\n\n/** Hosts a drive app or an editor: it loads in Suspense, and an error stays inside. */\nexport function EditorHost({\n resetKeys = [],\n label = \"editor\",\n children,\n}: EditorHostProps) {\n return (\n <EditorErrorBoundary resetKeys={resetKeys} label={label}>\n <Suspense\n name=\"EditorHost\"\n fallback={\n <p role=\"status\" className=\"p-6 text-core-muted\">\n Loading {label}…\n </p>\n }\n >\n {children}\n </Suspense>\n </EditorErrorBoundary>\n );\n}\n","import {\n DriveProvider,\n EditorDocumentProvider,\n useAppModuleById,\n useDispatch,\n useDocument,\n useEditorModuleFor,\n useRevisionHistoryVisible,\n} from \"@powerhousedao/reactor-browser\";\nimport type { PHDocument } from \"@powerhousedao/shared/document-model\";\nimport { Outlet } from \"@tanstack/react-router\";\nimport { useMemo } from \"react\";\nimport { useDriveRouteData } from \"../router/route-data.js\";\nimport { DirectoryListing } from \"./directory-listing.js\";\nimport { DocumentHistory } from \"./document-history.js\";\nimport { DocumentJson } from \"./document-json.js\";\nimport { EditorHost } from \"./editor-host.js\";\n\n/** `document`: its revision history while `?history` is set, else its\n * editor (given `document` and `dispatch`), else its JSON. */\nexport function DocumentView({ document }: { document: PHDocument }) {\n const [, dispatch] = useDispatch(document);\n const editor = useEditorModuleFor(document);\n const historyVisible = useRevisionHistoryVisible();\n if (historyVisible) return <DocumentHistory document={document} />;\n if (!editor) return <DocumentJson document={document} />;\n const Editor = editor.Component;\n return (\n <div\n className=\"relative h-full\"\n data-editor={editor.config.id}\n data-document-type={document.header.documentType}\n >\n <EditorDocumentProvider document={document} dispatch={dispatch}>\n <Editor\n documentId={document.header.id}\n document={document}\n dispatch={dispatch}\n context={{ readMode: false }}\n />\n </EditorDocumentProvider>\n </div>\n );\n}\n\nfunction OpenDocument({ documentId }: { documentId: string }) {\n const document = useDocument(documentId);\n return document ? <DocumentView document={document} /> : null;\n}\n\n/** The drive layout: the drive app its `preferredEditor` names (given the\n * drive as `document`), else the directory listing, around the node route. */\nexport function DriveLayout() {\n const { drive, folder, documentId } = useDriveRouteData();\n const app = useAppModuleById(drive?.header.meta?.preferredEditor);\n const [, dispatch] = useDispatch(drive);\n const nodeId = documentId ?? folder?.id;\n const context = useMemo(\n () => drive && { drive, dispatch, folder, nodeId },\n [drive, dispatch, folder, nodeId],\n );\n if (!drive || !context) return null;\n const App = app?.Component;\n // Drive apps show their own view until they get a document to show.\n const document = documentId ? <Outlet /> : null;\n return (\n <DriveProvider value={context}>\n <EditorHost\n resetKeys={[drive.header.id]}\n label={App ? \"drive app\" : \"drive view\"}\n >\n {App ? (\n <App document={drive} dispatch={dispatch}>\n {document}\n </App>\n ) : (\n <DirectoryListing drive={drive} folder={folder}>\n {document}\n </DirectoryListing>\n )}\n </EditorHost>\n </DriveProvider>\n );\n}\n\n/** The node route: the open document, or nothing on a folder or the drive's root. */\nexport function NodeView() {\n const { documentId } = useDriveRouteData();\n if (!documentId) return null;\n return (\n <EditorHost resetKeys={[documentId]} label=\"editor\">\n <OpenDocument documentId={documentId} />\n </EditorHost>\n );\n}\n","import {\n getDriveName,\n makeDriveSlug,\n preloadDrive,\n useAppModuleById,\n useDrives,\n useLinkProps,\n} from \"@powerhousedao/reactor-browser\";\nimport type { DocumentDriveDocument } from \"@powerhousedao/shared/document-drive\";\nimport {\n formatModified,\n IndexRow,\n IndexTable,\n linkClass,\n} from \"./index-table.js\";\n\nfunction DriveRow({ drive }: { drive: DocumentDriveDocument }) {\n const app = useAppModuleById(drive.header.meta?.preferredEditor);\n const link = useLinkProps({ driveSlug: makeDriveSlug(drive) });\n return (\n <IndexRow\n name={\n <a\n {...link}\n className={linkClass}\n onMouseEnter={() => {\n link.onMouseEnter();\n preloadDrive(drive);\n }}\n >\n {getDriveName(drive)}/\n </a>\n }\n type={app?.config.name ?? \"Drive\"}\n modified={formatModified(drive.header.lastModifiedAtUtcIso)}\n />\n );\n}\n\n/** Core's home: an index of the drives. */\nexport function DriveIndex() {\n const drives = useDrives();\n // Empty until the reactor lists its drives, e.g. in the prerendered shell.\n if (!drives) return null;\n return (\n <IndexTable title=\"Index of /\" label=\"Drives\">\n {drives.map((drive) => (\n <DriveRow key={drive.header.id} drive={drive} />\n ))}\n {!drives.length && (\n <tr>\n <td colSpan={3} className=\"py-2 text-core-muted\">\n No drives yet.\n </td>\n </tr>\n )}\n </IndexTable>\n );\n}\n","import { useTheme } from \"@powerhousedao/reactor-browser\";\n\n/** Flips between light and dark; the first flip pins the system theme's opposite. */\nexport function ThemeToggle({ className }: { className?: string }) {\n const { theme, setTheme } = useTheme();\n const next = theme === \"dark\" ? \"light\" : \"dark\";\n return (\n <button\n type=\"button\"\n aria-label={`Switch to ${next} theme`}\n title={`Switch to ${next} theme`}\n className={\n className ??\n \"rounded px-2 py-1 text-core-muted hover:bg-core-hover hover:text-core-fg\"\n }\n onClick={() => setTheme(next)}\n >\n {theme === \"dark\" ? \"☾\" : \"☀\"}\n </button>\n );\n}\n","// Core's modals: the ones editors, drive apps and the reactor open, in core's plain style.\nimport {\n addDocument,\n closePHModal,\n deleteNode,\n exportFile,\n getDocumentUpgradePreview,\n logout,\n openRenown,\n openTarget,\n setSelectedNode,\n showPHModal,\n upgradeDocument,\n useDocumentById,\n useDocumentModelModuleById,\n useModelRegistry,\n useNodeById,\n useNodeParentFolderById,\n usePHModal,\n useRenownAuth,\n useRenownLoginMethods,\n useUser,\n validateDocument,\n} from \"@powerhousedao/reactor-browser\";\nimport type { PHModal } from \"@powerhousedao/reactor-browser\";\nimport type { ReactNode } from \"react\";\nimport { createElement, useEffect, useId, useState } from \"react\";\nimport type { ModalFrameProps } from \"../router/modal-frame.js\";\nimport { ModalDialog, useModalFrame } from \"../router/modal-frame.js\";\nimport { useDriveRouteData } from \"../router/route-data.js\";\n\nconst buttonClass =\n \"rounded border border-core-border px-3 py-1 text-sm hover:bg-core-hover disabled:opacity-50\";\nconst primaryClass = `${buttonClass} font-semibold`;\n\n/** Core's modal frame: title, content, and the buttons on the right. */\nfunction CoreModalFrame({\n title,\n titleId,\n actions,\n children,\n}: ModalFrameProps) {\n return (\n <ModalDialog\n labelledBy={titleId}\n className=\"m-auto w-96 max-w-[calc(100vw-2rem)] rounded border border-core-border bg-core-bg p-5 text-core-fg backdrop:bg-black/30\"\n >\n <h2 id={titleId} className=\"mb-3 text-lg font-semibold\">\n {title}\n </h2>\n <div className=\"flex flex-col gap-2 text-sm\">{children}</div>\n <div className=\"mt-4 flex justify-end gap-2\">{actions}</div>\n </ModalDialog>\n );\n}\n\n/** A modal in the routes' frame, else core's. */\nfunction Dialog(props: {\n title: string;\n children: ReactNode;\n actions?: ReactNode;\n}) {\n const Frame = useModalFrame() ?? CoreModalFrame;\n const titleId = useId();\n const actions = props.actions ?? (\n <button type=\"button\" className={buttonClass} onClick={closePHModal}>\n Close\n </button>\n );\n // A registered frame, not one made here.\n return createElement(Frame, {\n title: props.title,\n titleId,\n actions,\n children: props.children,\n });\n}\n\nconst Cancel = () => (\n <button type=\"button\" className={buttonClass} onClick={closePHModal}>\n Cancel\n </button>\n);\n\nfunction useModal<T extends PHModal[\"type\"]>(type: T) {\n const modal = usePHModal();\n return modal?.type === type\n ? (modal as Extract<PHModal, { type: T }>)\n : undefined;\n}\n\n/** A new document of the modal's type, in the open drive and folder. */\nexport function CreateDocumentModal() {\n const modal = useModal(\"createDocument\");\n const module = useDocumentModelModuleById(\n modal?.documentType,\n modal?.documentModelVersion,\n );\n const { drive, folder } = useDriveRouteData();\n const [name, setName] = useState(\"\");\n const typeName = module?.documentModel.global.name ?? modal?.documentType;\n const create = async () => {\n if (!drive || !module || !modal) return;\n closePHModal();\n const node = await addDocument(\n drive.header.id,\n name.trim() || `New ${typeName}`,\n module.documentModel.global.id,\n folder?.id,\n undefined,\n undefined,\n undefined,\n modal.documentModelVersion,\n );\n setSelectedNode(node);\n };\n return (\n <Dialog\n title={`New ${typeName ?? \"document\"}`}\n actions={\n <>\n <Cancel />\n <button\n type=\"submit\"\n form=\"create-document\"\n className={primaryClass}\n disabled={!drive || !module}\n >\n Create\n </button>\n </>\n }\n >\n <form\n id=\"create-document\"\n onSubmit={(event) => {\n event.preventDefault();\n void create();\n }}\n >\n <label className=\"flex flex-col gap-1\">\n Name\n <input\n autoFocus\n value={name}\n onChange={(event) => setName(event.target.value)}\n placeholder={`New ${typeName}`}\n className=\"rounded border border-core-border bg-core-bg px-2 py-1\"\n />\n </label>\n </form>\n {!drive && <p className=\"text-core-muted\">Open a drive first.</p>}\n </Dialog>\n );\n}\n\n/** Signs in with Renown: the configured methods, else its portal. */\nexport function LoginModal() {\n const user = useUser();\n const methods = useRenownLoginMethods();\n const { login, pending, error } = useRenownAuth();\n useEffect(() => {\n if (user) closePHModal();\n }, [user]);\n return (\n <Dialog title=\"Log in\">\n {methods.length ? (\n methods.map((method) => (\n <button\n key={method.id}\n type=\"button\"\n className={buttonClass}\n disabled={pending}\n onClick={() => {\n closePHModal();\n login(undefined, method.id);\n }}\n >\n {method.label}\n </button>\n ))\n ) : (\n <button\n type=\"button\"\n className={primaryClass}\n onClick={() => openRenown()}\n >\n Continue with Renown\n </button>\n )}\n {error && <p className=\"text-core-muted\">{error.message}</p>}\n </Dialog>\n );\n}\n\n/** Deletes a file or folder, then opens its parent. */\nexport function DeleteItemModal() {\n const modal = useModal(\"deleteItem\");\n const node = useNodeById(modal?.id);\n const parent = useNodeParentFolderById(modal?.id);\n const { drive } = useDriveRouteData();\n const remove = async () => {\n closePHModal();\n if (!drive || !modal) return;\n await deleteNode(drive.header.id, modal.id);\n setSelectedNode(parent);\n };\n return (\n <Dialog\n title={`Delete ${node?.name ?? \"item\"}?`}\n actions={\n <>\n <Cancel />\n <button\n type=\"button\"\n className={primaryClass}\n onClick={() => void remove()}\n >\n Delete\n </button>\n </>\n }\n >\n <p>\n {node?.kind === \"folder\"\n ? \"The folder and everything in it will be deleted.\"\n : \"The document will be deleted.\"}\n </p>\n </Dialog>\n );\n}\n\n/** Upgrades a document to its model's latest version. */\nexport function ConfirmDocumentUpgradeModal() {\n const modal = useModal(\"confirmDocumentUpgrade\");\n const [document] = useDocumentById(modal?.documentId);\n const registry = useModelRegistry();\n const preview = document\n ? getDocumentUpgradePreview(document, registry)\n : undefined;\n if (!document || !preview) return null;\n const upgrade = () => {\n closePHModal();\n upgradeDocument(document.header.id).catch((error: unknown) => {\n console.error(\"[connect] the document upgrade failed:\", error);\n });\n };\n return (\n <Dialog\n title=\"Update document\"\n actions={\n <>\n <Cancel />\n <button type=\"button\" className={primaryClass} onClick={upgrade}>\n Update document\n </button>\n </>\n }\n >\n <p>\n From version {preview.fromVersion} to {preview.toVersion}. Existing\n content is migrated; this can't be undone.\n </p>\n {preview.steps\n .filter((step) => step.description)\n .map((step) => (\n <p key={step.toVersion}>\n v{step.toVersion}: {step.description}\n </p>\n ))}\n </Dialog>\n );\n}\n\n/** Exports a document that has validation errors, after listing them. */\nexport function DownloadDocumentWithErrorsModal() {\n const modal = useModal(\"downloadDocumentWithErrors\");\n const [document] = useDocumentById(modal?.documentId);\n if (!document) return null;\n const errors = validateDocument(document);\n const download = () => {\n closePHModal();\n exportFile(document).catch((error: unknown) => {\n console.error(\"[connect] the export failed:\", error);\n });\n };\n return (\n <Dialog\n title=\"The document has errors\"\n actions={\n <>\n <Cancel />\n <button type=\"button\" className={primaryClass} onClick={download}>\n Export anyway\n </button>\n </>\n }\n >\n <ul className=\"list-disc pl-5 text-core-muted\">\n {errors.map((error, index) => (\n <li key={index}>{error.message}</li>\n ))}\n </ul>\n </Dialog>\n );\n}\n\n/** A document whose model version no installed package provides. */\nexport function DocumentVersionUnsupportedModal() {\n const modal = useModal(\"documentVersionUnsupported\");\n if (!modal) return null;\n const { documentType, requiredVersion, availableVersions } = modal;\n return (\n <Dialog\n title=\"Document version not supported\"\n actions={\n <>\n <Cancel />\n <button\n type=\"button\"\n className={primaryClass}\n onClick={() => {\n closePHModal();\n openTarget({ settings: \"packages\" });\n }}\n >\n Show packages\n </button>\n </>\n }\n >\n <p>\n This document needs version {requiredVersion} of \"{documentType}\"; the\n installed packages provide {availableVersions.join(\", \")}.\n </p>\n </Dialog>\n );\n}\n\n/** A protected drive that couldn't be added: sign in, or as someone else. */\nexport function DriveAuthRequiredModal() {\n const user = useUser();\n return (\n <Dialog\n title={user ? \"No access to this drive\" : \"Log in to access this drive\"}\n actions={\n <>\n <Cancel />\n {user ? (\n <button\n type=\"button\"\n className={primaryClass}\n onClick={() => {\n closePHModal();\n void logout();\n }}\n >\n Log out\n </button>\n ) : (\n <button\n type=\"button\"\n className={primaryClass}\n onClick={() => showPHModal({ type: \"login\" })}\n >\n Log in\n </button>\n )}\n </>\n }\n >\n <p>\n {user\n ? \"The account you're signed in with can't open this drive.\"\n : \"This drive is only open to signed-in users.\"}\n </p>\n </Dialog>\n );\n}\n","import {\n initTheme,\n useLinkProps,\n useTheme,\n} from \"@powerhousedao/reactor-browser\";\nimport { HeadContent, Link, Outlet, useRouter } from \"@tanstack/react-router\";\nimport { Suspense } from \"react\";\nimport type { ConnectModals } from \"../router/modals.js\";\nimport { CORE_MODAL_VIEWS, ModalOutlet } from \"../router/modals.js\";\nimport { ContentOutlet } from \"../router/route-components.js\";\nimport { useNavRoutes, useSidebarMode } from \"../router/sidebar.js\";\nimport { appTitle } from \"../router/titles.js\";\nimport { useIsEmbedded } from \"../runtime/embedded.js\";\nimport { ThemeToggle } from \"./theme-toggle.js\";\nimport { linkClass } from \"./index-table.js\";\nimport * as modalViews from \"./modals.js\";\n\n// The layout shares the modals' chunk, so it renders them directly.\nconst coreModals: ConnectModals = Object.fromEntries(\n Object.entries(CORE_MODAL_VIEWS).map(([type, name]) => [\n type,\n modalViews[name],\n ]),\n);\n\n/** Core's root: the page, in the theme. */\nexport function CoreRoot() {\n initTheme();\n useTheme();\n return (\n <div className=\"h-screen overflow-auto bg-core-bg text-core-fg\">\n {/* The matched routes' head: the document title. */}\n <HeadContent />\n <Suspense name=\"CoreRoot\">\n <Outlet />\n </Suspense>\n <ModalOutlet modals={coreModals} />\n </div>\n );\n}\n\n/** Core's header: home, the `staticData.nav` routes, settings and the theme. */\nexport function CoreHeader() {\n const appName = useRouter().options.context.appName;\n const home = useLinkProps(undefined);\n const settings = useLinkProps({ settings: true });\n const navRoutes = useNavRoutes();\n return (\n <header className=\"flex items-center gap-4 border-b border-core-border px-4 py-2 text-sm\">\n <a {...home} className=\"font-semibold text-core-fg\">\n {appTitle(appName)}\n </a>\n <nav aria-label=\"Pages\" className=\"flex gap-3\">\n {navRoutes.map((item) => (\n // `to` is a plain string: the routes are only known at runtime.\n <Link key={item.routeId} to={item.to as never} className={linkClass}>\n {item.label}\n </Link>\n ))}\n </nav>\n <div className=\"ml-auto flex items-center gap-2\">\n <a {...settings} className={linkClass}>\n Settings\n </a>\n <ThemeToggle />\n </div>\n </header>\n );\n}\n\n/** Core's `_app` layout: the header above the matched route. Embedded mode\n * and `staticData.sidebar: \"hidden\"` drop the header. */\nexport function CoreLayout() {\n const isEmbedded = useIsEmbedded();\n const hidden = useSidebarMode() === \"hidden\";\n return (\n <div className=\"flex h-full flex-col\">\n {!isEmbedded && !hidden && <CoreHeader />}\n <main className=\"relative min-h-0 flex-1\">\n <ContentOutlet />\n </main>\n </div>\n );\n}\n","import { useLinkProps } from \"@powerhousedao/reactor-browser\";\nimport { useRouterState } from \"@tanstack/react-router\";\n\n/** The 404 page: what was asked for, and a way home. */\nexport function NotFoundPage({ driveSlug }: { driveSlug?: string }) {\n const pathname = useRouterState({ select: (s) => s.location.pathname });\n const home = useLinkProps(undefined);\n return (\n <div\n role=\"alert\"\n className=\"flex size-full flex-col items-center justify-center gap-3 p-6 text-center\"\n >\n <h1 className=\"text-2xl font-semibold text-core-fg\">\n {driveSlug ? `Drive ${driveSlug} not found` : \"Page not found\"}\n </h1>\n <p className=\"text-core-muted\">\n Nothing is at{\" \"}\n <code data-testid=\"not-found-path\" className=\"text-core-fg\">\n {pathname}\n </code>\n .\n </p>\n <a {...home} className=\"text-core-fg underline\">\n Go to the home page\n </a>\n </div>\n );\n}\n\nexport function DriveNotFoundPage({ driveSlug }: { driveSlug: string }) {\n return <NotFoundPage driveSlug={driveSlug} />;\n}\n","import type { ErrorComponentProps } from \"@tanstack/react-router\";\n\n/** A route's loader or render error. */\nexport function CoreRouteError({ error, reset }: ErrorComponentProps) {\n return (\n <div role=\"alert\" className=\"flex flex-col gap-2 p-6 text-core-fg\">\n <h1 className=\"text-lg font-semibold\">Something went wrong</h1>\n <pre className=\"overflow-x-auto text-sm text-core-muted\">\n {error instanceof Error ? error.message : JSON.stringify(error)}\n </pre>\n <button\n type=\"button\"\n className=\"self-start rounded border border-core-border px-3 py-1 hover:bg-core-hover\"\n onClick={reset}\n >\n Try again\n </button>\n </div>\n );\n}\n","import {\n useLinkProps,\n usePHNavigation,\n useTheme,\n} from \"@powerhousedao/reactor-browser\";\nimport { Outlet } from \"@tanstack/react-router\";\nimport { Suspense } from \"react\";\nimport type { SettingsTabEntry } from \"../router/settings.js\";\nimport { useSettingsTabs } from \"../router/settings.js\";\n\nfunction TabLink({ tab }: { tab: SettingsTabEntry }) {\n const link = useLinkProps({ settings: tab.id });\n const current = link[\"aria-current\"] === \"page\";\n const Icon = tab.icon;\n return (\n <a\n {...link}\n className={[\n \"flex items-center gap-2 rounded px-3 py-1.5\",\n current ? \"bg-core-hover font-semibold\" : \"hover:bg-core-hover\",\n tab.destructive ? \"text-core-danger\" : \"text-core-fg\",\n ].join(\" \")}\n >\n {Icon && <Icon size={16} />}\n {tab.label}\n </a>\n );\n}\n\n/** Core's settings page: the tabs from `staticData.settings` beside the open one. */\nexport function CoreSettingsPage() {\n const tabs = useSettingsTabs();\n const navigation = usePHNavigation();\n // Back to where settings was opened from, else home.\n const close = () => {\n if (navigation.closeOpened?.()) return;\n navigation.open(undefined, { replace: true });\n };\n return (\n <div className=\"flex h-full flex-col text-core-fg\">\n <div className=\"flex items-center justify-between border-b border-core-border px-4 py-3\">\n <h1 className=\"text-lg font-semibold\">Settings</h1>\n <button\n type=\"button\"\n className=\"rounded px-2 text-core-muted hover:bg-core-hover\"\n onClick={close}\n >\n Close\n </button>\n </div>\n <div className=\"flex min-h-0 flex-1\">\n <nav aria-label=\"Settings\" className=\"w-48 shrink-0 p-3\">\n <ul className=\"flex flex-col gap-1\">\n {tabs.map((tab) => (\n <li key={tab.id}>\n <TabLink tab={tab} />\n </li>\n ))}\n </ul>\n </nav>\n <section className=\"min-w-0 flex-1 overflow-auto p-6\">\n <Suspense name=\"SettingsTab\">\n <Outlet />\n </Suspense>\n </section>\n </div>\n </div>\n );\n}\n\nconst THEMES = [\n { value: \"light\", label: \"Light\" },\n { value: \"dark\", label: \"Dark\" },\n { value: \"system\", label: \"System\" },\n] as const;\n\n/** Core's Appearance tab: light, dark, or the system's. */\nexport function AppearanceTab() {\n const { theme, isSystem, setTheme } = useTheme();\n const selected = isSystem ? \"system\" : theme;\n return (\n <fieldset className=\"flex flex-col gap-2\">\n <legend className=\"mb-2 font-semibold\">Theme</legend>\n {THEMES.map((option) => (\n <label key={option.value} className=\"flex items-center gap-2\">\n <input\n type=\"radio\"\n name=\"theme\"\n value={option.value}\n checked={selected === option.value}\n onChange={() => setTheme(option.value)}\n />\n {option.label}\n </label>\n ))}\n </fieldset>\n );\n}\n","import {\n DRIVE_DOCUMENT_TYPES,\n useVetraPackageManager,\n useVetraPackages,\n} from \"@powerhousedao/reactor-browser\";\nimport type {\n DocumentModelLib,\n EditorModule,\n} from \"@powerhousedao/shared/document-model\";\nimport type { ReactNode } from \"react\";\n\nconst SOURCE_LABELS: Record<string, string> = {\n common: \"built-in\",\n project: \"project\",\n \"local-install\": \"local\",\n \"registry-install\": \"registry\",\n};\n\nconst isDriveApp = (editor: EditorModule) =>\n editor.documentTypes.some((type) =>\n (DRIVE_DOCUMENT_TYPES as readonly string[]).includes(type),\n );\n\n/** A package's document models by type, with every version it ships. */\nfunction modelsOf(pkg: DocumentModelLib) {\n const byType = new Map<string, { name: string; versions: number[] }>();\n for (const model of pkg.documentModels) {\n const { id, name } = model.documentModel.global;\n const entry = byType.get(id) ?? { name, versions: [] };\n entry.versions.push(model.version ?? 1);\n byType.set(id, entry);\n }\n return [...byType].map(([type, { name, versions }]) => ({\n type,\n name,\n versions: versions.sort((a, b) => a - b),\n }));\n}\n\nfunction Section(props: { title: string; children: ReactNode }) {\n return (\n <div className=\"mt-3\">\n <h3 className=\"mb-1 text-xs font-semibold tracking-wide text-core-muted uppercase\">\n {props.title}\n </h3>\n {props.children}\n </div>\n );\n}\n\nconst cell = \"py-1 pr-4 align-top break-words\";\n\nfunction EditorTable(props: { label: string; editors: EditorModule[] }) {\n return (\n <table\n aria-label={props.label}\n className=\"w-full table-fixed border-collapse text-sm\"\n >\n <tbody>\n {props.editors.map((editor) => (\n <tr key={editor.config.id} className=\"border-t border-core-border/50\">\n <td className={`${cell} w-1/3`}>{editor.config.name}</td>\n <td className={`${cell} w-1/3 font-mono text-core-muted`}>\n {editor.config.id}\n </td>\n <td className={`${cell} font-mono`}>\n {editor.documentTypes.join(\", \")}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n );\n}\n\nfunction PackageEntry({ pkg }: { pkg: DocumentModelLib }) {\n const manager = useVetraPackageManager();\n const name = pkg.manifest.name;\n const version = manager?.getPackageVersion(name);\n const source = manager?.getPackageSource(name);\n const models = modelsOf(pkg);\n const apps = pkg.editors.filter(isDriveApp);\n const editors = pkg.editors.filter((editor) => !isDriveApp(editor));\n return (\n <li\n aria-label={name}\n className=\"rounded border border-core-border px-4 py-3\"\n >\n <div className=\"flex flex-wrap items-baseline gap-x-3\">\n <h2 className=\"font-semibold\">{name}</h2>\n {version && (\n <span className=\"font-mono text-sm text-core-muted\">{version}</span>\n )}\n {source && (\n <span className=\"rounded border border-core-border px-1.5 text-xs text-core-muted\">\n {SOURCE_LABELS[source] ?? source}\n </span>\n )}\n </div>\n {models.length > 0 && (\n <Section title=\"Document models\">\n <table\n aria-label={`${name} document models`}\n className=\"w-full table-fixed border-collapse text-sm\"\n >\n <tbody>\n {models.map((model) => (\n <tr key={model.type} className=\"border-t border-core-border/50\">\n <td className={`${cell} w-1/3`}>{model.name}</td>\n <td className={`${cell} w-1/3 font-mono`}>{model.type}</td>\n <td className={`${cell} text-core-muted`}>\n {model.versions.map((v) => `v${v}`).join(\", \")}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </Section>\n )}\n {editors.length > 0 && (\n <Section title=\"Editors\">\n <EditorTable label={`${name} editors`} editors={editors} />\n </Section>\n )}\n {apps.length > 0 && (\n <Section title=\"Drive apps\">\n <EditorTable label={`${name} drive apps`} editors={apps} />\n </Section>\n )}\n </li>\n );\n}\n\n/** Core's Packages tab: the loaded packages, their document models, editors and drive apps. */\nexport function PackagesTab() {\n const packages = useVetraPackages();\n return (\n <div className=\"w-full max-w-3xl\">\n {packages.length === 0 ? (\n <p className=\"text-core-muted\">No packages are loaded.</p>\n ) : (\n <ul aria-label=\"Packages\" className=\"flex flex-col gap-3\">\n {packages.map((pkg, index) => (\n <PackageEntry key={`${pkg.manifest.name}:${index}`} pkg={pkg} />\n ))}\n </ul>\n )}\n </div>\n );\n}\n"],"mappings":"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"}