@inkandswitch/patchwork-pkg-base 0.0.113 → 0.0.115

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/module-settings-url +1 -1
  2. package/package.json +1 -1
  3. package/packages/account/dist/{AccountPicker-L3IHAMPQ.js → AccountPicker-TCOUU4YK.js} +36 -16
  4. package/packages/account/dist/AccountPicker-TCOUU4YK.js.map +7 -0
  5. package/packages/account/dist/index.js +1 -1
  6. package/packages/account/package.json +1 -1
  7. package/packages/account-history/dist/assets/{HistoryRecorder-mRdg9-Sa.js → HistoryRecorder-DhQqHws4.js} +2 -2
  8. package/packages/account-history/dist/assets/{HistoryRecorder-mRdg9-Sa.js.map → HistoryRecorder-DhQqHws4.js.map} +1 -1
  9. package/packages/account-history/dist/assets/{HistoryViewer-yhYv3jqn.js → HistoryViewer-Ba8kq_qW.js} +2 -2
  10. package/packages/account-history/dist/assets/{HistoryViewer-yhYv3jqn.js.map → HistoryViewer-Ba8kq_qW.js.map} +1 -1
  11. package/packages/account-history/dist/assets/{NotebookViewer-CLhIU0hN.js → NotebookViewer-io6-qkNu.js} +2 -2
  12. package/packages/account-history/dist/assets/{NotebookViewer-CLhIU0hN.js.map → NotebookViewer-io6-qkNu.js.map} +1 -1
  13. package/packages/account-history/dist/assets/{context-CgDNOWHV.js → context-BD8lKU7i.js} +24 -4
  14. package/packages/account-history/dist/assets/context-BD8lKU7i.js.map +1 -0
  15. package/packages/account-history/dist/assets/{index-Bx2CKRPA.js → index-BKhVzznZ.js} +5 -5
  16. package/packages/account-history/dist/assets/{index-Bx2CKRPA.js.map → index-BKhVzznZ.js.map} +1 -1
  17. package/packages/account-history/dist/index.js +1 -1
  18. package/packages/account-history/package.json +1 -1
  19. package/packages/chat/dist/{ChatRoot-Ly8PORLd.js → ChatRoot-BMMhWkHl.js} +1051 -1035
  20. package/packages/chat/dist/{context-tool-DHIbdY80.js → context-tool-Bcf797I3.js} +2 -2
  21. package/packages/chat/dist/{index-fGaJgJ-s.js → index-CQ0mHlc4.js} +3 -3
  22. package/packages/chat/dist/index.js +1 -1
  23. package/packages/chat/dist/{tool-CpslbjKC.js → tool-DifU2NW5.js} +1 -1
  24. package/packages/chat/package.json +1 -1
  25. package/packages/codemirror-base/dist/tool.js +1 -1
  26. package/packages/codemirror-base/dist/tool.js.map +1 -1
  27. package/packages/codemirror-base/package.json +1 -1
  28. package/packages/comments-view/dist/assets/{main-IR1Yfgas.js → main-DXYeEDFB.js} +24 -4
  29. package/packages/comments-view/dist/assets/main-DXYeEDFB.js.map +1 -0
  30. package/packages/comments-view/dist/index.js +3 -3
  31. package/packages/comments-view/package.json +1 -1
  32. package/packages/drafts/dist/assets/main-CG9HOCai.js.map +1 -1
  33. package/packages/drafts/package.json +1 -1
  34. package/packages/file/dist/index.js +1 -1
  35. package/packages/file/dist/{tool-DMegb4Cw.js → tool-Bucjz6Ay.js} +1803 -1787
  36. package/packages/file/dist/tool-Bucjz6Ay.js.map +1 -0
  37. package/packages/file/dist/{typescript-language-server-Cx5RlH3z.js → typescript-language-server-BId-R8tz.js} +2 -2
  38. package/packages/file/dist/{typescript-language-server-Cx5RlH3z.js.map → typescript-language-server-BId-R8tz.js.map} +1 -1
  39. package/packages/file/package.json +1 -1
  40. package/packages/history-view/dist/assets/{HistoryTimeline-DOndzpUR.js → HistoryTimeline-CdCl4jqV.js} +25 -5
  41. package/packages/history-view/dist/assets/HistoryTimeline-CdCl4jqV.js.map +1 -0
  42. package/packages/history-view/dist/assets/{index-D7nqWI0b.js → index-R__PBggS.js} +2 -2
  43. package/packages/history-view/dist/assets/{index-D7nqWI0b.js.map → index-R__PBggS.js.map} +1 -1
  44. package/packages/history-view/dist/index.js +1 -1
  45. package/packages/history-view/package.json +1 -1
  46. package/packages/settings/dist/assets/FrameConfigurator-M-u9az7g.js +3 -0
  47. package/packages/settings/dist/assets/FrameConfigurator-M-u9az7g.js.map +1 -0
  48. package/packages/settings/dist/index.js +1 -1
  49. package/packages/settings/package.json +1 -1
  50. package/packages/sideboard/dist/account-bar-6WTRIGGE.js +2 -0
  51. package/packages/sideboard/dist/chunk-3Q7KVV6Y.js +2 -0
  52. package/packages/sideboard/dist/chunk-3Q7KVV6Y.js.map +7 -0
  53. package/packages/sideboard/dist/{chunk-XIUFUJKM.js → chunk-EQ26U6B2.js} +2 -2
  54. package/packages/sideboard/dist/{chunk-XIUFUJKM.js.map → chunk-EQ26U6B2.js.map} +1 -1
  55. package/packages/sideboard/dist/{chunk-6KORX3GC.js → chunk-JE5VBSXY.js} +2 -2
  56. package/packages/sideboard/dist/document-list-panel-OKR5ALTE.js +2 -0
  57. package/packages/sideboard/dist/index.css +1 -1
  58. package/packages/sideboard/dist/index.css.map +2 -2
  59. package/packages/sideboard/dist/index.js +1 -1
  60. package/packages/sideboard/dist/sideboard/sideboard.js +1 -1
  61. package/packages/sideboard/package.json +1 -1
  62. package/packages/sync-indicator/dist/assets/SyncIndicator-oVMcVRXg.js.map +1 -1
  63. package/packages/sync-indicator/package.json +1 -1
  64. package/packages/threepane/dist/IsolatedDocumentArea-3HGASUGM.js +2 -0
  65. package/packages/threepane/dist/{PatchworkFrame-HCSYM5W5.js → PatchworkFrame-22ABHJVG.js} +2 -2
  66. package/packages/threepane/dist/{chunk-HXEHZ5WC.js → chunk-34WWZW2V.js} +6 -6
  67. package/packages/threepane/dist/chunk-34WWZW2V.js.map +7 -0
  68. package/packages/threepane/dist/index.js +1 -1
  69. package/packages/threepane/package.json +1 -1
  70. package/plugin-registry-url +1 -1
  71. package/packages/account/dist/AccountPicker-L3IHAMPQ.js.map +0 -7
  72. package/packages/account-history/dist/assets/context-CgDNOWHV.js.map +0 -1
  73. package/packages/comments-view/dist/assets/main-IR1Yfgas.js.map +0 -1
  74. package/packages/file/dist/tool-DMegb4Cw.js.map +0 -1
  75. package/packages/history-view/dist/assets/HistoryTimeline-DOndzpUR.js.map +0 -1
  76. package/packages/settings/dist/assets/FrameConfigurator-C0ZRifTs.js +0 -3
  77. package/packages/settings/dist/assets/FrameConfigurator-C0ZRifTs.js.map +0 -1
  78. package/packages/sideboard/dist/account-bar-67PDNT3H.js +0 -2
  79. package/packages/sideboard/dist/chunk-FFQGRRLJ.js +0 -2
  80. package/packages/sideboard/dist/chunk-FFQGRRLJ.js.map +0 -7
  81. package/packages/sideboard/dist/document-list-panel-SPPMZDMX.js +0 -2
  82. package/packages/threepane/dist/IsolatedDocumentArea-E3VEPUEG.js +0 -2
  83. package/packages/threepane/dist/chunk-HXEHZ5WC.js.map +0 -7
  84. /package/packages/sideboard/dist/{account-bar-67PDNT3H.js.map → account-bar-6WTRIGGE.js.map} +0 -0
  85. /package/packages/sideboard/dist/{chunk-6KORX3GC.js.map → chunk-JE5VBSXY.js.map} +0 -0
  86. /package/packages/sideboard/dist/{document-list-panel-SPPMZDMX.js.map → document-list-panel-OKR5ALTE.js.map} +0 -0
  87. /package/packages/threepane/dist/{IsolatedDocumentArea-E3VEPUEG.js.map → IsolatedDocumentArea-3HGASUGM.js.map} +0 -0
  88. /package/packages/threepane/dist/{PatchworkFrame-HCSYM5W5.js.map → PatchworkFrame-22ABHJVG.js.map} +0 -0
@@ -63,7 +63,7 @@ var plugins = [
63
63
  name: "Account Picker",
64
64
  supportedDatatypes: ["account"],
65
65
  async load() {
66
- const { AccountPickerTool } = await import("./AccountPicker-L3IHAMPQ.js");
66
+ const { AccountPickerTool } = await import("./AccountPicker-TCOUU4YK.js");
67
67
  const { styled } = await import("./styles-KCFZAQMN.js");
68
68
  return styled(AccountPickerTool);
69
69
  }
@@ -30,7 +30,7 @@
30
30
  "@inkandswitch/patchwork-providers": "^0.5.2",
31
31
  "@kobalte/core": "^0.13.11",
32
32
  "clsx": "^2.1.1",
33
- "solid-automerge": "^2.1.0",
33
+ "solid-automerge": "^2.1.1",
34
34
  "solid-js": "^1.9.9"
35
35
  },
