@powerhousedao/connect 1.0.23-staging.2 → 1.0.25-dev.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/.env +1 -1
  2. package/dist/assets/{app-_0wz8A4r.js → app-BUYipU-h.js} +21101 -19624
  3. package/dist/assets/app-BUYipU-h.js.map +1 -0
  4. package/dist/assets/{app-DFQhKB-Q.css → app-DWlDE8AF.css} +240 -181
  5. package/dist/assets/{app-loader-d7zgN9hh.js → app-loader-BnRwgIP_.js} +763 -437
  6. package/dist/assets/app-loader-BnRwgIP_.js.map +1 -0
  7. package/dist/assets/{app-loader-DczGHPG9.css → app-loader-NDVZu4bS.css} +239 -229
  8. package/dist/assets/browser-DLDtNgow.js +27224 -0
  9. package/dist/assets/browser-DLDtNgow.js.map +1 -0
  10. package/dist/assets/{ccip-C6W2FbjW.js → ccip-LS87QwZy.js} +6 -8
  11. package/dist/assets/ccip-LS87QwZy.js.map +1 -0
  12. package/dist/assets/{content-Bm5Tr4Hg.js → content-C_bg7acW.js} +1107 -470
  13. package/dist/assets/content-C_bg7acW.js.map +1 -0
  14. package/dist/assets/{index-CXXvva-l.js → index-CLG940Kn.js} +2582 -2923
  15. package/dist/assets/index-CLG940Kn.js.map +1 -0
  16. package/dist/assets/index-CNFyJkHA.js +208 -0
  17. package/dist/assets/index-CNFyJkHA.js.map +1 -0
  18. package/dist/assets/{index-BhxEM16y.js → index-DzfUrip3.js} +23 -171
  19. package/dist/assets/index-DzfUrip3.js.map +1 -0
  20. package/dist/assets/{index-DamVoHkh.js → index-N3PIlRbq.js} +4 -3
  21. package/dist/assets/index-N3PIlRbq.js.map +1 -0
  22. package/dist/assets/{main.Cq930vY3.js → main.DbDmc7wl.js} +3 -12
  23. package/dist/assets/main.DbDmc7wl.js.map +1 -0
  24. package/dist/assets/reactor-analytics-DOjP79na.js +42 -0
  25. package/dist/assets/reactor-analytics-DOjP79na.js.map +1 -0
  26. package/dist/assets/router-GU7qCi_d.js +1585 -0
  27. package/dist/assets/router-GU7qCi_d.js.map +1 -0
  28. package/dist/assets/{style-BQHqCxXa.css → style-CdxGKc2g.css} +42 -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 +23 -21
@@ -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-_0wz8A4r.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-BUYipU-h.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-d7zgN9hh.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-BnRwgIP_.js";
6
+ import { E as ENSAvatar, a as ErrorBoundary } from "./router-GU7qCi_d.js";
6
7
  import { flushSync } from "react-dom";
7
- import "./main.Cq930vY3.js";
8
+ import "./main.DbDmc7wl.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) {
@@ -1874,7 +2324,7 @@ function notUndefined(value, msg) {
1874
2324
  return value;
1875
2325
  }
1876
2326
  }
