@powerhousedao/connect 1.0.22-staging.1 → 1.0.23-dev.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/.env +1 -1
  2. package/dist/assets/{app-CSCydE8J.css → app-D5gNm0Gn.css} +240 -181
  3. package/dist/assets/{app-BIg_-piZ.js → app-DCtCV8Sz.js} +19842 -18216
  4. package/dist/assets/app-DCtCV8Sz.js.map +1 -0
  5. package/dist/assets/{app-loader-mwZgOVwV.js → app-loader-BAEWEx-m.js} +740 -422
  6. package/dist/assets/app-loader-BAEWEx-m.js.map +1 -0
  7. package/dist/assets/{app-loader-3ipafc56.css → app-loader-NDVZu4bS.css} +238 -228
  8. package/dist/assets/browser-BeUBqndM.js +27224 -0
  9. package/dist/assets/browser-BeUBqndM.js.map +1 -0
  10. package/dist/assets/{ccip-i-oLVbil.js → ccip-CMd6tRtn.js} +6 -8
  11. package/dist/assets/ccip-CMd6tRtn.js.map +1 -0
  12. package/dist/assets/{content-CsEKVDJz.js → content-DsWyfJvF.js} +1105 -463
  13. package/dist/assets/content-DsWyfJvF.js.map +1 -0
  14. package/dist/assets/{index-M4h38SB3.js → index-ADsM2QWh.js} +23 -171
  15. package/dist/assets/index-ADsM2QWh.js.map +1 -0
  16. package/dist/assets/{index-BOWJSJaO.js → index-CCDoOj0e.js} +4 -3
  17. package/dist/assets/index-CCDoOj0e.js.map +1 -0
  18. package/dist/assets/{index-B469WXKP.js → index-CSN0Iyem.js} +615 -830
  19. package/dist/assets/index-CSN0Iyem.js.map +1 -0
  20. package/dist/assets/index-Dl8ZqWS0.js +208 -0
  21. package/dist/assets/index-Dl8ZqWS0.js.map +1 -0
  22. package/dist/assets/{main.DfFOgz9f.js → main.DW9UCmAK.js} +3 -12
  23. package/dist/assets/main.DW9UCmAK.js.map +1 -0
  24. package/dist/assets/reactor-analytics-hlzA2WG5.js +42 -0
  25. package/dist/assets/reactor-analytics-hlzA2WG5.js.map +1 -0
  26. package/dist/assets/router-DJRPUFad.js +1585 -0
  27. package/dist/assets/router-DJRPUFad.js.map +1 -0
  28. package/dist/assets/{style-0ej1afQi.css → style-CdxGKc2g.css} +39 -95
  29. package/dist/external-packages.js +1 -0
  30. package/dist/external-packages.js.map +1 -0
  31. package/dist/hmr.js +1 -0
  32. package/dist/hmr.js.map +1 -0
  33. package/dist/index.html +1 -1
  34. package/dist/service-worker.js +1 -0
  35. package/dist/service-worker.js.map +1 -0
  36. package/dist/vite-envs.sh +1 -1
  37. package/package.json +26 -19
@@ -1,10 +1,11 @@
1
1
  import { jsx, jsxs, Fragment as Fragment$1 } from "react/jsx-runtime";
2
- import { t as twMerge, B as Button, m as mergeClassNameProps, E as ERROR, M as MISSING, C as CONFLICT, S as SUCCESS, k as SYNCING, I as INITIAL_SYNC, l as ConnectDropdownMenu, u as useOnClickOutside, n as useEventListener, o as useCopyToClipboard, p as Select, q as ENSAvatar, P as Provider, v as Root3, T as Trigger, w as Portal, x as Content2, y as validateInitialState, z as validateStateSchemaName, A as validateModules, D as useDocumentDrives, F as useUiNodesContext, G as useDriveContext, H as FILE$1, J as useUnwrappedReactor, K as useConnectDid, L as useConnectCrypto, N as useTranslation, O as useModal, Q as useAtomValue, U as themeAtom, V as useUser, W as useUserPermissions$1, X as useUiNodes, Y as exportFile, Z as useGetDocumentModelModule, _ as addActionContext$1, $ as signOperation$1, a0 as useDocumentDriveServer, a1 as useHotkeys, a2 as useGetEditor, a3 as isSameDocument, a4 as useNavigate, a5 as ErrorBoundary, a6 as DriveLayout, a7 as DriveContextProvider, a8 as SearchBar, a9 as useAsyncReactor, aa as useFilteredDocumentModels, ab as useDriveEditor, ac as useDocumentDriveById, ad as useParams, ae as useDocumentDrives$1, af as toast } from "./app-BIg_-piZ.js";
2
+ import { t as twMerge, B as Button, aO as mergeClassNameProps, aP as INITIAL_SYNC, aQ as SYNCING, S as SUCCESS, C as CONFLICT, aR as MISSING, x as ERROR, aS as ConnectDropdownMenu, aT as useOnClickOutside, aU as useEventListener, aV as useCopyToClipboard, aW as Select, aX as Provider, aY as Root3, aZ as Trigger, a_ as Portal, a$ as Content2, b0 as validateInitialState, b1 as validateStateSchemaName, b2 as validateModules, b3 as useDocumentDrives, A as useUiNodesContext, b4 as useDriveContext, b5 as FILE$1, F as useUnwrappedReactor, b6 as useConnectDid, b7 as useConnectCrypto, o as useTranslation, G as useModal, b8 as useAtomValue, b9 as themeAtom, ba as useUser, bb as useUserPermissions$1, p as useUiNodes, bc as exportFile, bd as useGetDocumentModelModule, be as addActionContext$1, bf as signOperation$1, e as useDocumentDriveServer, bg as useHotkeys, bh as DriveLayout, bi as DriveContextProvider, bj as SearchBar, N as useAnalyticsStore, bk as useQueryClient, u as useQuery, a3 as AnalyticsPath, bl as useAnalyticsEngine, a4 as DateTime, bm as AnalyticsGranularity, bn as useGetEditor, bo as isSameDocument, n as useNavigate, s as useAsyncReactor, bp as useFilteredDocumentModels, bq as useDriveEditor, br as useDocumentDriveById, z as useParams, q as useDocumentDrives$1, w as toast } from "./app-DCtCV8Sz.js";
3
3
  import * as React from "react";
4
4
  import React__default, { useState, useCallback, useMemo, useEffect, Fragment, useRef, useLayoutEffect, memo as memo$1, createElement, useSyncExternalStore, Suspense } from "react";
5
- import { _ as Icon, aX as getDimensions, aY as READ, aZ as nodeOptionsMap, a_ as defaultFileOptions, a$ as DELETE, b0 as RENAME, b1 as WRITE, b2 as DUPLICATE, b3 as defaultFolderOptions, b4 as garbageCollect, b5 as sortOperations, b6 as UI_NODE, aP as DRIVE, az as FILE, ae as buildSignedOperation, b7 as generateId$1, aw as isFolderNode, aB as generateNodesCopy, aC as copyNode, aA as moveNode, ay as updateNode, ax as deleteNode, ar as generateAddNodeAction, as as isFileNode, av as addFolder, b8 as undo, b9 as redo, ac as logger, ba as useDocumentDispatch$1, aQ as FOLDER, al as driveDocumentModelModule } from "./app-loader-mwZgOVwV.js";
5
+ import { $ as Icon, bX as getDimensions, bY as READ, bZ as nodeOptionsMap, b_ as defaultFileOptions, b$ as DUPLICATE, c0 as RENAME, c1 as WRITE, c2 as DELETE, c3 as defaultFolderOptions, c4 as garbageCollect, c5 as sortOperations, c6 as UI_NODE, aQ as DRIVE, aB as FILE, ae as buildSignedOperation, ax as addFolder, at as generateAddNodeAction, ay as isFolderNode, au as isFileNode, az as deleteNode, aA as updateNode, aC as moveNode, aD as generateNodesCopy, aE as copyNode, aq as generateId$1, c7 as undo, c8 as redo, _ as logger, aR as FOLDER, c9 as useDocumentDispatch$1, an as driveDocumentModelModule, ah as connectConfig } from "./app-loader-BAEWEx-m.js";
6
+ import { E as ENSAvatar, a as ErrorBoundary } from "./router-DJRPUFad.js";
6
7
  import { flushSync } from "react-dom";