36
36
  "devDependencies": {
@@ -18,7 +18,7 @@ import { getType } from "@inkandswitch/patchwork-filesystem";
18
18
  import { getFallbackTool, getRegistry } from "@inkandswitch/patchwork-plugins";
19
19
  import { createStore, reconcile } from "solid-js/store";
20
20
  import * as Providers from "@inkandswitch/patchwork-providers";
21
- import { A as ACCOUNT_HISTORY_DATATYPE, D as DEDUPLICATION_TIME_THRESHOLD, V as VIEWER_TOOL_ID } from "./index-Bx2CKRPA.js";
21
+ import { A as ACCOUNT_HISTORY_DATATYPE, D as DEDUPLICATION_TIME_THRESHOLD, V as VIEWER_TOOL_ID } from "./index-BKhVzznZ.js";
22
22
  function resolveElement(source) {
23
23
  return typeof source === "function" ? source() : source;
24
24
  }
@@ -196,4 +196,4 @@ export {
196
196
  HistoryRecorder,
197
197
  renderHistoryRecorder
198
198
  };
199
- //# sourceMappingURL=HistoryRecorder-mRdg9-Sa.js.map
199
+ //# sourceMappingURL=HistoryRecorder-DhQqHws4.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"HistoryRecorder-mRdg9-Sa.js","sources":["../../node_modules/.pnpm/@inkandswitch+patchwork-providers-solid@0.2.8_@automerge+automerge-repo@2.6.0-subductio_d2e51e9e7c14a6be5a72dab7789707e3/node_modules/@inkandswitch/patchwork-providers-solid/dist/index.js","../../src/HistoryRecorder.tsx"],"sourcesContent":["import { createEffect, createSignal, onCleanup, onMount, } from \"solid-js\";\nimport { createStore, reconcile } from \"solid-js/store\";\nimport * as Providers from \"@inkandswitch/patchwork-providers\";\nfunction resolveElement(source) {\n return typeof source === \"function\" ? source() : source;\n}\n/**\n * Generic reactive request. Resolves the first value a provider emits for\n * `selector` (via the one-shot `request` helper) and returns an accessor that\n * reads `undefined` until then. `T` is the response type.\n */\nexport function request(element, selector) {\n const [value, setValue] = createSignal(undefined);\n onMount(() => {\n const target = resolveElement(element);\n if (!target)\n return;\n Providers.request(target, selector).then((v) => {\n if (v == null)\n return;\n setValue(() => v);\n });\n });\n return value;\n}\nexport function subscribe(element, selector, initialValue) {\n const [value, setValue] = createSignal(initialValue);\n onMount(() => {\n const target = resolveElement(element);\n if (!target)\n return;\n const unsubscribe = Providers.subscribe(target, selector, setValue);\n onCleanup(unsubscribe);\n });\n return value;\n}\n/**\n * Store-backed subscription. Use this when a consumer wants Solid's\n * fine-grained nested reactivity for incoming JSON object or array snapshots.\n * Requires an initial object/array so the store has a stable root.\n *\n * `reconcile` preserves stable object/array identity where possible, so this\n * helper is not a good fit when the top-level value is used as an identity key\n * for resources or memos.\n */\nexport function subscribeReconciled(element, selector, initialValue) {\n const [store, setStore] = createStore(initialValue);\n onMount(() => {\n const target = resolveElement(element);\n if (!target)\n return;\n const unsubscribe = Providers.subscribe(target, selector, (v) => {\n setStore(reconcile(v));\n });\n onCleanup(unsubscribe);\n });\n return store;\n}\n/**\n * Handle-specialized subscription. Use when the answering provider emits an\n * `AutomergeUrl`. The handle is recovered locally from the global repo\n * (`window.repo`), so it stays fully live — reads project reactively and writes go\n * straight back to the same repo. Returns `[doc, handle]` matching the shape\n * of `solid-automerge`'s `useDocument`; both read `undefined` until the first\n * url arrives. `T` is the doc shape inside the handle.\n */\nexport function subscribeDoc(element, selector) {\n const [handle, setHandle] = createSignal(undefined);\n onMount(() => {\n const target = resolveElement(element);\n if (!target)\n return;\n let canceled = false;\n const unsubscribe = Providers.subscribe(target, selector, (url) => {\n if (!url)\n return;\n const repo = \"repo\" in window ? window.repo : undefined;\n if (!repo)\n return;\n void Promise.resolve(repo.find(url)).then((h) => {\n if (canceled)\n return;\n setHandle(() => h);\n });\n });\n onCleanup(() => {\n canceled = true;\n unsubscribe();\n });\n });\n // Mirror the doc into a store by `reconcile`-ing against the *materialized*\n // snapshot (`handle.doc()`) on every change, rather than replaying the\n // change's incremental patches (as `solid-automerge`'s `createDocumentProjection`\n // / `autoproduce` does).\n //\n // A whole-value write such as `doc.list = [...]` is lowered by Automerge to\n // `putObjectFromHydrate`, whose patch stream is a `put` that materializes the\n // new container *plus* per-element `insert` patches. Replaying that delta with\n // `applyPatches` double-applies the contents — the `put` seeds `[a, b]`, then\n // the inserts splice `a, b` in again, yielding `[a, b, a, b]` — even though the\n // document itself is correct. The materialized snapshot is always\n // authoritative, so reconciling against it is robust to any valid change,\n // whole-array reassignment included.\n const [store, setStore] = createStore({});\n const [ready, setReady] = createSignal(false);\n createEffect(() => {\n const h = handle();\n if (!h) {\n setReady(false);\n return;\n }\n const sync = () => {\n setStore(reconcile((h.doc() ?? {})));\n setReady(true);\n };\n sync();\n h.on(\"change\", sync);\n onCleanup(() => h.off(\"change\", sync));\n });\n const doc = () => (ready() ? store : undefined);\n return [doc, handle];\n}\n","import { onMount, onCleanup, createEffect } from \"solid-js\";\nimport { render } from \"solid-js/web\";\nimport { type AutomergeUrl } from \"@automerge/automerge-repo/slim\";\nimport type { ToolImplementation } from \"@inkandswitch/patchwork-plugins\";\nimport \"./index.css\";\nimport { OpenDocumentEvent } from \"@inkandswitch/patchwork-elements\";\nimport {\n getType,\n type HasPatchworkMetadata,\n} from \"@inkandswitch/patchwork-filesystem\";\nimport {\n getFallbackTool,\n getRegistry,\n type DatatypeDescription,\n type DatatypeImplementation,\n} from \"@inkandswitch/patchwork-plugins\";\nimport { subscribeDoc } from \"@inkandswitch/patchwork-providers-solid\";\nimport {\n ACCOUNT_HISTORY_DATATYPE,\n DEDUPLICATION_TIME_THRESHOLD,\n VIEWER_TOOL_ID,\n} from \"./constants.ts\";\nimport {\n type PatchworkToolProps,\n type HistoryDoc,\n type HistoryEntry,\n} from \"./types.ts\";\n\n// Key under which this tool's private storage doc is registered — see the\n// `patchwork:tool-storage` provider (patchwork-base/providers). Mounted as a\n// titlebar-tool, this component is bound to whatever *document* is focused,\n// not the account, so it can't reach its own storage via `props.handle`; the\n// provider gives it a private, account-scoped doc instead.\nconst TOOL_STORAGE_ID = \"account-history\";\n\nexport function HistoryRecorder(props: PatchworkToolProps<any>) {\n // Resolves (and, on first use, creates) this tool's private storage doc.\n // The provider only guarantees an empty doc exists — the shape below\n // (`entries`, `title`, `@patchwork`) is seeded by us the first time it's\n // used.\n const [historyDoc, historyHandle] = subscribeDoc<HistoryDoc>(\n props.element,\n { type: \"patchwork:tool-storage\", toolId: TOOL_STORAGE_ID }\n );\n\n const historyUrl = () => historyHandle()?.url;\n\n createEffect(() => {\n const handle = historyHandle();\n const doc = historyDoc();\n if (!handle || !doc || Array.isArray(doc.entries)) return;\n handle.change((d) => {\n if (Array.isArray(d.entries)) return; // lost an initialization race\n d[\"@patchwork\"] = { type: ACCOUNT_HISTORY_DATATYPE };\n d.title = \"Account History\";\n d.entries = [];\n });\n });\n\n onMount(() => {\n const onDocumentOpened = async (event: Event) => {\n const openEvent = event as OpenDocumentEvent;\n const { url: rawUrl, toolId: rawToolId } = openEvent.detail;\n const [docUrl, ...heads] = rawUrl.split(\"#\");\n const url = docUrl as AutomergeUrl;\n let toolId = rawToolId;\n\n // Get document to extract title and type\n const docHandle = await props.repo.find(url);\n const doc = docHandle.doc();\n\n if (!doc) {\n console.warn(\"HistoryRecorder: failed to load document\");\n return;\n }\n\n const datatype = getType(doc as Partial<HasPatchworkMetadata>);\n\n if (!toolId) {\n // if the tool id isn't defined, use the current fallback tool\n if (!datatype) {\n console.warn(\n \"HistoryRecorder: no tool found for document type; skipping history recording\"\n );\n return;\n }\n const fallbackTool = getFallbackTool(doc as HasPatchworkMetadata);\n if (!fallbackTool) {\n console.warn(\n \"HistoryRecorder: no tool found for document type; skipping history recording\"\n );\n return;\n }\n toolId = fallbackTool.id;\n }\n\n if (datatype === ACCOUNT_HISTORY_DATATYPE) {\n return; // Don't record when opening account history documents\n }\n\n const currentHistoryHandle = historyHandle();\n if (!currentHistoryHandle) {\n console.warn(\"HistoryRecorder: history handle not ready yet\");\n return;\n }\n const historyDocSnapshot = currentHistoryHandle.doc();\n if (!historyDocSnapshot) {\n console.warn(\"HistoryRecorder: history document not ready yet\");\n return;\n }\n\n // Deduplication: check if this entry is a duplicate from rapid clicks\n const lastEntry =\n historyDocSnapshot.entries[historyDocSnapshot.entries.length - 1];\n if (\n lastEntry &&\n lastEntry.docUrl === url &&\n lastEntry.toolId === toolId &&\n Date.now() - lastEntry.timestamp < DEDUPLICATION_TIME_THRESHOLD\n ) {\n return; // Skip recording - duplicate from rapid clicking\n }\n\n // Extract title\n let docTitle = \"Untitled\";\n if (datatype) {\n const registry = getRegistry<DatatypeDescription>(\"patchwork:datatype\");\n const loaded = registry.get(datatype);\n if (loaded && \"module\" in loaded) {\n const impl = loaded.module as DatatypeImplementation;\n try {\n docTitle = impl.getTitle(doc) || \"Untitled\";\n } catch {\n // getTitle may fail if the document shape doesn't match the datatype\n }\n }\n }\n\n // Get current heads, unless the URL specified a head\n let entryHeads = heads;\n if (entryHeads.length === 0) entryHeads = docHandle.heads();\n\n // Create new entry\n const newEntry: HistoryEntry = {\n timestamp: Date.now(),\n docUrl: url,\n docTitle,\n docType: datatype || \"unknown\",\n toolId,\n heads: entryHeads,\n };\n\n // Add entry to history\n currentHistoryHandle.change((doc) => {\n doc.entries.push(newEntry);\n });\n };\n\n // Listen to patchwork:open-document events (should fire once per user action)\n document.addEventListener(\n \"patchwork:open-document\",\n onDocumentOpened as EventListener,\n { capture: true }\n );\n\n onCleanup(() => {\n document.removeEventListener(\n \"patchwork:open-document\",\n onDocumentOpened as EventListener,\n { capture: true }\n );\n });\n });\n\n const openHistory = () => {\n const currentHistoryUrl = historyUrl();\n if (!currentHistoryUrl) {\n console.warn(\"HistoryRecorder: no history URL yet\");\n return;\n }\n\n // Dispatch open document event\n props.element.dispatchEvent(\n new OpenDocumentEvent({\n url: currentHistoryUrl,\n toolId: VIEWER_TOOL_ID,\n })\n );\n };\n\n return (\n <button\n onClick={openHistory}\n class=\"account-history-toolbar-button\"\n title=\"Open account history\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <polyline points=\"12 6 12 12 16 14\" />\n </svg>\n </button>\n );\n}\n\nexport const renderHistoryRecorder: ToolImplementation<any> = (\n handle,\n element\n) => render(() => <HistoryRecorder handle={handle} repo={element.repo} element={element} />, element);\n"],"names":["TOOL_STORAGE_ID","HistoryRecorder","props","historyDoc","historyHandle","subscribeDoc","element","type","toolId","historyUrl","url","createEffect","handle","doc","Array","isArray","entries","change","d","ACCOUNT_HISTORY_DATATYPE","title","onMount","onDocumentOpened","event","openEvent","rawUrl","rawToolId","detail","docUrl","heads","split","docHandle","repo","find","console","warn","datatype","getType","fallbackTool","getFallbackTool","id","currentHistoryHandle","historyDocSnapshot","lastEntry","length","Date","now","timestamp","DEDUPLICATION_TIME_THRESHOLD","docTitle","registry","getRegistry","loaded","get","impl","module","getTitle","entryHeads","newEntry","docType","push","document","addEventListener","capture","onCleanup","removeEventListener","openHistory","currentHistoryUrl","dispatchEvent","OpenDocumentEvent","VIEWER_TOOL_ID","_el$","_tmpl$","$$click","renderHistoryRecorder","render","_$createComponent","_$delegateEvents"],"mappings":"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","x_google_ignoreList":[0]}
1
+ {"version":3,"file":"HistoryRecorder-DhQqHws4.js","sources":["../../node_modules/.pnpm/@inkandswitch+patchwork-providers-solid@0.2.8_@automerge+automerge-repo@2.6.0-subductio_4966317fce3d0cbaed8048ac0669bcd9/node_modules/@inkandswitch/patchwork-providers-solid/dist/index.js","../../src/HistoryRecorder.tsx"],"sourcesContent":["import { createEffect, createSignal, onCleanup, onMount, } from \"solid-js\";\nimport { createStore, reconcile } from \"solid-js/store\";\nimport * as Providers from \"@inkandswitch/patchwork-providers\";\nfunction resolveElement(source) {\n return typeof source === \"function\" ? source() : source;\n}\n/**\n * Generic reactive request. Resolves the first value a provider emits for\n * `selector` (via the one-shot `request` helper) and returns an accessor that\n * reads `undefined` until then. `T` is the response type.\n */\nexport function request(element, selector) {\n const [value, setValue] = createSignal(undefined);\n onMount(() => {\n const target = resolveElement(element);\n if (!target)\n return;\n Providers.request(target, selector).then((v) => {\n if (v == null)\n return;\n setValue(() => v);\n });\n });\n return value;\n}\nexport function subscribe(element, selector, initialValue) {\n const [value, setValue] = createSignal(initialValue);\n onMount(() => {\n const target = resolveElement(element);\n if (!target)\n return;\n const unsubscribe = Providers.subscribe(target, selector, setValue);\n onCleanup(unsubscribe);\n });\n return value;\n}\n/**\n * Store-backed subscription. Use this when a consumer wants Solid's\n * fine-grained nested reactivity for incoming JSON object or array snapshots.\n * Requires an initial object/array so the store has a stable root.\n *\n * `reconcile` preserves stable object/array identity where possible, so this\n * helper is not a good fit when the top-level value is used as an identity key\n * for resources or memos.\n */\nexport function subscribeReconciled(element, selector, initialValue) {\n const [store, setStore] = createStore(initialValue);\n onMount(() => {\n const target = resolveElement(element);\n if (!target)\n return;\n const unsubscribe = Providers.subscribe(target, selector, (v) => {\n setStore(reconcile(v));\n });\n onCleanup(unsubscribe);\n });\n return store;\n}\n/**\n * Handle-specialized subscription. Use when the answering provider emits an\n * `AutomergeUrl`. The handle is recovered locally from the global repo\n * (`window.repo`), so it stays fully live — reads project reactively and writes go\n * straight back to the same repo. Returns `[doc, handle]` matching the shape\n * of `solid-automerge`'s `useDocument`; both read `undefined` until the first\n * url arrives. `T` is the doc shape inside the handle.\n */\nexport function subscribeDoc(element, selector) {\n const [handle, setHandle] = createSignal(undefined);\n onMount(() => {\n const target = resolveElement(element);\n if (!target)\n return;\n let canceled = false;\n const unsubscribe = Providers.subscribe(target, selector, (url) => {\n if (!url)\n return;\n const repo = \"repo\" in window ? window.repo : undefined;\n if (!repo)\n return;\n void Promise.resolve(repo.find(url)).then((h) => {\n if (canceled)\n return;\n setHandle(() => h);\n });\n });\n onCleanup(() => {\n canceled = true;\n unsubscribe();\n });\n });\n // Mirror the doc into a store by `reconcile`-ing against the *materialized*\n // snapshot (`handle.doc()`) on every change, rather than replaying the\n // change's incremental patches (as `solid-automerge`'s `createDocumentProjection`\n // / `autoproduce` does).\n //\n // A whole-value write such as `doc.list = [...]` is lowered by Automerge to\n // `putObjectFromHydrate`, whose patch stream is a `put` that materializes the\n // new container *plus* per-element `insert` patches. Replaying that delta with\n // `applyPatches` double-applies the contents — the `put` seeds `[a, b]`, then\n // the inserts splice `a, b` in again, yielding `[a, b, a, b]` — even though the\n // document itself is correct. The materialized snapshot is always\n // authoritative, so reconciling against it is robust to any valid change,\n // whole-array reassignment included.\n const [store, setStore] = createStore({});\n const [ready, setReady] = createSignal(false);\n createEffect(() => {\n const h = handle();\n if (!h) {\n setReady(false);\n return;\n }\n const sync = () => {\n setStore(reconcile((h.doc() ?? {})));\n setReady(true);\n };\n sync();\n h.on(\"change\", sync);\n onCleanup(() => h.off(\"change\", sync));\n });\n const doc = () => (ready() ? store : undefined);\n return [doc, handle];\n}\n","import { onMount, onCleanup, createEffect } from \"solid-js\";\nimport { render } from \"solid-js/web\";\nimport { type AutomergeUrl } from \"@automerge/automerge-repo/slim\";\nimport type { ToolImplementation } from \"@inkandswitch/patchwork-plugins\";\nimport \"./index.css\";\nimport { OpenDocumentEvent } from \"@inkandswitch/patchwork-elements\";\nimport {\n getType,\n type HasPatchworkMetadata,\n} from \"@inkandswitch/patchwork-filesystem\";\nimport {\n getFallbackTool,\n getRegistry,\n type DatatypeDescription,\n type DatatypeImplementation,\n} from \"@inkandswitch/patchwork-plugins\";\nimport { subscribeDoc } from \"@inkandswitch/patchwork-providers-solid\";\nimport {\n ACCOUNT_HISTORY_DATATYPE,\n DEDUPLICATION_TIME_THRESHOLD,\n VIEWER_TOOL_ID,\n} from \"./constants.ts\";\nimport {\n type PatchworkToolProps,\n type HistoryDoc,\n type HistoryEntry,\n} from \"./types.ts\";\n\n// Key under which this tool's private storage doc is registered — see the\n// `patchwork:tool-storage` provider (patchwork-base/providers). Mounted as a\n// titlebar-tool, this component is bound to whatever *document* is focused,\n// not the account, so it can't reach its own storage via `props.handle`; the\n// provider gives it a private, account-scoped doc instead.\nconst TOOL_STORAGE_ID = \"account-history\";\n\nexport function HistoryRecorder(props: PatchworkToolProps<any>) {\n // Resolves (and, on first use, creates) this tool's private storage doc.\n // The provider only guarantees an empty doc exists — the shape below\n // (`entries`, `title`, `@patchwork`) is seeded by us the first time it's\n // used.\n const [historyDoc, historyHandle] = subscribeDoc<HistoryDoc>(\n props.element,\n { type: \"patchwork:tool-storage\", toolId: TOOL_STORAGE_ID }\n );\n\n const historyUrl = () => historyHandle()?.url;\n\n createEffect(() => {\n const handle = historyHandle();\n const doc = historyDoc();\n if (!handle || !doc || Array.isArray(doc.entries)) return;\n handle.change((d) => {\n if (Array.isArray(d.entries)) return; // lost an initialization race\n d[\"@patchwork\"] = { type: ACCOUNT_HISTORY_DATATYPE };\n d.title = \"Account History\";\n d.entries = [];\n });\n });\n\n onMount(() => {\n const onDocumentOpened = async (event: Event) => {\n const openEvent = event as OpenDocumentEvent;\n const { url: rawUrl, toolId: rawToolId } = openEvent.detail;\n const [docUrl, ...heads] = rawUrl.split(\"#\");\n const url = docUrl as AutomergeUrl;\n let toolId = rawToolId;\n\n // Get document to extract title and type\n const docHandle = await props.repo.find(url);\n const doc = docHandle.doc();\n\n if (!doc) {\n console.warn(\"HistoryRecorder: failed to load document\");\n return;\n }\n\n const datatype = getType(doc as Partial<HasPatchworkMetadata>);\n\n if (!toolId) {\n // if the tool id isn't defined, use the current fallback tool\n if (!datatype) {\n console.warn(\n \"HistoryRecorder: no tool found for document type; skipping history recording\"\n );\n return;\n }\n const fallbackTool = getFallbackTool(doc as HasPatchworkMetadata);\n if (!fallbackTool) {\n console.warn(\n \"HistoryRecorder: no tool found for document type; skipping history recording\"\n );\n return;\n }\n toolId = fallbackTool.id;\n }\n\n if (datatype === ACCOUNT_HISTORY_DATATYPE) {\n return; // Don't record when opening account history documents\n }\n\n const currentHistoryHandle = historyHandle();\n if (!currentHistoryHandle) {\n console.warn(\"HistoryRecorder: history handle not ready yet\");\n return;\n }\n const historyDocSnapshot = currentHistoryHandle.doc();\n if (!historyDocSnapshot) {\n console.warn(\"HistoryRecorder: history document not ready yet\");\n return;\n }\n\n // Deduplication: check if this entry is a duplicate from rapid clicks\n const lastEntry =\n historyDocSnapshot.entries[historyDocSnapshot.entries.length - 1];\n if (\n lastEntry &&\n lastEntry.docUrl === url &&\n lastEntry.toolId === toolId &&\n Date.now() - lastEntry.timestamp < DEDUPLICATION_TIME_THRESHOLD\n ) {\n return; // Skip recording - duplicate from rapid clicking\n }\n\n // Extract title\n let docTitle = \"Untitled\";\n if (datatype) {\n const registry = getRegistry<DatatypeDescription>(\"patchwork:datatype\");\n const loaded = registry.get(datatype);\n if (loaded && \"module\" in loaded) {\n const impl = loaded.module as DatatypeImplementation;\n try {\n docTitle = impl.getTitle(doc) || \"Untitled\";\n } catch {\n // getTitle may fail if the document shape doesn't match the datatype\n }\n }\n }\n\n // Get current heads, unless the URL specified a head\n let entryHeads = heads;\n if (entryHeads.length === 0) entryHeads = docHandle.heads();\n\n // Create new entry\n const newEntry: HistoryEntry = {\n timestamp: Date.now(),\n docUrl: url,\n docTitle,\n docType: datatype || \"unknown\",\n toolId,\n heads: entryHeads,\n };\n\n // Add entry to history\n currentHistoryHandle.change((doc) => {\n doc.entries.push(newEntry);\n });\n };\n\n // Listen to patchwork:open-document events (should fire once per user action)\n document.addEventListener(\n \"patchwork:open-document\",\n onDocumentOpened as EventListener,\n { capture: true }\n );\n\n onCleanup(() => {\n document.removeEventListener(\n \"patchwork:open-document\",\n onDocumentOpened as EventListener,\n { capture: true }\n );\n });\n });\n\n const openHistory = () => {\n const currentHistoryUrl = historyUrl();\n if (!currentHistoryUrl) {\n console.warn(\"HistoryRecorder: no history URL yet\");\n return;\n }\n\n // Dispatch open document event\n props.element.dispatchEvent(\n new OpenDocumentEvent({\n url: currentHistoryUrl,\n toolId: VIEWER_TOOL_ID,\n })\n );\n };\n\n return (\n <button\n onClick={openHistory}\n class=\"account-history-toolbar-button\"\n title=\"Open account history\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <polyline points=\"12 6 12 12 16 14\" />\n </svg>\n </button>\n );\n}\n\nexport const renderHistoryRecorder: ToolImplementation<any> = (\n handle,\n element\n) => render(() => <HistoryRecorder handle={handle} repo={element.repo} element={element} />, element);\n"],"names":["TOOL_STORAGE_ID","HistoryRecorder","props","historyDoc","historyHandle","subscribeDoc","element","type","toolId","historyUrl","url","createEffect","handle","doc","Array","isArray","entries","change","d","ACCOUNT_HISTORY_DATATYPE","title","onMount","onDocumentOpened","event","openEvent","rawUrl","rawToolId","detail","docUrl","heads","split","docHandle","repo","find","console","warn","datatype","getType","fallbackTool","getFallbackTool","id","currentHistoryHandle","historyDocSnapshot","lastEntry","length","Date","now","timestamp","DEDUPLICATION_TIME_THRESHOLD","docTitle","registry","getRegistry","loaded","get","impl","module","getTitle","entryHeads","newEntry","docType","push","document","addEventListener","capture","onCleanup","removeEventListener","openHistory","currentHistoryUrl","dispatchEvent","OpenDocumentEvent","VIEWER_TOOL_ID","_el$","_tmpl$","$$click","renderHistoryRecorder","render","_$createComponent","_$delegateEvents"],"mappings":"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","x_google_ignoreList":[0]}
@@ -12,7 +12,7 @@
12
12
  })();
