noteloom 0.3.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/README.md +344 -53
  2. package/bin/noteloom.mjs +139 -0
  3. package/dist/canvas.cjs +2 -0
  4. package/dist/canvas.cjs.map +1 -0
  5. package/dist/canvas.d.ts +2 -0
  6. package/dist/canvas.js +5 -0
  7. package/dist/canvas.js.map +1 -0
  8. package/dist/collab.cjs +2 -0
  9. package/dist/collab.cjs.map +1 -0
  10. package/dist/collab.d.ts +19 -0
  11. package/dist/collab.js +379 -0
  12. package/dist/collab.js.map +1 -0
  13. package/dist/comments.cjs +2 -0
  14. package/dist/comments.cjs.map +1 -0
  15. package/dist/comments.d.ts +17 -0
  16. package/dist/comments.js +19 -0
  17. package/dist/comments.js.map +1 -0
  18. package/dist/index.cjs +2 -0
  19. package/dist/index.cjs.map +1 -0
  20. package/dist/index.d.ts +392 -32
  21. package/dist/index.js +3983 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/persistence.cjs +2 -0
  24. package/dist/persistence.cjs.map +1 -0
  25. package/dist/persistence.d.ts +11 -0
  26. package/dist/persistence.js +12 -0
  27. package/dist/persistence.js.map +1 -0
  28. package/dist/shared/CommentAvatar-TKqsM8vG.js +53 -0
  29. package/dist/shared/CommentAvatar-TKqsM8vG.js.map +1 -0
  30. package/dist/shared/CommentAvatar-V457IgoQ.cjs +2 -0
  31. package/dist/shared/CommentAvatar-V457IgoQ.cjs.map +1 -0
  32. package/dist/shared/CommentThreadCard-CAJ3oPdr.cjs +2 -0
  33. package/dist/shared/CommentThreadCard-CAJ3oPdr.cjs.map +1 -0
  34. package/dist/shared/CommentThreadCard-Cxf8GwHJ.js +213 -0
  35. package/dist/shared/CommentThreadCard-Cxf8GwHJ.js.map +1 -0
  36. package/dist/shared/CommentsPanel-BwVVyMOC.js +76 -0
  37. package/dist/shared/CommentsPanel-BwVVyMOC.js.map +1 -0
  38. package/dist/shared/CommentsPanel-CES4uzye.cjs +2 -0
  39. package/dist/shared/CommentsPanel-CES4uzye.cjs.map +1 -0
  40. package/dist/shared/VersionHistory-Bg6fufP5.js +1120 -0
  41. package/dist/shared/VersionHistory-Bg6fufP5.js.map +1 -0
  42. package/dist/shared/VersionHistory-DELa2Wbq.cjs +12 -0
  43. package/dist/shared/VersionHistory-DELa2Wbq.cjs.map +1 -0
  44. package/dist/shared/VoiceListeningIndicator-BOfVmLK0.js +338 -0
  45. package/dist/shared/VoiceListeningIndicator-BOfVmLK0.js.map +1 -0
  46. package/dist/shared/VoiceListeningIndicator-DNX8JlQM.cjs +2 -0
  47. package/dist/shared/VoiceListeningIndicator-DNX8JlQM.cjs.map +1 -0
  48. package/dist/shared/fieldRegistry-BoYyW3GH.cjs +2 -0
  49. package/dist/shared/fieldRegistry-BoYyW3GH.cjs.map +1 -0
  50. package/dist/shared/fieldRegistry-PjJWXFoB.js +223 -0
  51. package/dist/shared/fieldRegistry-PjJWXFoB.js.map +1 -0
  52. package/dist/shared/icons-C1_s0jKK.js +4269 -0
  53. package/dist/shared/icons-C1_s0jKK.js.map +1 -0
  54. package/dist/shared/icons-DtCsXuU6.cjs +3531 -0
  55. package/dist/shared/icons-DtCsXuU6.cjs.map +1 -0
  56. package/dist/shared/index-B9jyyL8u.js +2145 -0
  57. package/dist/shared/index-B9jyyL8u.js.map +1 -0
  58. package/dist/shared/index-D9WEXpYM.cjs +2 -0
  59. package/dist/shared/index-D9WEXpYM.cjs.map +1 -0
  60. package/dist/shared/indexedDbPersistence-BKlGPFTP.js +112 -0
  61. package/dist/shared/indexedDbPersistence-BKlGPFTP.js.map +1 -0
  62. package/dist/shared/indexedDbPersistence-BWJ1h5Vp.cjs +2 -0
  63. package/dist/shared/indexedDbPersistence-BWJ1h5Vp.cjs.map +1 -0
  64. package/dist/shared/leafBlockFactory-A9eUhSe-.js +335 -0
  65. package/dist/shared/leafBlockFactory-A9eUhSe-.js.map +1 -0
  66. package/dist/shared/leafBlockFactory-Dp382eP8.cjs +2 -0
  67. package/dist/shared/leafBlockFactory-Dp382eP8.cjs.map +1 -0
  68. package/dist/shared/serialize-DWEfk0vU.cjs +3 -0
  69. package/dist/shared/serialize-DWEfk0vU.cjs.map +1 -0
  70. package/dist/shared/serialize-T9Odwx24.js +86 -0
  71. package/dist/shared/serialize-T9Odwx24.js.map +1 -0
  72. package/dist/shared/starter-kit-CY5wzYDf.js +4980 -0
  73. package/dist/shared/starter-kit-CY5wzYDf.js.map +1 -0
  74. package/dist/shared/starter-kit-lPN-NpJ5.cjs +27 -0
  75. package/dist/shared/starter-kit-lPN-NpJ5.cjs.map +1 -0
  76. package/dist/shared/usePopoverEdgeClamp-CDG26jBM.cjs +2 -0
  77. package/dist/shared/usePopoverEdgeClamp-CDG26jBM.cjs.map +1 -0
  78. package/dist/shared/usePopoverEdgeClamp-gmFm0CnI.js +109 -0
  79. package/dist/shared/usePopoverEdgeClamp-gmFm0CnI.js.map +1 -0
  80. package/dist/shared/useServiceWorkerUpdate-BduabXv6.js +94 -0
  81. package/dist/shared/useServiceWorkerUpdate-BduabXv6.js.map +1 -0
  82. package/dist/shared/useServiceWorkerUpdate-DQboGesi.cjs +2 -0
  83. package/dist/shared/useServiceWorkerUpdate-DQboGesi.cjs.map +1 -0
  84. package/dist/starter-kit.cjs +2 -0
  85. package/dist/starter-kit.cjs.map +1 -0
  86. package/dist/starter-kit.d.ts +9 -0
  87. package/dist/starter-kit.js +10 -0
  88. package/dist/starter-kit.js.map +1 -0
  89. package/dist/style.css +3529 -3200
  90. package/dist/versions.cjs +2 -0
  91. package/dist/versions.cjs.map +1 -0
  92. package/dist/versions.d.ts +11 -0
  93. package/dist/versions.js +13 -0
  94. package/dist/versions.js.map +1 -0
  95. package/dist/voice.cjs +2 -0
  96. package/dist/voice.cjs.map +1 -0
  97. package/dist/voice.d.ts +7 -0
  98. package/dist/voice.js +8 -0
  99. package/dist/voice.js.map +1 -0
  100. package/package.json +159 -92
  101. package/dist/noteloom.cjs +0 -3209
  102. package/dist/noteloom.cjs.map +0 -1
  103. package/dist/noteloom.es.js +0 -14622
  104. package/dist/noteloom.es.js.map +0 -1