7
- import "./main.DfFOgz9f.js";
8
+ import "./main.DW9UCmAK.js";
8
9
  const PaginationButton = ({ active = false, ...props }) => {
9
10
  const className = twMerge("h-8 min-w-8 border border-solid border-gray-300 bg-white px-3 py-1 text-xs text-gray-900 hover:bg-gray-100", !active && "border-0");
10
11
  return jsx(Button, { color: "light", size: "small", ...mergeClassNameProps(props, className), children: props.children });
@@ -14,7 +15,7 @@ const Pagination = (props) => {
14
15
  return jsxs("div", { className: "flex gap-x-1", children: [firstPageLabel ? jsx(PaginationButton, { disabled: !isPreviousPageAvailable, onClick: () => goToFirstPage(), children: firstPageLabel }) : null, previousPageLabel ? jsxs(PaginationButton, { disabled: !isPreviousPageAvailable, onClick: () => goToPreviousPage(), children: [jsx(Icon, { className: "rotate-90", name: "ChevronDown", size: 16 }), previousPageLabel] }) : null, pages.map((page) => jsx(PaginationButton, { active: page.active, onClick: () => goToPage(page.index), children: page.number }, page.index)), hiddenNextPages ? jsx("span", { className: "flex items-center justify-center px-2", children: "..." }) : null, nextPageLabel ? jsxs(PaginationButton, { disabled: !isNextPageAvailable, onClick: () => goToNextPage(), children: [nextPageLabel, jsx(Icon, { className: "-rotate-90", name: "ChevronDown", size: 16 })] }) : null, lastPageLabel ? jsx(PaginationButton, { disabled: !isNextPageAvailable, onClick: () => goToLastPage(), children: lastPageLabel }) : null] });
15
16
  };
16
17
  function usePagination(items, options) {
17
- const { itemsPerPage = 20, initialPage = 0, pageRange = 3 } = options || {};
18
+ const { itemsPerPage = 20, initialPage = 0, pageRange = 3 } = options;
18
19
  const [currentPage, setCurrentPage] = useState(initialPage);
19
20
  const pageCount = Math.ceil(items.length / itemsPerPage);
20
21
  const isNextPageAvailable = currentPage < pageCount - 1;
@@ -151,131 +152,12 @@ function DefaultEditorLoader(props) {
151
152
  const { message: message2 = "Loading editor", ...divProps } = props;
152
153
  return jsx("div", { className: "grid h-full place-items-center", ...divProps, children: jsxs("div", { className: "-mt-20 grid place-items-center", children: [jsx("h3", { className: "mb-4 text-xl", children: message2 }), jsx(AnimatedLoader, {})] }) });
153
154
  }
154
- const DocumentToolbar = (props) => {
155
- const { undo: undo2, canUndo, redo: redo2, canRedo, title, onClose, onExport, className, onShowRevisionHistory, onSwitchboardLinkClick, onShowTimeline } = props;
156
- const isUndoDisabled = !canUndo || !undo2;
157
- const isRedoDisabled = !canRedo || !redo2;
158
- const isExportDisabled = !onExport;
159
- const isSwitchboardLinkDisabled = !onSwitchboardLinkClick;
160
- const isRevisionHistoryDisabled = !onShowRevisionHistory;
161
- const isTimelineDisabled = !onShowTimeline;
162
- return jsxs("div", { className: twMerge("flex h-12 w-full items-center justify-between rounded-xl border border-gray-200 bg-slate-50 px-4", className), children: [jsxs("div", { className: "flex items-center gap-x-2", children: [jsx("button", { className: twMerge("grid size-8 place-items-center rounded-lg border border-gray-200 bg-white", isUndoDisabled ? "cursor-not-allowed" : "cursor-pointer active:opacity-70"), onClick: undo2, disabled: isUndoDisabled, children: jsx(Icon, { name: "ArrowCouterclockwise", size: 16, className: isUndoDisabled ? "text-gray-500" : "text-gray-900" }) }), jsx("button", { className: twMerge("grid size-8 place-items-center rounded-lg border border-gray-200 bg-white", isRedoDisabled ? "cursor-not-allowed" : "cursor-pointer active:opacity-70"), onClick: redo2, disabled: isRedoDisabled, children: jsx("div", { className: "-scale-x-100", children: jsx(Icon, { name: "ArrowCouterclockwise", size: 16, className: isRedoDisabled ? "text-gray-500" : "text-gray-900" }) }) }), jsx("button", { className: twMerge("flex h-8 items-center rounded-lg border border-gray-200 bg-white px-3 text-sm", isExportDisabled ? "cursor-not-allowed" : "cursor-pointer active:opacity-70"), onClick: onExport, disabled: isExportDisabled, children: jsx("span", { className: isExportDisabled ? "text-gray-500" : "text-gray-900", children: "Export" }) })] }), jsx("div", { className: "flex items-center", children: jsx("h1", { className: "text-sm font-medium text-gray-500", children: title }) }), jsxs("div", { className: "flex items-center gap-x-2", children: [jsx("button", { className: twMerge("grid size-8 place-items-center rounded-lg border border-gray-200 bg-white", isSwitchboardLinkDisabled ? "cursor-not-allowed" : "cursor-pointer active:opacity-70"), onClick: onSwitchboardLinkClick, disabled: isSwitchboardLinkDisabled, children: jsx(Icon, { name: "Drive", size: 16, className: isSwitchboardLinkDisabled ? "text-gray-500" : "text-gray-900" }) }), jsx("button", { className: twMerge("grid size-8 place-items-center rounded-lg border border-gray-200 bg-white", isRevisionHistoryDisabled ? "cursor-not-allowed" : "cursor-pointer active:opacity-70"), onClick: onShowRevisionHistory, disabled: isRevisionHistoryDisabled, children: jsx(Icon, { name: "History", size: 16, className: isRevisionHistoryDisabled ? "text-gray-500" : "text-gray-900" }) }), jsx("button", { className: twMerge("grid size-8 place-items-center rounded-lg border border-gray-200 bg-white", isTimelineDisabled ? "cursor-not-allowed" : "cursor-pointer active:opacity-70"), onClick: onShowTimeline, disabled: isTimelineDisabled, children: jsx(Icon, { name: "Timeline", size: 16, className: twMerge("text-gray-900", isTimelineDisabled && "opacity-50") }) }), jsx("button", { className: "grid size-8 cursor-pointer place-items-center rounded-lg border border-gray-200 bg-white active:opacity-70", onClick: onClose, children: jsx(Icon, { name: "XmarkLight", size: 16, className: "text-gray-900" }) })] })] });
163
- };
164
- const syncIcons = {
165
- SYNCING: "Syncing",
166
- SUCCESS: "Synced",
167
- CONFLICT: "Error",
168
- MISSING: "Circle",
169
- ERROR: "Error",
170
- INITIAL_SYNC: "Syncing"
171
- };
172
- function SyncStatusIcon(props) {
173
- const { syncStatus, className, overrideSyncIcons = {}, ...iconProps } = props;
174
- const icons = { ...syncIcons, ...overrideSyncIcons };
175
- const syncStatusIcons = {
176
- [INITIAL_SYNC]: jsx(Icon, { size: 16, ...iconProps, className: twMerge("text-blue-900", className), name: icons[INITIAL_SYNC] }),
177
- [SYNCING]: jsx(Icon, { size: 16, ...iconProps, className: twMerge("text-blue-900", className), name: icons[SYNCING] }),
178
- [SUCCESS]: jsx(Icon, { size: 16, ...iconProps, className: twMerge("text-green-900", className), name: icons[SUCCESS] }),
179
- [CONFLICT]: jsx(Icon, { size: 16, ...iconProps, className: twMerge("text-orange-900", className), name: icons[CONFLICT] }),
180
- [MISSING]: jsx(Icon, { size: 16, ...iconProps, className: twMerge("text-red-900", className), name: icons[MISSING] }),
181
- [ERROR]: jsx(Icon, { size: 16, ...iconProps, className: twMerge("text-red-900", className), name: icons[ERROR] })
182
- };
183
- return syncStatusIcons[syncStatus];
184
- }
185
- function FileItem(props) {
186
- const { uiNode, className, customDocumentIconSrc, onSelectNode, onRenameNode, onDuplicateNode, onDeleteNode, isAllowedToCreateDocuments } = props;
187
- const [mode, setMode] = useState(READ);
188
- const [isDropdownMenuOpen, setIsDropdownMenuOpen] = useState(false);
189
- const { dragProps } = useDrag({ uiNode });
190
- const isReadMode = mode === READ;
191
- const dropdownMenuHandlers = {
192
- [DUPLICATE]: () => onDuplicateNode(uiNode),
193
- [RENAME]: () => setMode(WRITE),
194
- [DELETE]: () => onDeleteNode(uiNode)
195
- };
196
- const dropdownMenuOptions = Object.entries(nodeOptionsMap).map(([id, option]) => ({
197
- ...option,
198
- id
199
- })).filter((option) => defaultFileOptions.includes(option.id));
200
- function onSubmit(name) {
201
- onRenameNode(name, uiNode);
202
- setMode(READ);
203
- }
204
- function onCancel() {
205
- setMode(READ);
206
- }
207
- function onClick() {
208
- onSelectNode(uiNode);
209
- }
210
- function onDropdownMenuOptionClick(itemId) {
211
- const handler = dropdownMenuHandlers[itemId];
212
- if (!handler) {
213
- console.error(`No handler found for dropdown menu item: ${itemId}`);
214
- return;
215
- }
216
- handler();
217
- setIsDropdownMenuOpen(false);
218
- }
219
- const iconSrc = getDocumentIconSrc(uiNode.documentType, customDocumentIconSrc);
220
- const iconNode = jsxs("div", { className: "relative", children: [jsx("img", { alt: "file icon", className: "max-w-none", height: 34, src: iconSrc, width: 32 }), isReadMode && uiNode.syncStatus && jsx("div", { className: "absolute bottom-[-2px] right-0 size-3 rounded-full bg-white", children: jsx("div", { className: "absolute left-[-2px] top-[-2px]", children: jsx(SyncStatusIcon, { overrideSyncIcons: { SUCCESS: "CheckCircleFill" }, syncStatus: uiNode.syncStatus }) }) })] });
221
- const containerStyles = twMerge("group flex h-12 cursor-pointer select-none items-center rounded-lg bg-gray-200 px-2 text-gray-600 hover:text-gray-800", className);
222
- const content = isReadMode ? jsxs("div", { className: "flex w-52 items-center justify-between", children: [jsxs("div", { className: "mr-2 truncate group-hover:mr-0", children: [jsx("div", { className: "max-h-6 truncate text-sm font-medium group-hover:text-gray-800", children: uiNode.name }), jsx("div", { className: "max-h-6 truncate text-xs font-medium text-gray-600 group-hover:text-gray-800", children: uiNode.documentType })] }), isAllowedToCreateDocuments ? jsx(ConnectDropdownMenu, { items: dropdownMenuOptions, onItemClick: onDropdownMenuOptionClick, onOpenChange: setIsDropdownMenuOpen, open: isDropdownMenuOpen, children: jsx("button", { className: twMerge("hidden group-hover:block", isDropdownMenuOpen && "block"), onClick: (e) => {
223
- e.stopPropagation();
224
- setIsDropdownMenuOpen(true);
225
- }, children: jsx(Icon, { className: "text-gray-600", name: "VerticalDots" }) }) }) : null] }) : jsx(NodeInput, { className: "ml-3 flex-1 font-medium", defaultValue: uiNode.name, onCancel, onSubmit });
226
- return jsx("div", { className: "relative w-64", onClick, children: jsx("div", { ...dragProps, className: containerStyles, children: jsxs("div", { className: "flex items-center", children: [jsx("div", { className: "mr-1.5", children: iconNode }), content] }) }) });
227
- }
228
- function FolderItem(props) {
229
- const { uiNode, isAllowedToCreateDocuments, className, onRenameNode, onDuplicateNode, onDeleteNode, onSelectNode, onAddFile, onCopyNode, onMoveNode } = props;
230
- const [mode, setMode] = useState(READ);
231
- const [isDropdownMenuOpen, setIsDropdownMenuOpen] = useState(false);
232
- const { dragProps } = useDrag({ ...props, uiNode });
233
- const { isDropTarget, dropProps } = useDrop({
234
- uiNode,
235
- onAddFile,
236
- onCopyNode,
237
- onMoveNode
238
- });
239
- const isReadMode = mode === READ;
240
- function onCancel() {
241
- setMode(READ);
242
- }
243
- function onSubmit(name) {
244
- onRenameNode(name, uiNode);
245
- setMode(READ);
246
- }
247
- function onClick() {
248
- onSelectNode(uiNode);
249
- }
250
- const dropdownMenuHandlers = {
251
- [DUPLICATE]: () => onDuplicateNode(uiNode),
252
- [RENAME]: () => setMode(WRITE),
253
- [DELETE]: () => onDeleteNode(uiNode)
254
- };
255
- const dropdownMenuOptions = Object.entries(nodeOptionsMap).map(([id, option]) => ({
256
- ...option,
257
- id
258
- })).filter((option) => defaultFolderOptions.includes(option.id));
259
- function onDropdownMenuOptionClick(itemId) {
260
- const handler = dropdownMenuHandlers[itemId];
261
- if (!handler) {
262
- console.error(`No handler found for dropdown menu item: ${itemId}`);
263
- return;
264
- }
265
- handler();
266
- setIsDropdownMenuOpen(false);
267
- }
268
- const content = isReadMode || !isAllowedToCreateDocuments ? jsx("div", { className: "ml-3 max-h-6 truncate font-medium text-gray-600 group-hover:text-gray-800", children: uiNode.name }) : jsx(NodeInput, { className: "ml-3 font-medium", defaultValue: uiNode.name, onCancel, onSubmit });
269
- const containerStyles = twMerge("group flex h-12 cursor-pointer select-none items-center rounded-lg bg-gray-200 px-2", className, isDropTarget && "bg-blue-100");
270
- return jsx("div", { className: "relative w-64", onClick, children: jsxs("div", { ...dragProps, ...dropProps, className: containerStyles, children: [jsxs("div", { className: "flex items-center overflow-hidden", children: [jsx("div", { className: "p-1", children: jsxs("div", { className: "relative", children: [jsx(Icon, { name: "FolderClose", size: 24 }), isReadMode && uiNode.syncStatus ? jsx("div", { className: "absolute bottom-[-3px] right-[-2px] size-3 rounded-full bg-white", children: jsx("div", { className: "absolute left-[-2px] top-[-2px]", children: jsx(SyncStatusIcon, { overrideSyncIcons: {
271
- SUCCESS: "CheckCircleFill"
272
- }, syncStatus: uiNode.syncStatus }) }) }) : null] }) }), content] }), isReadMode && isAllowedToCreateDocuments ? jsx(ConnectDropdownMenu, { items: dropdownMenuOptions, onItemClick: onDropdownMenuOptionClick, onOpenChange: setIsDropdownMenuOpen, open: isDropdownMenuOpen, children: jsx("button", { className: twMerge("ml-auto hidden group-hover:block", isDropdownMenuOpen && "block"), onClick: (e) => {
273
- e.stopPropagation();
274
- setIsDropdownMenuOpen(true);
275
- }, children: jsx(Icon, { className: "text-gray-600", name: "VerticalDots" }) }) }) : null] }) });
276
- }
277
155
  const millisecondsInWeek = 6048e5;
278
156
  const millisecondsInDay = 864e5;
157
+ const millisecondsInMinute = 6e4;
158
+ const millisecondsInHour = 36e5;
159
+ const minutesInMonth = 43200;
160
+ const minutesInDay = 1440;
279
161
  const constructFromSymbol = Symbol.for("constructDateFrom");
280
162
  function constructFrom(date, value) {
281
163
  if (typeof date === "function") return date(value);
@@ -343,7 +225,7 @@ function getTimezoneOffsetInMilliseconds(date) {
343
225
  function normalizeDates(context, ...dates) {
344
226
  const normalize = constructFrom.bind(
345
227
  null,
346
- dates.find((date) => typeof date === "object")
228
+ context || dates.find((date) => typeof date === "object")
347
229
  );
348
230
  return dates.map(normalize);
349
231
  }
@@ -371,12 +253,83 @@ function startOfISOWeekYear(date, options) {
371
253
  fourthOfJanuary.setHours(0, 0, 0, 0);
372
254
  return startOfISOWeek(fourthOfJanuary);
373
255
  }
256
+ function compareAsc(dateLeft, dateRight) {
257
+ const diff = +toDate(dateLeft) - +toDate(dateRight);
258
+ if (diff < 0) return -1;
259
+ else if (diff > 0) return 1;
260
+ return diff;
261
+ }
262
+ function constructNow(date) {
263
+ return constructFrom(date, Date.now());
264
+ }
374
265
  function isDate(value) {
375
266
  return value instanceof Date || typeof value === "object" && Object.prototype.toString.call(value) === "[object Date]";
376
267
  }
377
268
  function isValid(date) {
378
269
  return !(!isDate(date) && typeof date !== "number" || isNaN(+toDate(date)));
379
270
  }
271
+ function differenceInCalendarMonths(laterDate, earlierDate, options) {
272
+ const [laterDate_, earlierDate_] = normalizeDates(
273
+ options == null ? void 0 : options.in,
274
+ laterDate,
275
+ earlierDate
276
+ );
277
+ const yearsDiff = laterDate_.getFullYear() - earlierDate_.getFullYear();
278
+ const monthsDiff = laterDate_.getMonth() - earlierDate_.getMonth();
279
+ return yearsDiff * 12 + monthsDiff;
280
+ }
281
+ function getRoundingMethod(method) {
282
+ return (number) => {
283
+ const round = method ? Math[method] : Math.trunc;
284
+ const result = round(number);
285
+ return result === 0 ? 0 : result;
286
+ };
287
+ }
288
+ function differenceInMilliseconds(laterDate, earlierDate) {
289
+ return +toDate(laterDate) - +toDate(earlierDate);
290
+ }
291
+ function endOfDay(date, options) {
292
+ const _date = toDate(date, options == null ? void 0 : options.in);
293
+ _date.setHours(23, 59, 59, 999);
294
+ return _date;
295
+ }
296
+ function endOfMonth(date, options) {
297
+ const _date = toDate(date, options == null ? void 0 : options.in);
298
+ const month = _date.getMonth();
299
+ _date.setFullYear(_date.getFullYear(), month + 1, 0);
300
+ _date.setHours(23, 59, 59, 999);
301
+ return _date;
302
+ }
303
+ function isLastDayOfMonth(date, options) {
304
+ const _date = toDate(date, options == null ? void 0 : options.in);
305
+ return +endOfDay(_date, options) === +endOfMonth(_date, options);
306
+ }
307
+ function differenceInMonths(laterDate, earlierDate, options) {
308
+ const [laterDate_, workingLaterDate, earlierDate_] = normalizeDates(
309
+ options == null ? void 0 : options.in,
310
+ laterDate,
311
+ laterDate,
312
+ earlierDate
313
+ );
314
+ const sign = compareAsc(workingLaterDate, earlierDate_);
315
+ const difference = Math.abs(
316
+ differenceInCalendarMonths(workingLaterDate, earlierDate_)
317
+ );
318
+ if (difference < 1) return 0;
319
+ if (workingLaterDate.getMonth() === 1 && workingLaterDate.getDate() > 27)
320
+ workingLaterDate.setDate(30);
321
+ workingLaterDate.setMonth(workingLaterDate.getMonth() - sign * difference);
322
+ let isLastMonthNotFull = compareAsc(workingLaterDate, earlierDate_) === -sign;
323
+ if (isLastDayOfMonth(laterDate_) && difference === 1 && compareAsc(laterDate_, earlierDate_) === 1) {
324
+ isLastMonthNotFull = false;
325
+ }
326
+ const result = sign * (difference - +isLastMonthNotFull);
327
+ return result === 0 ? 0 : result;
328
+ }
329
+ function differenceInSeconds(laterDate, earlierDate, options) {
330
+ const diff = differenceInMilliseconds(laterDate, earlierDate) / 1e3;
331
+ return getRoundingMethod(options == null ? void 0 : options.roundingMethod)(diff);
332
+ }
380
333
  function startOfYear(date, options) {
381
334
  const date_ = toDate(date, options == null ? void 0 : options.in);
382
335
  date_.setFullYear(date_.getFullYear(), 0, 1);
@@ -446,7 +399,7 @@ const formatDistanceLocale = {
446
399
  other: "almost {{count}} years"
447
400
  }
448
401
  };
449
- const formatDistance = (token, count, options) => {
402
+ const formatDistance$1 = (token, count, options) => {
450
403
  let result;
451
404
  const tokenValue = formatDistanceLocale[token];
452
405
  if (typeof tokenValue === "string") {
@@ -862,7 +815,7 @@ const match = {
862
815
  };
863
816
  const enUS = {
864
817
  code: "en-US",
865
- formatDistance,
818
+ formatDistance: formatDistance$1,
866
819
  formatLong,
867
820
  formatRelative,
868
821
  localize,
@@ -985,6 +938,8 @@ const lightFormatters = {
985
938
  }
986
939
  };
987
940
  const dayPeriodEnum = {
941
+ am: "am",
942
+ pm: "pm",
988
943
  midnight: "midnight",
989
944
  noon: "noon",
990
945
  morning: "morning",
@@ -1764,76 +1719,575 @@ function cleanEscapedString(input) {
1764
1719
  }
1765
1720
  return matched[1].replace(doubleQuoteRegExp, "'");
1766
1721
  }
1767
- function NodeInput(props) {
1768
- const { onSubmit, onCancel, defaultValue, className, minLength = 1, ...inputProps } = props;
1769
- const [value, setValue] = useState(defaultValue ?? "");
1770
- const ref = useRef(null);
1771
- useOnClickOutside(ref, handleSubmit);
1772
- useEventListener("keyup", (e) => {
1773
- if (e.key === "Enter") {
1774
- handleSubmit();
1722
+ function formatDistance(laterDate, earlierDate, options) {
1723
+ const defaultOptions2 = getDefaultOptions();
1724
+ const locale = (options == null ? void 0 : options.locale) ?? defaultOptions2.locale ?? enUS;
1725
+ const minutesInAlmostTwoDays = 2520;
1726
+ const comparison = compareAsc(laterDate, earlierDate);
1727
+ if (isNaN(comparison)) throw new RangeError("Invalid time value");
1728
+ const localizeOptions = Object.assign({}, options, {
1729
+ addSuffix: options == null ? void 0 : options.addSuffix,
1730
+ comparison
1731
+ });
1732
+ const [laterDate_, earlierDate_] = normalizeDates(
1733
+ options == null ? void 0 : options.in,
1734
+ ...comparison > 0 ? [earlierDate, laterDate] : [laterDate, earlierDate]
1735
+ );
1736
+ const seconds = differenceInSeconds(earlierDate_, laterDate_);
1737
+ const offsetInSeconds = (getTimezoneOffsetInMilliseconds(earlierDate_) - getTimezoneOffsetInMilliseconds(laterDate_)) / 1e3;
1738
+ const minutes = Math.round((seconds - offsetInSeconds) / 60);
1739
+ let months;
1740
+ if (minutes < 2) {
1741
+ if (options == null ? void 0 : options.includeSeconds) {
1742
+ if (seconds < 5) {
1743
+ return locale.formatDistance("lessThanXSeconds", 5, localizeOptions);
1744
+ } else if (seconds < 10) {
1745
+ return locale.formatDistance("lessThanXSeconds", 10, localizeOptions);
1746
+ } else if (seconds < 20) {
1747
+ return locale.formatDistance("lessThanXSeconds", 20, localizeOptions);
1748
+ } else if (seconds < 40) {
1749
+ return locale.formatDistance("halfAMinute", 0, localizeOptions);
1750
+ } else if (seconds < 60) {
1751
+ return locale.formatDistance("lessThanXMinutes", 1, localizeOptions);
1752
+ } else {
1753
+ return locale.formatDistance("xMinutes", 1, localizeOptions);
1754
+ }
1755
+ } else {
1756
+ if (minutes === 0) {
1757
+ return locale.formatDistance("lessThanXMinutes", 1, localizeOptions);
1758
+ } else {
1759
+ return locale.formatDistance("xMinutes", minutes, localizeOptions);
1760
+ }
1775
1761
  }
1776
- if (e.key === "Escape") {
1777
- onCancel();
1762
+ } else if (minutes < 45) {
1763
+ return locale.formatDistance("xMinutes", minutes, localizeOptions);
1764
+ } else if (minutes < 90) {
1765
+ return locale.formatDistance("aboutXHours", 1, localizeOptions);
1766
+ } else if (minutes < minutesInDay) {
1767
+ const hours = Math.round(minutes / 60);
1768
+ return locale.formatDistance("aboutXHours", hours, localizeOptions);
1769
+ } else if (minutes < minutesInAlmostTwoDays) {
1770
+ return locale.formatDistance("xDays", 1, localizeOptions);
1771
+ } else if (minutes < minutesInMonth) {
1772
+ const days = Math.round(minutes / minutesInDay);
1773
+ return locale.formatDistance("xDays", days, localizeOptions);
1774
+ } else if (minutes < minutesInMonth * 2) {
1775
+ months = Math.round(minutes / minutesInMonth);
1776
+ return locale.formatDistance("aboutXMonths", months, localizeOptions);
1777
+ }
1778
+ months = differenceInMonths(earlierDate_, laterDate_);
1779
+ if (months < 12) {
1780
+ const nearestMonth = Math.round(minutes / minutesInMonth);
1781
+ return locale.formatDistance("xMonths", nearestMonth, localizeOptions);
1782
+ } else {
1783
+ const monthsSinceStartOfYear = months % 12;
1784
+ const years = Math.trunc(months / 12);
1785
+ if (monthsSinceStartOfYear < 3) {
1786
+ return locale.formatDistance("aboutXYears", years, localizeOptions);
1787
+ } else if (monthsSinceStartOfYear < 9) {
1788
+ return locale.formatDistance("overXYears", years, localizeOptions);
1789
+ } else {
1790
+ return locale.formatDistance("almostXYears", years + 1, localizeOptions);
1778
1791
  }
1779
- });
1780
- useLayoutEffect(() => {
1781
- setTimeout(() => {
1782
- var _a, _b, _c;
1783
- (_a = ref.current) == null ? void 0 : _a.focus();
1784
- (_b = ref.current) == null ? void 0 : _b.select();
1785
- (_c = ref.current) == null ? void 0 : _c.scroll({ left: 9999 });
1786
- }, 100);
1787
- }, []);
1788
- function handleSubmit() {
1789
- if (value.length >= minLength) {
1790
- onSubmit(value);
1792
+ }
1793
+ }
1794
+ function formatDistanceToNow(date, options) {
1795
+ return formatDistance(date, constructNow(date), options);
1796
+ }
1797
+ function parseISO(argument, options) {
1798
+ const invalidDate = () => constructFrom(options == null ? void 0 : options.in, NaN);
1799
+ const additionalDigits = 2;
1800
+ const dateStrings = splitDateString(argument);
1801
+ let date;
1802
+ if (dateStrings.date) {
1803
+ const parseYearResult = parseYear(dateStrings.date, additionalDigits);
1804
+ date = parseDate(parseYearResult.restDateString, parseYearResult.year);
1805
+ }
1806
+ if (!date || isNaN(+date)) return invalidDate();
1807
+ const timestamp = +date;
1808
+ let time = 0;
1809
+ let offset;
1810
+ if (dateStrings.time) {
1811
+ time = parseTime(dateStrings.time);
1812
+ if (isNaN(time)) return invalidDate();
1813
+ }
1814
+ if (dateStrings.timezone) {
1815
+ offset = parseTimezone(dateStrings.timezone);
1816
+ if (isNaN(offset)) return invalidDate();
1817
+ } else {
1818
+ const tmpDate = new Date(timestamp + time);
1819
+ const result = toDate(0, options == null ? void 0 : options.in);
1820
+ result.setFullYear(
1821
+ tmpDate.getUTCFullYear(),
1822
+ tmpDate.getUTCMonth(),
1823
+ tmpDate.getUTCDate()
1824
+ );
1825
+ result.setHours(
1826
+ tmpDate.getUTCHours(),
1827
+ tmpDate.getUTCMinutes(),
1828
+ tmpDate.getUTCSeconds(),
1829
+ tmpDate.getUTCMilliseconds()
1830
+ );
1831
+ return result;
1832
+ }
1833
+ return toDate(timestamp + time + offset, options == null ? void 0 : options.in);
1834
+ }
1835
+ const patterns = {
1836
+ dateTimeDelimiter: /[T ]/,
1837
+ timeZoneDelimiter: /[Z ]/i,
1838
+ timezone: /([Z+-].*)$/
1839
+ };
1840
+ const dateRegex = /^-?(?:(\d{3})|(\d{2})(?:-?(\d{2}))?|W(\d{2})(?:-?(\d{1}))?|)$/;
1841
+ const timeRegex = /^(\d{2}(?:[.,]\d*)?)(?::?(\d{2}(?:[.,]\d*)?))?(?::?(\d{2}(?:[.,]\d*)?))?$/;
1842
+ const timezoneRegex = /^([+-])(\d{2})(?::?(\d{2}))?$/;
1843
+ function splitDateString(dateString) {
1844
+ const dateStrings = {};
1845
+ const array = dateString.split(patterns.dateTimeDelimiter);
1846
+ let timeString;
1847
+ if (array.length > 2) {
1848
+ return dateStrings;
1849
+ }
1850
+ if (/:/.test(array[0])) {
1851
+ timeString = array[0];
1852
+ } else {
1853
+ dateStrings.date = array[0];
1854
+ timeString = array[1];
1855
+ if (patterns.timeZoneDelimiter.test(dateStrings.date)) {
1856
+ dateStrings.date = dateString.split(patterns.timeZoneDelimiter)[0];
1857
+ timeString = dateString.substr(
1858
+ dateStrings.date.length,
1859
+ dateString.length
1860
+ );
1791
1861
  }
1792
1862
  }
1793
- return jsx("input", { ...inputProps, autoFocus: true, className: twMerge("bg-inherit text-inherit outline-none", className), minLength, onChange: (e) => setValue(e.target.value), ref, required: true, type: "text", value });
1863
+ if (timeString) {
1864
+ const token = patterns.timezone.exec(timeString);
1865
+ if (token) {
1866
+ dateStrings.time = timeString.replace(token[1], "");
1867
+ dateStrings.timezone = token[1];
1868
+ } else {
1869
+ dateStrings.time = timeString;
1870
+ }
1871
+ }
1872
+ return dateStrings;
1794
1873
  }
1795
- function Branch(props) {
1796
- const { branch = "main" } = props;
1797
- return jsxs("button", { className: "flex h-8 items-center gap-1 rounded-lg bg-slate-50 pl-1 pr-2 text-xs text-slate-100", children: [jsx(Icon, { name: "Branch" }), jsx("span", { children: "BRANCH" }), jsx("span", { className: "text-gray-900", children: branch })] });
1874
+ function parseYear(dateString, additionalDigits) {
1875
+ const regex = new RegExp(
1876
+ "^(?:(\\d{4}|[+-]\\d{" + (4 + additionalDigits) + "})|(\\d{2}|[+-]\\d{" + (2 + additionalDigits) + "})$)"
1877
+ );
1878
+ const captures = dateString.match(regex);
1879
+ if (!captures) return { year: NaN, restDateString: "" };
1880
+ const year = captures[1] ? parseInt(captures[1]) : null;
1881
+ const century = captures[2] ? parseInt(captures[2]) : null;
1882
+ return {
1883
+ year: century === null ? year : century * 100,
1884
+ restDateString: dateString.slice((captures[1] || captures[2]).length)
1885
+ };
1798
1886
  }
1799
- function DocId(props) {
1800
- const { docId } = props;
1801
- const [, copy] = useCopyToClipboard();
1802
- function handleCopy(text) {
1803
- return () => {
1804
- copy(text).catch((error) => {
1805
- console.error("Failed to copy!", error);
1806
- });
1807
- };
1887
+ function parseDate(dateString, year) {
1888
+ if (year === null) return /* @__PURE__ */ new Date(NaN);
1889
+ const captures = dateString.match(dateRegex);
1890
+ if (!captures) return /* @__PURE__ */ new Date(NaN);
1891
+ const isWeekDate = !!captures[4];
1892
+ const dayOfYear = parseDateUnit(captures[1]);
1893
+ const month = parseDateUnit(captures[2]) - 1;
1894
+ const day = parseDateUnit(captures[3]);
1895
+ const week = parseDateUnit(captures[4]);
1896
+ const dayOfWeek = parseDateUnit(captures[5]) - 1;
1897
+ if (isWeekDate) {
1898
+ if (!validateWeekDate(year, week, dayOfWeek)) {
1899
+ return /* @__PURE__ */ new Date(NaN);
1900
+ }
1901
+ return dayOfISOWeekYear(year, week, dayOfWeek);
1902
+ } else {
1903
+ const date = /* @__PURE__ */ new Date(0);
1904
+ if (!validateDate(year, month, day) || !validateDayOfYearDate(year, dayOfYear)) {
1905
+ return /* @__PURE__ */ new Date(NaN);
1906
+ }
1907
+ date.setUTCFullYear(year, month, Math.max(dayOfYear, day));
1908
+ return date;
1808
1909
  }
1809
- return jsxs("button", { className: "flex h-8 items-center gap-1 rounded-lg bg-slate-50 pl-1 pr-2 text-xs text-slate-100", onClick: handleCopy(docId), children: [jsx(Icon, { name: "Link" }), "DOC ID", jsx("span", { className: "text-gray-900", children: docId })] });
1810
1910
  }
1811
- function Scope(props) {
1812
- const { value, onChange } = props;
1813
- const items = [
1814
- { displayValue: "Global scope", value: "global" },
1815
- { displayValue: "Local scope", value: "local" }
1816
- ];
1817
- return jsx(Select, { absolutePositionMenu: true, containerClassName: "bg-slate-50 text-gray-500 rounded-lg w-fit text-xs z-10", id: "scope select", itemClassName: "py-2 text-gray-500 grid grid-cols-[auto,auto] gap-1", items, menuClassName: "min-w-0 text-gray-500", onChange, value });
1911
+ function parseDateUnit(value) {
1912
+ return value ? parseInt(value) : 1;
1818
1913
  }
1819
- function Header(props) {
1820
- const { title, docId, scope, onChangeScope, onClose, className, ...divProps } = props;
1821
- return jsxs("header", { className: twMerge("flex items-center justify-between bg-transparent", className), ...divProps, children: [jsxs("div", { className: "flex items-center gap-3", children: [jsx("button", { className: "shadow-button rounded-lg bg-gray-50 p-1 text-slate-100", onClick: onClose, children: jsx(Icon, { name: "VariantArrowLeft" }) }), jsx("h1", { className: "text-xs", children: title })] }), jsxs("div", { className: "flex items-center gap-2", children: [jsx(DocId, { docId }), jsx(Branch, {}), jsx(Scope, { onChange: onChangeScope, value: scope })] })] });
1914
+ function parseTime(timeString) {
1915
+ const captures = timeString.match(timeRegex);
1916
+ if (!captures) return NaN;
1917
+ const hours = parseTimeUnit(captures[1]);
1918
+ const minutes = parseTimeUnit(captures[2]);
1919
+ const seconds = parseTimeUnit(captures[3]);
1920
+ if (!validateTime(hours, minutes, seconds)) {
1921
+ return NaN;
1922
+ }
1923
+ return hours * millisecondsInHour + minutes * millisecondsInMinute + seconds * 1e3;
1822
1924
  }
1823
- function memo(getDeps, fn, opts) {
1824
- let deps = opts.initialDeps ?? [];
1825
- let result;
1826
- function memoizedFunction() {
1827
- var _a, _b, _c, _d;
1828
- let depTime;
1829
- if (opts.key && ((_a = opts.debug) == null ? void 0 : _a.call(opts))) depTime = Date.now();
1830
- const newDeps = getDeps();
1831
- const depsChanged = newDeps.length !== deps.length || newDeps.some((dep, index) => deps[index] !== dep);
1832
- if (!depsChanged) {
1833
- return result;
1925
+ function parseTimeUnit(value) {
1926
+ return value && parseFloat(value.replace(",", ".")) || 0;
1927
+ }
1928
+ function parseTimezone(timezoneString) {
1929
+ if (timezoneString === "Z") return 0;
1930
+ const captures = timezoneString.match(timezoneRegex);
1931
+ if (!captures) return 0;
1932
+ const sign = captures[1] === "+" ? -1 : 1;
1933
+ const hours = parseInt(captures[2]);
1934
+ const minutes = captures[3] && parseInt(captures[3]) || 0;
1935
+ if (!validateTimezone(hours, minutes)) {
1936
+ return NaN;
1937
+ }
1938
+ return sign * (hours * millisecondsInHour + minutes * millisecondsInMinute);
1939
+ }
1940
+ function dayOfISOWeekYear(isoWeekYear, week, day) {
1941
+ const date = /* @__PURE__ */ new Date(0);
1942
+ date.setUTCFullYear(isoWeekYear, 0, 4);
1943
+ const fourthOfJanuaryDay = date.getUTCDay() || 7;
1944
+ const diff = (week - 1) * 7 + day + 1 - fourthOfJanuaryDay;
1945
+ date.setUTCDate(date.getUTCDate() + diff);
1946
+ return date;
1947
+ }
1948
+ const daysInMonths = [31, null, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
1949
+ function isLeapYearIndex(year) {
1950
+ return year % 400 === 0 || year % 4 === 0 && year % 100 !== 0;
1951
+ }
1952
+ function validateDate(year, month, date) {
1953
+ return month >= 0 && month <= 11 && date >= 1 && date <= (daysInMonths[month] || (isLeapYearIndex(year) ? 29 : 28));
1954
+ }
1955
+ function validateDayOfYearDate(year, dayOfYear) {
1956
+ return dayOfYear >= 1 && dayOfYear <= (isLeapYearIndex(year) ? 366 : 365);
1957
+ }
1958
+ function validateWeekDate(_year, week, day) {
1959
+ return week >= 1 && week <= 53 && day >= 0 && day <= 6;
1960
+ }
1961
+ function validateTime(hours, minutes, seconds) {
1962
+ if (hours === 24) {
1963
+ return minutes === 0 && seconds === 0;
1964
+ }
1965
+ return seconds >= 0 && seconds < 60 && minutes >= 0 && minutes < 60 && hours >= 0 && hours < 25;
1966
+ }
1967
+ function validateTimezone(_hours, minutes) {
1968
+ return minutes >= 0 && minutes <= 59;
1969
+ }
1970
+ const HDivider = (props) => {
1971
+ const { className, timestamp, title, subtitle, onClick, isSelected = false } = props;
1972
+ const [open, setOpen] = useState(false);
1973
+ const hasContent = !!title || !!subtitle || !!timestamp;
1974
+ useEffect(() => {
1975
+ if (open) {
1976
+ setOpen(false);
1977
+ setTimeout(() => hasContent && setOpen(true), 50);
1834
1978
  }
1835
- deps = newDeps;
1836
- let resultTime;
1979
+ }, [title, subtitle, timestamp, hasContent]);
1980
+ const formatTimestamp2 = (isoString) => {
1981
+ if (!isoString)
1982
+ return "";
1983
+ try {
1984
+ return formatDistanceToNow(new Date(isoString), { addSuffix: true });
1985
+ } catch {
1986
+ return isoString;
1987
+ }
1988
+ };
1989
+ const tooltipContent = jsxs("div", { className: "flex flex-col text-xs", children: [!!title && jsx("div", { children: title }), !!subtitle && jsx("div", { className: "text-gray-300", children: subtitle }), !!timestamp && jsx("div", { children: formatTimestamp2(timestamp) })] });
1990
+ const handleMouseEnter = () => {
1991
+ if (hasContent) {
1992
+ setOpen(true);
1993
+ }
1994
+ };
1995
+ const handleMouseLeave = () => {
1996
+ setOpen(false);
1997
+ };
1998
+ return jsxs("div", { className: "relative", onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, children: [isSelected && jsx(Icon, { name: "TimelineCaret", color: "#4EA9FF", size: 10, className: "absolute top-[-11px] z-40" }), jsx(Tooltip, { className: "rounded-md bg-gray-900 text-white", content: tooltipContent, open: open && hasContent, onOpenChange: setOpen, delayDuration: 0, side: "bottom", sideOffset: 5, children: jsx("div", { className: twMerge("mx-0.5 flex h-[25px] w-1.5 cursor-pointer flex-col items-center justify-center rounded-[2px] hover:bg-blue-300", isSelected && "bg-blue-300", className), onClick, "data-title": title, "data-subtitle": subtitle, "data-timestamp": timestamp, children: jsx("div", { className: "h-0.5 w-1 rounded-full bg-gray-500" }) }) })] });
1999
+ };
2000
+ const getBarHeight = (size = 0) => {
2001
+ switch (true) {
2002
+ case size <= 0:
2003
+ return "h-[1px]";
2004
+ case size === 1:
2005
+ return "h-[3px]";
2006
+ case size === 2:
2007
+ return "h-[6px]";
2008
+ case size === 3:
2009
+ return "h-[9px]";
2010
+ case size >= 4:
2011
+ return "h-[12px]";
2012
+ default:
2013
+ return "h-[1px]";
2014
+ }
2015
+ };
2016
+ const formatTimestamp = (isoString) => {
2017
+ if (!isoString)
2018
+ return "";
2019
+ try {
2020
+ const date = parseISO(isoString);
2021
+ return format(date, "HH:mm, dd, MMMM");
2022
+ } catch {
2023
+ return isoString;
2024
+ }
2025
+ };
2026
+ const TimelineBar = ({ onClick, className, timestamp, additions, deletions, addSize = 0, delSize = 0, isSelected = false }) => {
2027
+ const [open, setOpen] = useState(false);
2028
+ const noChanges = addSize === 0 && delSize === 0;
2029
+ const addBarHeight = getBarHeight(addSize);
2030
+ const delBarHeight = getBarHeight(delSize);
2031
+ const tooltipContent = jsxs("div", { className: "flex flex-col text-xs", children: [jsx("div", { children: formatTimestamp(timestamp) }), jsx("div", { className: "text-green-900", children: `${additions} additions +` }), jsx("div", { className: "text-red-700", children: `${deletions} deletions -` })] });
2032
+ const handleMouseEnter = () => {
2033
+ if (!noChanges) {
2034
+ setOpen(true);
2035
+ }
2036
+ };
2037
+ const handleMouseLeave = () => {
2038
+ setOpen(false);
2039
+ };
2040
+ return jsxs("div", { className: "relative", onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, children: [isSelected && jsx(Icon, { name: "TimelineCaret", color: "#4EA9FF", size: 10, className: "absolute left-[-2px] top-[-11px] z-40" }), noChanges ? jsx("div", { className: twMerge("flex h-[25px] w-1.5 cursor-pointer flex-col items-center justify-center rounded-[2px] hover:bg-blue-300", className), "data-timestamp": timestamp, onClick, children: jsx("div", { className: "size-[3px] rounded-full bg-gray-500" }) }) : jsx(Tooltip, { className: "rounded-md bg-gray-900 text-white", content: tooltipContent, open, onOpenChange: setOpen, delayDuration: 0, side: "bottom", sideOffset: 5, children: jsxs("div", { className: twMerge("flex h-[25px] w-1.5 cursor-pointer flex-col items-center justify-center rounded-[2px] hover:bg-blue-300", className, isSelected && "bg-blue-300"), "data-timestamp": timestamp, onClick, children: [jsx("div", { className: "flex h-3 w-0.5 items-end", children: jsx("div", { className: twMerge("h-3 w-0.5 rounded-t-full bg-green-600", addBarHeight) }) }), jsx("div", { className: "flex h-3 w-0.5 items-start", children: jsx("div", { className: twMerge("h-3 w-0.5 rounded-b-full bg-red-600", delBarHeight) }) })] }) })] });
2041
+ };
2042
+ const defaultTimeLineItem = {
2043
+ id: "default",
2044
+ type: "bar",
2045
+ addSize: 0,
2046
+ delSize: 0
2047
+ };
2048
+ const DocumentTimeline = (props) => {
2049
+ const { timeline = [], onItemClick } = props;
2050
+ const [selectedItem, setSelectedItem] = useState(null);
2051
+ const scrollContainerRef = useRef(null);
2052
+ const handleClick = (item) => {
2053
+ if (item.id === selectedItem || item.id === defaultTimeLineItem.id) {
2054
+ onItemClick == null ? void 0 : onItemClick(null);
2055
+ setSelectedItem(null);
2056
+ } else {
2057
+ onItemClick == null ? void 0 : onItemClick(item);
2058
+ setSelectedItem(item.id);
2059
+ }
2060
+ };
2061
+ const mergedTimelineItems = [...timeline, defaultTimeLineItem];
2062
+ const [unselectedItems, selectedItems] = useMemo(() => {
2063
+ const indexSelected = mergedTimelineItems.findIndex((item) => item.id === selectedItem);
2064
+ return indexSelected === -1 ? [mergedTimelineItems, []] : [
2065
+ mergedTimelineItems.slice(0, indexSelected),
2066
+ mergedTimelineItems.slice(indexSelected)
2067
+ ];
2068
+ }, [mergedTimelineItems, selectedItem]);
2069
+ const renderTimelineItems = useCallback((items) => {
2070
+ return items.map((item) => {
2071
+ if (item.type === "divider") {
2072
+ const { timestamp, title, subtitle } = item;
2073
+ return jsx(HDivider, { timestamp, title, subtitle, onClick: () => handleClick(item), isSelected: item.id === selectedItem }, item.id);
2074
+ }
2075
+ return jsx(TimelineBar, { timestamp: item.timestamp, addSize: item.addSize, delSize: item.delSize, additions: item.additions, deletions: item.deletions, isSelected: item.id === selectedItem, onClick: () => handleClick(item) }, item.id);
2076
+ });
2077
+ }, [handleClick, selectedItem]);
2078
+ const unselectedContent = useMemo(() => renderTimelineItems(unselectedItems), [unselectedItems, renderTimelineItems]);
2079
+ const selectedContent = useMemo(() => renderTimelineItems(selectedItems), [selectedItems, renderTimelineItems]);
2080
+ useEffect(() => {
2081
+ if (scrollContainerRef.current) {
2082
+ scrollContainerRef.current.scrollLeft = scrollContainerRef.current.scrollWidth;
2083
+ }
2084
+ }, []);
2085
+ return jsx(TooltipProvider, { delayDuration: 0, skipDelayDuration: 0, children: jsxs("div", { className: "relative h-[36px] w-full", children: [jsx("div", { className: "absolute left-[0px] z-[20] h-[17px] w-[6px] bg-white", children: jsx("div", { className: "mt-[11px] h-[6px] w-[6px] rounded-tl-md bg-slate-50" }) }), jsx("div", { className: "absolute right-[0px] top-[11px] z-[20] h-[6px] w-[6px] bg-white", children: jsx("div", { className: "h-[6px] w-[6px] rounded-tr-md bg-slate-50" }) }), jsx("div", { className: "absolute inset-x-0 bottom-0 h-[25px] rounded-md bg-slate-50" }), jsx("div", { className: "absolute inset-x-0 bottom-0 h-[36px]", children: jsx("div", { ref: scrollContainerRef, className: "h-full overflow-x-auto rounded-md", children: jsxs("div", { className: "ml-auto flex h-[36px] w-max items-end px-2 pb-0", children: [jsx("div", { className: "flex", children: unselectedContent }), jsx("div", { className: "flex rounded-sm bg-blue-200", children: selectedContent })] }) }) }), jsx("div", { className: "pointer-events-none absolute bottom-0 left-0 z-10 h-[25px] w-2 rounded-l-md bg-slate-50" }), jsx("div", { className: "pointer-events-none absolute bottom-0 right-0 z-10 h-[25px] w-2 rounded-r-md bg-slate-50" })] }) });
2086
+ };
2087
+ const DocumentToolbar = (props) => {
2088
+ const { undo: undo2, canUndo, redo: redo2, canRedo, title, onClose, onExport, className, onShowRevisionHistory, onSwitchboardLinkClick, timelineItems = [], onTimelineItemClick, initialTimelineVisible = false, timelineButtonVisible = false } = props;
2089
+ const [showTimeline, setShowTimeline] = useState(initialTimelineVisible);
2090
+ const isUndoDisabled = !canUndo || !undo2;
2091
+ const isRedoDisabled = !canRedo || !redo2;
2092
+ const isExportDisabled = !onExport;
2093
+ const isSwitchboardLinkDisabled = !onSwitchboardLinkClick;
2094
+ const isRevisionHistoryDisabled = !onShowRevisionHistory;
2095
+ const isTimelineDisabled = timelineItems.length === 0;
2096
+ useEffect(() => {
2097
+ if (initialTimelineVisible) {
2098
+ setShowTimeline(true);
2099
+ }
2100
+ }, [initialTimelineVisible]);
2101
+ const handleTimelineToggle = () => {
2102
+ if (isTimelineDisabled)
2103
+ return;
2104
+ setShowTimeline(!showTimeline);
2105
+ };
2106
+ return jsxs("div", { className: "flex w-full flex-col", children: [jsxs("div", { className: twMerge("flex h-12 w-full items-center justify-between rounded-xl border border-gray-200 bg-slate-50 px-4", className), children: [jsxs("div", { className: "flex items-center gap-x-2", children: [jsx("button", { className: twMerge("grid size-8 place-items-center rounded-lg border border-gray-200 bg-white", isUndoDisabled ? "cursor-not-allowed" : "cursor-pointer active:opacity-70"), onClick: undo2, disabled: isUndoDisabled, children: jsx(Icon, { name: "ArrowCouterclockwise", size: 16, className: isUndoDisabled ? "text-gray-500" : "text-gray-900" }) }), jsx("button", { className: twMerge("grid size-8 place-items-center rounded-lg border border-gray-200 bg-white", isRedoDisabled ? "cursor-not-allowed" : "cursor-pointer active:opacity-70"), onClick: redo2, disabled: isRedoDisabled, children: jsx("div", { className: "-scale-x-100", children: jsx(Icon, { name: "ArrowCouterclockwise", size: 16, className: isRedoDisabled ? "text-gray-500" : "text-gray-900" }) }) }), jsx("button", { className: twMerge("flex h-8 items-center rounded-lg border border-gray-200 bg-white px-3 text-sm", isExportDisabled ? "cursor-not-allowed" : "cursor-pointer active:opacity-70"), onClick: onExport, disabled: isExportDisabled, children: jsx("span", { className: isExportDisabled ? "text-gray-500" : "text-gray-900", children: "Export" }) })] }), jsx("div", { className: "flex items-center", children: jsx("h1", { className: "text-sm font-medium text-gray-500", children: title }) }), jsxs("div", { className: "flex items-center gap-x-2", children: [jsx("button", { className: twMerge("grid size-8 place-items-center rounded-lg border border-gray-200 bg-white", isSwitchboardLinkDisabled ? "cursor-not-allowed" : "cursor-pointer active:opacity-70"), onClick: onSwitchboardLinkClick, disabled: isSwitchboardLinkDisabled, children: jsx(Icon, { name: "Drive", size: 16, className: isSwitchboardLinkDisabled ? "text-gray-500" : "text-gray-900" }) }), jsx("button", { className: twMerge("grid size-8 place-items-center rounded-lg border border-gray-200 bg-white", isRevisionHistoryDisabled ? "cursor-not-allowed" : "cursor-pointer active:opacity-70"), onClick: onShowRevisionHistory, disabled: isRevisionHistoryDisabled, children: jsx(Icon, { name: "History", size: 16, className: isRevisionHistoryDisabled ? "text-gray-500" : "text-gray-900" }) }), timelineButtonVisible && jsx("button", { className: twMerge("grid size-8 place-items-center rounded-lg border border-gray-200 bg-white", isTimelineDisabled ? "cursor-not-allowed" : "cursor-pointer active:opacity-70"), onClick: handleTimelineToggle, disabled: isTimelineDisabled, "aria-pressed": showTimeline, children: jsx(Icon, { name: "Timeline", size: 16, className: twMerge("text-gray-900", isTimelineDisabled && "opacity-50", showTimeline && "text-blue-600") }) }), jsx("button", { className: "grid size-8 cursor-pointer place-items-center rounded-lg border border-gray-200 bg-white active:opacity-70", onClick: onClose, children: jsx(Icon, { name: "XmarkLight", size: 16, className: "text-gray-900" }) })] })] }), showTimeline && jsx("div", { className: "mt-2 w-full", children: jsx(DocumentTimeline, { timeline: timelineItems, onItemClick: onTimelineItemClick }) })] });
2107
+ };
2108
+ const syncIcons = {
2109
+ SYNCING: "Syncing",
2110
+ SUCCESS: "Synced",
2111
+ CONFLICT: "Error",
2112
+ MISSING: "Circle",
2113
+ ERROR: "Error",
2114
+ INITIAL_SYNC: "Syncing"
2115
+ };
2116
+ function SyncStatusIcon(props) {
2117
+ const { syncStatus, className, overrideSyncIcons = {}, ...iconProps } = props;
2118
+ const icons = { ...syncIcons, ...overrideSyncIcons };
2119
+ const syncStatusIcons = {
2120
+ [INITIAL_SYNC]: jsx(Icon, { size: 16, ...iconProps, className: twMerge("text-blue-900", className), name: icons[INITIAL_SYNC] }),
2121
+ [SYNCING]: jsx(Icon, { size: 16, ...iconProps, className: twMerge("text-blue-900", className), name: icons[SYNCING] }),
2122
+ [SUCCESS]: jsx(Icon, { size: 16, ...iconProps, className: twMerge("text-green-900", className), name: icons[SUCCESS] }),
2123
+ [CONFLICT]: jsx(Icon, { size: 16, ...iconProps, className: twMerge("text-orange-900", className), name: icons[CONFLICT] }),
2124
+ [MISSING]: jsx(Icon, { size: 16, ...iconProps, className: twMerge("text-red-900", className), name: icons[MISSING] }),
2125
+ [ERROR]: jsx(Icon, { size: 16, ...iconProps, className: twMerge("text-red-900", className), name: icons[ERROR] })
2126
+ };
2127
+ return syncStatusIcons[syncStatus];
2128
+ }
2129
+ function FileItem(props) {
2130
+ const { uiNode, className, customDocumentIconSrc, onSelectNode, onRenameNode, onDuplicateNode, onDeleteNode, isAllowedToCreateDocuments } = props;
2131
+ const [mode, setMode] = useState(READ);
2132
+ const [isDropdownMenuOpen, setIsDropdownMenuOpen] = useState(false);
2133
+ const { dragProps } = useDrag({ uiNode });
2134
+ const isReadMode = mode === READ;
2135
+ const dropdownMenuHandlers = {
2136
+ [DUPLICATE]: () => onDuplicateNode(uiNode),
2137
+ [RENAME]: () => setMode(WRITE),
2138
+ [DELETE]: () => onDeleteNode(uiNode)
2139
+ };
2140
+ const dropdownMenuOptions = Object.entries(nodeOptionsMap).map(([id, option]) => ({
2141
+ ...option,
2142
+ id
2143
+ })).filter((option) => defaultFileOptions.includes(option.id));
2144
+ function onSubmit(name) {
2145
+ onRenameNode(name, uiNode);
2146
+ setMode(READ);
2147
+ }
2148
+ function onCancel() {
2149
+ setMode(READ);
2150
+ }
2151
+ function onClick() {
2152
+ onSelectNode(uiNode);
2153
+ }
2154
+ function onDropdownMenuOptionClick(itemId) {
2155
+ const handler = dropdownMenuHandlers[itemId];
2156
+ if (!handler) {
2157
+ console.error(`No handler found for dropdown menu item: ${itemId}`);
2158
+ return;
2159
+ }
2160
+ handler();
2161
+ setIsDropdownMenuOpen(false);
2162
+ }
2163
+ const iconSrc = getDocumentIconSrc(uiNode.documentType, customDocumentIconSrc);
2164
+ const iconNode = jsxs("div", { className: "relative", children: [jsx("img", { alt: "file icon", className: "max-w-none", height: 34, src: iconSrc, width: 32 }), isReadMode && uiNode.syncStatus && jsx("div", { className: "absolute bottom-[-2px] right-0 size-3 rounded-full bg-white", children: jsx("div", { className: "absolute left-[-2px] top-[-2px]", children: jsx(SyncStatusIcon, { overrideSyncIcons: { SUCCESS: "CheckCircleFill" }, syncStatus: uiNode.syncStatus }) }) })] });
2165
+ const containerStyles = twMerge("group flex h-12 cursor-pointer select-none items-center rounded-lg bg-gray-200 px-2 text-gray-600 hover:text-gray-800", className);
2166
+ const content = isReadMode ? jsxs("div", { className: "flex w-52 items-center justify-between", children: [jsxs("div", { className: "mr-2 truncate group-hover:mr-0", children: [jsx("div", { className: "max-h-6 truncate text-sm font-medium group-hover:text-gray-800", children: uiNode.name }), jsx("div", { className: "max-h-6 truncate text-xs font-medium text-gray-600 group-hover:text-gray-800", children: uiNode.documentType })] }), isAllowedToCreateDocuments ? jsx(ConnectDropdownMenu, { items: dropdownMenuOptions, onItemClick: onDropdownMenuOptionClick, onOpenChange: setIsDropdownMenuOpen, open: isDropdownMenuOpen, children: jsx("button", { className: twMerge("hidden group-hover:block", isDropdownMenuOpen && "block"), onClick: (e) => {
2167
+ e.stopPropagation();
2168
+ setIsDropdownMenuOpen(true);
2169
+ }, children: jsx(Icon, { className: "text-gray-600", name: "VerticalDots" }) }) }) : null] }) : jsx(NodeInput, { className: "ml-3 flex-1 font-medium", defaultValue: uiNode.name, onCancel, onSubmit });
2170
+ return jsx("div", { className: "relative w-64", onClick, children: jsx("div", { ...dragProps, className: containerStyles, children: jsxs("div", { className: "flex items-center", children: [jsx("div", { className: "mr-1.5", children: iconNode }), content] }) }) });
2171
+ }
2172
+ function FolderItem(props) {
2173
+ const { uiNode, isAllowedToCreateDocuments, className, onRenameNode, onDuplicateNode, onDeleteNode, onSelectNode, onAddFile, onCopyNode, onMoveNode } = props;
2174
+ const [mode, setMode] = useState(READ);
2175
+ const [isDropdownMenuOpen, setIsDropdownMenuOpen] = useState(false);
2176
+ const { dragProps } = useDrag({ ...props, uiNode });
2177
+ const { isDropTarget, dropProps } = useDrop({
2178
+ uiNode,
2179
+ onAddFile,
2180
+ onCopyNode,
2181
+ onMoveNode
2182
+ });
2183
+ const isReadMode = mode === READ;
2184
+ function onCancel() {
2185
+ setMode(READ);
2186
+ }
2187
+ function onSubmit(name) {
2188
+ onRenameNode(name, uiNode);
2189
+ setMode(READ);
2190
+ }
2191
+ function onClick() {
2192
+ onSelectNode(uiNode);
2193
+ }
2194
+ const dropdownMenuHandlers = {
2195
+ [DUPLICATE]: () => onDuplicateNode(uiNode),
2196
+ [RENAME]: () => setMode(WRITE),
2197
+ [DELETE]: () => onDeleteNode(uiNode)
2198
+ };
2199
+ const dropdownMenuOptions = Object.entries(nodeOptionsMap).map(([id, option]) => ({
2200
+ ...option,
2201
+ id
2202
+ })).filter((option) => defaultFolderOptions.includes(option.id));
2203
+ function onDropdownMenuOptionClick(itemId) {
2204
+ const handler = dropdownMenuHandlers[itemId];
2205
+ if (!handler) {
2206
+ console.error(`No handler found for dropdown menu item: ${itemId}`);
2207
+ return;
2208
+ }
2209
+ handler();
2210
+ setIsDropdownMenuOpen(false);
2211
+ }
2212
+ const content = isReadMode || !isAllowedToCreateDocuments ? jsx("div", { className: "ml-3 max-h-6 truncate font-medium text-gray-600 group-hover:text-gray-800", children: uiNode.name }) : jsx(NodeInput, { className: "ml-3 font-medium", defaultValue: uiNode.name, onCancel, onSubmit });
2213
+ const containerStyles = twMerge("group flex h-12 cursor-pointer select-none items-center rounded-lg bg-gray-200 px-2", className, isDropTarget && "bg-blue-100");
2214
+ return jsx("div", { className: "relative w-64", onClick, children: jsxs("div", { ...dragProps, ...dropProps, className: containerStyles, children: [jsxs("div", { className: "flex items-center overflow-hidden", children: [jsx("div", { className: "p-1", children: jsxs("div", { className: "relative", children: [jsx(Icon, { name: "FolderClose", size: 24 }), isReadMode && uiNode.syncStatus ? jsx("div", { className: "absolute bottom-[-3px] right-[-2px] size-3 rounded-full bg-white", children: jsx("div", { className: "absolute left-[-2px] top-[-2px]", children: jsx(SyncStatusIcon, { overrideSyncIcons: {
2215
+ SUCCESS: "CheckCircleFill"
2216
+ }, syncStatus: uiNode.syncStatus }) }) }) : null] }) }), content] }), isReadMode && isAllowedToCreateDocuments ? jsx(ConnectDropdownMenu, { items: dropdownMenuOptions, onItemClick: onDropdownMenuOptionClick, onOpenChange: setIsDropdownMenuOpen, open: isDropdownMenuOpen, children: jsx("button", { className: twMerge("ml-auto hidden group-hover:block", isDropdownMenuOpen && "block"), onClick: (e) => {
2217
+ e.stopPropagation();
2218
+ setIsDropdownMenuOpen(true);
2219
+ }, children: jsx(Icon, { className: "text-gray-600", name: "VerticalDots" }) }) }) : null] }) });
2220
+ }
2221
+ function NodeInput(props) {
2222
+ const { onSubmit, onCancel, defaultValue, className, minLength = 1, ...inputProps } = props;
2223
+ const [value, setValue] = useState(defaultValue ?? "");
2224
+ const ref = useRef(null);
2225
+ useOnClickOutside(ref, handleSubmit);
2226
+ useEventListener("keyup", (e) => {
2227
+ if (e.key === "Enter") {
2228
+ handleSubmit();
2229
+ }
2230
+ if (e.key === "Escape") {
2231
+ onCancel();
2232
+ }
2233
+ });
2234
+ useLayoutEffect(() => {
2235
+ setTimeout(() => {
2236
+ var _a, _b, _c;
2237
+ (_a = ref.current) == null ? void 0 : _a.focus();
2238
+ (_b = ref.current) == null ? void 0 : _b.select();
2239
+ (_c = ref.current) == null ? void 0 : _c.scroll({ left: 9999 });
2240
+ }, 100);
2241
+ }, []);
2242
+ function handleSubmit() {
2243
+ if (value.length >= minLength) {
2244
+ onSubmit(value);
2245
+ }
2246
+ }
2247
+ return jsx("input", { ...inputProps, autoFocus: true, className: twMerge("bg-inherit text-inherit outline-none", className), minLength, onChange: (e) => setValue(e.target.value), ref, required: true, type: "text", value });
2248
+ }
2249
+ function Branch(props) {
2250
+ const { branch = "main" } = props;
2251
+ return jsxs("button", { className: "flex h-8 items-center gap-1 rounded-lg bg-slate-50 pl-1 pr-2 text-xs text-slate-100", children: [jsx(Icon, { name: "Branch" }), jsx("span", { children: "BRANCH" }), jsx("span", { className: "text-gray-900", children: branch })] });
2252
+ }
2253
+ function DocId(props) {
2254
+ const { docId } = props;
2255
+ const [, copy] = useCopyToClipboard();
2256
+ function handleCopy(text) {
2257
+ return () => {
2258
+ copy(text).catch((error) => {
2259
+ console.error("Failed to copy!", error);
2260
+ });
2261
+ };
2262
+ }
2263
+ return jsxs("button", { className: "flex h-8 items-center gap-1 rounded-lg bg-slate-50 pl-1 pr-2 text-xs text-slate-100", onClick: handleCopy(docId), children: [jsx(Icon, { name: "Link" }), "DOC ID", jsx("span", { className: "text-gray-900", children: docId })] });
2264
+ }
2265
+ function Scope(props) {
2266
+ const { value, onChange } = props;
2267
+ const items = [
2268
+ { displayValue: "Global scope", value: "global" },
2269
+ { displayValue: "Local scope", value: "local" }
2270
+ ];
2271
+ return jsx(Select, { absolutePositionMenu: true, containerClassName: "bg-slate-50 text-gray-500 rounded-lg w-fit text-xs z-10", id: "scope select", itemClassName: "py-2 text-gray-500 grid grid-cols-[auto,auto] gap-1", items, menuClassName: "min-w-0 text-gray-500", onChange, value });
2272
+ }
2273
+ function Header(props) {
2274
+ const { title, docId, scope, onChangeScope, onClose, className, ...divProps } = props;
2275
+ return jsxs("header", { className: twMerge("flex items-center justify-between bg-transparent", className), ...divProps, children: [jsxs("div", { className: "flex items-center gap-3", children: [jsx("button", { className: "shadow-button rounded-lg bg-gray-50 p-1 text-slate-100", onClick: onClose, children: jsx(Icon, { name: "VariantArrowLeft" }) }), jsx("h1", { className: "text-xs", children: title })] }), jsxs("div", { className: "flex items-center gap-2", children: [jsx(DocId, { docId }), jsx(Branch, {}), jsx(Scope, { onChange: onChangeScope, value: scope })] })] });
2276
+ }
2277
+ function memo(getDeps, fn, opts) {
2278
+ let deps = opts.initialDeps ?? [];
2279
+ let result;
2280
+ return () => {
2281
+ var _a, _b, _c, _d;
2282
+ let depTime;
2283
+ if (opts.key && ((_a = opts.debug) == null ? void 0 : _a.call(opts))) depTime = Date.now();
2284
+ const newDeps = getDeps();
2285
+ const depsChanged = newDeps.length !== deps.length || newDeps.some((dep, index) => deps[index] !== dep);
2286
+ if (!depsChanged) {
2287
+ return result;
2288
+ }
2289
+ deps = newDeps;
2290
+ let resultTime;
1837
2291
  if (opts.key && ((_b = opts.debug) == null ? void 0 : _b.call(opts))) resultTime = Date.now();
1838
2292
  result = fn(...newDeps);
1839
2293
  if (opts.key && ((_c = opts.debug) == null ? void 0 : _c.call(opts))) {
@@ -1861,11 +2315,7 @@ function memo(getDeps, fn, opts) {
1861
2315
  }
1862
2316
  (_d = opts == null ? void 0 : opts.onChange) == null ? void 0 : _d.call(opts, result);
1863
2317
  return result;
1864
- }
1865
- memoizedFunction.updateDeps = (newDeps) => {
1866
- deps = newDeps;
1867
2318
  };
1868
- return memoizedFunction;
1869
2319
  }
1870
2320
  function notUndefined(value, msg) {
1871
2321
  if (value === void 0) {
@@ -1911,18 +2361,15 @@ const observeElementRect = (instance, cb) => {
1911
2361
  };
1912
2362
  }
1913
2363
  const observer = new targetWindow.ResizeObserver((entries) => {
1914
- const run = () => {
1915
- const entry = entries[0];
1916
- if (entry == null ? void 0 : entry.borderBoxSize) {
1917
- const box = entry.borderBoxSize[0];
1918
- if (box) {
1919
- handler({ width: box.inlineSize, height: box.blockSize });
1920
- return;
1921
- }
2364
+ const entry = entries[0];
2365
+ if (entry == null ? void 0 : entry.borderBoxSize) {
2366
+ const box = entry.borderBoxSize[0];
2367
+ if (box) {
2368
+ handler({ width: box.inlineSize, height: box.blockSize });
2369
+ return;
1922
2370
  }
1923
- handler(element.getBoundingClientRect());
1924
- };
1925
- instance.options.useAnimationFrameWithResizeObserver ? requestAnimationFrame(run) : run();
2371
+ }
2372
+ handler(element.getBoundingClientRect());
1926
2373
  });
1927
2374
  observer.observe(element, { box: "border-box" });
1928
2375
  return () => {
@@ -1960,15 +2407,10 @@ const observeElementOffset = (instance, cb) => {
1960
2407
  const endHandler = createHandler(false);
1961
2408
  endHandler();
1962
2409
  element.addEventListener("scroll", handler, addEventListenerOptions);
1963
- const registerScrollendEvent = instance.options.useScrollendEvent && supportsScrollend;
1964
- if (registerScrollendEvent) {
1965
- element.addEventListener("scrollend", endHandler, addEventListenerOptions);
1966
- }
2410
+ element.addEventListener("scrollend", endHandler, addEventListenerOptions);
1967
2411
  return () => {
1968
2412
  element.removeEventListener("scroll", handler);
1969
- if (registerScrollendEvent) {
1970
- element.removeEventListener("scrollend", endHandler);
1971
- }
2413
+ element.removeEventListener("scrollend", endHandler);
1972
2414
  };
1973
2415
  };
1974
2416
  const measureElement = (element, entry, instance) => {
@@ -2022,10 +2464,7 @@ class Virtualizer {
2022
2464
  }
2023
2465
  return _ro = new this.targetWindow.ResizeObserver((entries) => {
2024
2466
  entries.forEach((entry) => {
2025
- const run = () => {
2026
- this._measureElement(entry.target, entry);
2027
- };
2028
- this.options.useAnimationFrameWithResizeObserver ? requestAnimationFrame(run) : run();
2467
+ this._measureElement(entry.target, entry);
2029
2468
  });
2030
2469
  });
2031
2470
  };
@@ -2073,8 +2512,7 @@ class Virtualizer {
2073
2512
  isScrollingResetDelay: 150,
2074
2513
  enabled: true,
2075
2514
  isRtl: false,
2076
- useScrollendEvent: false,
2077
- useAnimationFrameWithResizeObserver: false,
2515
+ useScrollendEvent: true,
2078
2516
  ...opts2
2079
2517
  };
2080
2518
  };
@@ -2263,18 +2701,12 @@ class Virtualizer {
2263
2701
  }
2264
2702
  );
2265
2703
  this.calculateRange = memo(
2266
- () => [
2267
- this.getMeasurements(),
2268
- this.getSize(),
2269
- this.getScrollOffset(),
2270
- this.options.lanes
2271
- ],
2272
- (measurements, outerSize, scrollOffset, lanes) => {
2704
+ () => [this.getMeasurements(), this.getSize(), this.getScrollOffset()],
2705
+ (measurements, outerSize, scrollOffset) => {
2273
2706
  return this.range = measurements.length > 0 && outerSize > 0 ? calculateRange({
2274
2707
  measurements,
2275
2708
  outerSize,
2276
- scrollOffset,
2277
- lanes
2709
+ scrollOffset
2278
2710
  }) : null;
2279
2711
  },
2280
2712
  {
@@ -2282,7 +2714,7 @@ class Virtualizer {
2282
2714
  debug: () => this.options.debug
2283
2715
  }
2284
2716
  );
2285
- this.getVirtualIndexes = memo(
2717
+ this.getIndexes = memo(
2286
2718
  () => {
2287
2719
  let startIndex = null;
2288
2720
  let endIndex = null;
@@ -2291,7 +2723,6 @@ class Virtualizer {
2291
2723
  startIndex = range.startIndex;
2292
2724
  endIndex = range.endIndex;
2293
2725
  }
2294
- this.maybeNotify.updateDeps([this.isScrolling, startIndex, endIndex]);
2295
2726
  return [
2296
2727
  this.options.rangeExtractor,
2297
2728
  this.options.overscan,
@@ -2375,7 +2806,7 @@ class Virtualizer {
2375
2806
  this._measureElement(node, void 0);
2376
2807
  };
2377
2808
  this.getVirtualItems = memo(
2378
- () => [this.getVirtualIndexes(), this.getMeasurements()],
2809
+ () => [this.getIndexes(), this.getMeasurements()],
2379
2810
  (indexes, measurements) => {
2380
2811
  const virtualItems = [];
2381
2812
  for (let k = 0, len = indexes.length; k < len; k++) {
@@ -2404,15 +2835,15 @@ class Virtualizer {
2404
2835
  )]
2405
2836
  );
2406
2837
  };
2407
- this.getOffsetForAlignment = (toOffset, align, itemSize = 0) => {
2838
+ this.getOffsetForAlignment = (toOffset, align) => {
2408
2839
  const size = this.getSize();
2409
2840
  const scrollOffset = this.getScrollOffset();
2410
2841
  if (align === "auto") {
2411
- align = toOffset >= scrollOffset + size ? "end" : "start";
2842
+ if (toOffset >= scrollOffset + size) {
2843
+ align = "end";
2844
+ }
2412
2845
  }
2413
- if (align === "center") {
2414
- toOffset += (itemSize - size) / 2;
2415
- } else if (align === "end") {
2846
+ if (align === "end") {
2416
2847
  toOffset -= size;
2417
2848
  }
2418
2849
  const scrollSizeProp = this.options.horizontal ? "scrollWidth" : "scrollHeight";
@@ -2437,11 +2868,27 @@ class Virtualizer {
2437
2868
  return [scrollOffset, align];
2438
2869
  }
2439
2870
  }
2440
- const toOffset = align === "end" ? item.end + this.options.scrollPaddingEnd : item.start - this.options.scrollPaddingStart;
2441
- return [
2442
- this.getOffsetForAlignment(toOffset, align, item.size),
2443
- align
2444
- ];
2871
+ const centerOffset = item.start - this.options.scrollPaddingStart + (item.size - size) / 2;
2872
+ switch (align) {
2873
+ case "center":
2874
+ return [this.getOffsetForAlignment(centerOffset, align), align];
2875
+ case "end":
2876
+ return [
2877
+ this.getOffsetForAlignment(
2878
+ item.end + this.options.scrollPaddingEnd,
2879
+ align
2880
+ ),
2881
+ align
2882
+ ];
2883
+ default:
2884
+ return [
2885
+ this.getOffsetForAlignment(
2886
+ item.start - this.options.scrollPaddingStart,
2887
+ align
2888
+ ),
2889
+ align
2890
+ ];
2891
+ }
2445
2892
  };
2446
2893
  this.isDynamicMode = () => this.elementsCache.size > 0;
2447
2894
  this.cancelScrollToIndex = () => {
@@ -2511,19 +2958,10 @@ class Virtualizer {
2511
2958
  let end;
2512
2959
  if (measurements.length === 0) {
2513
2960
  end = this.options.paddingStart;
2514
- } else if (this.options.lanes === 1) {
2515
- end = ((_a = measurements[measurements.length - 1]) == null ? void 0 : _a.end) ?? 0;
2516
2961
  } else {
2517
- const endByLane = Array(this.options.lanes).fill(null);
2518
- let endIndex = measurements.length - 1;
2519
- while (endIndex >= 0 && endByLane.some((val) => val === null)) {
2520
- const item = measurements[endIndex];
2521
- if (endByLane[item.lane] === null) {
2522
- endByLane[item.lane] = item.end;
2523
- }
2524
- endIndex--;
2525
- }
2526
- end = Math.max(...endByLane.filter((val) => val !== null));
2962
+ end = this.options.lanes === 1 ? ((_a = measurements[measurements.length - 1]) == null ? void 0 : _a.end) ?? 0 : Math.max(
2963
+ ...measurements.slice(-this.options.lanes).map((m) => m.end)
2964
+ );
2527
2965
  }
2528
2966
  return Math.max(
2529
2967
  end - this.options.scrollMargin + this.options.paddingEnd,
@@ -2564,43 +3002,14 @@ const findNearestBinarySearch = (low, high, getCurrentValue, value) => {
2564
3002
  function calculateRange({
2565
3003
  measurements,
2566
3004
  outerSize,
2567
- scrollOffset,
2568
- lanes
3005
+ scrollOffset
2569
3006
  }) {
2570
- const lastIndex = measurements.length - 1;
3007
+ const count = measurements.length - 1;
2571
3008
  const getOffset = (index) => measurements[index].start;
2572
- if (measurements.length <= lanes) {
2573
- return {
2574
- startIndex: 0,
2575
- endIndex: lastIndex
2576
- };
2577
- }
2578
- let startIndex = findNearestBinarySearch(
2579
- 0,
2580
- lastIndex,
2581
- getOffset,
2582
- scrollOffset
2583
- );
3009
+ const startIndex = findNearestBinarySearch(0, count, getOffset, scrollOffset);
2584
3010
  let endIndex = startIndex;
2585
- if (lanes === 1) {
2586
- while (endIndex < lastIndex && measurements[endIndex].end < scrollOffset + outerSize) {
2587
- endIndex++;
2588
- }
2589
- } else if (lanes > 1) {
2590
- const endPerLane = Array(lanes).fill(0);
2591
- while (endIndex < lastIndex && endPerLane.some((pos) => pos < scrollOffset + outerSize)) {
2592
- const item = measurements[endIndex];
2593
- endPerLane[item.lane] = item.end;
2594
- endIndex++;
2595
- }
2596
- const startPerLane = Array(lanes).fill(scrollOffset + outerSize);
2597
- while (startIndex >= 0 && startPerLane.some((pos) => pos >= scrollOffset)) {
2598
- const item = measurements[startIndex];
2599
- startPerLane[item.lane] = item.start;
2600
- startIndex--;
2601
- }
2602
- startIndex = Math.max(0, startIndex - startIndex % lanes);
2603
- endIndex = Math.min(lastIndex, endIndex + (lanes - 1 - endIndex % lanes));
3011
+ while (endIndex < count && measurements[endIndex].end < scrollOffset + outerSize) {
3012
+ endIndex++;
2604
3013
  }
2605
3014
  return { startIndex, endIndex };
2606
3015
  }
@@ -2857,8 +3266,8 @@ function RevisionHistory(props) {
2857
3266
  return jsxs(TooltipProvider, { children: [jsx(Header, { docId: documentId, onChangeScope, onClose, scope, title: documentTitle }), PaginationComponent, jsx("div", { className: "mt-4 flex justify-center rounded-md bg-slate-50 p-4", children: visibleOperations.length > 0 ? jsx("div", { className: "grid grid-cols-[minmax(min-content,1018px)]", children: jsx(Timeline, { globalOperations: scope === "global" ? pageItems : [], localOperations: scope === "local" ? pageItems : [], scope }) }) : jsx("h3", { className: "my-40 text-gray-600", children: "This document has no recorded operations yet." }) }), PaginationComponent] });
2858
3267
  }
2859
3268
  function Tooltip(props) {
2860
- const { children, content, open, defaultOpen, onOpenChange, className, ...rest } = props;
2861
- return jsxs(Root3, { defaultOpen, delayDuration: 0, onOpenChange, open, children: [jsx(Trigger, { asChild: true, children }), jsx(Portal, { children: jsx(Content2, { ...rest, className: twMerge("shadow-tooltip rounded-lg border border-gray-200 bg-white p-2 text-xs", className), children: content }) })] });
3269
+ const { children, content, open, defaultOpen, onOpenChange, className, side = "top", sideOffset = 5, ...rest } = props;
3270
+ return jsxs(Root3, { defaultOpen, delayDuration: 0, onOpenChange, open, children: [jsx(Trigger, { asChild: true, children }), jsx(Portal, { children: jsx(Content2, { ...rest, side, sideOffset, className: twMerge("shadow-tooltip rounded-lg border border-gray-200 bg-white p-2 text-xs", className), children: content }) })] });
2862
3271
  }
2863
3272
  const TooltipProvider = Provider;
2864
3273
  const BUDGET = "powerhouse/budget-statement";
@@ -3106,9 +3515,7 @@ function useAddDebouncedOperations(reactor, props) {
3106
3515
  const { driveId, documentId } = props;
3107
3516
  const [documentDrives] = useDocumentDrives(reactor);
3108
3517
  const documentDrivesRef = useRef(documentDrives);
3109
- const { isAllowedToEditDocuments } = useUserPermissions() || {
3110
- isAllowedToEditDocuments: false
3111
- };
3518
+ const { isAllowedToEditDocuments } = useUserPermissions();
3112
3519
  useEffect(() => {
3113
3520
  documentDrivesRef.current = documentDrives;
3114
3521
  }, [documentDrives]);
@@ -3119,7 +3526,7 @@ function useAddDebouncedOperations(reactor, props) {
3119
3526
  if (!reactor) {
3120
3527
  throw new Error("Reactor is not loaded");
3121
3528
  }
3122
- const drive = documentDrivesRef.current.find((drive2) => drive2.state.global.id === driveId2);
3529
+ const drive = documentDrivesRef.current.find((drive2) => drive2.id === driveId2);
3123
3530
  if (!drive) {
3124
3531
  throw new Error(`Drive with id ${driveId2} not found`);
3125
3532
  }
@@ -3198,7 +3605,7 @@ function getNode(id, drive) {
3198
3605
  }
3199
3606
  function createDriveActions(document2, dispatch, context) {
3200
3607
  const drive = document2;
3201
- const { id: driveId } = drive.state.global;
3608
+ const driveId = drive.id;
3202
3609
  const { selectedNode } = context;
3203
3610
  const handleAddFolder = async (name, parentFolder, id = generateId()) => {
3204
3611
  dispatch(addFolder({
@@ -3488,6 +3895,17 @@ function useEditorProps(document2, node, documentDispatch, onAddOperation) {
3488
3895
  isAllowedToEditDocuments: (userPermissions == null ? void 0 : userPermissions.isAllowedToEditDocuments) ?? false
3489
3896
  };
3490
3897
  }
3898
+ function useGetDocument() {
3899
+ const { openFile } = useDocumentDriveServer();
3900
+ const getDocument = useCallback(
3901
+ async (driveId, documentId, options) => {
3902
+ const document2 = await openFile(driveId, documentId, options);
3903
+ return document2;
3904
+ },
3905
+ [openFile]
3906
+ );
3907
+ return getDocument;
3908
+ }
3491
3909
  function useSyncStatus(driveId, documentId) {
3492
3910
  const { getSyncStatusSync, onSyncStatus, documentDrives } = useDocumentDriveServer();
3493
3911
  const syncStatus = useSyncExternalStore(
@@ -3497,9 +3915,7 @@ function useSyncStatus(driveId, documentId) {
3497
3915
  },
3498
3916
  () => {
3499
3917
  var _a;
3500
- const drive = documentDrives.find(
3501
- (_drive) => _drive.state.global.id === driveId
3502
- );
3918
+ const drive = documentDrives.find((_drive) => _drive.id === driveId);
3503
3919
  if (!drive) return;
3504
3920
  const isReadDrive = "readContext" in drive;
3505
3921
  const _sharingType = !isReadDrive ? (_a = drive.state.local.sharingType) == null ? void 0 : _a.toUpperCase() : "PUBLIC";
@@ -3558,10 +3974,342 @@ const useUndoRedoShortcuts = (props) => {
3558
3974
  [canRedo, redo2]
3559
3975
  );
3560
3976
  };
3561
- function EditorLoader(props) {
3562
- const [showLoading, setShowLoading] = useState(false);
3563
- useEffect(() => {
3564
- setTimeout(() => {
3977
+ function getDocumentSpec(doc) {
3978
+ if ("documentModelState" in doc) {
3979
+ return doc.documentModelState;
3980
+ }
3981
+ return doc.documentModel;
3982
+ }
3983
+ const CreateDocument = ({ documentModels, createDocument }) => {
3984
+ return jsxs("div", { className: "px-6", children: [jsx("h3", { className: "mb-3 mt-4 text-xl font-bold text-gray-600", children: "New document" }), jsx("div", { className: "flex w-full flex-wrap gap-4", children: documentModels == null ? void 0 : documentModels.map((doc) => {
3985
+ const spec = getDocumentSpec(doc);
3986
+ return jsx(Button, { color: "light", "aria-details": spec.description, onClick: () => createDocument(doc), children: jsx("span", { className: "text-sm", children: spec.name }) }, spec.id);
3987
+ }) })] });
3988
+ };
3989
+ function sortUiNodesByName(a, b) {
3990
+ return a.name.localeCompare(b.name);
3991
+ }
3992
+ const GAP = 8;
3993
+ const ITEM_WIDTH = 256;
3994
+ const ITEM_HEIGHT = 48;
3995
+ const USED_SPACE = 420;
3996
+ function FileContentView(props) {
3997
+ const parentRef = useRef(null);
3998
+ const { t } = useTranslation();
3999
+ const windowSize = useWindowSize();
4000
+ const { fileNodes, ...fileProps } = props;
4001
+ const availableWidth = windowSize.innerWidth - USED_SPACE;
4002
+ const columnCount = Math.floor(availableWidth / (ITEM_WIDTH + GAP)) || 1;
4003
+ const rowCount = Math.ceil(fileNodes.length / columnCount);
4004
+ const rowVirtualizer = useVirtualizer({
4005
+ count: rowCount,
4006
+ getScrollElement: () => parentRef.current,
4007
+ estimateSize: (index) => {
4008
+ if (index > 0) {
4009
+ return ITEM_HEIGHT + GAP;
4010
+ }
4011
+ return ITEM_HEIGHT;
4012
+ },
4013
+ overscan: 5
4014
+ });
4015
+ const columnVirtualizer = useVirtualizer({
4016
+ horizontal: true,
4017
+ count: columnCount,
4018
+ getScrollElement: () => parentRef.current,
4019
+ estimateSize: (index) => {
4020
+ if (index > 0) {
4021
+ return ITEM_WIDTH + GAP;
4022
+ }
4023
+ return ITEM_WIDTH;
4024
+ },
4025
+ overscan: 5
4026
+ });
4027
+ const getItemIndex = (rowIndex, columnIndex) => rowIndex * columnCount + columnIndex;
4028
+ const getItem = (rowIndex, columnIndex) => {
4029
+ const index = getItemIndex(rowIndex, columnIndex);
4030
+ return fileNodes[index] || null;
4031
+ };
4032
+ if (fileNodes.length === 0) {
4033
+ return jsx("div", { className: "mb-8 text-sm text-gray-400", children: t("folderView.sections.documents.empty", {
4034
+ defaultValue: "No documents or files 📄"
4035
+ }) });
4036
+ }
4037
+ const renderItem = (rowIndex, columnIndex) => {
4038
+ const fileNode = getItem(rowIndex, columnIndex);
4039
+ if (!fileNode) {
4040
+ return null;
4041
+ }
4042
+ return jsx("div", { style: {
4043
+ marginLeft: columnIndex === 0 ? 0 : GAP
4044
+ }, children: jsx(FileItem, { uiNode: fileNode, ...fileProps }, fileNode.id) });
4045
+ };
4046
+ return jsx("div", { ref: parentRef, style: {
4047
+ height: `400px`,
4048
+ width: `100%`,
4049
+ overflow: "auto"
4050
+ }, children: jsx("div", { style: {
4051
+ height: `${rowVirtualizer.getTotalSize()}px`,
4052
+ width: `${columnVirtualizer.getTotalSize()}px`,
4053
+ position: "relative"
4054
+ }, children: rowVirtualizer.getVirtualItems().map((virtualRow) => jsx(React__default.Fragment, { children: columnVirtualizer.getVirtualItems().map((virtualColumn) => jsx("div", { style: {
4055
+ position: "absolute",
4056
+ top: 0,
4057
+ left: 0,
4058
+ marginTop: virtualRow.index === 0 ? 0 : GAP,
4059
+ width: `${virtualColumn.size}px`,
4060
+ height: `${virtualRow.size}px`,
4061
+ transform: `translateX(${virtualColumn.start}px) translateY(${virtualRow.start}px)`
4062
+ }, children: renderItem(virtualRow.index, virtualColumn.index) }, virtualColumn.key)) }, virtualRow.key)) }) });
4063
+ }
4064
+ function FolderView(props) {
4065
+ const { node, className, isDropTarget, containerProps, ...nodeProps } = props;
4066
+ const { t } = useTranslation();
4067
+ const folderNodes = node.children.filter((node2) => node2.kind === FOLDER).sort(sortUiNodesByName);
4068
+ const fileNodes = node.children.filter((node2) => node2.kind === FILE).sort(sortUiNodesByName);
4069
+ const folderCallbacks = {
4070
+ onSelectNode: (node2) => nodeProps.onSelectNode(node2),
4071
+ onRenameNode: (name, node2) => nodeProps.onRenameNode(name, node2),
4072
+ onDuplicateNode: (node2) => nodeProps.onDuplicateNode(node2),
4073
+ onDeleteNode: (node2) => nodeProps.onDeleteNode(node2)
4074
+ };
4075
+ const fileCallbacks = {
4076
+ onSelectNode: (node2) => nodeProps.onSelectNode(node2),
4077
+ onRenameNode: (name, node2) => nodeProps.onRenameNode(name, node2),
4078
+ onDuplicateNode: (node2) => nodeProps.onDuplicateNode(node2),
4079
+ onDeleteNode: (node2) => nodeProps.onDeleteNode(node2)
4080
+ };
4081
+ const baseNodeCallbacks = {
4082
+ onAddFile: async (file, parentNode) => {
4083
+ await nodeProps.onAddFile(file, parentNode);
4084
+ },
4085
+ onCopyNode: async (uiNode, targetNode) => {
4086
+ await nodeProps.onCopyNode(uiNode, targetNode);
4087
+ },
4088
+ onMoveNode: async (uiNode, targetNode) => {
4089
+ await nodeProps.onMoveNode(uiNode, targetNode);
4090
+ }
4091
+ };
4092
+ return jsxs("div", { className: twMerge("rounded-md border-2 border-transparent p-2", isDropTarget && "border-dashed border-blue-100", className), ...containerProps, children: [jsx(DriveLayout.ContentSection, { title: t("folderView.sections.folders.title", {
4093
+ defaultValue: "Folders"
4094
+ }), className: "mb-4", children: folderNodes.length > 0 ? folderNodes.map((folderNode) => jsx(FolderItem, { uiNode: folderNode, ...baseNodeCallbacks, ...folderCallbacks, isAllowedToCreateDocuments: nodeProps.isAllowedToCreateDocuments }, folderNode.id)) : jsx("div", { className: "mb-8 text-sm text-gray-400", children: t("folderView.sections.folders.empty", {
4095
+ defaultValue: "No documents or files 📄"
4096
+ }) }) }), jsx(DriveLayout.ContentSection, { title: t("folderView.sections.documents.title", {
4097
+ defaultValue: "Documents and files"
4098
+ }), children: jsx("div", { className: twMerge("w-full", fileNodes.length > 0 ? "min-h-[400px]" : "min-h-14"), children: jsx(FileContentView, { fileNodes, ...fileCallbacks, isAllowedToCreateDocuments: nodeProps.isAllowedToCreateDocuments }) }) })] });
4099
+ }
4100
+ function BaseEditor(props) {
4101
+ const { document: document2, dispatch, className, children } = props;
4102
+ const { id: driveId } = document2;
4103
+ const { showSearchBar, isAllowedToCreateDocuments, documentModels, showCreateDocumentModal } = useDriveContext();
4104
+ const { driveNodes, selectedNode, selectedNodePath, getNodeById, setSelectedNode } = useUiNodesContext();
4105
+ const driveNode = useMemo(() => driveNodes.find((n) => n.id === driveId), [driveNodes, driveId]);
4106
+ const { addDocument, addFile, addFolder: addFolder2, renameNode, deleteNode: deleteNode2, moveNode: moveNode2, copyNode: copyNode2, duplicateNode } = useDriveActionsWithUiNodes(document2, dispatch);
4107
+ const onCreateDocument = useCallback(async (documentModel) => {
4108
+ const { name } = await showCreateDocumentModal(documentModel);
4109
+ const document3 = documentModel.utils.createDocument();
4110
+ await addDocument(name, documentModel.documentModel.name, document3, selectedNode == null ? void 0 : selectedNode.id);
4111
+ }, [addDocument, showCreateDocumentModal, selectedNode == null ? void 0 : selectedNode.id]);
4112
+ const { isDropTarget, dropProps } = useDrop({
4113
+ uiNode: selectedNode,
4114
+ onAddFile: addFile,
4115
+ onCopyNode: copyNode2,
4116
+ onMoveNode: moveNode2
4117
+ });
4118
+ const { breadcrumbs, onBreadcrumbSelected } = useBreadcrumbs({
4119
+ selectedNodePath,
4120
+ getNodeById,
4121
+ setSelectedNode
4122
+ });
4123
+ if (!driveNode) {
4124
+ return jsx("div", { children: "Drive not found" });
4125
+ } else if ((selectedNode == null ? void 0 : selectedNode.kind) === FILE$1) {
4126
+ return jsx(Fragment$1, {});
4127
+ }
4128
+ return jsxs(DriveLayout, { className, children: [children, jsxs(DriveLayout.Header, { children: [jsx(Breadcrumbs, { breadcrumbs, createEnabled: isAllowedToCreateDocuments, onCreate: addFolder2, onBreadcrumbSelected }), showSearchBar && jsx(SearchBar, {})] }), jsx(DriveLayout.Content, { children: jsx(FolderView, { node: selectedNode || driveNode, onSelectNode: setSelectedNode, onRenameNode: renameNode, onDuplicateNode: duplicateNode, onDeleteNode: deleteNode2, onAddFile: addFile, onCopyNode: copyNode2, onMoveNode: moveNode2, isDropTarget, isAllowedToCreateDocuments }) }), jsx(DriveLayout.Footer, { children: isAllowedToCreateDocuments && jsx(CreateDocument, { documentModels, createDocument: onCreateDocument }) })] });
4129
+ }
4130
+ function Editor(props) {
4131
+ return jsx(DriveContextProvider, { value: props.context, children: jsx(BaseEditor, { ...props }) });
4132
+ }
4133
+ const GenericDriveExplorer = {
4134
+ Component: Editor,
4135
+ documentTypes: ["powerhouse/document-drive"],
4136
+ config: {
4137
+ id: "GenericDriveExplorer",
4138
+ disableExternalControls: true,
4139
+ documentToolbarEnabled: true,
4140
+ showSwitchboardLink: true
4141
+ }
4142
+ };
4143
+ function useAnalyticsQueryWrapper(options) {
4144
+ const { queryFn, ...queryOptions } = options;
4145
+ const store = useAnalyticsStore();
4146
+ const engine = useAnalyticsEngine();
4147
+ return useQuery({
4148
+ ...queryOptions,
4149
+ queryFn: () => {
4150
+ if (!store || !engine) {
4151
+ throw new Error("No analytics store available. Use within an AnalyticsProvider.");
4152
+ }
4153
+ return queryFn({ store, engine });
4154
+ }
4155
+ });
4156
+ }
4157
+ function useAnalyticsQuery(query, options) {
4158
+ const store = useAnalyticsStore();
4159
+ const { data: querySources } = useQuerySources(query);
4160
+ const queryClient = useQueryClient();
4161
+ const subscriptions = useRef([]);
4162
+ const result = useAnalyticsQueryWrapper({
4163
+ queryKey: ["analytics", "query", query],
4164
+ queryFn: ({ engine }) => engine.execute(query),
4165
+ ...options
4166
+ });
4167
+ useEffect(() => {
4168
+ if (!(querySources == null ? void 0 : querySources.length) || !store) {
4169
+ return;
4170
+ }
4171
+ querySources.forEach((source) => {
4172
+ const unsub = store.subscribeToSource(source, () => {
4173
+ return queryClient.invalidateQueries({
4174
+ queryKey: ["analytics", "query", query]
4175
+ });
4176
+ });
4177
+ subscriptions.current.push(unsub);
4178
+ });
4179
+ return () => {
4180
+ subscriptions.current.forEach((unsub) => unsub());
4181
+ subscriptions.current = [];
4182
+ };
4183
+ }, [querySources]);
4184
+ return result;
4185
+ }
4186
+ function useMatchingSeries(query, options) {
4187
+ const result = useAnalyticsQueryWrapper({
4188
+ queryKey: ["analytics", "matchingSeries", query],
4189
+ queryFn: ({ store }) => store.getMatchingSeries(query),
4190
+ ...options
4191
+ });
4192
+ return result;
4193
+ }
4194
+ function useQuerySources(query, options) {
4195
+ const { data: matchingSeries } = useMatchingSeries(query);
4196
+ return useQuery({
4197
+ queryKey: ["analytics", "sources", query],
4198
+ queryFn: () => {
4199
+ if (!(matchingSeries == null ? void 0 : matchingSeries.length)) {
4200
+ return [];
4201
+ }
4202
+ const uniqueSources = [
4203
+ ...new Set(matchingSeries.map((s) => s.source.toString()))
4204
+ ];
4205
+ return uniqueSources.map((source) => AnalyticsPath.fromString(source));
4206
+ },
4207
+ enabled: !!matchingSeries,
4208
+ ...options
4209
+ });
4210
+ }
4211
+ const getBarSize = (value) => {
4212
+ if (value <= 0)
4213
+ return 0;
4214
+ if (value > 0 && value <= 50)
4215
+ return 1;
4216
+ if (value > 50 && value <= 100)
4217
+ return 2;
4218
+ if (value > 100 && value <= 250)
4219
+ return 3;
4220
+ return 4;
4221
+ };
4222
+ const useTimelineItems = (documentId, startTimestamp) => {
4223
+ const start = startTimestamp ? DateTime.fromISO(startTimestamp) : DateTime.now().startOf("day");
4224
+ const { data: diffResult, isLoading } = useAnalyticsQuery({
4225
+ start,
4226
+ end: DateTime.now().endOf("day"),
4227
+ granularity: AnalyticsGranularity.Hourly,
4228
+ metrics: ["Count"],
4229
+ select: {
4230
+ changes: [AnalyticsPath.fromString(`changes`)],
4231
+ document: [AnalyticsPath.fromString(`document/${documentId}`)]
4232
+ },
4233
+ lod: {
4234
+ changes: 2
4235
+ },
4236
+ currency: AnalyticsPath.fromString("")
4237
+ });
4238
+ const mappedResult = useMemo(() => {
4239
+ if (!diffResult)
4240
+ return [];
4241
+ return diffResult.sort((a, b) => {
4242
+ const aDate = new Date(a.start);
4243
+ const bDate = new Date(b.start);
4244
+ return aDate.getTime() - bDate.getTime();
4245
+ }).filter((result) => {
4246
+ return result.rows.every((row) => row.value > 0);
4247
+ }).map((result) => {
4248
+ const { additions, deletions } = result.rows.reduce((acc, row) => {
4249
+ if (row.dimensions.changes.path === "changes/add") {
4250
+ acc.additions += row.value;
4251
+ } else if (row.dimensions.changes.path === "changes/remove") {
4252
+ acc.deletions += row.value;
4253
+ }
4254
+ return acc;
4255
+ }, { additions: 0, deletions: 0 });
4256
+ const startDate = new Date(result.start);
4257
+ return {
4258
+ id: startDate.toISOString(),
4259
+ type: "bar",
4260
+ addSize: getBarSize(additions),
4261
+ delSize: getBarSize(deletions),
4262
+ additions,
4263
+ deletions,
4264
+ timestamp: startDate.toISOString(),
4265
+ startDate,
4266
+ endDate: new Date(result.end),
4267
+ revision: 0
4268
+ };
4269
+ });
4270
+ }, [diffResult]);
4271
+ const resultWithDividers = useMemo(() => {
4272
+ if (!mappedResult.length)
4273
+ return [];
4274
+ const result = [];
4275
+ mappedResult.forEach((item, index) => {
4276
+ result.push(item);
4277
+ if (index < mappedResult.length - 1) {
4278
+ const currentDate = new Date(item.startDate);
4279
+ const nextDate = new Date(mappedResult[index + 1].startDate);
4280
+ const currentHour = currentDate.getHours();
4281
+ const nextHour = nextDate.getHours();
4282
+ const currentDay = currentDate.toDateString();
4283
+ const nextDay = nextDate.toDateString();
4284
+ if (currentDay !== nextDay || currentDay === nextDay && Math.abs(nextHour - currentHour) > 1) {
4285
+ result.push({
4286
+ id: `divider-${item.id}-${mappedResult[index + 1].id}`,
4287
+ type: "divider",
4288
+ revision: 0
4289
+ });
4290
+ }
4291
+ }
4292
+ });
4293
+ return result;
4294
+ }, [mappedResult]);
4295
+ return {
4296
+ isLoading,
4297
+ data: resultWithDividers
4298
+ };
4299
+ };
4300
+ const getRevisionFromDate = (startDate, endDate, operations = []) => {
4301
+ if (!startDate || !endDate)
4302
+ return 0;
4303
+ const operation = operations.find((operation2) => {
4304
+ const operationDate = new Date(operation2.timestamp);
4305
+ return operationDate >= startDate && operationDate <= endDate;
4306
+ });
4307
+ return operation ? operation.index : 0;
4308
+ };
4309
+ function EditorLoader(props) {
4310
+ const [showLoading, setShowLoading] = useState(false);
4311
+ useEffect(() => {
4312
+ setTimeout(() => {
3565
4313
  setShowLoading(true);
3566
4314
  }, props.loadingTimeout ?? 200);
3567
4315
  }, [props]);
@@ -3585,9 +4333,11 @@ const DocumentEditor = (props) => {
3585
4333
  onChange,
3586
4334
  onExport,
3587
4335
  onAddOperation,
4336
+ onGetDocumentRevision,
3588
4337
  onOpenSwitchboardLink
3589
4338
  } = props;
3590
4339
  const documentId = fileNodeDocument == null ? void 0 : fileNodeDocument.documentId;
4340
+ const [selectedTimelineItem, setSelectedTimelineItem] = useState(null);
3591
4341
  const [revisionHistoryVisible, setRevisionHistoryVisible] = useState(false);
3592
4342
  const theme = useAtomValue(themeAtom);
3593
4343
  const user = useUser() || void 0;
@@ -3613,6 +4363,10 @@ const DocumentEditor = (props) => {
3613
4363
  [theme, user]
3614
4364
  );
3615
4365
  const userPermissions = useUserPermissions$1();
4366
+ const timelineItems = useTimelineItems(
4367
+ documentId,
4368
+ initialDocument == null ? void 0 : initialDocument.created
4369
+ );
3616
4370
  const currentDocument = useRef({ ...fileNodeDocument, document: document2 });
3617
4371
  useEffect(() => {
3618
4372
  var _a;
@@ -3789,7 +4543,8 @@ const DocumentEditor = (props) => {
3789
4543
  const {
3790
4544
  disableExternalControls,
3791
4545
  documentToolbarEnabled,
3792
- showSwitchboardLink
4546
+ showSwitchboardLink,
4547
+ timelineEnabled
3793
4548
  } = editor.config || {};
3794
4549
  const handleSwitchboardLinkClick = showSwitchboardLink !== false ? onOpenSwitchboardLink : void 0;
3795
4550
  return /* @__PURE__ */ jsxs("div", { className: "relative h-full", id: "document-editor-context", children: [
@@ -3800,7 +4555,10 @@ const DocumentEditor = (props) => {
3800
4555
  onExport,
3801
4556
  onShowRevisionHistory: showRevisionHistory,
3802
4557
  title: fileNodeDocument.name || document2.name,
3803
- onSwitchboardLinkClick: handleSwitchboardLinkClick
4558
+ onSwitchboardLinkClick: handleSwitchboardLinkClick,
4559
+ timelineButtonVisible: timelineEnabled,
4560
+ timelineItems: timelineItems.data,
4561
+ onTimelineItemClick: setSelectedTimelineItem
3804
4562
  }
3805
4563
  ),
3806
4564
  !disableExternalControls && /* @__PURE__ */ jsxs("div", { className: "mb-4 flex justify-end gap-10", children: [
@@ -3830,7 +4588,16 @@ const DocumentEditor = (props) => {
3830
4588
  EditorComponent,
3831
4589
  {
3832
4590
  error,
3833
- context,
4591
+ context: {
4592
+ ...context,
4593
+ getDocumentRevision: onGetDocumentRevision,
4594
+ readMode: !!selectedTimelineItem,
4595
+ selectedTimelineRevision: getRevisionFromDate(
4596
+ selectedTimelineItem == null ? void 0 : selectedTimelineItem.startDate,
4597
+ selectedTimelineItem == null ? void 0 : selectedTimelineItem.endDate,
4598
+ document2.operations.global
4599
+ )
4600
+ },
3834
4601
  document: document2,
3835
4602
  documentNodeName: fileNodeDocument.name,
3836
4603
  dispatch,
@@ -3868,6 +4635,7 @@ function DocumentEditorContainer() {
3868
4635
  renameNode,
3869
4636
  getDocumentModelModule
3870
4637
  } = useUiNodes();
4638
+ const getDocument = useGetDocument();
3871
4639
  const handleAddOperationToSelectedDocument = useCallback(
3872
4640
  async (operation) => {
3873
4641
  if (!selectedDocument) {
@@ -3930,6 +4698,20 @@ function DocumentEditorContainer() {
3930
4698
  },
3931
4699
  [getDocumentModelModule, showModal, t]
3932
4700
  );
4701
+ const onGetDocumentRevision = useCallback(
4702
+ (options) => {
4703
+ if (!selectedNode) {
4704
+ console.error("No selected node");
4705
+ return Promise.reject(new Error("No selected node"));
4706
+ }
4707
+ return getDocument(
4708
+ selectedNode.driveId,
4709
+ selectedNode.id,
4710
+ options
4711
+ );
4712
+ },
4713
+ [getDocument, selectedNode]
4714
+ );
3933
4715
  const onExport = useCallback(() => {
3934
4716
  if (selectedDocument) {
3935
4717
  return exportDocument(selectedDocument);
@@ -3951,6 +4733,7 @@ function DocumentEditorContainer() {
3951
4733
  onChange: onDocumentChangeHandler,
3952
4734
  onClose,
3953
4735
  onExport,
4736
+ onGetDocumentRevision,
3954
4737
  onAddOperation: handleAddOperationToSelectedDocument,
3955
4738
  onOpenSwitchboardLink
3956
4739
  }
@@ -3959,165 +4742,6 @@ function DocumentEditorContainer() {
3959
4742
  fileNodeDocument.documentId
3960
4743
  );
3961
4744
  }
3962
- function getDocumentSpec(doc) {
3963
- if ("documentModelState" in doc) {
3964
- return doc.documentModelState;
3965
- }
3966
- return doc.documentModel;
3967
- }
3968
- const CreateDocument = ({ documentModels, createDocument }) => {
3969
- return jsxs("div", { className: "px-6", children: [jsx("h3", { className: "mb-3 mt-4 text-xl font-bold text-gray-600", children: "New document" }), jsx("div", { className: "flex w-full flex-wrap gap-4", children: documentModels == null ? void 0 : documentModels.map((doc) => {
3970
- const spec = getDocumentSpec(doc);
3971
- return jsx(Button, { color: "light", "aria-details": spec.description, onClick: () => createDocument(doc), children: jsx("span", { className: "text-sm", children: spec.name }) }, spec.id);
3972
- }) })] });
3973
- };
3974
- function sortUiNodesByName(a, b) {
3975
- return a.name.localeCompare(b.name);
3976
- }
3977
- const GAP = 8;
3978
- const ITEM_WIDTH = 256;
3979
- const ITEM_HEIGHT = 48;
3980
- const USED_SPACE = 420;
3981
- function FileContentView(props) {
3982
- const parentRef = useRef(null);
3983
- const { t } = useTranslation();
3984
- const windowSize = useWindowSize();
3985
- const { fileNodes, ...fileProps } = props;
3986
- const availableWidth = windowSize.innerWidth - USED_SPACE;
3987
- const columnCount = Math.floor(availableWidth / (ITEM_WIDTH + GAP)) || 1;
3988
- const rowCount = Math.ceil(fileNodes.length / columnCount);
3989
- const rowVirtualizer = useVirtualizer({
3990
- count: rowCount,
3991
- getScrollElement: () => parentRef.current,
3992
- estimateSize: (index) => {
3993
- if (index > 0) {
3994
- return ITEM_HEIGHT + GAP;
3995
- }
3996
- return ITEM_HEIGHT;
3997
- },
3998
- overscan: 5
3999
- });
4000
- const columnVirtualizer = useVirtualizer({
4001
- horizontal: true,
4002
- count: columnCount,
4003
- getScrollElement: () => parentRef.current,
4004
- estimateSize: (index) => {
4005
- if (index > 0) {
4006
- return ITEM_WIDTH + GAP;
4007
- }
4008
- return ITEM_WIDTH;
4009
- },
4010
- overscan: 5
4011
- });
4012
- const getItemIndex = (rowIndex, columnIndex) => rowIndex * columnCount + columnIndex;
4013
- const getItem = (rowIndex, columnIndex) => {
4014
- const index = getItemIndex(rowIndex, columnIndex);
4015
- return fileNodes[index] || null;
4016
- };
4017
- if (fileNodes.length === 0) {
4018
- return jsx("div", { className: "mb-8 text-sm text-gray-400", children: t("folderView.sections.documents.empty", {
4019
- defaultValue: "No documents or files 📄"
4020
- }) });
4021
- }
4022
- const renderItem = (rowIndex, columnIndex) => {
4023
- const fileNode = getItem(rowIndex, columnIndex);
4024
- if (!fileNode) {
4025
- return null;
4026
- }
4027
- return jsx("div", { style: {
4028
- marginLeft: columnIndex === 0 ? 0 : GAP
4029
- }, children: jsx(FileItem, { uiNode: fileNode, ...fileProps }, fileNode.id) });
4030
- };
4031
- return jsx("div", { ref: parentRef, style: {
4032
- height: `400px`,
4033
- width: `100%`,
4034
- overflow: "auto"
4035
- }, children: jsx("div", { style: {
4036
- height: `${rowVirtualizer.getTotalSize()}px`,
4037
- width: `${columnVirtualizer.getTotalSize()}px`,
4038
- position: "relative"
4039
- }, children: rowVirtualizer.getVirtualItems().map((virtualRow) => jsx(React__default.Fragment, { children: columnVirtualizer.getVirtualItems().map((virtualColumn) => jsx("div", { style: {
4040
- position: "absolute",
4041
- top: 0,
4042
- left: 0,
4043
- marginTop: virtualRow.index === 0 ? 0 : GAP,
4044
- width: `${virtualColumn.size}px`,
4045
- height: `${virtualRow.size}px`,
4046
- transform: `translateX(${virtualColumn.start}px) translateY(${virtualRow.start}px)`
4047
- }, children: renderItem(virtualRow.index, virtualColumn.index) }, virtualColumn.key)) }, virtualRow.key)) }) });
4048
- }
4049
- function FolderView(props) {
4050
- const { node, className, isDropTarget, containerProps, ...nodeProps } = props;
4051
- const { t } = useTranslation();
4052
- const folderNodes = node.children.filter((node2) => node2.kind === FOLDER).sort(sortUiNodesByName);
4053
- const fileNodes = node.children.filter((node2) => node2.kind === FILE).sort(sortUiNodesByName);
4054
- const folderCallbacks = {
4055
- onSelectNode: (node2) => nodeProps.onSelectNode(node2),
4056
- onRenameNode: (name, node2) => nodeProps.onRenameNode(name, node2),
4057
- onDuplicateNode: (node2) => nodeProps.onDuplicateNode(node2),
4058
- onDeleteNode: (node2) => nodeProps.onDeleteNode(node2)
4059
- };
4060
- const fileCallbacks = {
4061
- onSelectNode: (node2) => nodeProps.onSelectNode(node2),
4062
- onRenameNode: (name, node2) => nodeProps.onRenameNode(name, node2),
4063
- onDuplicateNode: (node2) => nodeProps.onDuplicateNode(node2),
4064
- onDeleteNode: (node2) => nodeProps.onDeleteNode(node2)
4065
- };
4066
- const baseNodeCallbacks = {
4067
- onAddFile: async (file, parentNode) => {
4068
- await nodeProps.onAddFile(file, parentNode);
4069
- },
4070
- onCopyNode: async (uiNode, targetNode) => {
4071
- await nodeProps.onCopyNode(uiNode, targetNode);
4072
- },
4073
- onMoveNode: async (uiNode, targetNode) => {
4074
- await nodeProps.onMoveNode(uiNode, targetNode);
4075
- }
4076
- };
4077
- return jsxs("div", { className: twMerge("rounded-md border-2 border-transparent p-2", isDropTarget && "border-dashed border-blue-100", className), ...containerProps, children: [jsx(DriveLayout.ContentSection, { title: t("folderView.sections.folders.title", {
4078
- defaultValue: "Folders"
4079
- }), className: "mb-4", children: folderNodes.length > 0 ? folderNodes.map((folderNode) => jsx(FolderItem, { uiNode: folderNode, ...baseNodeCallbacks, ...folderCallbacks, isAllowedToCreateDocuments: nodeProps.isAllowedToCreateDocuments }, folderNode.id)) : jsx("div", { className: "mb-8 text-sm text-gray-400", children: t("folderView.sections.folders.empty", {
4080
- defaultValue: "No documents or files 📄"
4081
- }) }) }), jsx(DriveLayout.ContentSection, { title: t("folderView.sections.documents.title", {
4082
- defaultValue: "Documents and files"
4083
- }), children: jsx("div", { className: twMerge("w-full", fileNodes.length > 0 ? "min-h-[400px]" : "min-h-14"), children: jsx(FileContentView, { fileNodes, ...fileCallbacks, isAllowedToCreateDocuments: nodeProps.isAllowedToCreateDocuments }) }) })] });
4084
- }
4085
- function BaseEditor(props) {
4086
- const { document: document2, dispatch, className, children } = props;
4087
- const { state: { global: { id: driveId } } } = document2;
4088
- const { showSearchBar, isAllowedToCreateDocuments, documentModels, showCreateDocumentModal } = useDriveContext();
4089
- const { driveNodes, selectedNode, selectedNodePath, getNodeById, setSelectedNode } = useUiNodesContext();
4090
- const driveNode = useMemo(() => driveNodes.find((n) => n.id === driveId), [driveNodes, driveId]);
4091
- const { addDocument, addFile, addFolder: addFolder2, renameNode, deleteNode: deleteNode2, moveNode: moveNode2, copyNode: copyNode2, duplicateNode } = useDriveActionsWithUiNodes(document2, dispatch);
4092
- const onCreateDocument = useCallback(async (documentModel) => {
4093
- const { name } = await showCreateDocumentModal(documentModel);
4094
- const document3 = documentModel.utils.createDocument();
4095
- await addDocument(name, documentModel.documentModel.name, document3, selectedNode == null ? void 0 : selectedNode.id);
4096
- }, [addDocument, showCreateDocumentModal, selectedNode == null ? void 0 : selectedNode.id]);
4097
- const { isDropTarget, dropProps } = useDrop({
4098
- uiNode: selectedNode,
4099
- onAddFile: addFile,
4100
- onCopyNode: copyNode2,
4101
- onMoveNode: moveNode2
4102
- });
4103
- const { breadcrumbs, onBreadcrumbSelected } = useBreadcrumbs({
4104
- selectedNodePath,
4105
- getNodeById,
4106
- setSelectedNode
4107
- });
4108
- if (!driveNode) {
4109
- return jsx("div", { children: "Drive not found" });
4110
- } else if ((selectedNode == null ? void 0 : selectedNode.kind) === FILE$1) {
4111
- return jsx(Fragment$1, {});
4112
- }
4113
- return jsxs(DriveLayout, { className, children: [children, jsxs(DriveLayout.Header, { children: [jsx(Breadcrumbs, { breadcrumbs, createEnabled: isAllowedToCreateDocuments, onCreate: addFolder2, onBreadcrumbSelected }), showSearchBar && jsx(SearchBar, {})] }), jsx(DriveLayout.Content, { children: jsx(FolderView, { node: selectedNode || driveNode, onSelectNode: setSelectedNode, onRenameNode: renameNode, onDuplicateNode: duplicateNode, onDeleteNode: deleteNode2, onAddFile: addFile, onCopyNode: copyNode2, onMoveNode: moveNode2, isDropTarget, isAllowedToCreateDocuments }) }), jsx(DriveLayout.Footer, { children: isAllowedToCreateDocuments && jsx(CreateDocument, { documentModels, createDocument: onCreateDocument }) })] });
4114
- }
4115
- function Editor(props) {
4116
- return jsx(DriveContextProvider, { value: props.context, children: jsx(BaseEditor, { ...props }) });
4117
- }
4118
- const GenericDriveExplorer = {
4119
- Component: Editor
4120
- };
4121
4745
  function useDocumentsState(args) {
4122
4746
  const { reactor, driveId, documentIds, options } = args;
4123
4747
  const [statesByDocumentId, setStatesByDocumentId] = useState({});
@@ -4304,6 +4928,19 @@ function DriveEditorContainer() {
4304
4928
  const { addFile, addDocument } = useDocumentDriveServer();
4305
4929
  const documentModels = useFilteredDocumentModels();
4306
4930
  const useDriveDocumentState = makeDriveDocumentStateHook(reactor);
4931
+ const getDocument = useGetDocument();
4932
+ const getDocumentModelModule = useGetDocumentModelModule();
4933
+ const getEditor = useGetEditor();
4934
+ const onGetDocumentRevision = useCallback(
4935
+ (documentId, options) => {
4936
+ if (!selectedNode) {
4937
+ console.error("No selected node");
4938
+ return Promise.reject(new Error("No selected node"));
4939
+ }
4940
+ return getDocument(selectedNode.driveId, documentId, options);
4941
+ },
4942
+ [getDocument, selectedNode]
4943
+ );
4307
4944
  const driveContext = useMemo(
4308
4945
  () => ({
4309
4946
  showSearchBar: false,
@@ -4346,7 +4983,11 @@ function DriveEditorContainer() {
4346
4983
  ...editorProps,
4347
4984
  context: {
4348
4985
  ...editorProps.context,
4349
- ...driveContext
4986
+ ...driveContext,
4987
+ analyticsDatabaseName: connectConfig.analyticsDatabaseName,
4988
+ getDocumentRevision: onGetDocumentRevision,
4989
+ getDocumentModelModule,
4990
+ getEditor
4350
4991
  },
4351
4992
  onSwitchboardLinkClick: void 0,
4352
4993
  document: document2,
@@ -4380,7 +5021,7 @@ function Content() {
4380
5021
  }, [selectedDriveNode, selectedNode, addFile]);
4381
5022
  useEffect(() => {
4382
5023
  if ((status === "LOADED" || status === "ERROR") && !documentDrives.find(
4383
- (d) => d.state.global.id === driveId || d.state.global.slug === driveId || d.state.global.name === driveId
5024
+ (d) => d.id === driveId || d.slug === driveId || d.state.global.name === driveId
4384
5025
  )) {
4385
5026
  toast(/* @__PURE__ */ jsxs("p", { children: [
4386
5027
  "Drive ",
@@ -4395,3 +5036,4 @@ function Content() {
4395
5036
  export {
4396
5037
  Content as default
4397
5038
  };
5039
+ //# sourceMappingURL=content-DsWyfJvF.js.map