13
13
  import { render, createComponent, insert, effect, className, setAttribute, template, delegateEvents } from "solid-js/web";
14
14
  import { createSignal, createEffect, createMemo, Show, For } from "solid-js";
15
- import { m as makeDocumentProjection } from "./context-CgDNOWHV.js";
15
+ import { m as makeDocumentProjection } from "./context-BD8lKU7i.js";
16
16
  import { OpenDocumentEvent } from "@inkandswitch/patchwork-elements";
17
17
  import { getRegistry } from "@inkandswitch/patchwork-plugins";
18
18
 
@@ -320,4 +320,4 @@ export {
320
320
  HistoryViewer,
321
321
  renderHistoryViewer
322
322
  };
323
- //# sourceMappingURL=HistoryViewer-yhYv3jqn.js.map
323
+ //# sourceMappingURL=HistoryViewer-Ba8kq_qW.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"HistoryViewer-yhYv3jqn.js","sources":["../../src/HistoryViewer.tsx"],"sourcesContent":["import { createSignal, createMemo, createEffect, For, Show } from \"solid-js\";\nimport { render } from \"solid-js/web\";\nimport type { AutomergeUrl } from \"@automerge/automerge-repo/slim\";\nimport { makeDocumentProjection } from \"solid-automerge\";\nimport { OpenDocumentEvent } from \"@inkandswitch/patchwork-elements\";\nimport {\n getRegistry,\n type ToolDescription,\n type ToolImplementation,\n} from \"@inkandswitch/patchwork-plugins\";\nimport {\n type PatchworkToolProps,\n type HistoryDoc,\n type HistoryEntry,\n} from \"./types.ts\";\nimport \"./index.css\";\n\ntype GroupingMode = \"date\" | \"document\";\ntype DocumentSortMode = \"recent\" | \"visits\";\n\nconst dateGroupFormatter = new Intl.DateTimeFormat(\"en-US\", {\n year: \"numeric\",\n month: \"long\",\n day: \"numeric\",\n});\n\nconst timeFormatter = new Intl.DateTimeFormat(\"en-US\", {\n hour: \"numeric\",\n minute: \"2-digit\",\n hour12: true,\n});\n\nconst shortDateFormatter = new Intl.DateTimeFormat(\"en-US\", {\n month: \"short\",\n day: \"numeric\",\n hour: \"numeric\",\n minute: \"2-digit\",\n});\n\n// Helper function to get tool metadata from registry\nfunction getToolMetadata(toolId: string): { name: string; icon?: string } {\n const toolRegistry = getRegistry<ToolDescription>(\"patchwork:tool\");\n const tool = toolRegistry.get(toolId);\n\n if (tool) {\n return {\n name: tool.name || toolId,\n icon: tool.icon,\n };\n }\n\n // Fallback if tool not found in registry\n return {\n name: toolId,\n icon: \"File\",\n };\n}\n\nfunction HistoryEntryRow(props: {\n entry: HistoryEntry;\n timeDisplay: string;\n urlDisplay: string;\n onOpen: (entry: HistoryEntry) => void;\n onDelete: (e: MouseEvent, entry: HistoryEntry) => void;\n}) {\n const toolMetadata = getToolMetadata(props.entry.toolId);\n\n return (\n <div class=\"account-history-entry\">\n <div class=\"account-history-entry-time\">{props.timeDisplay}</div>\n <div\n class=\"account-history-entry-content\"\n onClick={() => props.onOpen(props.entry)}\n >\n <span class=\"account-history-entry-title\">{props.entry.docTitle}</span>\n <span class=\"account-history-entry-tool\">— {toolMetadata.name}</span>\n <span class=\"account-history-entry-url\">{props.urlDisplay}</span>\n </div>\n <div class=\"account-history-entry-actions\">\n <button\n class=\"account-history-entry-delete\"\n onClick={(e) => props.onDelete(e, props.entry)}\n aria-label=\"Delete from history\"\n title=\"Delete from history\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </div>\n </div>\n );\n}\n\nexport function HistoryViewer(props: PatchworkToolProps<HistoryDoc>) {\n const historyDoc = makeDocumentProjection<HistoryDoc>(props.handle);\n\n // Load preferences from localStorage\n const savedGroupingMode = (localStorage.getItem(\"history-grouping-mode\") ||\n \"date\") as GroupingMode;\n const savedSortMode = (localStorage.getItem(\"history-document-sort-mode\") ||\n \"recent\") as DocumentSortMode;\n const savedSearchQuery = localStorage.getItem(\"history-search-query\") || \"\";\n\n const [groupingMode, setGroupingMode] =\n createSignal<GroupingMode>(savedGroupingMode);\n const [documentSortMode, setDocumentSortMode] =\n createSignal<DocumentSortMode>(savedSortMode);\n const [searchQuery, setSearchQuery] = createSignal<string>(savedSearchQuery);\n const [expandedGroups, setExpandedGroups] = createSignal<Set<AutomergeUrl>>(\n new Set()\n );\n\n // Save preferences to localStorage when they change\n createEffect(() => {\n localStorage.setItem(\"history-grouping-mode\", groupingMode());\n });\n\n createEffect(() => {\n localStorage.setItem(\"history-document-sort-mode\", documentSortMode());\n });\n\n createEffect(() => {\n localStorage.setItem(\"history-search-query\", searchQuery());\n });\n\n // Filter entries based on search query\n const filteredEntries = createMemo(() => {\n const query = searchQuery().toLowerCase().trim();\n if (!query) {\n return historyDoc.entries || [];\n }\n\n return (historyDoc.entries || []).filter((entry) => {\n const titleMatch = entry.docTitle?.toLowerCase().includes(query);\n const urlMatch = entry.docUrl?.toLowerCase().includes(query);\n return titleMatch || urlMatch;\n });\n });\n\n // Group entries by date (returns array of [dateString, entries] tuples)\n const groupedByDate = createMemo(() => {\n const groups = new Map<string, HistoryEntry[]>();\n\n // Reverse to show most recent first\n const entries = [...filteredEntries()].reverse();\n\n for (const entry of entries) {\n const date = dateGroupFormatter.format(new Date(entry.timestamp));\n\n if (!groups.has(date)) {\n groups.set(date, []);\n }\n groups.get(date)!.push(entry);\n }\n\n return Array.from(groups);\n });\n\n // Group entries by document\n const groupedByDocument = createMemo(() => {\n const groups = new Map<AutomergeUrl, HistoryEntry[]>();\n\n // Reverse to show most recent first within each document group\n const entries = [...filteredEntries()].reverse();\n\n for (const entry of entries) {\n if (!groups.has(entry.docUrl)) {\n groups.set(entry.docUrl, []);\n }\n groups.get(entry.docUrl)!.push(entry);\n }\n\n return groups;\n });\n\n // Sorted document groups\n const sortedDocumentGroups = createMemo(() => {\n const groups = Array.from(groupedByDocument());\n const sortMode = documentSortMode();\n\n if (sortMode === \"visits\") {\n // Sort by number of visits (descending)\n return groups.sort((a, b) => b[1].length - a[1].length);\n } else {\n // Precompute max timestamps to avoid recalculating in comparator\n const maxTimestamps = new Map<AutomergeUrl, number>();\n for (const [url, entries] of groups) {\n let max = 0;\n for (const e of entries) {\n if (e.timestamp > max) max = e.timestamp;\n }\n maxTimestamps.set(url, max);\n }\n return groups.sort(\n (a, b) => maxTimestamps.get(b[0])! - maxTimestamps.get(a[0])!\n );\n }\n });\n\n const openDocument = (entry: HistoryEntry) => {\n // TODO: it makes sense to load the document at the specific moment in history, but for now\n // this isn't indicated well in the UI, so it's likely to be confusing.\n // const url =\n // entry.heads.length > 0\n // ? (`${entry.docUrl}#${entry.heads[0]}` as AutomergeUrl)\n // : entry.docUrl;\n const url = entry.docUrl;\n\n // Open document with saved tool\n props.element.dispatchEvent(\n new OpenDocumentEvent({\n url,\n toolId: entry.toolId,\n })\n );\n };\n\n const formatTime = (timestamp: number) => {\n return timeFormatter.format(new Date(timestamp));\n };\n\n const formatShortDate = (timestamp: number) => {\n return shortDateFormatter.format(new Date(timestamp));\n };\n\n const deleteEntry = (e: MouseEvent, entryToDelete: HistoryEntry) => {\n e.stopPropagation();\n\n props.handle.change((doc) => {\n const index = doc.entries.findIndex(\n (e) =>\n e.timestamp === entryToDelete.timestamp &&\n e.docUrl === entryToDelete.docUrl\n );\n if (index !== -1) {\n doc.entries.splice(index, 1);\n }\n });\n };\n\n const toggleGroup = (docUrl: AutomergeUrl) => {\n setExpandedGroups((prev) => {\n const newSet = new Set(prev);\n if (newSet.has(docUrl)) {\n newSet.delete(docUrl);\n } else {\n newSet.add(docUrl);\n }\n return newSet;\n });\n };\n\n const openDocumentGroup = (docUrl: AutomergeUrl) => {\n // Open document without specifying heads or tool (opens most recent version with default tool)\n props.element.dispatchEvent(\n new OpenDocumentEvent({\n url: docUrl,\n })\n );\n };\n\n return (\n <div class=\"account-history-viewer\">\n <div class=\"account-history-header\">\n <h1 class=\"account-history-title\">Account History</h1>\n <div class=\"account-history-header-controls\">\n <span class=\"account-history-group-label\">Group by:</span>\n <button\n onClick={() => setGroupingMode(\"date\")}\n class={`account-history-toggle-button ${groupingMode() === \"date\" ? \"active\" : \"\"}`}\n >\n Date\n </button>\n <button\n onClick={() => setGroupingMode(\"document\")}\n class={`account-history-toggle-button ${groupingMode() === \"document\" ? \"active\" : \"\"}`}\n >\n Document\n </button>\n <Show when={groupingMode() === \"document\"}>\n <span class=\"account-history-sort-label\">Sort by:</span>\n <button\n onClick={() => setDocumentSortMode(\"recent\")}\n class={`account-history-sort-button ${documentSortMode() === \"recent\" ? \"active\" : \"\"}`}\n >\n Most Recent\n </button>\n <button\n onClick={() => setDocumentSortMode(\"visits\")}\n class={`account-history-sort-button ${documentSortMode() === \"visits\" ? \"active\" : \"\"}`}\n >\n Most Visits\n </button>\n </Show>\n </div>\n <div class=\"account-history-search\">\n <svg\n class=\"account-history-search-icon\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <path d=\"m21 21-4.35-4.35\" />\n </svg>\n <input\n type=\"text\"\n class=\"account-history-search-input\"\n placeholder=\"search history\"\n value={searchQuery()}\n onInput={(e) => setSearchQuery(e.currentTarget.value)}\n />\n </div>\n </div>\n\n <div class=\"account-history-content\">\n <Show when={groupingMode() === \"date\"}>\n <For each={groupedByDate()}>\n {([date, entries]) => (\n <div class=\"account-history-group\">\n <div class=\"account-history-group-header\">\n <h2 class=\"account-history-group-title\">{date}</h2>\n </div>\n <div class=\"account-history-entries\">\n <For each={entries}>\n {(entry) => (\n <HistoryEntryRow\n entry={entry}\n timeDisplay={formatTime(entry.timestamp)}\n urlDisplay={entry.docUrl}\n onOpen={openDocument}\n onDelete={deleteEntry}\n />\n )}\n </For>\n </div>\n </div>\n )}\n </For>\n </Show>\n\n <Show when={groupingMode() === \"document\"}>\n <For each={sortedDocumentGroups()}>\n {([docUrl, entries]) => {\n const isExpanded = () => expandedGroups().has(docUrl);\n\n return (\n <div class=\"account-history-group\">\n <div\n class=\"account-history-group-header account-history-group-header-clickable\"\n onClick={() => openDocumentGroup(docUrl)}\n >\n <div class=\"account-history-group-header-content\">\n <h2 class=\"account-history-group-title\">\n {entries[0]?.docTitle ?? \"Untitled\"}\n </h2>\n <p class=\"account-history-group-meta\">\n {entries[0]?.docType ?? \"unknown\"} • {entries.length}{\" \"}\n {entries.length === 1 ? \"visit\" : \"visits\"}\n </p>\n </div>\n <button\n class=\"account-history-group-toggle\"\n onClick={(e) => {\n e.stopPropagation();\n toggleGroup(docUrl);\n }}\n aria-label={isExpanded() ? \"Collapse\" : \"Expand\"}\n title={isExpanded() ? \"Collapse\" : \"Expand\"}\n >\n {isExpanded() ? \"−\" : \"+\"}\n </button>\n </div>\n <Show when={isExpanded()}>\n <div class=\"account-history-entries\">\n <For each={entries}>\n {(entry) => (\n <HistoryEntryRow\n entry={entry}\n timeDisplay={formatShortDate(entry.timestamp)}\n urlDisplay={`(#${entry.heads})`}\n onOpen={openDocument}\n onDelete={deleteEntry}\n />\n )}\n </For>\n </div>\n </Show>\n </div>\n );\n }}\n </For>\n </Show>\n\n <Show when={!historyDoc.entries || historyDoc.entries.length === 0}>\n <div class=\"account-history-empty\">\n No history yet. Open some documents to start tracking your history.\n </div>\n </Show>\n </div>\n </div>\n );\n}\n\nexport const renderHistoryViewer: ToolImplementation<HistoryDoc> = (\n handle,\n element\n) => render(() => <HistoryViewer handle={handle} repo={element.repo} element={element} />, element);\n"],"names":["dateGroupFormatter","Intl","DateTimeFormat","year","month","day","timeFormatter","hour","minute","hour12","shortDateFormatter","getToolMetadata","toolId","toolRegistry","getRegistry","tool","get","name","icon","HistoryEntryRow","props","toolMetadata","entry","_el$","_tmpl$","_el$2","firstChild","_el$3","nextSibling","_el$4","_el$5","_el$7","_el$8","_el$9","_$insert","timeDisplay","$$click","onOpen","docTitle","urlDisplay","e","onDelete","HistoryViewer","historyDoc","makeDocumentProjection","handle","savedGroupingMode","localStorage","getItem","savedSortMode","savedSearchQuery","groupingMode","setGroupingMode","createSignal","documentSortMode","setDocumentSortMode","searchQuery","setSearchQuery","expandedGroups","setExpandedGroups","Set","createEffect","setItem","filteredEntries","createMemo","query","toLowerCase","trim","entries","filter","titleMatch","includes","urlMatch","docUrl","groupedByDate","groups","Map","reverse","date","format","Date","timestamp","has","set","push","Array","from","groupedByDocument","sortedDocumentGroups","sortMode","sort","a","b","length","maxTimestamps","url","max","openDocument","element","dispatchEvent","OpenDocumentEvent","formatTime","formatShortDate","deleteEntry","entryToDelete","stopPropagation","change","doc","index","findIndex","splice","toggleGroup","prev","newSet","delete","add","openDocumentGroup","_el$0","_tmpl$6","_el$1","_el$10","_el$11","_el$12","_el$13","_el$14","_el$18","_el$19","_el$20","_el$21","_$createComponent","Show","when","children","_tmpl$2","_el$16","_tmpl$3","_$effect","_$className","_el$17","_tmpl$4","$$input","currentTarget","value","For","each","_el$23","_tmpl$7","_el$24","_el$25","_el$26","isExpanded","_el$27","_tmpl$9","_el$28","_el$29","_el$30","_el$31","_el$32","_el$34","_el$35","docType","_el$36","_tmpl$8","heads","_p$","_v$3","_v$4","_$setAttribute","t","undefined","_tmpl$5","_v$","_v$2","renderHistoryViewer","render","repo","_$delegateEvents"],"mappings":"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"}
1
+ {"version":3,"file":"HistoryViewer-Ba8kq_qW.js","sources":["../../src/HistoryViewer.tsx"],"sourcesContent":["import { createSignal, createMemo, createEffect, For, Show } from \"solid-js\";\nimport { render } from \"solid-js/web\";\nimport type { AutomergeUrl } from \"@automerge/automerge-repo/slim\";\nimport { makeDocumentProjection } from \"solid-automerge\";\nimport { OpenDocumentEvent } from \"@inkandswitch/patchwork-elements\";\nimport {\n getRegistry,\n type ToolDescription,\n type ToolImplementation,\n} from \"@inkandswitch/patchwork-plugins\";\nimport {\n type PatchworkToolProps,\n type HistoryDoc,\n type HistoryEntry,\n} from \"./types.ts\";\nimport \"./index.css\";\n\ntype GroupingMode = \"date\" | \"document\";\ntype DocumentSortMode = \"recent\" | \"visits\";\n\nconst dateGroupFormatter = new Intl.DateTimeFormat(\"en-US\", {\n year: \"numeric\",\n month: \"long\",\n day: \"numeric\",\n});\n\nconst timeFormatter = new Intl.DateTimeFormat(\"en-US\", {\n hour: \"numeric\",\n minute: \"2-digit\",\n hour12: true,\n});\n\nconst shortDateFormatter = new Intl.DateTimeFormat(\"en-US\", {\n month: \"short\",\n day: \"numeric\",\n hour: \"numeric\",\n minute: \"2-digit\",\n});\n\n// Helper function to get tool metadata from registry\nfunction getToolMetadata(toolId: string): { name: string; icon?: string } {\n const toolRegistry = getRegistry<ToolDescription>(\"patchwork:tool\");\n const tool = toolRegistry.get(toolId);\n\n if (tool) {\n return {\n name: tool.name || toolId,\n icon: tool.icon,\n };\n }\n\n // Fallback if tool not found in registry\n return {\n name: toolId,\n icon: \"File\",\n };\n}\n\nfunction HistoryEntryRow(props: {\n entry: HistoryEntry;\n timeDisplay: string;\n urlDisplay: string;\n onOpen: (entry: HistoryEntry) => void;\n onDelete: (e: MouseEvent, entry: HistoryEntry) => void;\n}) {\n const toolMetadata = getToolMetadata(props.entry.toolId);\n\n return (\n <div class=\"account-history-entry\">\n <div class=\"account-history-entry-time\">{props.timeDisplay}</div>\n <div\n class=\"account-history-entry-content\"\n onClick={() => props.onOpen(props.entry)}\n >\n <span class=\"account-history-entry-title\">{props.entry.docTitle}</span>\n <span class=\"account-history-entry-tool\">— {toolMetadata.name}</span>\n <span class=\"account-history-entry-url\">{props.urlDisplay}</span>\n </div>\n <div class=\"account-history-entry-actions\">\n <button\n class=\"account-history-entry-delete\"\n onClick={(e) => props.onDelete(e, props.entry)}\n aria-label=\"Delete from history\"\n title=\"Delete from history\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </div>\n </div>\n );\n}\n\nexport function HistoryViewer(props: PatchworkToolProps<HistoryDoc>) {\n const historyDoc = makeDocumentProjection<HistoryDoc>(props.handle);\n\n // Load preferences from localStorage\n const savedGroupingMode = (localStorage.getItem(\"history-grouping-mode\") ||\n \"date\") as GroupingMode;\n const savedSortMode = (localStorage.getItem(\"history-document-sort-mode\") ||\n \"recent\") as DocumentSortMode;\n const savedSearchQuery = localStorage.getItem(\"history-search-query\") || \"\";\n\n const [groupingMode, setGroupingMode] =\n createSignal<GroupingMode>(savedGroupingMode);\n const [documentSortMode, setDocumentSortMode] =\n createSignal<DocumentSortMode>(savedSortMode);\n const [searchQuery, setSearchQuery] = createSignal<string>(savedSearchQuery);\n const [expandedGroups, setExpandedGroups] = createSignal<Set<AutomergeUrl>>(\n new Set()\n );\n\n // Save preferences to localStorage when they change\n createEffect(() => {\n localStorage.setItem(\"history-grouping-mode\", groupingMode());\n });\n\n createEffect(() => {\n localStorage.setItem(\"history-document-sort-mode\", documentSortMode());\n });\n\n createEffect(() => {\n localStorage.setItem(\"history-search-query\", searchQuery());\n });\n\n // Filter entries based on search query\n const filteredEntries = createMemo(() => {\n const query = searchQuery().toLowerCase().trim();\n if (!query) {\n return historyDoc.entries || [];\n }\n\n return (historyDoc.entries || []).filter((entry) => {\n const titleMatch = entry.docTitle?.toLowerCase().includes(query);\n const urlMatch = entry.docUrl?.toLowerCase().includes(query);\n return titleMatch || urlMatch;\n });\n });\n\n // Group entries by date (returns array of [dateString, entries] tuples)\n const groupedByDate = createMemo(() => {\n const groups = new Map<string, HistoryEntry[]>();\n\n // Reverse to show most recent first\n const entries = [...filteredEntries()].reverse();\n\n for (const entry of entries) {\n const date = dateGroupFormatter.format(new Date(entry.timestamp));\n\n if (!groups.has(date)) {\n groups.set(date, []);\n }\n groups.get(date)!.push(entry);\n }\n\n return Array.from(groups);\n });\n\n // Group entries by document\n const groupedByDocument = createMemo(() => {\n const groups = new Map<AutomergeUrl, HistoryEntry[]>();\n\n // Reverse to show most recent first within each document group\n const entries = [...filteredEntries()].reverse();\n\n for (const entry of entries) {\n if (!groups.has(entry.docUrl)) {\n groups.set(entry.docUrl, []);\n }\n groups.get(entry.docUrl)!.push(entry);\n }\n\n return groups;\n });\n\n // Sorted document groups\n const sortedDocumentGroups = createMemo(() => {\n const groups = Array.from(groupedByDocument());\n const sortMode = documentSortMode();\n\n if (sortMode === \"visits\") {\n // Sort by number of visits (descending)\n return groups.sort((a, b) => b[1].length - a[1].length);\n } else {\n // Precompute max timestamps to avoid recalculating in comparator\n const maxTimestamps = new Map<AutomergeUrl, number>();\n for (const [url, entries] of groups) {\n let max = 0;\n for (const e of entries) {\n if (e.timestamp > max) max = e.timestamp;\n }\n maxTimestamps.set(url, max);\n }\n return groups.sort(\n (a, b) => maxTimestamps.get(b[0])! - maxTimestamps.get(a[0])!\n );\n }\n });\n\n const openDocument = (entry: HistoryEntry) => {\n // TODO: it makes sense to load the document at the specific moment in history, but for now\n // this isn't indicated well in the UI, so it's likely to be confusing.\n // const url =\n // entry.heads.length > 0\n // ? (`${entry.docUrl}#${entry.heads[0]}` as AutomergeUrl)\n // : entry.docUrl;\n const url = entry.docUrl;\n\n // Open document with saved tool\n props.element.dispatchEvent(\n new OpenDocumentEvent({\n url,\n toolId: entry.toolId,\n })\n );\n };\n\n const formatTime = (timestamp: number) => {\n return timeFormatter.format(new Date(timestamp));\n };\n\n const formatShortDate = (timestamp: number) => {\n return shortDateFormatter.format(new Date(timestamp));\n };\n\n const deleteEntry = (e: MouseEvent, entryToDelete: HistoryEntry) => {\n e.stopPropagation();\n\n props.handle.change((doc) => {\n const index = doc.entries.findIndex(\n (e) =>\n e.timestamp === entryToDelete.timestamp &&\n e.docUrl === entryToDelete.docUrl\n );\n if (index !== -1) {\n doc.entries.splice(index, 1);\n }\n });\n };\n\n const toggleGroup = (docUrl: AutomergeUrl) => {\n setExpandedGroups((prev) => {\n const newSet = new Set(prev);\n if (newSet.has(docUrl)) {\n newSet.delete(docUrl);\n } else {\n newSet.add(docUrl);\n }\n return newSet;\n });\n };\n\n const openDocumentGroup = (docUrl: AutomergeUrl) => {\n // Open document without specifying heads or tool (opens most recent version with default tool)\n props.element.dispatchEvent(\n new OpenDocumentEvent({\n url: docUrl,\n })\n );\n };\n\n return (\n <div class=\"account-history-viewer\">\n <div class=\"account-history-header\">\n <h1 class=\"account-history-title\">Account History</h1>\n <div class=\"account-history-header-controls\">\n <span class=\"account-history-group-label\">Group by:</span>\n <button\n onClick={() => setGroupingMode(\"date\")}\n class={`account-history-toggle-button ${groupingMode() === \"date\" ? \"active\" : \"\"}`}\n >\n Date\n </button>\n <button\n onClick={() => setGroupingMode(\"document\")}\n class={`account-history-toggle-button ${groupingMode() === \"document\" ? \"active\" : \"\"}`}\n >\n Document\n </button>\n <Show when={groupingMode() === \"document\"}>\n <span class=\"account-history-sort-label\">Sort by:</span>\n <button\n onClick={() => setDocumentSortMode(\"recent\")}\n class={`account-history-sort-button ${documentSortMode() === \"recent\" ? \"active\" : \"\"}`}\n >\n Most Recent\n </button>\n <button\n onClick={() => setDocumentSortMode(\"visits\")}\n class={`account-history-sort-button ${documentSortMode() === \"visits\" ? \"active\" : \"\"}`}\n >\n Most Visits\n </button>\n </Show>\n </div>\n <div class=\"account-history-search\">\n <svg\n class=\"account-history-search-icon\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <path d=\"m21 21-4.35-4.35\" />\n </svg>\n <input\n type=\"text\"\n class=\"account-history-search-input\"\n placeholder=\"search history\"\n value={searchQuery()}\n onInput={(e) => setSearchQuery(e.currentTarget.value)}\n />\n </div>\n </div>\n\n <div class=\"account-history-content\">\n <Show when={groupingMode() === \"date\"}>\n <For each={groupedByDate()}>\n {([date, entries]) => (\n <div class=\"account-history-group\">\n <div class=\"account-history-group-header\">\n <h2 class=\"account-history-group-title\">{date}</h2>\n </div>\n <div class=\"account-history-entries\">\n <For each={entries}>\n {(entry) => (\n <HistoryEntryRow\n entry={entry}\n timeDisplay={formatTime(entry.timestamp)}\n urlDisplay={entry.docUrl}\n onOpen={openDocument}\n onDelete={deleteEntry}\n />\n )}\n </For>\n </div>\n </div>\n )}\n </For>\n </Show>\n\n <Show when={groupingMode() === \"document\"}>\n <For each={sortedDocumentGroups()}>\n {([docUrl, entries]) => {\n const isExpanded = () => expandedGroups().has(docUrl);\n\n return (\n <div class=\"account-history-group\">\n <div\n class=\"account-history-group-header account-history-group-header-clickable\"\n onClick={() => openDocumentGroup(docUrl)}\n >\n <div class=\"account-history-group-header-content\">\n <h2 class=\"account-history-group-title\">\n {entries[0]?.docTitle ?? \"Untitled\"}\n </h2>\n <p class=\"account-history-group-meta\">\n {entries[0]?.docType ?? \"unknown\"} • {entries.length}{\" \"}\n {entries.length === 1 ? \"visit\" : \"visits\"}\n </p>\n </div>\n <button\n class=\"account-history-group-toggle\"\n onClick={(e) => {\n e.stopPropagation();\n toggleGroup(docUrl);\n }}\n aria-label={isExpanded() ? \"Collapse\" : \"Expand\"}\n title={isExpanded() ? \"Collapse\" : \"Expand\"}\n >\n {isExpanded() ? \"−\" : \"+\"}\n </button>\n </div>\n <Show when={isExpanded()}>\n <div class=\"account-history-entries\">\n <For each={entries}>\n {(entry) => (\n <HistoryEntryRow\n entry={entry}\n timeDisplay={formatShortDate(entry.timestamp)}\n urlDisplay={`(#${entry.heads})`}\n onOpen={openDocument}\n onDelete={deleteEntry}\n />\n )}\n </For>\n </div>\n </Show>\n </div>\n );\n }}\n </For>\n </Show>\n\n <Show when={!historyDoc.entries || historyDoc.entries.length === 0}>\n <div class=\"account-history-empty\">\n No history yet. Open some documents to start tracking your history.\n </div>\n </Show>\n </div>\n </div>\n );\n}\n\nexport const renderHistoryViewer: ToolImplementation<HistoryDoc> = (\n handle,\n element\n) => render(() => <HistoryViewer handle={handle} repo={element.repo} element={element} />, element);\n"],"names":["dateGroupFormatter","Intl","DateTimeFormat","year","month","day","timeFormatter","hour","minute","hour12","shortDateFormatter","getToolMetadata","toolId","toolRegistry","getRegistry","tool","get","name","icon","HistoryEntryRow","props","toolMetadata","entry","_el$","_tmpl$","_el$2","firstChild","_el$3","nextSibling","_el$4","_el$5","_el$7","_el$8","_el$9","_$insert","timeDisplay","$$click","onOpen","docTitle","urlDisplay","e","onDelete","HistoryViewer","historyDoc","makeDocumentProjection","handle","savedGroupingMode","localStorage","getItem","savedSortMode","savedSearchQuery","groupingMode","setGroupingMode","createSignal","documentSortMode","setDocumentSortMode","searchQuery","setSearchQuery","expandedGroups","setExpandedGroups","Set","createEffect","setItem","filteredEntries","createMemo","query","toLowerCase","trim","entries","filter","titleMatch","includes","urlMatch","docUrl","groupedByDate","groups","Map","reverse","date","format","Date","timestamp","has","set","push","Array","from","groupedByDocument","sortedDocumentGroups","sortMode","sort","a","b","length","maxTimestamps","url","max","openDocument","element","dispatchEvent","OpenDocumentEvent","formatTime","formatShortDate","deleteEntry","entryToDelete","stopPropagation","change","doc","index","findIndex","splice","toggleGroup","prev","newSet","delete","add","openDocumentGroup","_el$0","_tmpl$6","_el$1","_el$10","_el$11","_el$12","_el$13","_el$14","_el$18","_el$19","_el$20","_el$21","_$createComponent","Show","when","children","_tmpl$2","_el$16","_tmpl$3","_$effect","_$className","_el$17","_tmpl$4","$$input","currentTarget","value","For","each","_el$23","_tmpl$7","_el$24","_el$25","_el$26","isExpanded","_el$27","_tmpl$9","_el$28","_el$29","_el$30","_el$31","_el$32","_el$34","_el$35","docType","_el$36","_tmpl$8","heads","_p$","_v$3","_v$4","_$setAttribute","t","undefined","_tmpl$5","_v$","_v$2","renderHistoryViewer","render","repo","_$delegateEvents"],"mappings":"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"}
@@ -866,7 +866,7 @@
866
866
  })();