1877
- const approxEqual = (a, b) => Math.abs(a - b) <= 1;
2327
+ const approxEqual = (a, b) => Math.abs(a - b) < 1;
1878
2328
  const debounce = (targetWindow, fn, ms) => {
1879
2329
  let timeoutId;
1880
2330
  return function(...args) {
@@ -1882,10 +2332,6 @@ const debounce = (targetWindow, fn, ms) => {
1882
2332
  timeoutId = targetWindow.setTimeout(() => fn.apply(this, args), ms);
1883
2333
  };
1884
2334
  };
1885
- const getRect = (element) => {
1886
- const { offsetWidth, offsetHeight } = element;
1887
- return { width: offsetWidth, height: offsetHeight };
1888
- };
1889
2335
  const defaultKeyExtractor = (index) => index;
1890
2336
  const defaultRangeExtractor = (range) => {
1891
2337
  const start = Math.max(range.startIndex - range.overscan, 0);
@@ -1909,24 +2355,21 @@ const observeElementRect = (instance, cb) => {
1909
2355
  const { width, height } = rect;
1910
2356
  cb({ width: Math.round(width), height: Math.round(height) });
1911
2357
  };
1912
- handler(getRect(element));
2358
+ handler(element.getBoundingClientRect());
1913
2359
  if (!targetWindow.ResizeObserver) {
1914
2360
  return () => {
1915
2361
  };
1916
2362
  }
1917
2363
  const observer = new targetWindow.ResizeObserver((entries) => {
1918
- const run = () => {
1919
- const entry = entries[0];
1920
- if (entry == null ? void 0 : entry.borderBoxSize) {
1921
- const box = entry.borderBoxSize[0];
1922
- if (box) {
1923
- handler({ width: box.inlineSize, height: box.blockSize });
1924
- return;
1925
- }
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;
1926
2370
  }
1927
- handler(getRect(element));
1928
- };
1929
- instance.options.useAnimationFrameWithResizeObserver ? requestAnimationFrame(run) : run();
2371
+ }
2372
+ handler(element.getBoundingClientRect());
1930
2373
  });
1931
2374
  observer.observe(element, { box: "border-box" });
1932
2375
  return () => {
@@ -1964,15 +2407,10 @@ const observeElementOffset = (instance, cb) => {
1964
2407
  const endHandler = createHandler(false);
1965
2408
  endHandler();
1966
2409
  element.addEventListener("scroll", handler, addEventListenerOptions);
1967
- const registerScrollendEvent = instance.options.useScrollendEvent && supportsScrollend;
1968
- if (registerScrollendEvent) {
1969
- element.addEventListener("scrollend", endHandler, addEventListenerOptions);
1970
- }
2410
+ element.addEventListener("scrollend", endHandler, addEventListenerOptions);
1971
2411
  return () => {
1972
2412
  element.removeEventListener("scroll", handler);
1973
- if (registerScrollendEvent) {
1974
- element.removeEventListener("scrollend", endHandler);
1975
- }
2413
+ element.removeEventListener("scrollend", endHandler);
1976
2414
  };
1977
2415
  };
1978
2416
  const measureElement = (element, entry, instance) => {
@@ -1985,7 +2423,9 @@ const measureElement = (element, entry, instance) => {
1985
2423
  return size;
1986
2424
  }
1987
2425
  }
1988
- return element[instance.options.horizontal ? "offsetWidth" : "offsetHeight"];
2426
+ return Math.round(
2427
+ element.getBoundingClientRect()[instance.options.horizontal ? "width" : "height"]
2428
+ );
1989
2429
  };
1990
2430
  const elementScroll = (offset, {
1991
2431
  adjustments = 0,
@@ -2024,10 +2464,7 @@ class Virtualizer {
2024
2464
  }
2025
2465
  return _ro = new this.targetWindow.ResizeObserver((entries) => {
2026
2466
  entries.forEach((entry) => {
2027
- const run = () => {
2028
- this._measureElement(entry.target, entry);
2029
- };
2030
- this.options.useAnimationFrameWithResizeObserver ? requestAnimationFrame(run) : run();
2467
+ this._measureElement(entry.target, entry);
2031
2468
  });
2032
2469
  });
2033
2470
  };
@@ -2075,8 +2512,7 @@ class Virtualizer {
2075
2512
  isScrollingResetDelay: 150,
2076
2513
  enabled: true,
2077
2514
  isRtl: false,
2078
- useScrollendEvent: false,
2079
- useAnimationFrameWithResizeObserver: false,
2515
+ useScrollendEvent: true,
2080
2516
  ...opts2
2081
2517
  };
2082
2518
  };
@@ -2265,18 +2701,12 @@ class Virtualizer {
2265
2701
  }
2266
2702
  );