@@ -0,0 +1,112 @@
1
+ const w = "noteloom-documents", a = "documents", i = "templates", u = "versions";
2
+ let l = null;
3
+ function c() {
4
+ return l || (l = new Promise((r, o) => {
5
+ const t = indexedDB.open(w, 3);
6
+ t.onupgradeneeded = () => {
7
+ t.result.objectStoreNames.contains(a) || t.result.createObjectStore(a), t.result.objectStoreNames.contains(i) || t.result.createObjectStore(i, { keyPath: "id" }), t.result.objectStoreNames.contains(u) || t.result.createObjectStore(u, { keyPath: "id" });
8
+ }, t.onsuccess = () => r(t.result), t.onerror = () => o(t.error);
9
+ }), l);
10
+ }
11
+ async function S(r, o) {
12
+ const t = await c();
13
+ return new Promise((s, e) => {
14
+ const n = t.transaction(a, "readwrite");
15
+ n.objectStore(a).put(o, r), n.oncomplete = () => s(), n.onerror = () => e(n.error);
16
+ });
17
+ }
18
+ async function y(r) {
19
+ const o = await c();
20
+ return new Promise((t, s) => {
21
+ const n = o.transaction(a, "readonly").objectStore(a).get(r);
22
+ n.onsuccess = () => t(n.result ?? null), n.onerror = () => s(n.error);
23
+ });
24
+ }
25
+ async function P(r) {
26
+ const o = await c();
27
+ return new Promise((t, s) => {
28
+ const e = o.transaction(a, "readwrite");
29
+ e.objectStore(a).delete(r), e.oncomplete = () => t(), e.onerror = () => s(e.error);
30
+ });
31
+ }
32
+ async function p() {
33
+ const r = await c();
34
+ return new Promise((o, t) => {
35
+ const e = r.transaction(a, "readonly").objectStore(a).getAllKeys();
36
+ e.onsuccess = () => o(e.result), e.onerror = () => t(e.error);
37
+ });
38
+ }
39
+ async function x(r) {
40
+ const o = await c();
41
+ return new Promise((t, s) => {
42
+ const e = o.transaction(i, "readwrite");
43
+ e.objectStore(i).put(r), e.oncomplete = () => t(), e.onerror = () => s(e.error);
44
+ });
45
+ }
46
+ async function f(r) {
47
+ const o = await c();
48
+ return new Promise((t, s) => {
49
+ const n = o.transaction(i, "readonly").objectStore(i).get(r);
50
+ n.onsuccess = () => t(n.result ?? null), n.onerror = () => s(n.error);
51
+ });
52
+ }
53
+ async function j(r) {
54
+ const o = await c();
55
+ return new Promise((t, s) => {
56
+ const e = o.transaction(i, "readwrite");
57
+ e.objectStore(i).delete(r), e.oncomplete = () => t(), e.onerror = () => s(e.error);
58
+ });
59
+ }
60
+ async function D() {
61
+ const r = await c();
62
+ return new Promise((o, t) => {
63
+ const e = r.transaction(i, "readonly").objectStore(i).getAll();
64
+ e.onsuccess = () => o(e.result), e.onerror = () => t(e.error);
65
+ });
66
+ }
67
+ async function E(r) {
68
+ const o = await c();
69
+ return new Promise((t, s) => {
70
+ const e = o.transaction(u, "readwrite");
71
+ e.objectStore(u).put(r), e.oncomplete = () => t(), e.onerror = () => s(e.error);
72
+ });
73
+ }
74
+ async function N(r) {
75
+ const o = await c();
76
+ return new Promise((t, s) => {
77
+ const n = o.transaction(u, "readonly").objectStore(u).get(r);
78
+ n.onsuccess = () => t(n.result ?? null), n.onerror = () => s(n.error);
79
+ });
80
+ }
81
+ async function O(r) {
82
+ const o = await c();
83
+ return new Promise((t, s) => {
84
+ const e = o.transaction(u, "readwrite");
85
+ e.objectStore(u).delete(r), e.oncomplete = () => t(), e.onerror = () => s(e.error);
86
+ });
87
+ }
88
+ async function T(r) {
89
+ const o = await c();
90
+ return new Promise((t, s) => {
91
+ const n = o.transaction(u, "readonly").objectStore(u).getAll();
92
+ n.onsuccess = () => {
93
+ const m = n.result.filter((d) => d.docId === r);
94
+ m.sort((d, b) => b.timestamp - d.timestamp), t(m);
95
+ }, n.onerror = () => s(n.error);
96
+ });
97
+ }
98
+ export {
99
+ y as a,
100
+ O as b,
101
+ T as c,
102
+ P as d,
103
+ N as e,
104
+ E as f,
105
+ D as g,
106
+ j as h,
107
+ f as i,
108
+ x as j,
109
+ p as l,
110
+ S as s
111
+ };
112
+ //# sourceMappingURL=indexedDbPersistence-BKlGPFTP.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"indexedDbPersistence-BKlGPFTP.js","sources":["../../src/persistence/indexedDbPersistence.js"],"sourcesContent":["const DB_NAME = 'noteloom-documents';\nconst STORE_NAME = 'documents';\nconst TEMPLATES_STORE_NAME = 'templates';\nconst VERSIONS_STORE_NAME = 'versions';\nconst DB_VERSION = 3;\n\n/**\n * IndexedDB-backed local persistence for documents (the shape `EditorStore\n * .toJSON()`/`.fromJSON()` already produce/accept) — native browser API,\n * no added dependency. Chosen over `localStorage` deliberately: documents\n * can carry large embedded media as `data:` URLs (this editor doesn't do\n * server uploads — see EmbedBlock.jsx), easily exceeding localStorage's\n * ~5-10MB synchronous string-only quota, whereas IndexedDB is async and\n * has a much larger practical ceiling.\n *\n * One shared connection is reused across calls rather than opened fresh\n * each time (opening is itself an async round-trip) — lazily created on\n * first use, cached in-module.\n */\nlet dbPromise = null;\n\nfunction openDatabase() {\n if (dbPromise) return dbPromise;\n dbPromise = new Promise((resolve, reject) => {\n const request = indexedDB.open(DB_NAME, DB_VERSION);\n request.onupgradeneeded = () => {\n if (!request.result.objectStoreNames.contains(STORE_NAME)) {\n request.result.createObjectStore(STORE_NAME);\n }\n if (!request.result.objectStoreNames.contains(TEMPLATES_STORE_NAME)) {\n // Inline-keyed (unlike `documents`' external key) -- listTemplates()\n // needs getAll() to return full {id, name, ...} objects in one read\n // for a gallery UI, not just keys.\n request.result.createObjectStore(TEMPLATES_STORE_NAME, { keyPath: 'id' });\n }\n if (!request.result.objectStoreNames.contains(VERSIONS_STORE_NAME)) {\n // Same inline-keyed shape as templates, same reason (a version\n // history list needs full {id, docId, timestamp, ...} objects in\n // one read). No index on docId -- listDocumentVersions() filters\n // client-side after getAll(), same no-index precedent as\n // listTemplates(); per-document version counts are small enough\n // that this is fine.\n request.result.createObjectStore(VERSIONS_STORE_NAME, { keyPath: 'id' });\n }\n };\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n return dbPromise;\n}\n\n/** Persists `doc` (a plain object, e.g. from `store.toJSON()`) under `docId`, overwriting whatever was there before. */\nexport async function savePersistedDocument(docId, doc) {\n const db = await openDatabase();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, 'readwrite');\n tx.objectStore(STORE_NAME).put(doc, docId);\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n}\n\n/** Returns the persisted document for `docId`, or `null` if nothing has been saved under that id yet. */\nexport async function loadPersistedDocument(docId) {\n const db = await openDatabase();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, 'readonly');\n const request = tx.objectStore(STORE_NAME).get(docId);\n request.onsuccess = () => resolve(request.result ?? null);\n request.onerror = () => reject(request.error);\n });\n}\n\n/** Removes the persisted document for `docId`, if any. A no-op if nothing was stored under that id. */\nexport async function deletePersistedDocument(docId) {\n const db = await openDatabase();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, 'readwrite');\n tx.objectStore(STORE_NAME).delete(docId);\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n}\n\n/** Every docId with a persisted document — e.g. for a \"recent documents\" list. Insertion/write order is not guaranteed. */\nexport async function listPersistedDocumentIds() {\n const db = await openDatabase();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, 'readonly');\n const request = tx.objectStore(STORE_NAME).getAllKeys();\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n}\n\n/**\n * Persists a template — `{ id, scope: 'document' | 'block', name,\n * description?, doc }`, where `doc` is a full document (for `'document'`\n * scope, e.g. from `exportDocumentJSON`) or `{ roots }` (for `'block'`\n * scope, from `captureBlockTemplate`) — overwriting whatever was stored\n * under the same `id` before. Separate object store from `documents`\n * (see openDatabase above): a template is independent of any one document\n * instance, not \"the current document.\"\n */\nexport async function saveTemplate(template) {\n const db = await openDatabase();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(TEMPLATES_STORE_NAME, 'readwrite');\n tx.objectStore(TEMPLATES_STORE_NAME).put(template);\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n}\n\n/** Returns the template stored under `id`, or `null` if none exists. */\nexport async function loadTemplate(id) {\n const db = await openDatabase();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(TEMPLATES_STORE_NAME, 'readonly');\n const request = tx.objectStore(TEMPLATES_STORE_NAME).get(id);\n request.onsuccess = () => resolve(request.result ?? null);\n request.onerror = () => reject(request.error);\n });\n}\n\n/** Removes the template stored under `id`, if any. A no-op if nothing was stored under that id. */\nexport async function deleteTemplate(id) {\n const db = await openDatabase();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(TEMPLATES_STORE_NAME, 'readwrite');\n tx.objectStore(TEMPLATES_STORE_NAME).delete(id);\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n}\n\n/** Every stored template, in full (unlike listPersistedDocumentIds, which only returns keys) — for rendering a gallery/picker without a per-template round trip. Insertion/write order is not guaranteed. */\nexport async function listTemplates() {\n const db = await openDatabase();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(TEMPLATES_STORE_NAME, 'readonly');\n const request = tx.objectStore(TEMPLATES_STORE_NAME).getAll();\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n}\n\n/**\n * Persists one point-in-time snapshot of a document — `{ id, docId,\n * timestamp, authorId?, authorIds?, summary?, label?, doc }`, where `doc`\n * is a full document (the same shape a document-scope template uses).\n * Separate object store from both `documents` and `templates` (see\n * openDatabase above): a version is tied to one specific document's\n * history, not \"the current document\" or a reusable starter. Overwrites\n * whatever was stored under the same `id` before, though callers normally\n * mint a fresh `id` per snapshot (see `createAutoVersionHistory`, which\n * saves one automatically after each burst of edits settles) rather than\n * reusing one.\n */\nexport async function saveDocumentVersion(version) {\n const db = await openDatabase();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(VERSIONS_STORE_NAME, 'readwrite');\n tx.objectStore(VERSIONS_STORE_NAME).put(version);\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n}\n\n/** Returns the version stored under `id`, or `null` if none exists. */\nexport async function loadDocumentVersion(id) {\n const db = await openDatabase();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(VERSIONS_STORE_NAME, 'readonly');\n const request = tx.objectStore(VERSIONS_STORE_NAME).get(id);\n request.onsuccess = () => resolve(request.result ?? null);\n request.onerror = () => reject(request.error);\n });\n}\n\n/** Removes the version stored under `id`, if any. A no-op if nothing was stored under that id. */\nexport async function deleteDocumentVersion(id) {\n const db = await openDatabase();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(VERSIONS_STORE_NAME, 'readwrite');\n tx.objectStore(VERSIONS_STORE_NAME).delete(id);\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n}\n\n/** Every version saved for `docId`, in full, newest first. Filters client-side after a full getAll() -- see openDatabase's own note on why there's no docId index. */\nexport async function listDocumentVersions(docId) {\n const db = await openDatabase();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(VERSIONS_STORE_NAME, 'readonly');\n const request = tx.objectStore(VERSIONS_STORE_NAME).getAll();\n request.onsuccess = () => {\n const all = request.result.filter((v) => v.docId === docId);\n all.sort((a, b) => b.timestamp - a.timestamp);\n resolve(all);\n };\n request.onerror = () => reject(request.error);\n });\n}\n"],"names":["DB_NAME","STORE_NAME","TEMPLATES_STORE_NAME","VERSIONS_STORE_NAME","dbPromise","openDatabase","resolve","reject","request","savePersistedDocument","docId","doc","db","tx","loadPersistedDocument","deletePersistedDocument","listPersistedDocumentIds","saveTemplate","template","loadTemplate","id","deleteTemplate","listTemplates","saveDocumentVersion","version","loadDocumentVersion","deleteDocumentVersion","listDocumentVersions","all","v","a"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ "use strict";const w="noteloom-documents",a="documents",i="templates",u="versions";let l=null;function c(){return l||(l=new Promise((o,r)=>{const t=indexedDB.open(w,3);t.onupgradeneeded=()=>{t.result.objectStoreNames.contains(a)||t.result.createObjectStore(a),t.result.objectStoreNames.contains(i)||t.result.createObjectStore(i,{keyPath:"id"}),t.result.objectStoreNames.contains(u)||t.result.createObjectStore(u,{keyPath:"id"})},t.onsuccess=()=>o(t.result),t.onerror=()=>r(t.error)}),l)}async function S(o,r){const t=await c();return new Promise((s,e)=>{const n=t.transaction(a,"readwrite");n.objectStore(a).put(r,o),n.oncomplete=()=>s(),n.onerror=()=>e(n.error)})}async function P(o){const r=await c();return new Promise((t,s)=>{const n=r.transaction(a,"readonly").objectStore(a).get(o);n.onsuccess=()=>t(n.result??null),n.onerror=()=>s(n.error)})}async function p(o){const r=await c();return new Promise((t,s)=>{const e=r.transaction(a,"readwrite");e.objectStore(a).delete(o),e.oncomplete=()=>t(),e.onerror=()=>s(e.error)})}async function y(){const o=await c();return new Promise((r,t)=>{const e=o.transaction(a,"readonly").objectStore(a).getAllKeys();e.onsuccess=()=>r(e.result),e.onerror=()=>t(e.error)})}async function D(o){const r=await c();return new Promise((t,s)=>{const e=r.transaction(i,"readwrite");e.objectStore(i).put(o),e.oncomplete=()=>t(),e.onerror=()=>s(e.error)})}async function x(o){const r=await c();return new Promise((t,s)=>{const n=r.transaction(i,"readonly").objectStore(i).get(o);n.onsuccess=()=>t(n.result??null),n.onerror=()=>s(n.error)})}async function f(o){const r=await c();return new Promise((t,s)=>{const e=r.transaction(i,"readwrite");e.objectStore(i).delete(o),e.oncomplete=()=>t(),e.onerror=()=>s(e.error)})}async function j(){const o=await c();return new Promise((r,t)=>{const e=o.transaction(i,"readonly").objectStore(i).getAll();e.onsuccess=()=>r(e.result),e.onerror=()=>t(e.error)})}async function T(o){const r=await c();return new Promise((t,s)=>{const e=r.transaction(u,"readwrite");e.objectStore(u).put(o),e.oncomplete=()=>t(),e.onerror=()=>s(e.error)})}async function E(o){const r=await c();return new Promise((t,s)=>{const n=r.transaction(u,"readonly").objectStore(u).get(o);n.onsuccess=()=>t(n.result??null),n.onerror=()=>s(n.error)})}async function V(o){const r=await c();return new Promise((t,s)=>{const e=r.transaction(u,"readwrite");e.objectStore(u).delete(o),e.oncomplete=()=>t(),e.onerror=()=>s(e.error)})}async function N(o){const r=await c();return new Promise((t,s)=>{const n=r.transaction(u,"readonly").objectStore(u).getAll();n.onsuccess=()=>{const m=n.result.filter(d=>d.docId===o);m.sort((d,b)=>b.timestamp-d.timestamp),t(m)},n.onerror=()=>s(n.error)})}exports.deleteDocumentVersion=V;exports.deletePersistedDocument=p;exports.deleteTemplate=f;exports.listDocumentVersions=N;exports.listPersistedDocumentIds=y;exports.listTemplates=j;exports.loadDocumentVersion=E;exports.loadPersistedDocument=P;exports.loadTemplate=x;exports.saveDocumentVersion=T;exports.savePersistedDocument=S;exports.saveTemplate=D;
2
+ //# sourceMappingURL=indexedDbPersistence-BWJ1h5Vp.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"indexedDbPersistence-BWJ1h5Vp.cjs","sources":["../../src/persistence/indexedDbPersistence.js"],"sourcesContent":["const DB_NAME = 'noteloom-documents';\nconst STORE_NAME = 'documents';\nconst TEMPLATES_STORE_NAME = 'templates';\nconst VERSIONS_STORE_NAME = 'versions';\nconst DB_VERSION = 3;\n\n/**\n * IndexedDB-backed local persistence for documents (the shape `EditorStore\n * .toJSON()`/`.fromJSON()` already produce/accept) — native browser API,\n * no added dependency. Chosen over `localStorage` deliberately: documents\n * can carry large embedded media as `data:` URLs (this editor doesn't do\n * server uploads — see EmbedBlock.jsx), easily exceeding localStorage's\n * ~5-10MB synchronous string-only quota, whereas IndexedDB is async and\n * has a much larger practical ceiling.\n *\n * One shared connection is reused across calls rather than opened fresh\n * each time (opening is itself an async round-trip) — lazily created on\n * first use, cached in-module.\n */\nlet dbPromise = null;\n\nfunction openDatabase() {\n if (dbPromise) return dbPromise;\n dbPromise = new Promise((resolve, reject) => {\n const request = indexedDB.open(DB_NAME, DB_VERSION);\n request.onupgradeneeded = () => {\n if (!request.result.objectStoreNames.contains(STORE_NAME)) {\n request.result.createObjectStore(STORE_NAME);\n }\n if (!request.result.objectStoreNames.contains(TEMPLATES_STORE_NAME)) {\n // Inline-keyed (unlike `documents`' external key) -- listTemplates()\n // needs getAll() to return full {id, name, ...} objects in one read\n // for a gallery UI, not just keys.\n request.result.createObjectStore(TEMPLATES_STORE_NAME, { keyPath: 'id' });\n }\n if (!request.result.objectStoreNames.contains(VERSIONS_STORE_NAME)) {\n // Same inline-keyed shape as templates, same reason (a version\n // history list needs full {id, docId, timestamp, ...} objects in\n // one read). No index on docId -- listDocumentVersions() filters\n // client-side after getAll(), same no-index precedent as\n // listTemplates(); per-document version counts are small enough\n // that this is fine.\n request.result.createObjectStore(VERSIONS_STORE_NAME, { keyPath: 'id' });\n }\n };\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n return dbPromise;\n}\n\n/** Persists `doc` (a plain object, e.g. from `store.toJSON()`) under `docId`, overwriting whatever was there before. */\nexport async function savePersistedDocument(docId, doc) {\n const db = await openDatabase();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, 'readwrite');\n tx.objectStore(STORE_NAME).put(doc, docId);\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n}\n\n/** Returns the persisted document for `docId`, or `null` if nothing has been saved under that id yet. */\nexport async function loadPersistedDocument(docId) {\n const db = await openDatabase();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, 'readonly');\n const request = tx.objectStore(STORE_NAME).get(docId);\n request.onsuccess = () => resolve(request.result ?? null);\n request.onerror = () => reject(request.error);\n });\n}\n\n/** Removes the persisted document for `docId`, if any. A no-op if nothing was stored under that id. */\nexport async function deletePersistedDocument(docId) {\n const db = await openDatabase();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, 'readwrite');\n tx.objectStore(STORE_NAME).delete(docId);\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n}\n\n/** Every docId with a persisted document — e.g. for a \"recent documents\" list. Insertion/write order is not guaranteed. */\nexport async function listPersistedDocumentIds() {\n const db = await openDatabase();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, 'readonly');\n const request = tx.objectStore(STORE_NAME).getAllKeys();\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n}\n\n/**\n * Persists a template — `{ id, scope: 'document' | 'block', name,\n * description?, doc }`, where `doc` is a full document (for `'document'`\n * scope, e.g. from `exportDocumentJSON`) or `{ roots }` (for `'block'`\n * scope, from `captureBlockTemplate`) — overwriting whatever was stored\n * under the same `id` before. Separate object store from `documents`\n * (see openDatabase above): a template is independent of any one document\n * instance, not \"the current document.\"\n */\nexport async function saveTemplate(template) {\n const db = await openDatabase();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(TEMPLATES_STORE_NAME, 'readwrite');\n tx.objectStore(TEMPLATES_STORE_NAME).put(template);\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n}\n\n/** Returns the template stored under `id`, or `null` if none exists. */\nexport async function loadTemplate(id) {\n const db = await openDatabase();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(TEMPLATES_STORE_NAME, 'readonly');\n const request = tx.objectStore(TEMPLATES_STORE_NAME).get(id);\n request.onsuccess = () => resolve(request.result ?? null);\n request.onerror = () => reject(request.error);\n });\n}\n\n/** Removes the template stored under `id`, if any. A no-op if nothing was stored under that id. */\nexport async function deleteTemplate(id) {\n const db = await openDatabase();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(TEMPLATES_STORE_NAME, 'readwrite');\n tx.objectStore(TEMPLATES_STORE_NAME).delete(id);\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n}\n\n/** Every stored template, in full (unlike listPersistedDocumentIds, which only returns keys) — for rendering a gallery/picker without a per-template round trip. Insertion/write order is not guaranteed. */\nexport async function listTemplates() {\n const db = await openDatabase();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(TEMPLATES_STORE_NAME, 'readonly');\n const request = tx.objectStore(TEMPLATES_STORE_NAME).getAll();\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n}\n\n/**\n * Persists one point-in-time snapshot of a document — `{ id, docId,\n * timestamp, authorId?, authorIds?, summary?, label?, doc }`, where `doc`\n * is a full document (the same shape a document-scope template uses).\n * Separate object store from both `documents` and `templates` (see\n * openDatabase above): a version is tied to one specific document's\n * history, not \"the current document\" or a reusable starter. Overwrites\n * whatever was stored under the same `id` before, though callers normally\n * mint a fresh `id` per snapshot (see `createAutoVersionHistory`, which\n * saves one automatically after each burst of edits settles) rather than\n * reusing one.\n */\nexport async function saveDocumentVersion(version) {\n const db = await openDatabase();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(VERSIONS_STORE_NAME, 'readwrite');\n tx.objectStore(VERSIONS_STORE_NAME).put(version);\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n}\n\n/** Returns the version stored under `id`, or `null` if none exists. */\nexport async function loadDocumentVersion(id) {\n const db = await openDatabase();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(VERSIONS_STORE_NAME, 'readonly');\n const request = tx.objectStore(VERSIONS_STORE_NAME).get(id);\n request.onsuccess = () => resolve(request.result ?? null);\n request.onerror = () => reject(request.error);\n });\n}\n\n/** Removes the version stored under `id`, if any. A no-op if nothing was stored under that id. */\nexport async function deleteDocumentVersion(id) {\n const db = await openDatabase();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(VERSIONS_STORE_NAME, 'readwrite');\n tx.objectStore(VERSIONS_STORE_NAME).delete(id);\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n}\n\n/** Every version saved for `docId`, in full, newest first. Filters client-side after a full getAll() -- see openDatabase's own note on why there's no docId index. */\nexport async function listDocumentVersions(docId) {\n const db = await openDatabase();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(VERSIONS_STORE_NAME, 'readonly');\n const request = tx.objectStore(VERSIONS_STORE_NAME).getAll();\n request.onsuccess = () => {\n const all = request.result.filter((v) => v.docId === docId);\n all.sort((a, b) => b.timestamp - a.timestamp);\n resolve(all);\n };\n request.onerror = () => reject(request.error);\n });\n}\n"],"names":["DB_NAME","STORE_NAME","TEMPLATES_STORE_NAME","VERSIONS_STORE_NAME","dbPromise","openDatabase","resolve","reject","request","savePersistedDocument","docId","doc","db","tx","loadPersistedDocument","deletePersistedDocument","listPersistedDocumentIds","saveTemplate","template","loadTemplate","id","deleteTemplate","listTemplates","saveDocumentVersion","version","loadDocumentVersion","deleteDocumentVersion","listDocumentVersions","all","v","a"],"mappings":"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"}
@@ -0,0 +1,335 @@
1
+ import { g as p, k as h, l as N, n as T, o as F } from "./icons-C1_s0jKK.js";
2
+ function b(t, n) {
3
+ const s = document.querySelector(`[data-run-id="${t}"]`);
4
+ if (!s) return;
5
+ s.focus();
6
+ const o = s.firstChild, e = document.createRange();
7
+ if (o && o.nodeType === 3) {
8
+ const r = Math.max(0, Math.min(n, o.length));
9
+ e.setStart(o, r), e.setEnd(o, r);
10
+ } else
11
+ e.selectNodeContents(s), e.collapse(n <= 0);
12
+ const c = window.getSelection();
13
+ c == null || c.removeAllRanges(), c == null || c.addRange(e);
14
+ }
15
+ function C(t, n) {
16
+ requestAnimationFrame(() => {
17
+ const s = document.querySelector(`[data-run-id="${t}"]`);
18
+ if (!s) return;
19
+ s.focus();
20
+ const o = document.createRange();
21
+ o.selectNodeContents(s), o.collapse(n);
22
+ const e = window.getSelection();
23
+ e == null || e.removeAllRanges(), e == null || e.addRange(o);
24
+ });
25
+ }
26
+ function R(t) {
27
+ C(t, !1);
28
+ }
29
+ function W(t) {
30
+ C(t, !0);
31
+ }
32
+ function Y(t, n) {
33
+ requestAnimationFrame(() => b(t, n));
34
+ }
35
+ function Z(t, n) {
36
+ b(t, n);
37
+ }
38
+ function L(t, n, s) {
39
+ const o = t.getBlock(n), e = o && t.getBlock(o.parentId);
40
+ if (!e) return null;
41
+ const c = e.contentIds.indexOf(n), r = s === "up" ? c - 1 : c + 1;
42
+ return r < 0 || r >= e.contentIds.length ? null : e.contentIds[r];
43
+ }
44
+ function j(t, n, s) {
45
+ let o = n;
46
+ for (; ; ) {
47
+ const e = L(t, o, s);
48
+ if (!e) return null;
49
+ const c = s === "up" ? x(t, e) : m(t, e);
50
+ if (c) return c;
51
+ o = e;
52
+ }
53
+ }
54
+ function z(t, n, s) {
55
+ const o = j(t, n, s);
56
+ o && R(o);
57
+ }
58
+ function m(t, n) {
59
+ var c;
60
+ const s = t.getBlock(n);
61
+ if (!s) return null;
62
+ const o = ((c = s.props) == null ? void 0 : c.titleRunIds) ?? s.contentIds;
63
+ if (!o || o.length === 0) return null;
64
+ const e = o[0];
65
+ return t.getRun(e) ? e : m(t, e);
66
+ }
67
+ function k(t, n) {
68
+ const s = m(t, n);
69
+ s && R(s);
70
+ }
71
+ function x(t, n) {
72
+ var c;
73
+ const s = t.getBlock(n);
74
+ if (!s) return null;
75
+ const o = ((c = s.props) == null ? void 0 : c.titleRunIds) ?? s.contentIds;
76
+ if (!o || o.length === 0) return null;
77
+ const e = o[o.length - 1];
78
+ return t.getRun(e) ? e : x(t, e);
79
+ }
80
+ function G(t, n) {
81
+ const s = x(t, n);
82
+ s && R(s);
83
+ }
84
+ const J = "​", M = /​/g;
85
+ function g(t) {
86
+ return (t ?? "").replace(M, "");
87
+ }
88
+ function B(t) {
89
+ return g(t.textContent);
90
+ }
91
+ function K(t, n) {
92
+ var l;
93
+ const s = new Map(n.map((u) => [u.id, u])), o = /* @__PURE__ */ new Set(), e = [];
94
+ let c = !0;
95
+ for (const u of t.childNodes) {
96
+ const i = u.nodeType === 1 ? (l = u.dataset) == null ? void 0 : l.runId : void 0;
97
+ if (i && s.has(i)) {
98
+ o.add(i);
99
+ const a = s.get(i);
100
+ if (a.type !== "text") {
101
+ e.push(a);
102
+ continue;
103
+ }
104
+ const f = B(u);
105
+ e.push(f === a.value ? a : { ...a, value: f });
106
+ continue;
107
+ }
108
+ c = !1;
109
+ const d = B(u);
110
+ d && e.push({ id: p(), type: "text", value: d, marks: {} });
111
+ }
112
+ if (n.some((u) => !o.has(u.id)) && (c = !1), e.length !== n.length && (c = !1), c) {
113
+ for (let u = 0; u < e.length; u += 1)
114
+ if (e[u].id !== n[u].id) {
115
+ c = !1;
116
+ break;
117
+ }
118
+ }
119
+ const r = !c || e.some((u, i) => u !== n[i]);
120
+ return { runs: e, changed: r, onlyValueChanges: c };
121
+ }
122
+ function X() {
123
+ var l, u;
124
+ const t = (l = window.getSelection) == null ? void 0 : l.call(window);
125
+ if (!t || t.rangeCount === 0) return null;
126
+ const n = t.getRangeAt(0);
127
+ if (n.collapsed || n.startContainer !== n.endContainer) return null;
128
+ const s = n.startContainer, o = s.nodeType === 1 ? s : s.parentElement, e = (u = o == null ? void 0 : o.closest) == null ? void 0 : u.call(o, "[data-run-id]");
129
+ if (!e) return null;
130
+ const c = e.closest("[data-block-id]");
131
+ if (!c) return null;
132
+ const r = s.textContent ?? "";
133
+ return {
134
+ runId: e.getAttribute("data-run-id"),
135
+ blockId: c.getAttribute("data-block-id"),
136
+ startOffset: g(r.slice(0, n.startOffset)).length,
137
+ endOffset: g(r.slice(0, n.endOffset)).length
138
+ };
139
+ }
140
+ function P(t, n) {
141
+ var l, u;
142
+ if ((t == null ? void 0 : t.nodeType) !== 1 || ((l = t.getAttribute) == null ? void 0 : l.call(t, "contenteditable")) !== "true") return null;
143
+ const s = t.childNodes;
144
+ if (s.length === 0) return null;
145
+ const o = n >= s.length, e = s[o ? s.length - 1 : Math.max(0, n)], c = (e == null ? void 0 : e.nodeType) === 1 ? (u = e.dataset) == null ? void 0 : u.runId : void 0;
146
+ if (!c) return null;
147
+ const r = e.closest("[data-block-id]");
148
+ return r ? {
149
+ runId: c,
150
+ blockId: r.getAttribute("data-block-id"),
151
+ // Raw DOM length, not the logical (placeholder-stripped) length: a run
152
+ // that started empty and was later typed into keeps a leftover
153
+ // zero-width-space byte in its actual text node forever (see
154
+ // TextRunSpan in EditableBlockContent.jsx — never rewritten, to avoid
155
+ // resetting the caret on every keystroke), even though run.value itself
156
+ // is clean. Using the raw length here would put native select-all's
157
+ // offset one character ahead of run.value.length for exactly those
158
+ // blocks, which is exactly what silently broke "is the whole block
159
+ // selected" detection for any block typed into after being created
160
+ // empty (slash-menu-created blocks, Enter-split blocks, etc.).
161
+ offset: o ? g(e.textContent ?? "").length : 0
162
+ } : null;
163
+ }
164
+ function I(t, n) {
165
+ var l;
166
+ const s = P(t, n);
167
+ if (s) return s;
168
+ let o = (t == null ? void 0 : t.nodeType) === 1 ? t : t == null ? void 0 : t.parentElement;
169
+ const e = (l = o == null ? void 0 : o.closest) == null ? void 0 : l.call(o, "[data-run-id]");
170
+ if (!e) return null;
171
+ const c = e.closest("[data-block-id]");
172
+ if (!c) return null;
173
+ let r = g((t.textContent ?? "").slice(0, n)).length;
174
+ if (t === e) {
175
+ r = 0;
176
+ for (let u = 0; u < n && u < e.childNodes.length; u += 1)
177
+ r += g(e.childNodes[u].textContent ?? "").length;
178
+ }
179
+ return {
180
+ runId: e.getAttribute("data-run-id"),
181
+ blockId: c.getAttribute("data-block-id"),
182
+ offset: r
183
+ };
184
+ }
185
+ function q() {
186
+ var n;
187
+ const t = (n = window.getSelection) == null ? void 0 : n.call(window);
188
+ return !t || t.rangeCount === 0 || !t.isCollapsed ? null : I(t.anchorNode, t.anchorOffset);
189
+ }
190
+ function tt() {
191
+ var o;
192
+ const t = (o = window.getSelection) == null ? void 0 : o.call(window);
193
+ if (!t || t.rangeCount === 0 || t.isCollapsed) return null;
194
+ const n = I(t.anchorNode, t.anchorOffset), s = I(t.focusNode, t.focusOffset);
195
+ return !n || !s || n.blockId !== s.blockId ? null : {
196
+ blockId: n.blockId,
197
+ startRunId: n.runId,
198
+ startOffset: n.offset,
199
+ endRunId: s.runId,
200
+ endOffset: s.offset
201
+ };
202
+ }
203
+ function nt(t) {
204
+ var a;
205
+ const n = (a = window.getSelection) == null ? void 0 : a.call(window);
206
+ if (!n || n.rangeCount === 0 || n.isCollapsed) return null;
207
+ const s = I(n.anchorNode, n.anchorOffset), o = I(n.focusNode, n.focusOffset);
208
+ if (!s || !o || s.blockId === o.blockId) return null;
209
+ const e = t.getBlock(s.blockId), c = e && t.getBlock(e.parentId);
210
+ if (!c) return null;
211
+ const r = c.contentIds, l = r.indexOf(s.blockId), u = r.indexOf(o.blockId);
212
+ if (l === -1 || u === -1) return null;
213
+ const [i, d] = l <= u ? [l, u] : [u, l];
214
+ return {
215
+ blockIds: r.slice(i, d + 1),
216
+ startBlockId: s.blockId,
217
+ startRunId: s.runId,
218
+ startOffset: s.offset,
219
+ endBlockId: o.blockId,
220
+ endRunId: o.runId,
221
+ endOffset: o.offset
222
+ };
223
+ }
224
+ function V(t, n, s) {
225
+ const e = t.getBlock(n).parentId, r = t.getBlock(e).contentIds.indexOf(n) + 1, { block: l, runs: u = [], subtreeBlocks: i = [] } = s(e);
226
+ return t.applyOperation(
227
+ h(l, e, r, { blocks: [l, ...i], runs: u })
228
+ ), l.id;
229
+ }
230
+ function A(t, n, s) {
231
+ const o = V(t, n, s);
232
+ return k(t, o), o;
233
+ }
234
+ function _(t, n, s) {
235
+ const { block: o, runs: e = [], subtreeBlocks: c = [] } = s(n);
236
+ return t.applyOperation(
237
+ h(o, n, 0, { blocks: [o, ...c], runs: e })
238
+ ), k(t, o.id), o.id;
239
+ }
240
+ function O(t, n) {
241
+ if (typeof t.performBatch == "function")
242
+ t.performBatch(n);
243
+ else
244
+ for (const s of n) t.applyOperation(s);
245
+ }
246
+ function D(t, n, s) {
247
+ const o = t.findIndex((i) => i.id === n);
248
+ if (o === -1) return null;
249
+ const e = t[o], c = t.slice(0, o), r = t.slice(o + 1);
250
+ if (e.type === "text") {
251
+ const i = e.value ?? "", d = i.slice(0, s), a = i.slice(s);
252
+ d && a ? (c.push({ ...e, value: d }), r.unshift({ ...e, id: p(), value: a })) : a ? r.unshift(e) : c.push(e);
253
+ } else s > 0 ? c.push(e) : r.unshift(e);
254
+ const l = c.length ? c : [{ id: p(), type: "text", value: "", marks: {} }], u = r.length ? r : [{ id: p(), type: "text", value: "", marks: {} }];
255
+ return { leftRuns: l, rightRuns: u };
256
+ }
257
+ function et(t, n, s, o) {
258
+ const e = t.getBlock(n), c = t.getBlock(e.parentId), r = c.contentIds.indexOf(n) + 1;
259
+ return v(t, n, s, o, {
260
+ insertParentId: c.id,
261
+ insertIndex: r,
262
+ fallback: () => A(t, n, o)
263
+ });
264
+ }
265
+ function st(t, n, s, o) {
266
+ return v(t, n, s, o, {
267
+ insertParentId: n,
268
+ insertIndex: 0,
269
+ fallback: () => _(t, n, o)
270
+ });
271
+ }
272
+ function v(t, n, s, o, { insertParentId: e, insertIndex: c, fallback: r }) {
273
+ const l = q();
274
+ if (!l || l.blockId !== n) return r();
275
+ const u = s.map((E) => t.getRun(E)).filter(Boolean), i = D(u, l.runId, l.offset);
276
+ if (!i) return r();
277
+ const { leftRuns: d, rightRuns: a } = i, { block: f, runs: y = a, subtreeBlocks: S = [] } = o(e, a), w = d.length ? d : [{ id: p(), type: "text", value: "", marks: {} }];
278
+ return O(t, [
279
+ F(n, w),
280
+ h(f, e, c, { blocks: [f, ...S], runs: y })
281
+ ]), k(t, f.id), f.id;
282
+ }
283
+ function H(t) {
284
+ var n;
285
+ return ((n = t == null ? void 0 : t.props) == null ? void 0 : n.titleRunIds) ?? (t == null ? void 0 : t.contentIds) ?? [];
286
+ }
287
+ function $(t) {
288
+ var n, s;
289
+ return !!((n = t == null ? void 0 : t.props) != null && n.titleRunIds) && (((s = t.contentIds) == null ? void 0 : s.length) ?? 0) > 0;
290
+ }
291
+ function Q(t, n, s) {
292
+ const e = t.getBlock(n).parentId, r = t.getBlock(e).contentIds.indexOf(n), { block: l, runs: u = [], subtreeBlocks: i = [] } = s(e);
293
+ return O(t, [
294
+ T(n),
295
+ h(l, e, r, { blocks: [l, ...i], runs: u })
296
+ ]), k(t, l.id), l.id;
297
+ }
298
+ function ot(t, { blockId: n, runId: s, sliceStart: o, sliceEnd: e }, c) {
299
+ const r = t.getRun(s), l = (r == null ? void 0 : r.value) ?? "", u = l.slice(0, o) + l.slice(e), i = t.getBlock(n), d = H(i);
300
+ return d.length === 1 && d[0] === s && u === "" && !$(i) ? Q(t, n, c) : (t.applyOperation(N(s, { value: u })), A(t, n, c));
301
+ }
302
+ function ct(t, n = {}) {
303
+ return function(o, e) {
304
+ const c = p(), r = e != null && e.length ? e : [{ id: p(), type: "text", value: "", marks: {} }];
305
+ return {
306
+ block: { id: c, type: t, parentId: o, contentIds: r.map((l) => l.id), props: n },
307
+ runs: r
308
+ };
309
+ };
310
+ }
311
+ export {
312
+ J as E,
313
+ k as a,
314
+ W as b,
315
+ ct as c,
316
+ V as d,
317
+ G as e,
318
+ Y as f,
319
+ tt as g,
320
+ nt as h,
321
+ A as i,
322
+ R as j,
323
+ X as k,
324
+ g as l,
325
+ K as m,
326
+ x as n,
327
+ et as o,
328
+ z as p,
329
+ st as q,
330
+ q as r,
331
+ Z as s,
332
+ ot as t,
333
+ j as u
334
+ };
335
+ //# sourceMappingURL=leafBlockFactory-A9eUhSe-.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"leafBlockFactory-A9eUhSe-.js","sources":["../../src/react/focusRun.js","../../src/blocks/shared/navigationCommands.js","../../src/react/domRunSync.js","../../src/react/selectionResolve.js","../../src/blocks/shared/blockCommands.js","../../src/blocks/shared/leafBlockFactory.js"],"sourcesContent":["function setCaretAtOffsetNow(runId, offset) {\n const el = document.querySelector(`[data-run-id=\"${runId}\"]`);\n if (!el) return;\n el.focus();\n const textNode = el.firstChild;\n const range = document.createRange();\n if (textNode && textNode.nodeType === 3) {\n const clamped = Math.max(0, Math.min(offset, textNode.length));\n range.setStart(textNode, clamped);\n range.setEnd(textNode, clamped);\n } else {\n range.selectNodeContents(el);\n range.collapse(offset <= 0);\n }\n const selection = window.getSelection();\n selection?.removeAllRanges();\n selection?.addRange(range);\n}\n\nfunction focusRunAt(runId, atStart) {\n requestAnimationFrame(() => {\n const el = document.querySelector(`[data-run-id=\"${runId}\"]`);\n if (!el) return;\n el.focus();\n const range = document.createRange();\n range.selectNodeContents(el);\n range.collapse(atStart);\n const selection = window.getSelection();\n selection?.removeAllRanges();\n selection?.addRange(range);\n });\n}\n\n/** Best-effort: move DOM focus + caret to the end of the given run's editable element. */\nexport function focusRunEnd(runId) {\n focusRunAt(runId, false);\n}\n\n/** Best-effort: move DOM focus + caret to the start of the given run's editable element. */\nexport function focusRunStart(runId) {\n focusRunAt(runId, true);\n}\n\n/**\n * Best-effort: move DOM focus + caret to a specific character offset within\n * the given (text) run — deferred to the next animation frame, since most\n * callers use this right after a structural change (a new block/run that\n * may not exist in the DOM yet on this exact tick).\n */\nexport function focusRunAtOffset(runId, offset) {\n requestAnimationFrame(() => setCaretAtOffsetNow(runId, offset));\n}\n\n/**\n * Synchronous (no requestAnimationFrame) variant of focusRunAtOffset —\n * for the one call site (voice dictation's live interim-text hot path,\n * see useVoiceTyping.js) where the target run's DOM node is already\n * known to exist and has *already* been synchronously rewritten by the\n * time this is called. Deferring here would leave a window where a\n * rapid-fire next event reads the selection before it's been fixed,\n * which is exactly the caret-corruption bug this exists to avoid — every\n * other call site should keep using the rAF-deferred focusRunAtOffset\n * above.\n */\nexport function setCaretSync(runId, offset) {\n setCaretAtOffsetNow(runId, offset);\n}\n","import { focusRunEnd } from '../../react/focusRun.js';\n\nfunction adjacentSiblingId(store, blockId, direction) {\n const block = store.getBlock(blockId);\n const parent = block && store.getBlock(block.parentId);\n if (!parent) return null;\n const index = parent.contentIds.indexOf(blockId);\n const adjacentIndex = direction === 'up' ? index - 1 : index + 1;\n if (adjacentIndex < 0 || adjacentIndex >= parent.contentIds.length) return null;\n return parent.contentIds[adjacentIndex];\n}\n\n/**\n * Resolves which run id should receive focus when moving from `blockId` in\n * `direction` ('up' | 'down') — pure logic, no DOM, so it's directly\n * testable. When the adjacent sibling is a container with actual content\n * (a table with rows, a layout with columns holding blocks), this *enters*\n * it — landing in its first cell/child when moving down, or its last when\n * moving up — via resolveBlockFirstRun/resolveBlockLastRun. Only a sibling\n * with truly nothing focusable at all (a divider, or an empty table with\n * zero rows) gets skipped over entirely, continuing the search to the next\n * sibling after it.\n */\nexport function resolveAdjacentFocusTarget(store, blockId, direction) {\n let currentId = blockId;\n while (true) {\n const adjacentId = adjacentSiblingId(store, currentId, direction);\n if (!adjacentId) return null;\n const runId =\n direction === 'up'\n ? resolveBlockLastRun(store, adjacentId)\n : resolveBlockFirstRun(store, adjacentId);\n if (runId) return runId;\n currentId = adjacentId; // truly empty (no rows/children at all): keep walking past it\n }\n}\n\n/** Moves focus to the nearest focusable sibling block's text in `direction` (see resolveAdjacentFocusTarget). */\nexport function focusAdjacentBlock(store, blockId, direction) {\n const targetRunId = resolveAdjacentFocusTarget(store, blockId, direction);\n if (targetRunId) focusRunEnd(targetRunId);\n}\n\n/**\n * Resolves the first directly-focusable run inside `blockId`, descending\n * into containers as needed — a leaf's own contentIds/titleRunIds are\n * already run ids, but a table's contentIds are row *block* ids (recurse\n * into the first row, then its first cell, then that cell's runs), and\n * likewise for a layout's columns. Used to focus into a block right after\n * it's created (Enter, a slash command), so the caret always lands\n * somewhere typeable instead of staying on the block that triggered it.\n */\nexport function resolveBlockFirstRun(store, blockId) {\n const block = store.getBlock(blockId);\n if (!block) return null;\n const runIds = block.props?.titleRunIds ?? block.contentIds;\n if (!runIds || runIds.length === 0) return null;\n const firstId = runIds[0];\n if (store.getRun(firstId)) return firstId; // a leaf's ids are runs directly\n return resolveBlockFirstRun(store, firstId); // a container's ids are child blocks: recurse\n}\n\n/** Moves focus to the first typeable position inside `blockId` (see resolveBlockFirstRun). */\nexport function focusBlockStart(store, blockId) {\n const runId = resolveBlockFirstRun(store, blockId);\n if (runId) focusRunEnd(runId);\n}\n\n/** Symmetric to resolveBlockFirstRun: the last directly-focusable run inside `blockId`, descending into containers' last child. */\nexport function resolveBlockLastRun(store, blockId) {\n const block = store.getBlock(blockId);\n if (!block) return null;\n const runIds = block.props?.titleRunIds ?? block.contentIds;\n if (!runIds || runIds.length === 0) return null;\n const lastId = runIds[runIds.length - 1];\n if (store.getRun(lastId)) return lastId;\n return resolveBlockLastRun(store, lastId);\n}\n\n/** Moves focus to the last typeable position inside `blockId` (see resolveBlockLastRun). */\nexport function focusBlockEnd(store, blockId) {\n const runId = resolveBlockLastRun(store, blockId);\n if (runId) focusRunEnd(runId);\n}\n","import { genId } from '../utils/idGen.js';\n\n/**\n * A completely empty `<span></span>` (no text node at all) is not a valid\n * caret anchor in many browsers' contentEditable implementation: clicking\n * into it places the caret at the *container* level instead, and typing\n * then inserts a brand-new text node as a *sibling* of the empty span\n * rather than inside it. That stray node is never one React created, so it\n * becomes invisible to React's reconciliation from that point on — every\n * subsequent keystroke reads a DOM that's drifted further from what React\n * thinks it rendered, which is what produced runaway duplicated/shrinking\n * text. The fix (the same one Slate/Lexical use) is to never render a\n * truly empty text node: an empty run gets this zero-width-space\n * placeholder instead, giving the browser a real anchor, and it's stripped\n * back out whenever DOM text is read back into a run's logical value.\n */\nexport const EMPTY_RUN_PLACEHOLDER = '​';\n\nconst ZERO_WIDTH_SPACE_RE = /​/g;\n\n/** Strips the placeholder out of a string, however many times it appears. */\nexport function stripEmptyRunPlaceholder(text) {\n return (text ?? '').replace(ZERO_WIDTH_SPACE_RE, '');\n}\n\nfunction readRunText(node) {\n return stripEmptyRunPlaceholder(node.textContent);\n}\n\n/**\n * Reconciles a contentEditable container's *actual current* child nodes\n * back against the run list it was last rendered with. This is what makes\n * one shared contentEditable region per block work: React renders each run\n * as a child (a plain `<span data-run-id>` for text, an atomic\n * `contentEditable={false}` island for a non-text inline type), the browser\n * mutates that DOM natively as the user types/deletes/pastes, and this\n * function reads the result back into run objects on the container's\n * `input` event.\n *\n * Fast path (`onlyValueChanges: true`): every child still has the same\n * data-run-id, in the same order, and only text values differ — the\n * common case for ordinary typing, since the browser's native text edit\n * stays inside the existing span whose data-run-id attribute survives\n * untouched. Callers should apply per-run `updateRun` ops in this case, to\n * preserve History's per-run undo coalescing.\n *\n * Slow path (`onlyValueChanges: false`): node(s) appeared/disappeared/\n * reordered — e.g. paste, IME composition boundaries, or an atomic inline\n * chip being deleted as a whole unit. Callers should apply one\n * `setBlockRuns` op (see operations.js) as a single coarser undo step.\n *\n * Atomic (non-text) runs are matched by id only and never have their value\n * re-derived from DOM text content — they render their own UI, not plain\n * text, so `textContent` isn't a meaningful \"value\" for them.\n */\nexport function reconcileDomToRuns(containerEl, currentRuns) {\n const byId = new Map(currentRuns.map((run) => [run.id, run]));\n const seen = new Set();\n const nextRuns = [];\n let sameIdentityAndOrder = true;\n\n for (const node of containerEl.childNodes) {\n const runId = node.nodeType === 1 ? node.dataset?.runId : undefined;\n\n if (runId && byId.has(runId)) {\n seen.add(runId);\n const existing = byId.get(runId);\n\n if (existing.type !== 'text') {\n nextRuns.push(existing); // atomic: identity-only, never re-derive from DOM\n continue;\n }\n\n const newValue = readRunText(node);\n nextRuns.push(newValue === existing.value ? existing : { ...existing, value: newValue });\n continue;\n }\n\n // No existing run matches this DOM node at all: a structural change\n // (new text node from typing at a boundary, paste, IME, etc.).\n sameIdentityAndOrder = false;\n const text = readRunText(node);\n if (text) nextRuns.push({ id: genId(), type: 'text', value: text, marks: {} });\n }\n\n if (currentRuns.some((run) => !seen.has(run.id))) sameIdentityAndOrder = false; // a run's node vanished\n if (nextRuns.length !== currentRuns.length) sameIdentityAndOrder = false;\n if (sameIdentityAndOrder) {\n for (let i = 0; i < nextRuns.length; i += 1) {\n if (nextRuns[i].id !== currentRuns[i].id) {\n sameIdentityAndOrder = false;\n break;\n }\n }\n }\n\n const changed = !sameIdentityAndOrder || nextRuns.some((run, i) => run !== currentRuns[i]);\n\n return { runs: nextRuns, changed, onlyValueChanges: sameIdentityAndOrder };\n}\n","import { stripEmptyRunPlaceholder } from './domRunSync.js';\n\n/**\n * v1 scope: resolves the native selection only when it's a non-collapsed\n * range entirely within one run's single text node — matches the same\n * single-run limitation as toggleMarkOnRunRange and the clipboard range\n * resolution. Returns null for collapsed selections or ranges spanning\n * multiple runs/blocks.\n */\nexport function resolveRunSelection() {\n const selection = window.getSelection?.();\n if (!selection || selection.rangeCount === 0) return null;\n const range = selection.getRangeAt(0);\n if (range.collapsed || range.startContainer !== range.endContainer) return null;\n\n const container = range.startContainer;\n const el = container.nodeType === 1 ? container : container.parentElement;\n const runEl = el?.closest?.('[data-run-id]');\n if (!runEl) return null;\n const blockEl = runEl.closest('[data-block-id]');\n if (!blockEl) return null;\n\n const rawText = container.textContent ?? '';\n return {\n runId: runEl.getAttribute('data-run-id'),\n blockId: blockEl.getAttribute('data-block-id'),\n startOffset: stripEmptyRunPlaceholder(rawText.slice(0, range.startOffset)).length,\n endOffset: stripEmptyRunPlaceholder(rawText.slice(0, range.endOffset)).length,\n };\n}\n\n/**\n * Native selection gestures that don't drill into a specific run's text\n * node — Ctrl+A \"select all\" within one contentEditable region is the main\n * one — anchor directly on the shared contentEditable container instead,\n * addressing by child-index rather than character offset. Without this,\n * detecting \"the whole current block is already selected\" (the trigger for\n * promoting a second Ctrl+A to a whole-document selection) silently fails\n * for exactly the selection shape native select-all actually produces.\n */\nfunction resolveContainerLevelSelection(node, offset) {\n if (node?.nodeType !== 1 || node.getAttribute?.('contenteditable') !== 'true') return null;\n const children = node.childNodes;\n if (children.length === 0) return null;\n\n const atEnd = offset >= children.length;\n const child = children[atEnd ? children.length - 1 : Math.max(0, offset)];\n const runId = child?.nodeType === 1 ? child.dataset?.runId : undefined;\n if (!runId) return null;\n const blockEl = child.closest('[data-block-id]');\n if (!blockEl) return null;\n\n return {\n runId,\n blockId: blockEl.getAttribute('data-block-id'),\n // Raw DOM length, not the logical (placeholder-stripped) length: a run\n // that started empty and was later typed into keeps a leftover\n // zero-width-space byte in its actual text node forever (see\n // TextRunSpan in EditableBlockContent.jsx — never rewritten, to avoid\n // resetting the caret on every keystroke), even though run.value itself\n // is clean. Using the raw length here would put native select-all's\n // offset one character ahead of run.value.length for exactly those\n // blocks, which is exactly what silently broke \"is the whole block\n // selected\" detection for any block typed into after being created\n // empty (slash-menu-created blocks, Enter-split blocks, etc.).\n offset: atEnd ? stripEmptyRunPlaceholder(child.textContent ?? '').length : 0,\n };\n}\n\nfunction resolveRunAndOffset(node, offset) {\n const containerLevel = resolveContainerLevelSelection(node, offset);\n if (containerLevel) return containerLevel;\n\n let el = node?.nodeType === 1 ? node : node?.parentElement;\n const runEl = el?.closest?.('[data-run-id]');\n if (!runEl) return null;\n const blockEl = runEl.closest('[data-block-id]');\n if (!blockEl) return null;\n\n // `offset` is a raw DOM char index when node is the run's own text node;\n // when the selection anchors on the run element itself (e.g. an empty/\n // atomic island), it's a child-node index instead — convert to a char\n // count. Either way, strip any leftover placeholder byte so the result\n // lines up with run.value.length (see the matching comment in\n // resolveContainerLevelSelection above — same underlying cause).\n let charOffset = stripEmptyRunPlaceholder((node.textContent ?? '').slice(0, offset)).length;\n if (node === runEl) {\n charOffset = 0;\n for (let i = 0; i < offset && i < runEl.childNodes.length; i += 1) {\n charOffset += stripEmptyRunPlaceholder(runEl.childNodes[i].textContent ?? '').length;\n }\n }\n\n return {\n runId: runEl.getAttribute('data-run-id'),\n blockId: blockEl.getAttribute('data-block-id'),\n offset: charOffset,\n };\n}\n\n/**\n * Resolves a *collapsed* caret to the run+char-offset it sits at — used by\n * Enter-to-split so the new block gets exactly the text after the caret,\n * instead of always starting blank. Returns null for a non-collapsed\n * selection or a caret that isn't inside any run at all.\n */\nexport function resolveCollapsedCaret() {\n const selection = window.getSelection?.();\n if (!selection || selection.rangeCount === 0 || !selection.isCollapsed) return null;\n return resolveRunAndOffset(selection.anchorNode, selection.anchorOffset);\n}\n\n/**\n * Resolves a non-collapsed selection that may span *multiple runs within\n * the same block* (e.g. selecting text that crosses a bold boundary) —\n * generalizes resolveRunSelection's single-run limitation. Returns null if\n * the selection spans multiple blocks (use resolveCrossBlockSelection for\n * that) or if either end isn't inside a run at all.\n */\nexport function resolveMultiRunSelection() {\n const selection = window.getSelection?.();\n if (!selection || selection.rangeCount === 0 || selection.isCollapsed) return null;\n\n const anchor = resolveRunAndOffset(selection.anchorNode, selection.anchorOffset);\n const focus = resolveRunAndOffset(selection.focusNode, selection.focusOffset);\n if (!anchor || !focus) return null;\n if (anchor.blockId !== focus.blockId) return null; // cross-block: use resolveCrossBlockSelection\n\n return {\n blockId: anchor.blockId,\n startRunId: anchor.runId,\n startOffset: anchor.offset,\n endRunId: focus.runId,\n endOffset: focus.offset,\n };\n}\n\n/**\n * Resolves a non-collapsed selection spanning *multiple sibling blocks*\n * under a shared parent (e.g. from the middle of one paragraph through the\n * middle of another a few blocks down) — for toggleMarkOverBlockRange.\n * Needs `store` (unlike the other resolvers here) to walk the parent's\n * contentIds and slice out the sibling range. Returns null when the\n * selection is actually within one block (use resolveMultiRunSelection\n * instead), or when the two blocks aren't siblings under the same parent\n * (nested at different depths — not supported in v1).\n */\nexport function resolveCrossBlockSelection(store) {\n const selection = window.getSelection?.();\n if (!selection || selection.rangeCount === 0 || selection.isCollapsed) return null;\n\n const anchor = resolveRunAndOffset(selection.anchorNode, selection.anchorOffset);\n const focus = resolveRunAndOffset(selection.focusNode, selection.focusOffset);\n if (!anchor || !focus) return null;\n if (anchor.blockId === focus.blockId) return null; // same block: use resolveMultiRunSelection\n\n const startBlock = store.getBlock(anchor.blockId);\n const parent = startBlock && store.getBlock(startBlock.parentId);\n if (!parent) return null;\n\n const ids = parent.contentIds;\n const i1 = ids.indexOf(anchor.blockId);\n const i2 = ids.indexOf(focus.blockId);\n if (i1 === -1 || i2 === -1) return null; // not siblings under the same parent\n\n const [from, to] = i1 <= i2 ? [i1, i2] : [i2, i1];\n\n return {\n blockIds: ids.slice(from, to + 1),\n startBlockId: anchor.blockId,\n startRunId: anchor.runId,\n startOffset: anchor.offset,\n endBlockId: focus.blockId,\n endRunId: focus.runId,\n endOffset: focus.offset,\n };\n}\n","import { insertBlock, updateRun, setBlockRuns, removeBlock } from '../../store/operations.js';\nimport { focusBlockStart } from './navigationCommands.js';\nimport { resolveCollapsedCaret } from '../../react/selectionResolve.js';\nimport { genId } from '../../utils/idGen.js';\n\n/**\n * Inserts a new block immediately after `currentBlockId`, as a sibling under\n * the same parent. `factory(parentId)` must return `{ block, runs, subtreeBlocks }`\n * — `runs` may be empty for non-leaf types, and `subtreeBlocks` (default [])\n * holds any additional descendant blocks for multi-level inserts (e.g. a\n * table's rows/cells alongside its own root block). Shared by every block\n * type's slash command so \"where do I insert relative to the current block\"\n * is written once.\n */\nexport function insertSiblingAfter(store, currentBlockId, factory) {\n const current = store.getBlock(currentBlockId);\n const parentId = current.parentId;\n const parent = store.getBlock(parentId);\n const index = parent.contentIds.indexOf(currentBlockId) + 1;\n const { block, runs = [], subtreeBlocks = [] } = factory(parentId);\n store.applyOperation(\n insertBlock(block, parentId, index, { blocks: [block, ...subtreeBlocks], runs }),\n );\n return block.id;\n}\n\n/**\n * Same as insertSiblingAfter, but also moves focus into the new block —\n * every editor does this (Enter, or picking a block from the slash menu,\n * always lands the caret in the thing you just created, never leaves it on\n * the block you triggered it from). Descends into containers (table,\n * layout) to find the first actually-typeable position.\n */\nexport function insertSiblingAfterAndFocus(store, currentBlockId, factory) {\n const newBlockId = insertSiblingAfter(store, currentBlockId, factory);\n focusBlockStart(store, newBlockId);\n return newBlockId;\n}\n\n/**\n * Inserts a new block as the *first child* of `parentBlockId` and focuses\n * it. Used when a container block (a list item with nested items beneath\n * it) needs the new block to appear visually right after the parent's own\n * content but before its existing children — since children render\n * *inside* the parent's own DOM subtree, a \"sibling in the grandparent's\n * array\" would only ever land after that whole subtree, not between the\n * parent's title and its first child.\n */\nexport function insertFirstChildAndFocus(store, parentBlockId, factory) {\n const { block, runs = [], subtreeBlocks = [] } = factory(parentBlockId);\n store.applyOperation(\n insertBlock(block, parentBlockId, 0, { blocks: [block, ...subtreeBlocks], runs }),\n );\n focusBlockStart(store, block.id);\n return block.id;\n}\n\nfunction applyOps(store, ops) {\n if (typeof store.performBatch === 'function') {\n store.performBatch(ops);\n } else {\n for (const op of ops) store.applyOperation(op);\n }\n}\n\n/**\n * Pure: splits an ordered list of Run objects at `caretRunId`/`caretOffset`\n * into \"everything before the caret\" and \"everything at/after it\",\n * splitting the caret's own run in two when it's a text run with content on\n * both sides. Identity is preserved wherever possible (a run that doesn't\n * actually get cut keeps its id) so only a genuine mid-run split spends a\n * new id. Neither side is ever left with zero runs — a block needs at least\n * one run to render/anchor a caret in, so an empty side gets a fresh blank\n * text run.\n */\nexport function splitRunsAtCaret(runs, caretRunId, caretOffset) {\n const idx = runs.findIndex((r) => r.id === caretRunId);\n if (idx === -1) return null;\n\n const caretRun = runs[idx];\n const before = runs.slice(0, idx);\n const after = runs.slice(idx + 1);\n\n if (caretRun.type === 'text') {\n const value = caretRun.value ?? '';\n const leftValue = value.slice(0, caretOffset);\n const rightValue = value.slice(caretOffset);\n if (leftValue && rightValue) {\n before.push({ ...caretRun, value: leftValue });\n after.unshift({ ...caretRun, id: genId(), value: rightValue });\n } else if (rightValue) {\n after.unshift(caretRun); // caret at the run's start: whole run moves right, unchanged\n } else {\n before.push(caretRun); // caret at the run's end (or run already empty): stays left, unchanged\n }\n } else if (caretOffset > 0) {\n before.push(caretRun); // atomic run: never split inside it, only before/after\n } else {\n after.unshift(caretRun);\n }\n\n const leftRuns = before.length ? before : [{ id: genId(), type: 'text', value: '', marks: {} }];\n const rightRuns = after.length ? after : [{ id: genId(), type: 'text', value: '', marks: {} }];\n return { leftRuns, rightRuns };\n}\n\n/**\n * Enter-to-split: every real editor splits the block's content at the\n * caret (text before stays, text after moves into the new sibling) rather\n * than always creating a blank sibling and leaving all the text behind.\n * Falls back to the old \"just append an empty sibling\" behavior when there\n * is no resolvable live caret in this exact block (no DOM selection at all,\n * as in most non-interactive tests, or a caret that landed somewhere else).\n *\n * `currentRunIds` must be the block's own run ids (contentIds for a plain\n * leaf, props.titleRunIds for a listItem) — same convention as\n * EditableBlockContent's `runIds` prop. `factory(parentId, initialRuns?)`\n * must accept the optional pre-built run list (see createTextLeafBlock/\n * createListItemBlock).\n */\nexport function insertSiblingSplitAtCaretAndFocus(store, blockId, currentRunIds, factory) {\n const current = store.getBlock(blockId);\n const parent = store.getBlock(current.parentId);\n const index = parent.contentIds.indexOf(blockId) + 1;\n return splitAndInsertAtCaret(store, blockId, currentRunIds, factory, {\n insertParentId: parent.id,\n insertIndex: index,\n fallback: () => insertSiblingAfterAndFocus(store, blockId, factory),\n });\n}\n\n/**\n * Same idea as insertSiblingSplitAtCaretAndFocus, but for the \"this item has\n * nested children\" case (see insertFirstChildAndFocus): the new block's\n * content is the split-off right-hand runs, and it lands as the first child\n * of `blockId` itself (whose own title runs get truncated to the left half)\n * rather than as its sibling.\n */\nexport function insertFirstChildSplitAtCaretAndFocus(store, blockId, currentRunIds, factory) {\n return splitAndInsertAtCaret(store, blockId, currentRunIds, factory, {\n insertParentId: blockId,\n insertIndex: 0,\n fallback: () => insertFirstChildAndFocus(store, blockId, factory),\n });\n}\n\nfunction splitAndInsertAtCaret(\n store,\n blockId,\n currentRunIds,\n factory,\n { insertParentId, insertIndex, fallback },\n) {\n const caret = resolveCollapsedCaret();\n if (!caret || caret.blockId !== blockId) return fallback();\n\n const currentRuns = currentRunIds.map((id) => store.getRun(id)).filter(Boolean);\n const split = splitRunsAtCaret(currentRuns, caret.runId, caret.offset);\n if (!split) return fallback();\n\n const { leftRuns, rightRuns } = split;\n const { block, runs = rightRuns, subtreeBlocks = [] } = factory(insertParentId, rightRuns);\n\n // Enter at the very start of a block's content leaves nothing before the\n // caret, so leftRuns comes back empty — but the block staying behind\n // must never end up with zero runs: an empty contentEditable region isn't\n // a valid caret anchor in most browsers, so the next time someone types\n // into it, every keystroke mints a brand-new run instead of updating one\n // in place (the same \"characters double\" bug this exact guard fixes for\n // removeRun/handleInput in EditableBlockContent).\n const survivingLeftRuns = leftRuns.length\n ? leftRuns\n : [{ id: genId(), type: 'text', value: '', marks: {} }];\n\n applyOps(store, [\n setBlockRuns(blockId, survivingLeftRuns),\n insertBlock(block, insertParentId, insertIndex, { blocks: [block, ...subtreeBlocks], runs }),\n ]);\n focusBlockStart(store, block.id);\n return block.id;\n}\n\nfunction getOwnRunIds(block) {\n return block?.props?.titleRunIds ?? block?.contentIds ?? [];\n}\n\n// A listItem's own text lives in props.titleRunIds while contentIds holds\n// its nested child *blocks* — so for it (and any other block shaped that\n// way), contentIds having entries means it has children, not extra runs.\nfunction hasNestedChildren(block) {\n return Boolean(block?.props?.titleRunIds) && (block.contentIds?.length ?? 0) > 0;\n}\n\n/**\n * Converts an empty block in place to a different type, instead of leaving\n * the old empty block behind with a new sibling after it — e.g. picking\n * \"Heading\" from the slash menu on a still-empty paragraph turns that same\n * paragraph into the heading, rather than inserting a heading after an\n * orphaned blank paragraph. Removes the old block and inserts the new one\n * at the same index as one atomic step, so undo/redo treats it as a single\n * operation.\n */\nfunction replaceBlockInPlace(store, blockId, factory) {\n const current = store.getBlock(blockId);\n const parentId = current.parentId;\n const parent = store.getBlock(parentId);\n const index = parent.contentIds.indexOf(blockId);\n const { block, runs = [], subtreeBlocks = [] } = factory(parentId);\n\n applyOps(store, [\n removeBlock(blockId),\n insertBlock(block, parentId, index, { blocks: [block, ...subtreeBlocks], runs }),\n ]);\n focusBlockStart(store, block.id);\n return block.id;\n}\n\n/**\n * Slash-command entry point for block-level commands: removes the\n * \"/query\" span from the triggering run (merging whatever was before and\n * after it — a block command doesn't need to preserve a split point the\n * way an inline command does, since it's creating an entirely separate\n * sibling block, not splicing into this one).\n *\n * If trimming the query leaves the block completely empty — it was the\n * block's only run and the block has no nested children — the block is\n * converted in place (replaceBlockInPlace) rather than inserted after,\n * which would otherwise leave a pointless empty block sitting above the\n * one the user actually meant to create. Otherwise, behaves as before:\n * trims the query and inserts+focuses the new block after the current one.\n */\nexport function trimSlashQueryAndInsertAfter(\n store,\n { blockId, runId, sliceStart, sliceEnd },\n factory,\n) {\n const run = store.getRun(runId);\n const value = run?.value ?? '';\n const newValue = value.slice(0, sliceStart) + value.slice(sliceEnd);\n\n const block = store.getBlock(blockId);\n const ownRunIds = getOwnRunIds(block);\n const isOnlyRun = ownRunIds.length === 1 && ownRunIds[0] === runId;\n const wouldBeEmpty = isOnlyRun && newValue === '' && !hasNestedChildren(block);\n\n if (wouldBeEmpty) {\n return replaceBlockInPlace(store, blockId, factory);\n }\n\n store.applyOperation(updateRun(runId, { value: newValue }));\n return insertSiblingAfterAndFocus(store, blockId, factory);\n}\n","import { genId } from '../../utils/idGen.js';\n\n/**\n * Builds a factory(parentId, initialRuns?) -> {block, runs} for a text leaf\n * block. Most callers (slash commands) omit `initialRuns` and get a single\n * blank run; Enter-to-split passes the runs that landed after the caret so\n * the new block starts with that text instead of empty.\n */\nexport function createTextLeafBlock(type, props = {}) {\n return function factory(parentId, initialRuns) {\n const blockId = genId();\n const runs = initialRuns?.length\n ? initialRuns\n : [{ id: genId(), type: 'text', value: '', marks: {} }];\n return {\n block: { id: blockId, type, parentId, contentIds: runs.map((r) => r.id), props },\n runs,\n };\n };\n}\n"],"names":["setCaretAtOffsetNow","runId","offset","el","textNode","range","clamped","selection","focusRunAt","atStart","focusRunEnd","focusRunStart","focusRunAtOffset","setCaretSync","adjacentSiblingId","store","blockId","direction","block","parent","index","adjacentIndex","resolveAdjacentFocusTarget","currentId","adjacentId","resolveBlockLastRun","resolveBlockFirstRun","focusAdjacentBlock","targetRunId","runIds","_a","firstId","focusBlockStart","lastId","focusBlockEnd","EMPTY_RUN_PLACEHOLDER","ZERO_WIDTH_SPACE_RE","stripEmptyRunPlaceholder","text","readRunText","node","reconcileDomToRuns","containerEl","currentRuns","byId","run","seen","nextRuns","sameIdentityAndOrder","existing","newValue","genId","i","changed","resolveRunSelection","container","runEl","_b","blockEl","rawText","resolveContainerLevelSelection","children","atEnd","child","resolveRunAndOffset","containerLevel","charOffset","resolveCollapsedCaret","resolveMultiRunSelection","anchor","focus","resolveCrossBlockSelection","startBlock","ids","i1","i2","from","to","insertSiblingAfter","currentBlockId","factory","parentId","runs","subtreeBlocks","insertBlock","insertSiblingAfterAndFocus","newBlockId","insertFirstChildAndFocus","parentBlockId","applyOps","ops","op","splitRunsAtCaret","caretRunId","caretOffset","idx","r","caretRun","before","after","value","leftValue","rightValue","leftRuns","rightRuns","insertSiblingSplitAtCaretAndFocus","currentRunIds","current","splitAndInsertAtCaret","insertFirstChildSplitAtCaretAndFocus","insertParentId","insertIndex","fallback","caret","id","split","survivingLeftRuns","setBlockRuns","getOwnRunIds","hasNestedChildren","replaceBlockInPlace","removeBlock","trimSlashQueryAndInsertAfter","sliceStart","sliceEnd","ownRunIds","updateRun","createTextLeafBlock","type","props","initialRuns"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ "use strict";const a=require("./icons-DtCsXuU6.cjs");function m(t,n){const o=document.querySelector(`[data-run-id="${t}"]`);if(!o)return;o.focus();const s=o.firstChild,e=document.createRange();if(s&&s.nodeType===3){const r=Math.max(0,Math.min(n,s.length));e.setStart(s,r),e.setEnd(s,r)}else e.selectNodeContents(o),e.collapse(n<=0);const c=window.getSelection();c==null||c.removeAllRanges(),c==null||c.addRange(e)}function x(t,n){requestAnimationFrame(()=>{const o=document.querySelector(`[data-run-id="${t}"]`);if(!o)return;o.focus();const s=document.createRange();s.selectNodeContents(o),s.collapse(n);const e=window.getSelection();e==null||e.removeAllRanges(),e==null||e.addRange(s)})}function k(t){x(t,!1)}function F(t){x(t,!0)}function L(t,n){requestAnimationFrame(()=>m(t,n))}function P(t,n){m(t,n)}function M(t,n,o){const s=t.getBlock(n),e=s&&t.getBlock(s.parentId);if(!e)return null;const c=e.contentIds.indexOf(n),r=o==="up"?c-1:c+1;return r<0||r>=e.contentIds.length?null:e.contentIds[r]}function S(t,n,o){let s=n;for(;;){const e=M(t,s,o);if(!e)return null;const c=o==="up"?R(t,e):A(t,e);if(c)return c;s=e}}function j(t,n,o){const s=S(t,n,o);s&&k(s)}function A(t,n){var c;const o=t.getBlock(n);if(!o)return null;const s=((c=o.props)==null?void 0:c.titleRunIds)??o.contentIds;if(!s||s.length===0)return null;const e=s[0];return t.getRun(e)?e:A(t,e)}function h(t,n){const o=A(t,n);o&&k(o)}function R(t,n){var c;const o=t.getBlock(n);if(!o)return null;const s=((c=o.props)==null?void 0:c.titleRunIds)??o.contentIds;if(!s||s.length===0)return null;const e=s[s.length-1];return t.getRun(e)?e:R(t,e)}function _(t,n){const o=R(t,n);o&&k(o)}const q="​",D=/​/g;function p(t){return(t??"").replace(D,"")}function C(t){return p(t.textContent)}function V(t,n){var u;const o=new Map(n.map(l=>[l.id,l])),s=new Set,e=[];let c=!0;for(const l of t.childNodes){const i=l.nodeType===1?(u=l.dataset)==null?void 0:u.runId:void 0;if(i&&o.has(i)){s.add(i);const d=o.get(i);if(d.type!=="text"){e.push(d);continue}const g=C(l);e.push(g===d.value?d:{...d,value:g});continue}c=!1;const f=C(l);f&&e.push({id:a.genId(),type:"text",value:f,marks:{}})}if(n.some(l=>!s.has(l.id))&&(c=!1),e.length!==n.length&&(c=!1),c){for(let l=0;l<e.length;l+=1)if(e[l].id!==n[l].id){c=!1;break}}const r=!c||e.some((l,i)=>l!==n[i]);return{runs:e,changed:r,onlyValueChanges:c}}function H(){var u,l;const t=(u=window.getSelection)==null?void 0:u.call(window);if(!t||t.rangeCount===0)return null;const n=t.getRangeAt(0);if(n.collapsed||n.startContainer!==n.endContainer)return null;const o=n.startContainer,s=o.nodeType===1?o:o.parentElement,e=(l=s==null?void 0:s.closest)==null?void 0:l.call(s,"[data-run-id]");if(!e)return null;const c=e.closest("[data-block-id]");if(!c)return null;const r=o.textContent??"";return{runId:e.getAttribute("data-run-id"),blockId:c.getAttribute("data-block-id"),startOffset:p(r.slice(0,n.startOffset)).length,endOffset:p(r.slice(0,n.endOffset)).length}}function Q(t,n){var u,l;if((t==null?void 0:t.nodeType)!==1||((u=t.getAttribute)==null?void 0:u.call(t,"contenteditable"))!=="true")return null;const o=t.childNodes;if(o.length===0)return null;const s=n>=o.length,e=o[s?o.length-1:Math.max(0,n)],c=(e==null?void 0:e.nodeType)===1?(l=e.dataset)==null?void 0:l.runId:void 0;if(!c)return null;const r=e.closest("[data-block-id]");return r?{runId:c,blockId:r.getAttribute("data-block-id"),offset:s?p(e.textContent??"").length:0}:null}function I(t,n){var u;const o=Q(t,n);if(o)return o;let s=(t==null?void 0:t.nodeType)===1?t:t==null?void 0:t.parentElement;const e=(u=s==null?void 0:s.closest)==null?void 0:u.call(s,"[data-run-id]");if(!e)return null;const c=e.closest("[data-block-id]");if(!c)return null;let r=p((t.textContent??"").slice(0,n)).length;if(t===e){r=0;for(let l=0;l<n&&l<e.childNodes.length;l+=1)r+=p(e.childNodes[l].textContent??"").length}return{runId:e.getAttribute("data-run-id"),blockId:c.getAttribute("data-block-id"),offset:r}}function b(){var n;const t=(n=window.getSelection)==null?void 0:n.call(window);return!t||t.rangeCount===0||!t.isCollapsed?null:I(t.anchorNode,t.anchorOffset)}function U(){var s;const t=(s=window.getSelection)==null?void 0:s.call(window);if(!t||t.rangeCount===0||t.isCollapsed)return null;const n=I(t.anchorNode,t.anchorOffset),o=I(t.focusNode,t.focusOffset);return!n||!o||n.blockId!==o.blockId?null:{blockId:n.blockId,startRunId:n.runId,startOffset:n.offset,endRunId:o.runId,endOffset:o.offset}}function Y(t){var d;const n=(d=window.getSelection)==null?void 0:d.call(window);if(!n||n.rangeCount===0||n.isCollapsed)return null;const o=I(n.anchorNode,n.anchorOffset),s=I(n.focusNode,n.focusOffset);if(!o||!s||o.blockId===s.blockId)return null;const e=t.getBlock(o.blockId),c=e&&t.getBlock(e.parentId);if(!c)return null;const r=c.contentIds,u=r.indexOf(o.blockId),l=r.indexOf(s.blockId);if(u===-1||l===-1)return null;const[i,f]=u<=l?[u,l]:[l,u];return{blockIds:r.slice(i,f+1),startBlockId:o.blockId,startRunId:o.runId,startOffset:o.offset,endBlockId:s.blockId,endRunId:s.runId,endOffset:s.offset}}function v(t,n,o){const e=t.getBlock(n).parentId,r=t.getBlock(e).contentIds.indexOf(n)+1,{block:u,runs:l=[],subtreeBlocks:i=[]}=o(e);return t.applyOperation(a.insertBlock(u,e,r,{blocks:[u,...i],runs:l})),u.id}function B(t,n,o){const s=v(t,n,o);return h(t,s),s}function $(t,n,o){const{block:s,runs:e=[],subtreeBlocks:c=[]}=o(n);return t.applyOperation(a.insertBlock(s,n,0,{blocks:[s,...c],runs:e})),h(t,s.id),s.id}function O(t,n){if(typeof t.performBatch=="function")t.performBatch(n);else for(const o of n)t.applyOperation(o)}function W(t,n,o){const s=t.findIndex(i=>i.id===n);if(s===-1)return null;const e=t[s],c=t.slice(0,s),r=t.slice(s+1);if(e.type==="text"){const i=e.value??"",f=i.slice(0,o),d=i.slice(o);f&&d?(c.push({...e,value:f}),r.unshift({...e,id:a.genId(),value:d})):d?r.unshift(e):c.push(e)}else o>0?c.push(e):r.unshift(e);const u=c.length?c:[{id:a.genId(),type:"text",value:"",marks:{}}],l=r.length?r:[{id:a.genId(),type:"text",value:"",marks:{}}];return{leftRuns:u,rightRuns:l}}function Z(t,n,o,s){const e=t.getBlock(n),c=t.getBlock(e.parentId),r=c.contentIds.indexOf(n)+1;return y(t,n,o,s,{insertParentId:c.id,insertIndex:r,fallback:()=>B(t,n,s)})}function z(t,n,o,s){return y(t,n,o,s,{insertParentId:n,insertIndex:0,fallback:()=>$(t,n,s)})}function y(t,n,o,s,{insertParentId:e,insertIndex:c,fallback:r}){const u=b();if(!u||u.blockId!==n)return r();const l=o.map(N=>t.getRun(N)).filter(Boolean),i=W(l,u.runId,u.offset);if(!i)return r();const{leftRuns:f,rightRuns:d}=i,{block:g,runs:E=d,subtreeBlocks:w=[]}=s(e,d),T=f.length?f:[{id:a.genId(),type:"text",value:"",marks:{}}];return O(t,[a.setBlockRuns(n,T),a.insertBlock(g,e,c,{blocks:[g,...w],runs:E})]),h(t,g.id),g.id}function G(t){var n;return((n=t==null?void 0:t.props)==null?void 0:n.titleRunIds)??(t==null?void 0:t.contentIds)??[]}function J(t){var n,o;return!!((n=t==null?void 0:t.props)!=null&&n.titleRunIds)&&(((o=t.contentIds)==null?void 0:o.length)??0)>0}function K(t,n,o){const e=t.getBlock(n).parentId,r=t.getBlock(e).contentIds.indexOf(n),{block:u,runs:l=[],subtreeBlocks:i=[]}=o(e);return O(t,[a.removeBlock(n),a.insertBlock(u,e,r,{blocks:[u,...i],runs:l})]),h(t,u.id),u.id}function X(t,{blockId:n,runId:o,sliceStart:s,sliceEnd:e},c){const r=t.getRun(o),u=(r==null?void 0:r.value)??"",l=u.slice(0,s)+u.slice(e),i=t.getBlock(n),f=G(i);return f.length===1&&f[0]===o&&l===""&&!J(i)?K(t,n,c):(t.applyOperation(a.updateRun(o,{value:l})),B(t,n,c))}function tt(t,n={}){return function(s,e){const c=a.genId(),r=e!=null&&e.length?e:[{id:a.genId(),type:"text",value:"",marks:{}}];return{block:{id:c,type:t,parentId:s,contentIds:r.map(u=>u.id),props:n},runs:r}}}exports.EMPTY_RUN_PLACEHOLDER=q;exports.createTextLeafBlock=tt;exports.focusAdjacentBlock=j;exports.focusBlockEnd=_;exports.focusBlockStart=h;exports.focusRunAtOffset=L;exports.focusRunEnd=k;exports.focusRunStart=F;exports.insertFirstChildSplitAtCaretAndFocus=z;exports.insertSiblingAfter=v;exports.insertSiblingAfterAndFocus=B;exports.insertSiblingSplitAtCaretAndFocus=Z;exports.reconcileDomToRuns=V;exports.resolveAdjacentFocusTarget=S;exports.resolveBlockLastRun=R;exports.resolveCollapsedCaret=b;exports.resolveCrossBlockSelection=Y;exports.resolveMultiRunSelection=U;exports.resolveRunSelection=H;exports.setCaretSync=P;exports.stripEmptyRunPlaceholder=p;exports.trimSlashQueryAndInsertAfter=X;
2
+ //# sourceMappingURL=leafBlockFactory-Dp382eP8.cjs.map