867
867
  import { render, createComponent, insert, effect, setAttribute, className, getOwner, memo, template, delegateEvents } from "solid-js/web";
868
868
  import { createMemo, createSignal, onCleanup, createEffect, Show, For } from "solid-js";
869
- import { m as makeDocumentProjection } from "./context-CgDNOWHV.js";
869
+ import { m as makeDocumentProjection } from "./context-BD8lKU7i.js";
870
870
  import { OpenDocumentEvent } from "@inkandswitch/patchwork-elements";
871
871
 
872
872
  import "solid-js/store";
@@ -1358,4 +1358,4 @@ export {
1358
1358
  NotebookViewer,
1359
1359
  renderNotebookViewer
1360
1360
  };
1361
- //# sourceMappingURL=NotebookViewer-CLhIU0hN.js.map
1361
+ //# sourceMappingURL=NotebookViewer-io6-qkNu.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"NotebookViewer-CLhIU0hN.js","sources":["../../src/NotebookViewer.tsx"],"sourcesContent":["import { createSignal, createMemo, createEffect, Show, For, onCleanup } from \"solid-js\";\nimport { render } from \"solid-js/web\";\nimport type { AutomergeUrl } from \"@automerge/automerge-repo/slim\";\nimport { makeDocumentProjection } from \"solid-automerge\";\nimport { OpenDocumentEvent } from \"@inkandswitch/patchwork-elements\";\nimport type { ToolImplementation } from \"@inkandswitch/patchwork-plugins\";\nimport {\n type PatchworkToolProps,\n type HistoryDoc,\n type HistoryEntry,\n} from \"./types.ts\";\nimport \"./NotebookViewer.css\";\nimport \"./index.css\";\n\nconst LS_INDEX_KEY = \"notebook-viewer-current-index\";\nconst LS_STEP_KEY = \"notebook-viewer-step-size\";\nconst LS_STEP_MODE_KEY = \"notebook-viewer-step-mode\";\nconst LS_TIME_UNIT_KEY = \"notebook-viewer-time-unit\";\nconst LS_TIME_AMOUNT_KEY = \"notebook-viewer-time-amount\";\n\n// Discrete step size options for \"entries\" mode\nconst ALL_STEP_SIZES = [1, 5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000, 10000];\n\ntype StepMode = \"entries\" | \"time\";\ntype TimeUnit = \"minutes\" | \"hours\" | \"days\" | \"weeks\";\n\nconst TIME_UNIT_OPTIONS: { unit: TimeUnit; label: string; amounts: number[]; msPerUnit: number }[] = [\n { unit: \"minutes\", label: \"min\", amounts: [1, 5, 15, 30, 60], msPerUnit: 60 * 1000 },\n { unit: \"hours\", label: \"hr\", amounts: [1, 2, 4, 6, 8, 12, 24], msPerUnit: 60 * 60 * 1000 },\n { unit: \"days\", label: \"day\", amounts: [1, 2, 3, 5, 7], msPerUnit: 24 * 60 * 60 * 1000 },\n { unit: \"weeks\", label: \"wk\", amounts: [1, 2, 4, 6, 13, 26, 52], msPerUnit: 7 * 24 * 60 * 60 * 1000 },\n];\n\nconst dateTimeFormatter = new Intl.DateTimeFormat(\"en-US\", {\n year: \"numeric\",\n month: \"long\",\n day: \"numeric\",\n hour: \"numeric\",\n minute: \"2-digit\",\n hour12: true,\n});\n\n/** Find the index of the entry nearest to targetTimestamp, searching in the given direction. */\nfunction findNearestEntryIndex(\n entries: HistoryEntry[],\n currentIdx: number,\n targetTimestamp: number,\n direction: \"back\" | \"forward\"\n): number {\n if (direction === \"back\") {\n // Search backwards from currentIdx for the last entry at or before targetTimestamp\n for (let i = currentIdx - 1; i >= 0; i--) {\n if (entries[i].timestamp <= targetTimestamp) return i;\n }\n return 0; // clamp to first\n } else {\n // Search forwards from currentIdx for the first entry at or after targetTimestamp\n for (let i = currentIdx + 1; i < entries.length; i++) {\n if (entries[i].timestamp >= targetTimestamp) return i;\n }\n return entries.length - 1; // clamp to last\n }\n}\n\nexport function NotebookViewer(props: PatchworkToolProps<HistoryDoc>) {\n const historyDoc = makeDocumentProjection<HistoryDoc>(props.handle);\n\n // Entries are already in chronological order (HistoryRecorder appends)\n const entries = createMemo(() => historyDoc.entries || []);\n const totalEntries = createMemo(() => entries().length);\n\n // Total time span of history in ms\n const historySpanMs = createMemo(() => {\n const e = entries();\n if (e.length < 2) return 0;\n return e[e.length - 1].timestamp - e[0].timestamp;\n });\n\n // --- Entry step sizes ---\n const availableStepSizes = createMemo(() => {\n const total = totalEntries();\n return ALL_STEP_SIZES.filter((s) => s <= total);\n });\n\n // --- Time step: available amounts per unit, filtered by history span ---\n const availableTimeAmounts = createMemo(() => {\n const span = historySpanMs();\n const result: Record<TimeUnit, number[]> = {\n minutes: [],\n hours: [],\n days: [],\n weeks: [],\n };\n for (const opt of TIME_UNIT_OPTIONS) {\n result[opt.unit] = opt.amounts.filter((a) => a * opt.msPerUnit <= span);\n }\n return result;\n });\n\n // Which time units have at least one available amount\n const availableTimeUnits = createMemo(() =>\n TIME_UNIT_OPTIONS.filter((opt) => availableTimeAmounts()[opt.unit].length > 0)\n );\n\n // --- Load saved state from localStorage ---\n const savedIndexRaw = localStorage.getItem(LS_INDEX_KEY);\n const hasSavedIndex = savedIndexRaw !== null;\n const savedIndex = hasSavedIndex ? parseInt(savedIndexRaw, 10) : -1;\n const savedStepSize = parseInt(localStorage.getItem(LS_STEP_KEY) || \"1\", 10);\n const savedStepMode = (localStorage.getItem(LS_STEP_MODE_KEY) || \"entries\") as StepMode;\n const savedTimeUnit = (localStorage.getItem(LS_TIME_UNIT_KEY) || \"hours\") as TimeUnit;\n const savedTimeAmount = parseInt(localStorage.getItem(LS_TIME_AMOUNT_KEY) || \"1\", 10);\n\n const [rawCurrentIndex, setRawCurrentIndex] = createSignal(\n hasSavedIndex && Number.isFinite(savedIndex) ? Math.max(0, savedIndex) : -1\n );\n const [stepSize, setStepSize] = createSignal(\n Number.isFinite(savedStepSize) ? Math.max(1, savedStepSize) : 1\n );\n const [stepMode, setStepMode] = createSignal<StepMode>(savedStepMode);\n const [timeUnit, setTimeUnit] = createSignal<TimeUnit>(savedTimeUnit);\n const [timeAmount, setTimeAmount] = createSignal(\n Number.isFinite(savedTimeAmount) ? Math.max(1, savedTimeAmount) : 1\n );\n\n // Clamped current index: -1 means \"no saved position\" → latest entry\n const currentIndex = createMemo(() => {\n const total = totalEntries();\n if (total === 0) return 0;\n const raw = rawCurrentIndex();\n if (raw < 0) return total - 1;\n return Math.min(Math.max(0, raw), total - 1);\n });\n\n const currentEntry = createMemo(() => {\n const e = entries();\n const idx = currentIndex();\n return e.length > 0 ? e[idx] : undefined;\n });\n\n const currentDateLabel = createMemo(() => {\n const entry = currentEntry();\n if (!entry) return \"\";\n return dateTimeFormatter.format(new Date(entry.timestamp));\n });\n\n const viewDocUrl = createMemo(() => {\n const entry = currentEntry();\n if (!entry) return undefined;\n if (entry.heads && entry.heads.length > 0) {\n return `${entry.docUrl}#${entry.heads.join(\"|\")}` as AutomergeUrl;\n }\n return entry.docUrl;\n });\n\n const viewToolId = createMemo(() => currentEntry()?.toolId);\n\n const viewKey = createMemo(() => {\n const url = viewDocUrl();\n const toolId = viewToolId();\n return url ? `${url}-${toolId || \"default\"}` : undefined;\n });\n\n // --- Navigation ---\n const canGoBack = createMemo(() => currentIndex() > 0);\n const canGoForward = createMemo(() => {\n const total = totalEntries();\n return total > 0 && currentIndex() < total - 1;\n });\n\n // Compute time step duration in ms\n const timeStepMs = createMemo(() => {\n const unit = timeUnit();\n const amount = timeAmount();\n const opt = TIME_UNIT_OPTIONS.find((o) => o.unit === unit);\n return opt ? amount * opt.msPerUnit : 0;\n });\n\n const goBack = () => {\n if (stepMode() === \"entries\") {\n setRawCurrentIndex(Math.max(0, currentIndex() - stepSize()));\n } else {\n const entry = currentEntry();\n if (!entry) return;\n const targetTs = entry.timestamp - timeStepMs();\n const newIdx = findNearestEntryIndex(entries(), currentIndex(), targetTs, \"back\");\n setRawCurrentIndex(newIdx);\n }\n };\n\n const goForward = () => {\n if (stepMode() === \"entries\") {\n setRawCurrentIndex(Math.min(totalEntries() - 1, currentIndex() + stepSize()));\n } else {\n const entry = currentEntry();\n if (!entry) return;\n const targetTs = entry.timestamp + timeStepMs();\n const newIdx = findNearestEntryIndex(entries(), currentIndex(), targetTs, \"forward\");\n setRawCurrentIndex(newIdx);\n }\n };\n\n // --- Entry step size slider helpers ---\n const stepSizeSliderIndex = createMemo(() => {\n const sizes = availableStepSizes();\n const idx = sizes.indexOf(stepSize());\n if (idx >= 0) return idx;\n for (let i = sizes.length - 1; i >= 0; i--) {\n if (sizes[i] <= stepSize()) return i;\n }\n return 0;\n });\n\n const updateStepSizeFromSlider = (sliderIndex: number) => {\n const sizes = availableStepSizes();\n const clamped = Math.max(0, Math.min(sliderIndex, sizes.length - 1));\n setStepSize(sizes[clamped] || 1);\n };\n\n // --- Time amount slider helpers ---\n const currentTimeAmounts = createMemo(() => availableTimeAmounts()[timeUnit()] || []);\n\n const timeAmountSliderIndex = createMemo(() => {\n const amounts = currentTimeAmounts();\n const idx = amounts.indexOf(timeAmount());\n if (idx >= 0) return idx;\n for (let i = amounts.length - 1; i >= 0; i--) {\n if (amounts[i] <= timeAmount()) return i;\n }\n return 0;\n });\n\n const updateTimeAmountFromSlider = (sliderIndex: number) => {\n const amounts = currentTimeAmounts();\n const clamped = Math.max(0, Math.min(sliderIndex, amounts.length - 1));\n setTimeAmount(amounts[clamped] || 1);\n };\n\n // Format the time step display label\n const timeStepLabel = createMemo(() => {\n const amount = timeAmount();\n const unit = timeUnit();\n const opt = TIME_UNIT_OPTIONS.find((o) => o.unit === unit);\n if (!opt) return \"\";\n const label = amount === 1 ? opt.label : opt.label + \"s\";\n return `${amount} ${label}`;\n });\n\n const goToFirst = () => setRawCurrentIndex(0);\n const goToLatest = () => setRawCurrentIndex(totalEntries() - 1);\n\n // --- Playback ---\n const [isPlaying, setIsPlaying] = createSignal(false);\n const [playDirection, setPlayDirection] = createSignal<\"forward\" | \"reverse\">(\"forward\");\n let playIntervalId: number | undefined;\n\n const stopPlayback = () => {\n setIsPlaying(false);\n if (playIntervalId !== undefined) {\n clearInterval(playIntervalId);\n playIntervalId = undefined;\n }\n };\n\n const togglePlayback = () => {\n if (isPlaying()) {\n stopPlayback();\n } else {\n setIsPlaying(true);\n playIntervalId = window.setInterval(() => {\n const dir = playDirection();\n if (dir === \"forward\") {\n if (!canGoForward()) {\n stopPlayback();\n return;\n }\n goForward();\n } else {\n if (!canGoBack()) {\n stopPlayback();\n return;\n }\n goBack();\n }\n }, 1000);\n }\n };\n\n onCleanup(stopPlayback);\n\n // --- Open Document ---\n const [showVersionDropdown, setShowVersionDropdown] = createSignal(false);\n\n // Check if the current entry has saved heads (meaning it's a snapshot from a point in time).\n // If it has heads, we offer the choice of opening \"this version\" vs \"latest version\".\n const hasHeads = createMemo(() => {\n const entry = currentEntry();\n return !!(entry && entry.heads && entry.heads.length > 0);\n });\n\n const openDocument = (useLatest: boolean) => {\n const entry = currentEntry();\n if (!entry) return;\n\n let url: AutomergeUrl;\n if (useLatest || !entry.heads || entry.heads.length === 0) {\n url = entry.docUrl;\n } else {\n url = `${entry.docUrl}#${entry.heads.join(\"|\")}` as AutomergeUrl;\n }\n\n props.element.dispatchEvent(\n new OpenDocumentEvent({\n url,\n toolId: entry.toolId,\n })\n );\n\n setShowVersionDropdown(false);\n };\n\n const handleOpenDocClick = () => {\n if (hasHeads()) {\n setShowVersionDropdown((v) => !v);\n } else {\n openDocument(true);\n }\n };\n\n // Close dropdown when clicking outside\n const onClickOutside = (e: MouseEvent) => {\n const target = e.target as HTMLElement;\n if (!target.closest(\".notebook-viewer-open-doc\")) {\n setShowVersionDropdown(false);\n }\n };\n\n document.addEventListener(\"click\", onClickOutside);\n onCleanup(() => document.removeEventListener(\"click\", onClickOutside));\n\n // Keyboard navigation\n const onKeyDown = (e: KeyboardEvent) => {\n const target = e.target as HTMLElement;\n if (target.tagName === \"INPUT\" || target.tagName === \"TEXTAREA\" || target.isContentEditable) {\n return;\n }\n if (e.key === \"ArrowLeft\") {\n e.preventDefault();\n goBack();\n } else if (e.key === \"ArrowRight\") {\n e.preventDefault();\n goForward();\n }\n };\n\n document.addEventListener(\"keydown\", onKeyDown);\n onCleanup(() => document.removeEventListener(\"keydown\", onKeyDown));\n\n // Persist state to localStorage\n createEffect(() => localStorage.setItem(LS_INDEX_KEY, String(currentIndex())));\n createEffect(() => localStorage.setItem(LS_STEP_KEY, String(stepSize())));\n createEffect(() => localStorage.setItem(LS_STEP_MODE_KEY, stepMode()));\n createEffect(() => localStorage.setItem(LS_TIME_UNIT_KEY, timeUnit()));\n createEffect(() => localStorage.setItem(LS_TIME_AMOUNT_KEY, String(timeAmount())));\n\n // Arrow tooltip text\n const stepDescription = createMemo(() => {\n if (stepMode() === \"entries\") {\n const s = stepSize();\n return `${s} ${s === 1 ? \"entry\" : \"entries\"}`;\n }\n return timeStepLabel();\n });\n\n return (\n <div class=\"notebook-viewer\">\n <Show\n when={totalEntries() > 0}\n fallback={\n <div class=\"notebook-viewer-empty\">\n No history entries yet. Open some documents to start tracking history.\n </div>\n }\n >\n {/* Playback controls — floating top-left */}\n <div class=\"notebook-viewer-playback\">\n {/* Direction toggle */}\n <div\n class=\"notebook-viewer-direction-toggle\"\n onClick={() => setPlayDirection((d) => d === \"forward\" ? \"reverse\" : \"forward\")}\n title={`Direction: ${playDirection()}`}\n >\n <span class={`notebook-viewer-direction-option ${playDirection() === \"reverse\" ? \"active\" : \"\"}`}>\n Rev\n </span>\n <span class={`notebook-viewer-direction-option ${playDirection() === \"forward\" ? \"active\" : \"\"}`}>\n Fwd\n </span>\n <div class={`notebook-viewer-direction-thumb ${playDirection() === \"forward\" ? \"right\" : \"left\"}`} />\n </div>\n\n {/* Play/Pause button */}\n <button\n class=\"notebook-viewer-play-button\"\n onClick={togglePlayback}\n title={isPlaying() ? \"Pause\" : \"Play\"}\n >\n <Show when={!isPlaying()}>\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\"\n fill=\"currentColor\" stroke=\"none\">\n <polygon points=\"6 3 20 12 6 21\" />\n </svg>\n </Show>\n <Show when={isPlaying()}>\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\"\n fill=\"currentColor\" stroke=\"none\">\n <rect x=\"5\" y=\"3\" width=\"5\" height=\"18\" />\n <rect x=\"14\" y=\"3\" width=\"5\" height=\"18\" />\n </svg>\n </Show>\n </button>\n </div>\n\n {/* Open document — floating top-right */}\n <div class=\"notebook-viewer-open-doc\">\n <button\n class=\"notebook-viewer-open-doc-button\"\n onClick={handleOpenDocClick}\n title=\"Open this document\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\"\n fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6\" />\n <polyline points=\"15 3 21 3 21 9\" />\n <line x1=\"10\" y1=\"14\" x2=\"21\" y2=\"3\" />\n </svg>\n Open document\n </button>\n\n <Show when={showVersionDropdown()}>\n <div class=\"notebook-viewer-version-dropdown\">\n <button\n class=\"notebook-viewer-version-option\"\n onClick={() => openDocument(true)}\n >\n Latest version\n </button>\n <button\n class=\"notebook-viewer-version-option\"\n onClick={() => openDocument(false)}\n >\n This version\n </button>\n </div>\n </Show>\n </div>\n\n {/* Timeline controls */}\n <div class=\"notebook-viewer-timeline\">\n <div class=\"notebook-viewer-date-label\">{currentDateLabel()}</div>\n <div class=\"notebook-viewer-timeline-row\">\n <button\n class=\"notebook-viewer-timeline-label\"\n onClick={goToFirst}\n title=\"Go to first entry\"\n >\n First\n </button>\n <input\n type=\"range\"\n class=\"notebook-viewer-timeline-slider\"\n min={0}\n max={totalEntries() - 1}\n value={currentIndex()}\n onInput={(e) => setRawCurrentIndex(parseInt(e.currentTarget.value, 10))}\n />\n <button\n class=\"notebook-viewer-timeline-label\"\n onClick={goToLatest}\n title=\"Go to latest entry\"\n >\n Latest\n </button>\n </div>\n </div>\n\n {/* Page area with arrow buttons */}\n <div class=\"notebook-viewer-page-area\">\n <button\n class=\"notebook-viewer-arrow\"\n onClick={goBack}\n disabled={!canGoBack()}\n aria-label=\"Go back\"\n title={`Go back ${stepDescription()}`}\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"32\" height=\"32\" viewBox=\"0 0 24 24\"\n fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <polyline points=\"15 18 9 12 15 6\" />\n </svg>\n </button>\n\n <div class=\"notebook-viewer-page\">\n <Show when={viewKey()} keyed>\n {(_key) => (\n <patchwork-view\n doc-url={viewDocUrl()!}\n tool-id={viewToolId()!}\n />\n )}\n </Show>\n </div>\n\n <button\n class=\"notebook-viewer-arrow\"\n onClick={goForward}\n disabled={!canGoForward()}\n aria-label=\"Go forward\"\n title={`Go forward ${stepDescription()}`}\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"32\" height=\"32\" viewBox=\"0 0 24 24\"\n fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <polyline points=\"9 18 15 12 9 6\" />\n </svg>\n </button>\n </div>\n\n {/* Bottom controls */}\n <div class=\"notebook-viewer-bottom\">\n <div class=\"notebook-viewer-step-row\">\n {/* Step mode dropdown */}\n <select\n class=\"notebook-viewer-select\"\n value={stepMode()}\n onChange={(e) => setStepMode(e.currentTarget.value as StepMode)}\n >\n <option value=\"entries\">Step by entries</option>\n <option value=\"time\">Step by time</option>\n </select>\n\n {/* Time unit dropdown (only in time mode) */}\n <Show when={stepMode() === \"time\"}>\n <select\n class=\"notebook-viewer-select\"\n value={timeUnit()}\n onChange={(e) => {\n const unit = e.currentTarget.value as TimeUnit;\n setTimeUnit(unit);\n const amounts = availableTimeAmounts()[unit];\n if (amounts.length > 0 && !amounts.includes(timeAmount())) {\n setTimeAmount(amounts[0]);\n }\n }}\n >\n <For each={availableTimeUnits()}>\n {(opt) => (\n <option value={opt.unit}>{opt.unit}</option>\n )}\n </For>\n </select>\n </Show>\n\n {/* Slider + value for entries mode */}\n <Show when={stepMode() === \"entries\"}>\n <input\n type=\"range\"\n class=\"notebook-viewer-step-slider\"\n min={0}\n max={Math.max(0, availableStepSizes().length - 1)}\n value={stepSizeSliderIndex()}\n onInput={(e) => updateStepSizeFromSlider(parseInt(e.currentTarget.value, 10))}\n />\n <span class=\"notebook-viewer-step-value\">{stepSize()}</span>\n </Show>\n\n {/* Slider + value for time mode */}\n <Show when={stepMode() === \"time\" && currentTimeAmounts().length > 0}>\n <input\n type=\"range\"\n class=\"notebook-viewer-step-slider\"\n min={0}\n max={Math.max(0, currentTimeAmounts().length - 1)}\n value={timeAmountSliderIndex()}\n onInput={(e) => updateTimeAmountFromSlider(parseInt(e.currentTarget.value, 10))}\n />\n <span class=\"notebook-viewer-step-value\">{timeStepLabel()}</span>\n </Show>\n </div>\n\n <div class=\"notebook-viewer-entry-info\">\n <span class=\"notebook-viewer-entry-info-position\">\n Entry {currentIndex() + 1} of {totalEntries()}\n </span>\n <span>{currentEntry()?.docTitle}</span>\n </div>\n </div>\n </Show>\n </div>\n );\n}\n\nexport const renderNotebookViewer: ToolImplementation<HistoryDoc> = (\n handle,\n element\n) => render(() => <NotebookViewer handle={handle} repo={element.repo} element={element} />, element);\n"],"names":["LS_INDEX_KEY","LS_STEP_KEY","LS_STEP_MODE_KEY","LS_TIME_UNIT_KEY","LS_TIME_AMOUNT_KEY","ALL_STEP_SIZES","TIME_UNIT_OPTIONS","unit","label","amounts","msPerUnit","dateTimeFormatter","Intl","DateTimeFormat","year","month","day","hour","minute","hour12","findNearestEntryIndex","entries","currentIdx","targetTimestamp","direction","i","timestamp","length","NotebookViewer","props","historyDoc","makeDocumentProjection","handle","createMemo","totalEntries","historySpanMs","e","availableStepSizes","total","filter","s","availableTimeAmounts","span","result","minutes","hours","days","weeks","opt","a","availableTimeUnits","savedIndexRaw","localStorage","getItem","hasSavedIndex","savedIndex","parseInt","savedStepSize","savedStepMode","savedTimeUnit","savedTimeAmount","rawCurrentIndex","setRawCurrentIndex","createSignal","Number","isFinite","Math","max","stepSize","setStepSize","stepMode","setStepMode","timeUnit","setTimeUnit","timeAmount","setTimeAmount","currentIndex","raw","min","currentEntry","idx","undefined","currentDateLabel","entry","format","Date","viewDocUrl","heads","docUrl","join","viewToolId","toolId","viewKey","url","canGoBack","canGoForward","timeStepMs","amount","find","o","goBack","targetTs","newIdx","goForward","stepSizeSliderIndex","sizes","indexOf","updateStepSizeFromSlider","sliderIndex","clamped","currentTimeAmounts","timeAmountSliderIndex","updateTimeAmountFromSlider","timeStepLabel","goToFirst","goToLatest","isPlaying","setIsPlaying","playDirection","setPlayDirection","playIntervalId","stopPlayback","clearInterval","togglePlayback","window","setInterval","dir","onCleanup","showVersionDropdown","setShowVersionDropdown","hasHeads","openDocument","useLatest","element","dispatchEvent","OpenDocumentEvent","handleOpenDocClick","v","onClickOutside","target","closest","document","addEventListener","removeEventListener","onKeyDown","tagName","isContentEditable","key","preventDefault","createEffect","setItem","String","stepDescription","_el$","_tmpl$10","_$insert","_$createComponent","Show","when","fallback","_tmpl$11","children","_el$2","_tmpl$3","_el$3","firstChild","_el$4","_el$5","nextSibling","_el$6","_el$7","$$click","d","_tmpl$","_tmpl$2","_$effect","_p$","_v$","_v$2","_v$3","_v$4","_v$5","_$setAttribute","t","_$className","_el$0","_tmpl$5","_el$1","_el$10","_tmpl$4","_el$11","_el$12","_el$13","_tmpl$6","_el$14","_el$15","_el$16","_el$17","_el$18","$$input","currentTarget","value","_el$19","_tmpl$7","_el$20","_el$21","_el$22","keyed","_key","_el$38","_tmpl$12","_$owner","_$getOwner","_v$0","_v$1","_v$6","_v$7","_v$8","_v$9","disabled","_el$23","_tmpl$1","_el$24","_el$25","_el$31","_el$32","_el$33","_el$35","_el$36","_el$26","_tmpl$8","includes","For","each","_el$39","_tmpl$13","_el$27","_tmpl$9","_el$28","_tmpl$0","_$memo","_el$29","_el$30","docTitle","renderNotebookViewer","render","repo","_$delegateEvents"],"mappings":"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"}
1
+ {"version":3,"file":"NotebookViewer-io6-qkNu.js","sources":["../../src/NotebookViewer.tsx"],"sourcesContent":["import { createSignal, createMemo, createEffect, Show, For, onCleanup } from \"solid-js\";\nimport { render } from \"solid-js/web\";\nimport type { AutomergeUrl } from \"@automerge/automerge-repo/slim\";\nimport { makeDocumentProjection } from \"solid-automerge\";\nimport { OpenDocumentEvent } from \"@inkandswitch/patchwork-elements\";\nimport type { ToolImplementation } from \"@inkandswitch/patchwork-plugins\";\nimport {\n type PatchworkToolProps,\n type HistoryDoc,\n type HistoryEntry,\n} from \"./types.ts\";\nimport \"./NotebookViewer.css\";\nimport \"./index.css\";\n\nconst LS_INDEX_KEY = \"notebook-viewer-current-index\";\nconst LS_STEP_KEY = \"notebook-viewer-step-size\";\nconst LS_STEP_MODE_KEY = \"notebook-viewer-step-mode\";\nconst LS_TIME_UNIT_KEY = \"notebook-viewer-time-unit\";\nconst LS_TIME_AMOUNT_KEY = \"notebook-viewer-time-amount\";\n\n// Discrete step size options for \"entries\" mode\nconst ALL_STEP_SIZES = [1, 5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000, 10000];\n\ntype StepMode = \"entries\" | \"time\";\ntype TimeUnit = \"minutes\" | \"hours\" | \"days\" | \"weeks\";\n\nconst TIME_UNIT_OPTIONS: { unit: TimeUnit; label: string; amounts: number[]; msPerUnit: number }[] = [\n { unit: \"minutes\", label: \"min\", amounts: [1, 5, 15, 30, 60], msPerUnit: 60 * 1000 },\n { unit: \"hours\", label: \"hr\", amounts: [1, 2, 4, 6, 8, 12, 24], msPerUnit: 60 * 60 * 1000 },\n { unit: \"days\", label: \"day\", amounts: [1, 2, 3, 5, 7], msPerUnit: 24 * 60 * 60 * 1000 },\n { unit: \"weeks\", label: \"wk\", amounts: [1, 2, 4, 6, 13, 26, 52], msPerUnit: 7 * 24 * 60 * 60 * 1000 },\n];\n\nconst dateTimeFormatter = new Intl.DateTimeFormat(\"en-US\", {\n year: \"numeric\",\n month: \"long\",\n day: \"numeric\",\n hour: \"numeric\",\n minute: \"2-digit\",\n hour12: true,\n});\n\n/** Find the index of the entry nearest to targetTimestamp, searching in the given direction. */\nfunction findNearestEntryIndex(\n entries: HistoryEntry[],\n currentIdx: number,\n targetTimestamp: number,\n direction: \"back\" | \"forward\"\n): number {\n if (direction === \"back\") {\n // Search backwards from currentIdx for the last entry at or before targetTimestamp\n for (let i = currentIdx - 1; i >= 0; i--) {\n if (entries[i].timestamp <= targetTimestamp) return i;\n }\n return 0; // clamp to first\n } else {\n // Search forwards from currentIdx for the first entry at or after targetTimestamp\n for (let i = currentIdx + 1; i < entries.length; i++) {\n if (entries[i].timestamp >= targetTimestamp) return i;\n }\n return entries.length - 1; // clamp to last\n }\n}\n\nexport function NotebookViewer(props: PatchworkToolProps<HistoryDoc>) {\n const historyDoc = makeDocumentProjection<HistoryDoc>(props.handle);\n\n // Entries are already in chronological order (HistoryRecorder appends)\n const entries = createMemo(() => historyDoc.entries || []);\n const totalEntries = createMemo(() => entries().length);\n\n // Total time span of history in ms\n const historySpanMs = createMemo(() => {\n const e = entries();\n if (e.length < 2) return 0;\n return e[e.length - 1].timestamp - e[0].timestamp;\n });\n\n // --- Entry step sizes ---\n const availableStepSizes = createMemo(() => {\n const total = totalEntries();\n return ALL_STEP_SIZES.filter((s) => s <= total);\n });\n\n // --- Time step: available amounts per unit, filtered by history span ---\n const availableTimeAmounts = createMemo(() => {\n const span = historySpanMs();\n const result: Record<TimeUnit, number[]> = {\n minutes: [],\n hours: [],\n days: [],\n weeks: [],\n };\n for (const opt of TIME_UNIT_OPTIONS) {\n result[opt.unit] = opt.amounts.filter((a) => a * opt.msPerUnit <= span);\n }\n return result;\n });\n\n // Which time units have at least one available amount\n const availableTimeUnits = createMemo(() =>\n TIME_UNIT_OPTIONS.filter((opt) => availableTimeAmounts()[opt.unit].length > 0)\n );\n\n // --- Load saved state from localStorage ---\n const savedIndexRaw = localStorage.getItem(LS_INDEX_KEY);\n const hasSavedIndex = savedIndexRaw !== null;\n const savedIndex = hasSavedIndex ? parseInt(savedIndexRaw, 10) : -1;\n const savedStepSize = parseInt(localStorage.getItem(LS_STEP_KEY) || \"1\", 10);\n const savedStepMode = (localStorage.getItem(LS_STEP_MODE_KEY) || \"entries\") as StepMode;\n const savedTimeUnit = (localStorage.getItem(LS_TIME_UNIT_KEY) || \"hours\") as TimeUnit;\n const savedTimeAmount = parseInt(localStorage.getItem(LS_TIME_AMOUNT_KEY) || \"1\", 10);\n\n const [rawCurrentIndex, setRawCurrentIndex] = createSignal(\n hasSavedIndex && Number.isFinite(savedIndex) ? Math.max(0, savedIndex) : -1\n );\n const [stepSize, setStepSize] = createSignal(\n Number.isFinite(savedStepSize) ? Math.max(1, savedStepSize) : 1\n );\n const [stepMode, setStepMode] = createSignal<StepMode>(savedStepMode);\n const [timeUnit, setTimeUnit] = createSignal<TimeUnit>(savedTimeUnit);\n const [timeAmount, setTimeAmount] = createSignal(\n Number.isFinite(savedTimeAmount) ? Math.max(1, savedTimeAmount) : 1\n );\n\n // Clamped current index: -1 means \"no saved position\" → latest entry\n const currentIndex = createMemo(() => {\n const total = totalEntries();\n if (total === 0) return 0;\n const raw = rawCurrentIndex();\n if (raw < 0) return total - 1;\n return Math.min(Math.max(0, raw), total - 1);\n });\n\n const currentEntry = createMemo(() => {\n const e = entries();\n const idx = currentIndex();\n return e.length > 0 ? e[idx] : undefined;\n });\n\n const currentDateLabel = createMemo(() => {\n const entry = currentEntry();\n if (!entry) return \"\";\n return dateTimeFormatter.format(new Date(entry.timestamp));\n });\n\n const viewDocUrl = createMemo(() => {\n const entry = currentEntry();\n if (!entry) return undefined;\n if (entry.heads && entry.heads.length > 0) {\n return `${entry.docUrl}#${entry.heads.join(\"|\")}` as AutomergeUrl;\n }\n return entry.docUrl;\n });\n\n const viewToolId = createMemo(() => currentEntry()?.toolId);\n\n const viewKey = createMemo(() => {\n const url = viewDocUrl();\n const toolId = viewToolId();\n return url ? `${url}-${toolId || \"default\"}` : undefined;\n });\n\n // --- Navigation ---\n const canGoBack = createMemo(() => currentIndex() > 0);\n const canGoForward = createMemo(() => {\n const total = totalEntries();\n return total > 0 && currentIndex() < total - 1;\n });\n\n // Compute time step duration in ms\n const timeStepMs = createMemo(() => {\n const unit = timeUnit();\n const amount = timeAmount();\n const opt = TIME_UNIT_OPTIONS.find((o) => o.unit === unit);\n return opt ? amount * opt.msPerUnit : 0;\n });\n\n const goBack = () => {\n if (stepMode() === \"entries\") {\n setRawCurrentIndex(Math.max(0, currentIndex() - stepSize()));\n } else {\n const entry = currentEntry();\n if (!entry) return;\n const targetTs = entry.timestamp - timeStepMs();\n const newIdx = findNearestEntryIndex(entries(), currentIndex(), targetTs, \"back\");\n setRawCurrentIndex(newIdx);\n }\n };\n\n const goForward = () => {\n if (stepMode() === \"entries\") {\n setRawCurrentIndex(Math.min(totalEntries() - 1, currentIndex() + stepSize()));\n } else {\n const entry = currentEntry();\n if (!entry) return;\n const targetTs = entry.timestamp + timeStepMs();\n const newIdx = findNearestEntryIndex(entries(), currentIndex(), targetTs, \"forward\");\n setRawCurrentIndex(newIdx);\n }\n };\n\n // --- Entry step size slider helpers ---\n const stepSizeSliderIndex = createMemo(() => {\n const sizes = availableStepSizes();\n const idx = sizes.indexOf(stepSize());\n if (idx >= 0) return idx;\n for (let i = sizes.length - 1; i >= 0; i--) {\n if (sizes[i] <= stepSize()) return i;\n }\n return 0;\n });\n\n const updateStepSizeFromSlider = (sliderIndex: number) => {\n const sizes = availableStepSizes();\n const clamped = Math.max(0, Math.min(sliderIndex, sizes.length - 1));\n setStepSize(sizes[clamped] || 1);\n };\n\n // --- Time amount slider helpers ---\n const currentTimeAmounts = createMemo(() => availableTimeAmounts()[timeUnit()] || []);\n\n const timeAmountSliderIndex = createMemo(() => {\n const amounts = currentTimeAmounts();\n const idx = amounts.indexOf(timeAmount());\n if (idx >= 0) return idx;\n for (let i = amounts.length - 1; i >= 0; i--) {\n if (amounts[i] <= timeAmount()) return i;\n }\n return 0;\n });\n\n const updateTimeAmountFromSlider = (sliderIndex: number) => {\n const amounts = currentTimeAmounts();\n const clamped = Math.max(0, Math.min(sliderIndex, amounts.length - 1));\n setTimeAmount(amounts[clamped] || 1);\n };\n\n // Format the time step display label\n const timeStepLabel = createMemo(() => {\n const amount = timeAmount();\n const unit = timeUnit();\n const opt = TIME_UNIT_OPTIONS.find((o) => o.unit === unit);\n if (!opt) return \"\";\n const label = amount === 1 ? opt.label : opt.label + \"s\";\n return `${amount} ${label}`;\n });\n\n const goToFirst = () => setRawCurrentIndex(0);\n const goToLatest = () => setRawCurrentIndex(totalEntries() - 1);\n\n // --- Playback ---\n const [isPlaying, setIsPlaying] = createSignal(false);\n const [playDirection, setPlayDirection] = createSignal<\"forward\" | \"reverse\">(\"forward\");\n let playIntervalId: number | undefined;\n\n const stopPlayback = () => {\n setIsPlaying(false);\n if (playIntervalId !== undefined) {\n clearInterval(playIntervalId);\n playIntervalId = undefined;\n }\n };\n\n const togglePlayback = () => {\n if (isPlaying()) {\n stopPlayback();\n } else {\n setIsPlaying(true);\n playIntervalId = window.setInterval(() => {\n const dir = playDirection();\n if (dir === \"forward\") {\n if (!canGoForward()) {\n stopPlayback();\n return;\n }\n goForward();\n } else {\n if (!canGoBack()) {\n stopPlayback();\n return;\n }\n goBack();\n }\n }, 1000);\n }\n };\n\n onCleanup(stopPlayback);\n\n // --- Open Document ---\n const [showVersionDropdown, setShowVersionDropdown] = createSignal(false);\n\n // Check if the current entry has saved heads (meaning it's a snapshot from a point in time).\n // If it has heads, we offer the choice of opening \"this version\" vs \"latest version\".\n const hasHeads = createMemo(() => {\n const entry = currentEntry();\n return !!(entry && entry.heads && entry.heads.length > 0);\n });\n\n const openDocument = (useLatest: boolean) => {\n const entry = currentEntry();\n if (!entry) return;\n\n let url: AutomergeUrl;\n if (useLatest || !entry.heads || entry.heads.length === 0) {\n url = entry.docUrl;\n } else {\n url = `${entry.docUrl}#${entry.heads.join(\"|\")}` as AutomergeUrl;\n }\n\n props.element.dispatchEvent(\n new OpenDocumentEvent({\n url,\n toolId: entry.toolId,\n })\n );\n\n setShowVersionDropdown(false);\n };\n\n const handleOpenDocClick = () => {\n if (hasHeads()) {\n setShowVersionDropdown((v) => !v);\n } else {\n openDocument(true);\n }\n };\n\n // Close dropdown when clicking outside\n const onClickOutside = (e: MouseEvent) => {\n const target = e.target as HTMLElement;\n if (!target.closest(\".notebook-viewer-open-doc\")) {\n setShowVersionDropdown(false);\n }\n };\n\n document.addEventListener(\"click\", onClickOutside);\n onCleanup(() => document.removeEventListener(\"click\", onClickOutside));\n\n // Keyboard navigation\n const onKeyDown = (e: KeyboardEvent) => {\n const target = e.target as HTMLElement;\n if (target.tagName === \"INPUT\" || target.tagName === \"TEXTAREA\" || target.isContentEditable) {\n return;\n }\n if (e.key === \"ArrowLeft\") {\n e.preventDefault();\n goBack();\n } else if (e.key === \"ArrowRight\") {\n e.preventDefault();\n goForward();\n }\n };\n\n document.addEventListener(\"keydown\", onKeyDown);\n onCleanup(() => document.removeEventListener(\"keydown\", onKeyDown));\n\n // Persist state to localStorage\n createEffect(() => localStorage.setItem(LS_INDEX_KEY, String(currentIndex())));\n createEffect(() => localStorage.setItem(LS_STEP_KEY, String(stepSize())));\n createEffect(() => localStorage.setItem(LS_STEP_MODE_KEY, stepMode()));\n createEffect(() => localStorage.setItem(LS_TIME_UNIT_KEY, timeUnit()));\n createEffect(() => localStorage.setItem(LS_TIME_AMOUNT_KEY, String(timeAmount())));\n\n // Arrow tooltip text\n const stepDescription = createMemo(() => {\n if (stepMode() === \"entries\") {\n const s = stepSize();\n return `${s} ${s === 1 ? \"entry\" : \"entries\"}`;\n }\n return timeStepLabel();\n });\n\n return (\n <div class=\"notebook-viewer\">\n <Show\n when={totalEntries() > 0}\n fallback={\n <div class=\"notebook-viewer-empty\">\n No history entries yet. Open some documents to start tracking history.\n </div>\n }\n >\n {/* Playback controls — floating top-left */}\n <div class=\"notebook-viewer-playback\">\n {/* Direction toggle */}\n <div\n class=\"notebook-viewer-direction-toggle\"\n onClick={() => setPlayDirection((d) => d === \"forward\" ? \"reverse\" : \"forward\")}\n title={`Direction: ${playDirection()}`}\n >\n <span class={`notebook-viewer-direction-option ${playDirection() === \"reverse\" ? \"active\" : \"\"}`}>\n Rev\n </span>\n <span class={`notebook-viewer-direction-option ${playDirection() === \"forward\" ? \"active\" : \"\"}`}>\n Fwd\n </span>\n <div class={`notebook-viewer-direction-thumb ${playDirection() === \"forward\" ? \"right\" : \"left\"}`} />\n </div>\n\n {/* Play/Pause button */}\n <button\n class=\"notebook-viewer-play-button\"\n onClick={togglePlayback}\n title={isPlaying() ? \"Pause\" : \"Play\"}\n >\n <Show when={!isPlaying()}>\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\"\n fill=\"currentColor\" stroke=\"none\">\n <polygon points=\"6 3 20 12 6 21\" />\n </svg>\n </Show>\n <Show when={isPlaying()}>\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\"\n fill=\"currentColor\" stroke=\"none\">\n <rect x=\"5\" y=\"3\" width=\"5\" height=\"18\" />\n <rect x=\"14\" y=\"3\" width=\"5\" height=\"18\" />\n </svg>\n </Show>\n </button>\n </div>\n\n {/* Open document — floating top-right */}\n <div class=\"notebook-viewer-open-doc\">\n <button\n class=\"notebook-viewer-open-doc-button\"\n onClick={handleOpenDocClick}\n title=\"Open this document\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\"\n fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6\" />\n <polyline points=\"15 3 21 3 21 9\" />\n <line x1=\"10\" y1=\"14\" x2=\"21\" y2=\"3\" />\n </svg>\n Open document\n </button>\n\n <Show when={showVersionDropdown()}>\n <div class=\"notebook-viewer-version-dropdown\">\n <button\n class=\"notebook-viewer-version-option\"\n onClick={() => openDocument(true)}\n >\n Latest version\n </button>\n <button\n class=\"notebook-viewer-version-option\"\n onClick={() => openDocument(false)}\n >\n This version\n </button>\n </div>\n </Show>\n </div>\n\n {/* Timeline controls */}\n <div class=\"notebook-viewer-timeline\">\n <div class=\"notebook-viewer-date-label\">{currentDateLabel()}</div>\n <div class=\"notebook-viewer-timeline-row\">\n <button\n class=\"notebook-viewer-timeline-label\"\n onClick={goToFirst}\n title=\"Go to first entry\"\n >\n First\n </button>\n <input\n type=\"range\"\n class=\"notebook-viewer-timeline-slider\"\n min={0}\n max={totalEntries() - 1}\n value={currentIndex()}\n onInput={(e) => setRawCurrentIndex(parseInt(e.currentTarget.value, 10))}\n />\n <button\n class=\"notebook-viewer-timeline-label\"\n onClick={goToLatest}\n title=\"Go to latest entry\"\n >\n Latest\n </button>\n </div>\n </div>\n\n {/* Page area with arrow buttons */}\n <div class=\"notebook-viewer-page-area\">\n <button\n class=\"notebook-viewer-arrow\"\n onClick={goBack}\n disabled={!canGoBack()}\n aria-label=\"Go back\"\n title={`Go back ${stepDescription()}`}\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"32\" height=\"32\" viewBox=\"0 0 24 24\"\n fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <polyline points=\"15 18 9 12 15 6\" />\n </svg>\n </button>\n\n <div class=\"notebook-viewer-page\">\n <Show when={viewKey()} keyed>\n {(_key) => (\n <patchwork-view\n doc-url={viewDocUrl()!}\n tool-id={viewToolId()!}\n />\n )}\n </Show>\n </div>\n\n <button\n class=\"notebook-viewer-arrow\"\n onClick={goForward}\n disabled={!canGoForward()}\n aria-label=\"Go forward\"\n title={`Go forward ${stepDescription()}`}\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"32\" height=\"32\" viewBox=\"0 0 24 24\"\n fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <polyline points=\"9 18 15 12 9 6\" />\n </svg>\n </button>\n </div>\n\n {/* Bottom controls */}\n <div class=\"notebook-viewer-bottom\">\n <div class=\"notebook-viewer-step-row\">\n {/* Step mode dropdown */}\n <select\n class=\"notebook-viewer-select\"\n value={stepMode()}\n onChange={(e) => setStepMode(e.currentTarget.value as StepMode)}\n >\n <option value=\"entries\">Step by entries</option>\n <option value=\"time\">Step by time</option>\n </select>\n\n {/* Time unit dropdown (only in time mode) */}\n <Show when={stepMode() === \"time\"}>\n <select\n class=\"notebook-viewer-select\"\n value={timeUnit()}\n onChange={(e) => {\n const unit = e.currentTarget.value as TimeUnit;\n setTimeUnit(unit);\n const amounts = availableTimeAmounts()[unit];\n if (amounts.length > 0 && !amounts.includes(timeAmount())) {\n setTimeAmount(amounts[0]);\n }\n }}\n >\n <For each={availableTimeUnits()}>\n {(opt) => (\n <option value={opt.unit}>{opt.unit}</option>\n )}\n </For>\n </select>\n </Show>\n\n {/* Slider + value for entries mode */}\n <Show when={stepMode() === \"entries\"}>\n <input\n type=\"range\"\n class=\"notebook-viewer-step-slider\"\n min={0}\n max={Math.max(0, availableStepSizes().length - 1)}\n value={stepSizeSliderIndex()}\n onInput={(e) => updateStepSizeFromSlider(parseInt(e.currentTarget.value, 10))}\n />\n <span class=\"notebook-viewer-step-value\">{stepSize()}</span>\n </Show>\n\n {/* Slider + value for time mode */}\n <Show when={stepMode() === \"time\" && currentTimeAmounts().length > 0}>\n <input\n type=\"range\"\n class=\"notebook-viewer-step-slider\"\n min={0}\n max={Math.max(0, currentTimeAmounts().length - 1)}\n value={timeAmountSliderIndex()}\n onInput={(e) => updateTimeAmountFromSlider(parseInt(e.currentTarget.value, 10))}\n />\n <span class=\"notebook-viewer-step-value\">{timeStepLabel()}</span>\n </Show>\n </div>\n\n <div class=\"notebook-viewer-entry-info\">\n <span class=\"notebook-viewer-entry-info-position\">\n Entry {currentIndex() + 1} of {totalEntries()}\n </span>\n <span>{currentEntry()?.docTitle}</span>\n </div>\n </div>\n </Show>\n </div>\n );\n}\n\nexport const renderNotebookViewer: ToolImplementation<HistoryDoc> = (\n handle,\n element\n) => render(() => <NotebookViewer handle={handle} repo={element.repo} element={element} />, element);\n"],"names":["LS_INDEX_KEY","LS_STEP_KEY","LS_STEP_MODE_KEY","LS_TIME_UNIT_KEY","LS_TIME_AMOUNT_KEY","ALL_STEP_SIZES","TIME_UNIT_OPTIONS","unit","label","amounts","msPerUnit","dateTimeFormatter","Intl","DateTimeFormat","year","month","day","hour","minute","hour12","findNearestEntryIndex","entries","currentIdx","targetTimestamp","direction","i","timestamp","length","NotebookViewer","props","historyDoc","makeDocumentProjection","handle","createMemo","totalEntries","historySpanMs","e","availableStepSizes","total","filter","s","availableTimeAmounts","span","result","minutes","hours","days","weeks","opt","a","availableTimeUnits","savedIndexRaw","localStorage","getItem","hasSavedIndex","savedIndex","parseInt","savedStepSize","savedStepMode","savedTimeUnit","savedTimeAmount","rawCurrentIndex","setRawCurrentIndex","createSignal","Number","isFinite","Math","max","stepSize","setStepSize","stepMode","setStepMode","timeUnit","setTimeUnit","timeAmount","setTimeAmount","currentIndex","raw","min","currentEntry","idx","undefined","currentDateLabel","entry","format","Date","viewDocUrl","heads","docUrl","join","viewToolId","toolId","viewKey","url","canGoBack","canGoForward","timeStepMs","amount","find","o","goBack","targetTs","newIdx","goForward","stepSizeSliderIndex","sizes","indexOf","updateStepSizeFromSlider","sliderIndex","clamped","currentTimeAmounts","timeAmountSliderIndex","updateTimeAmountFromSlider","timeStepLabel","goToFirst","goToLatest","isPlaying","setIsPlaying","playDirection","setPlayDirection","playIntervalId","stopPlayback","clearInterval","togglePlayback","window","setInterval","dir","onCleanup","showVersionDropdown","setShowVersionDropdown","hasHeads","openDocument","useLatest","element","dispatchEvent","OpenDocumentEvent","handleOpenDocClick","v","onClickOutside","target","closest","document","addEventListener","removeEventListener","onKeyDown","tagName","isContentEditable","key","preventDefault","createEffect","setItem","String","stepDescription","_el$","_tmpl$10","_$insert","_$createComponent","Show","when","fallback","_tmpl$11","children","_el$2","_tmpl$3","_el$3","firstChild","_el$4","_el$5","nextSibling","_el$6","_el$7","$$click","d","_tmpl$","_tmpl$2","_$effect","_p$","_v$","_v$2","_v$3","_v$4","_v$5","_$setAttribute","t","_$className","_el$0","_tmpl$5","_el$1","_el$10","_tmpl$4","_el$11","_el$12","_el$13","_tmpl$6","_el$14","_el$15","_el$16","_el$17","_el$18","$$input","currentTarget","value","_el$19","_tmpl$7","_el$20","_el$21","_el$22","keyed","_key","_el$38","_tmpl$12","_$owner","_$getOwner","_v$0","_v$1","_v$6","_v$7","_v$8","_v$9","disabled","_el$23","_tmpl$1","_el$24","_el$25","_el$31","_el$32","_el$33","_el$35","_el$36","_el$26","_tmpl$8","includes","For","each","_el$39","_tmpl$13","_el$27","_tmpl$9","_el$28","_tmpl$0","_$memo","_el$29","_el$30","docTitle","renderNotebookViewer","render","repo","_$delegateEvents"],"mappings":"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"}
@@ -476,7 +476,18 @@ var browserExports = requireBrowser();
476
476
  const debug = /* @__PURE__ */ getDefaultExportFromCjs(browserExports);