2267
2703
  this.calculateRange = memo(
2268
- () => [
2269
- this.getMeasurements(),
2270
- this.getSize(),
2271
- this.getScrollOffset(),
2272
- this.options.lanes
2273
- ],
2274
- (measurements, outerSize, scrollOffset, lanes) => {
2704
+ () => [this.getMeasurements(), this.getSize(), this.getScrollOffset()],
2705
+ (measurements, outerSize, scrollOffset) => {
2275
2706
  return this.range = measurements.length > 0 && outerSize > 0 ? calculateRange({
2276
2707
  measurements,
2277
2708
  outerSize,
2278
- scrollOffset,
2279
- lanes
2709
+ scrollOffset
2280
2710
  }) : null;
2281
2711
  },
2282
2712
  {
@@ -2284,7 +2714,7 @@ class Virtualizer {
2284
2714
  debug: () => this.options.debug
2285
2715
  }
2286
2716
  );
2287
- this.getVirtualIndexes = memo(
2717
+ this.getIndexes = memo(
2288
2718
  () => {
2289
2719
  let startIndex = null;
2290
2720
  let endIndex = null;
@@ -2293,7 +2723,6 @@ class Virtualizer {
2293
2723
  startIndex = range.startIndex;
2294
2724
  endIndex = range.endIndex;
2295
2725
  }
2296
- this.maybeNotify.updateDeps([this.isScrolling, startIndex, endIndex]);
2297
2726
  return [
2298
2727
  this.options.rangeExtractor,
2299
2728
  this.options.overscan,
@@ -2377,7 +2806,7 @@ class Virtualizer {
2377
2806
  this._measureElement(node, void 0);
2378
2807
  };
2379
2808
  this.getVirtualItems = memo(
2380
- () => [this.getVirtualIndexes(), this.getMeasurements()],
2809
+ () => [this.getIndexes(), this.getMeasurements()],
2381
2810
  (indexes, measurements) => {
2382
2811
  const virtualItems = [];
2383
2812
  for (let k = 0, len = indexes.length; k < len; k++) {
@@ -2406,18 +2835,20 @@ class Virtualizer {
2406
2835
  )]
2407
2836
  );
2408
2837
  };
2409
- this.getOffsetForAlignment = (toOffset, align, itemSize = 0) => {
2838
+ this.getOffsetForAlignment = (toOffset, align) => {
2410
2839
  const size = this.getSize();
2411
2840
  const scrollOffset = this.getScrollOffset();
2412
2841
  if (align === "auto") {
2413
- align = toOffset >= scrollOffset + size ? "end" : "start";
2842
+ if (toOffset >= scrollOffset + size) {
2843
+ align = "end";
2844
+ }
2414
2845
  }
2415
- if (align === "center") {
2416
- toOffset += (itemSize - size) / 2;
2417
- } else if (align === "end") {
2846
+ if (align === "end") {
2418
2847
  toOffset -= size;
2419
2848
  }
2420
- const maxOffset = this.getTotalSize() - size;
2849
+ const scrollSizeProp = this.options.horizontal ? "scrollWidth" : "scrollHeight";
2850
+ const scrollSize = this.scrollElement ? "document" in this.scrollElement ? this.scrollElement.document.documentElement[scrollSizeProp] : this.scrollElement[scrollSizeProp] : 0;
2851
+ const maxOffset = scrollSize - size;
2421
2852
  return Math.max(Math.min(maxOffset, toOffset), 0);
2422
2853
  };
2423
2854
  this.getOffsetForIndex = (index, align = "auto") => {
@@ -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 = () => {
@@ -2484,8 +2931,7 @@ class Virtualizer {
2484
2931
  const [latestOffset] = notUndefined(
2485
2932
  this.getOffsetForIndex(index, align)
2486
2933
  );
2487
- const currentScrollOffset = this.getScrollOffset();
2488
- if (!approxEqual(latestOffset, currentScrollOffset)) {
2934
+ if (!approxEqual(latestOffset, this.getScrollOffset())) {
2489
2935
  this.scrollToIndex(index, { align, behavior });
2490
2936
  }
2491
2937
  } else {
@@ -2512,19 +2958,10 @@ class Virtualizer {
2512
2958
  let end;
2513
2959
  if (measurements.length === 0) {
2514
2960
  end = this.options.paddingStart;
2515
- } else if (this.options.lanes === 1) {
2516
- end = ((_a = measurements[measurements.length - 1]) == null ? void 0 : _a.end) ?? 0;
2517
2961
  } else {
2518
- const endByLane = Array(this.options.lanes).fill(null);
2519
- let endIndex = measurements.length - 1;
2520
- while (endIndex >= 0 && endByLane.some((val) => val === null)) {
2521
- const item = measurements[endIndex];
2522
- if (endByLane[item.lane] === null) {
2523
- endByLane[item.lane] = item.end;
2524
- }
2525
- endIndex--;
2526
- }
2527
- 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
+ );
2528
2965
  }
2529
2966
  return Math.max(
2530
2967
  end - this.options.scrollMargin + this.options.paddingEnd,
@@ -2565,43 +3002,14 @@ const findNearestBinarySearch = (low, high, getCurrentValue, value) => {
2565
3002
  function calculateRange({
2566
3003
  measurements,
2567
3004
  outerSize,
2568
- scrollOffset,
2569
- lanes
3005
+ scrollOffset
2570
3006
  }) {
2571
- const lastIndex = measurements.length - 1;
3007
+ const count = measurements.length - 1;
2572
3008
  const getOffset = (index) => measurements[index].start;
2573
- if (measurements.length <= lanes) {
2574
- return {
2575
- startIndex: 0,
2576
- endIndex: lastIndex
2577
- };
2578
- }
2579
- let startIndex = findNearestBinarySearch(
2580
- 0,
2581
- lastIndex,
2582
- getOffset,
2583
- scrollOffset
2584
- );
3009
+ const startIndex = findNearestBinarySearch(0, count, getOffset, scrollOffset);
2585
3010
  let endIndex = startIndex;
2586
- if (lanes === 1) {
2587
- while (endIndex < lastIndex && measurements[endIndex].end < scrollOffset + outerSize) {
2588
- endIndex++;
2589
- }
2590
- } else if (lanes > 1) {
2591
- const endPerLane = Array(lanes).fill(0);
2592
- while (endIndex < lastIndex && endPerLane.some((pos) => pos < scrollOffset + outerSize)) {
2593
- const item = measurements[endIndex];
2594
- endPerLane[item.lane] = item.end;
2595
- endIndex++;
2596
- }
2597
- const startPerLane = Array(lanes).fill(scrollOffset + outerSize);
2598
- while (startIndex >= 0 && startPerLane.some((pos) => pos >= scrollOffset)) {
2599
- const item = measurements[startIndex];
2600
- startPerLane[item.lane] = item.start;
2601
- startIndex--;
2602
- }
2603
- startIndex = Math.max(0, startIndex - startIndex % lanes);
2604
- endIndex = Math.min(lastIndex, endIndex + (lanes - 1 - endIndex % lanes));
3011
+ while (endIndex < count && measurements[endIndex].end < scrollOffset + outerSize) {
3012
+ endIndex++;
2605
3013
  }
2606
3014
  return { startIndex, endIndex };
2607
3015
  }
@@ -2858,8 +3266,8 @@ function RevisionHistory(props) {
2858
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] });
2859
3267
  }
2860
3268
  function Tooltip(props) {
2861
- const { children, content, open, defaultOpen, onOpenChange, className, ...rest } = props;
2862
- 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 }) })] });
2863
3271
  }
2864
3272
  const TooltipProvider = Provider;
2865
3273
  const BUDGET = "powerhouse/budget-statement";
@@ -3107,9 +3515,7 @@ function useAddDebouncedOperations(reactor, props) {
3107
3515
  const { driveId, documentId } = props;
3108
3516
  const [documentDrives] = useDocumentDrives(reactor);
3109
3517
  const documentDrivesRef = useRef(documentDrives);
3110
- const { isAllowedToEditDocuments } = useUserPermissions() || {
3111
- isAllowedToEditDocuments: false
3112
- };
3518
+ const { isAllowedToEditDocuments } = useUserPermissions();
3113
3519
  useEffect(() => {
3114
3520
  documentDrivesRef.current = documentDrives;
3115
3521
  }, [documentDrives]);
@@ -3120,7 +3526,7 @@ function useAddDebouncedOperations(reactor, props) {
3120
3526
  if (!reactor) {
3121
3527
  throw new Error("Reactor is not loaded");
3122
3528
  }
3123
- const drive = documentDrivesRef.current.find((drive2) => drive2.state.global.id === driveId2);
3529
+ const drive = documentDrivesRef.current.find((drive2) => drive2.id === driveId2);
3124
3530
  if (!drive) {
3125
3531
  throw new Error(`Drive with id ${driveId2} not found`);
3126
3532
  }
@@ -3199,7 +3605,7 @@ function getNode(id, drive) {
3199
3605
  }
3200
3606
  function createDriveActions(document2, dispatch, context) {
3201
3607
  const drive = document2;
3202
- const { id: driveId } = drive.state.global;
3608
+ const driveId = drive.id;
3203
3609
  const { selectedNode } = context;
3204
3610
  const handleAddFolder = async (name, parentFolder, id = generateId()) => {
3205
3611
  dispatch(addFolder({
@@ -3489,6 +3895,17 @@ function useEditorProps(document2, node, documentDispatch, onAddOperation) {
3489
3895
  isAllowedToEditDocuments: (userPermissions == null ? void 0 : userPermissions.isAllowedToEditDocuments) ?? false
3490
3896
  };
3491
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
+ }
3492
3909
  function useSyncStatus(driveId, documentId) {
3493
3910
  const { getSyncStatusSync, onSyncStatus, documentDrives } = useDocumentDriveServer();
3494
3911
  const syncStatus = useSyncExternalStore(
@@ -3498,9 +3915,7 @@ function useSyncStatus(driveId, documentId) {
3498
3915
  },
3499
3916
  () => {
3500
3917
  var _a;
3501
- const drive = documentDrives.find(
3502
- (_drive) => _drive.state.global.id === driveId
3503
- );
3918
+ const drive = documentDrives.find((_drive) => _drive.id === driveId);
3504
3919
  if (!drive) return;
3505
3920
  const isReadDrive = "readContext" in drive;
3506
3921
  const _sharingType = !isReadDrive ? (_a = drive.state.local.sharingType) == null ? void 0 : _a.toUpperCase() : "PUBLIC";
@@ -3559,8 +3974,340 @@ const useUndoRedoShortcuts = (props) => {
3559
3974
  [canRedo, redo2]
3560
3975
  );
3561
3976
  };
3562
- function EditorLoader(props) {
3563
- const [showLoading, setShowLoading] = useState(false);
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);
3564
4311
  useEffect(() => {
3565
4312
  setTimeout(() => {
3566
4313
  setShowLoading(true);
@@ -3586,9 +4333,11 @@ const DocumentEditor = (props) => {
3586
4333
  onChange,
3587
4334
  onExport,
3588
4335
  onAddOperation,
4336
+ onGetDocumentRevision,
3589
4337
  onOpenSwitchboardLink
3590
4338
  } = props;
3591
4339
  const documentId = fileNodeDocument == null ? void 0 : fileNodeDocument.documentId;
4340
+ const [selectedTimelineItem, setSelectedTimelineItem] = useState(null);
3592
4341
  const [revisionHistoryVisible, setRevisionHistoryVisible] = useState(false);
3593
4342
  const theme = useAtomValue(themeAtom);
3594
4343
  const user = useUser() || void 0;
@@ -3614,6 +4363,10 @@ const DocumentEditor = (props) => {
3614
4363
  [theme, user]
3615
4364
  );
3616
4365
  const userPermissions = useUserPermissions$1();
4366
+ const timelineItems = useTimelineItems(
4367
+ documentId,
4368
+ initialDocument == null ? void 0 : initialDocument.created
4369
+ );
3617
4370
  const currentDocument = useRef({ ...fileNodeDocument, document: document2 });
3618
4371
  useEffect(() => {
3619
4372
  var _a;
@@ -3790,7 +4543,8 @@ const DocumentEditor = (props) => {
3790
4543
  const {
3791
4544
  disableExternalControls,
3792
4545
  documentToolbarEnabled,
3793
- showSwitchboardLink
4546
+ showSwitchboardLink,
4547
+ timelineEnabled
3794
4548
  } = editor.config || {};
3795
4549
  const handleSwitchboardLinkClick = showSwitchboardLink !== false ? onOpenSwitchboardLink : void 0;
3796
4550
  return /* @__PURE__ */ jsxs("div", { className: "relative h-full", id: "document-editor-context", children: [
@@ -3801,7 +4555,10 @@ const DocumentEditor = (props) => {
3801
4555
  onExport,
3802
4556
  onShowRevisionHistory: showRevisionHistory,
3803
4557
  title: fileNodeDocument.name || document2.name,
3804
- onSwitchboardLinkClick: handleSwitchboardLinkClick
4558
+ onSwitchboardLinkClick: handleSwitchboardLinkClick,
4559
+ timelineButtonVisible: timelineEnabled,
4560
+ timelineItems: timelineItems.data,
4561
+ onTimelineItemClick: setSelectedTimelineItem
3805
4562
  }
3806
4563
  ),
3807
4564
  !disableExternalControls && /* @__PURE__ */ jsxs("div", { className: "mb-4 flex justify-end gap-10", children: [
@@ -3831,7 +4588,16 @@ const DocumentEditor = (props) => {
3831
4588
  EditorComponent,
3832
4589
  {
3833
4590
  error,
3834
- 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
+ },
3835
4601
  document: document2,
3836
4602
  documentNodeName: fileNodeDocument.name,
3837
4603
  dispatch,
@@ -3869,6 +4635,7 @@ function DocumentEditorContainer() {
3869
4635
  renameNode,
3870
4636
  getDocumentModelModule
3871
4637
  } = useUiNodes();
4638
+ const getDocument = useGetDocument();
3872
4639
  const handleAddOperationToSelectedDocument = useCallback(
3873
4640
  async (operation) => {
3874
4641
  if (!selectedDocument) {
@@ -3931,6 +4698,20 @@ function DocumentEditorContainer() {
3931
4698
  },
3932
4699
  [getDocumentModelModule, showModal, t]
3933
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
+ );
3934
4715
  const onExport = useCallback(() => {
3935
4716
  if (selectedDocument) {
3936
4717
  return exportDocument(selectedDocument);
@@ -3952,6 +4733,7 @@ function DocumentEditorContainer() {
3952
4733
  onChange: onDocumentChangeHandler,
3953
4734
  onClose,
3954
4735
  onExport,
4736
+ onGetDocumentRevision,
3955
4737
  onAddOperation: handleAddOperationToSelectedDocument,
3956
4738
  onOpenSwitchboardLink
3957
4739
  }
@@ -3960,165 +4742,6 @@ function DocumentEditorContainer() {
3960
4742
  fileNodeDocument.documentId
3961
4743
  );
3962
4744
  }
3963
- function getDocumentSpec(doc) {
3964
- if ("documentModelState" in doc) {
3965
- return doc.documentModelState;
3966
- }
3967
- return doc.documentModel;
3968
- }
3969
- const CreateDocument = ({ documentModels, createDocument }) => {
3970
- 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) => {
3971
- const spec = getDocumentSpec(doc);
3972
- return jsx(Button, { color: "light", "aria-details": spec.description, onClick: () => createDocument(doc), children: jsx("span", { className: "text-sm", children: spec.name }) }, spec.id);
3973
- }) })] });
3974
- };
3975
- function sortUiNodesByName(a, b) {
3976
- return a.name.localeCompare(b.name);
3977
- }
3978
- const GAP = 8;
3979
- const ITEM_WIDTH = 256;
3980
- const ITEM_HEIGHT = 48;
3981
- const USED_SPACE = 420;
3982
- function FileContentView(props) {
3983
- const parentRef = useRef(null);
3984
- const { t } = useTranslation();
3985
- const windowSize = useWindowSize();
3986
- const { fileNodes, ...fileProps } = props;
3987
- const availableWidth = windowSize.innerWidth - USED_SPACE;
3988
- const columnCount = Math.floor(availableWidth / (ITEM_WIDTH + GAP)) || 1;
3989
- const rowCount = Math.ceil(fileNodes.length / columnCount);
3990
- const rowVirtualizer = useVirtualizer({
3991
- count: rowCount,
3992
- getScrollElement: () => parentRef.current,
3993
- estimateSize: (index) => {
3994
- if (index > 0) {
3995
- return ITEM_HEIGHT + GAP;
3996
- }
3997
- return ITEM_HEIGHT;
3998
- },
3999
- overscan: 5
4000
- });
4001
- const columnVirtualizer = useVirtualizer({
4002
- horizontal: true,
4003
- count: columnCount,
4004
- getScrollElement: () => parentRef.current,
4005
- estimateSize: (index) => {
4006
- if (index > 0) {
4007
- return ITEM_WIDTH + GAP;
4008
- }
4009
- return ITEM_WIDTH;
4010
- },
4011
- overscan: 5
4012
- });
4013
- const getItemIndex = (rowIndex, columnIndex) => rowIndex * columnCount + columnIndex;
4014
- const getItem = (rowIndex, columnIndex) => {
4015
- const index = getItemIndex(rowIndex, columnIndex);
4016
- return fileNodes[index] || null;
4017
- };
4018
- if (fileNodes.length === 0) {
4019
- return jsx("div", { className: "mb-8 text-sm text-gray-400", children: t("folderView.sections.documents.empty", {
4020
- defaultValue: "No documents or files 📄"
4021
- }) });
4022
- }
4023
- const renderItem = (rowIndex, columnIndex) => {
4024
- const fileNode = getItem(rowIndex, columnIndex);
4025
- if (!fileNode) {
4026
- return null;
4027
- }
4028
- return jsx("div", { style: {
4029
- marginLeft: columnIndex === 0 ? 0 : GAP
4030
- }, children: jsx(FileItem, { uiNode: fileNode, ...fileProps }, fileNode.id) });
4031
- };
4032
- return jsx("div", { ref: parentRef, style: {
4033
- height: `400px`,
4034
- width: `100%`,
4035
- overflow: "auto"
4036
- }, children: jsx("div", { style: {
4037
- height: `${rowVirtualizer.getTotalSize()}px`,
4038
- width: `${columnVirtualizer.getTotalSize()}px`,
4039
- position: "relative"
4040
- }, children: rowVirtualizer.getVirtualItems().map((virtualRow) => jsx(React__default.Fragment, { children: columnVirtualizer.getVirtualItems().map((virtualColumn) => jsx("div", { style: {
4041
- position: "absolute",
4042
- top: 0,
4043
- left: 0,
4044
- marginTop: virtualRow.index === 0 ? 0 : GAP,
4045
- width: `${virtualColumn.size}px`,
4046
- height: `${virtualRow.size}px`,
4047
- transform: `translateX(${virtualColumn.start}px) translateY(${virtualRow.start}px)`
4048
- }, children: renderItem(virtualRow.index, virtualColumn.index) }, virtualColumn.key)) }, virtualRow.key)) }) });
4049
- }
4050
- function FolderView(props) {
4051
- const { node, className, isDropTarget, containerProps, ...nodeProps } = props;
4052
- const { t } = useTranslation();
4053
- const folderNodes = node.children.filter((node2) => node2.kind === FOLDER).sort(sortUiNodesByName);
4054
- const fileNodes = node.children.filter((node2) => node2.kind === FILE).sort(sortUiNodesByName);
4055
- const folderCallbacks = {
4056
- onSelectNode: (node2) => nodeProps.onSelectNode(node2),
4057
- onRenameNode: (name, node2) => nodeProps.onRenameNode(name, node2),
4058
- onDuplicateNode: (node2) => nodeProps.onDuplicateNode(node2),
4059
- onDeleteNode: (node2) => nodeProps.onDeleteNode(node2)
4060
- };
4061
- const fileCallbacks = {
4062
- onSelectNode: (node2) => nodeProps.onSelectNode(node2),
4063
- onRenameNode: (name, node2) => nodeProps.onRenameNode(name, node2),
4064
- onDuplicateNode: (node2) => nodeProps.onDuplicateNode(node2),
4065
- onDeleteNode: (node2) => nodeProps.onDeleteNode(node2)
4066
- };
4067
- const baseNodeCallbacks = {
4068
- onAddFile: async (file, parentNode) => {
4069
- await nodeProps.onAddFile(file, parentNode);
4070
- },
4071
- onCopyNode: async (uiNode, targetNode) => {
4072
- await nodeProps.onCopyNode(uiNode, targetNode);
4073
- },
4074
- onMoveNode: async (uiNode, targetNode) => {
4075
- await nodeProps.onMoveNode(uiNode, targetNode);
4076
- }
4077
- };
4078
- 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", {
4079
- defaultValue: "Folders"
4080
- }), 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", {
4081
- defaultValue: "No documents or files 📄"
4082
- }) }) }), jsx(DriveLayout.ContentSection, { title: t("folderView.sections.documents.title", {
4083
- defaultValue: "Documents and files"
4084
- }), children: jsx("div", { className: twMerge("w-full", fileNodes.length > 0 ? "min-h-[400px]" : "min-h-14"), children: jsx(FileContentView, { fileNodes, ...fileCallbacks, isAllowedToCreateDocuments: nodeProps.isAllowedToCreateDocuments }) }) })] });
4085
- }
4086
- function BaseEditor(props) {
4087
- const { document: document2, dispatch, className, children } = props;
4088
- const { state: { global: { id: driveId } } } = document2;
4089
- const { showSearchBar, isAllowedToCreateDocuments, documentModels, showCreateDocumentModal } = useDriveContext();
4090
- const { driveNodes, selectedNode, selectedNodePath, getNodeById, setSelectedNode } = useUiNodesContext();
4091
- const driveNode = useMemo(() => driveNodes.find((n) => n.id === driveId), [driveNodes, driveId]);
4092
- const { addDocument, addFile, addFolder: addFolder2, renameNode, deleteNode: deleteNode2, moveNode: moveNode2, copyNode: copyNode2, duplicateNode } = useDriveActionsWithUiNodes(document2, dispatch);
4093
- const onCreateDocument = useCallback(async (documentModel) => {
4094
- const { name } = await showCreateDocumentModal(documentModel);
4095
- const document3 = documentModel.utils.createDocument();
4096
- await addDocument(name, documentModel.documentModel.name, document3, selectedNode == null ? void 0 : selectedNode.id);
4097
- }, [addDocument, showCreateDocumentModal, selectedNode == null ? void 0 : selectedNode.id]);
4098
- const { isDropTarget, dropProps } = useDrop({
4099
- uiNode: selectedNode,
4100
- onAddFile: addFile,
4101
- onCopyNode: copyNode2,
4102
- onMoveNode: moveNode2
4103
- });
4104
- const { breadcrumbs, onBreadcrumbSelected } = useBreadcrumbs({
4105
- selectedNodePath,
4106
- getNodeById,
4107
- setSelectedNode
4108
- });
4109
- if (!driveNode) {
4110
- return jsx("div", { children: "Drive not found" });
4111
- } else if ((selectedNode == null ? void 0 : selectedNode.kind) === FILE$1) {
4112
- return jsx(Fragment$1, {});
4113
- }
4114
- 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 }) })] });
4115
- }
4116
- function Editor(props) {
4117
- return jsx(DriveContextProvider, { value: props.context, children: jsx(BaseEditor, { ...props }) });
4118
- }
4119
- const GenericDriveExplorer = {
4120
- Component: Editor
4121
- };
4122
4745
  function useDocumentsState(args) {
4123
4746
  const { reactor, driveId, documentIds, options } = args;
4124
4747
  const [statesByDocumentId, setStatesByDocumentId] = useState({});
@@ -4305,8 +4928,19 @@ function DriveEditorContainer() {
4305
4928
  const { addFile, addDocument } = useDocumentDriveServer();
4306
4929
  const documentModels = useFilteredDocumentModels();
4307
4930
  const useDriveDocumentState = makeDriveDocumentStateHook(reactor);
4931
+ const getDocument = useGetDocument();
4308
4932
  const getDocumentModelModule = useGetDocumentModelModule();
4309
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
+ );
4310
4944
  const driveContext = useMemo(
4311
4945
  () => ({
4312
4946
  showSearchBar: false,
@@ -4350,6 +4984,8 @@ function DriveEditorContainer() {
4350
4984
  context: {
4351
4985
  ...editorProps.context,
4352
4986
  ...driveContext,
4987
+ analyticsDatabaseName: connectConfig.analyticsDatabaseName,
4988
+ getDocumentRevision: onGetDocumentRevision,
4353
4989
  getDocumentModelModule,
4354
4990
  getEditor
4355
4991
  },
@@ -4385,7 +5021,7 @@ function Content() {
4385
5021
  }, [selectedDriveNode, selectedNode, addFile]);
4386
5022
  useEffect(() => {
4387
5023
  if ((status === "LOADED" || status === "ERROR") && !documentDrives.find(
4388
- (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
4389
5025
  )) {
4390
5026
  toast(/* @__PURE__ */ jsxs("p", { children: [
4391
5027
  "Drive ",
@@ -4400,3 +5036,4 @@ function Content() {
4400
5036
  export {
4401
5037
  Content as default
4402
5038
  };
5039
+ //# sourceMappingURL=content-C_bg7acW.js.map