477
477
  var log = debug("cabbages");
478
478
  function pojo(target) {
479
- return typeof target == "object" && typeof target != null && Object.getPrototypeOf(target) == Object.prototype;
479
+ return typeof target == "object" && target != null && Object.getPrototypeOf(target) == Object.prototype;
480
+ }
481
+ function copy(value) {
482
+ if (Array.isArray(value)) return value.map(copy);
483
+ if (pojo(value)) {
484
+ let result = {};
485
+ for (let key of Object.keys(value)) result[key] = copy(value[key]);
486
+ return result;
487
+ }
488
+ if (value instanceof Date) return new Date(value);
489
+ if (ArrayBuffer.isView(value)) return value.slice();
490
+ return value;
480
491
  }
481
492
  var BLOCK_MARKER = "";
482
493
  function apply(target, ...rest) {
@@ -605,6 +616,15 @@ function apply(target, ...rest) {
605
616
  }
606
617
  }
607
618
  target = target[key];
619
+ if (typeof target == "string") {
620
+ log("ignoring patch to a block marker in a string", path, range);
621
+ return;
622
+ }
623
+ if (target == null || typeof target != "object" && typeof target != "function") {
624
+ throw new TypeError(
625
+ `invalid path ${JSON.stringify(path)}: ${String(key)} is ${target}`
626
+ );
627
+ }
608
628
  }
609
629
  }
610
630
  function get(obj, key) {
@@ -646,14 +666,14 @@ function fromAutomerge(autopatch, payload) {
646
666
  return [
647
667
  path,
648
668
  [key, key],
649
- structuredClone(autopatch.values)
669
+ copy(autopatch.values)
650
670
  ];
651
671
  }
652
672
  case "splice": {
653
673
  return [path, [key, key], [autopatch.value]];
654
674
  }
655
675
  case "put": {
656
- return [path, key, structuredClone(autopatch.value)];
676
+ return [path, key, copy(autopatch.value)];
657
677
  }
658
678
  }
659
679
  }
@@ -708,4 +728,4 @@ createContext(
708
728
  export {
709
729
  makeDocumentProjection as m
710
730
  };
711
- //# sourceMappingURL=context-CgDNOWHV.js.map
731
+ //# sourceMappingURL=context-BD8lKU7i.js.map