noteloom 0.3.3 → 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.
- package/README.md +284 -55
- package/bin/noteloom.mjs +139 -0
- package/dist/canvas.cjs +2 -0
- package/dist/canvas.cjs.map +1 -0
- package/dist/canvas.d.ts +2 -0
- package/dist/canvas.js +5 -0
- package/dist/canvas.js.map +1 -0
- package/dist/collab.cjs +2 -0
- package/dist/collab.cjs.map +1 -0
- package/dist/collab.d.ts +19 -0
- package/dist/collab.js +379 -0
- package/dist/collab.js.map +1 -0
- package/dist/comments.cjs +2 -0
- package/dist/comments.cjs.map +1 -0
- package/dist/comments.d.ts +17 -0
- package/dist/comments.js +19 -0
- package/dist/comments.js.map +1 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +372 -33
- package/dist/index.js +3983 -0
- package/dist/index.js.map +1 -0
- package/dist/persistence.cjs +2 -0
- package/dist/persistence.cjs.map +1 -0
- package/dist/persistence.d.ts +11 -0
- package/dist/persistence.js +12 -0
- package/dist/persistence.js.map +1 -0
- package/dist/shared/CommentAvatar-TKqsM8vG.js +53 -0
- package/dist/shared/CommentAvatar-TKqsM8vG.js.map +1 -0
- package/dist/shared/CommentAvatar-V457IgoQ.cjs +2 -0
- package/dist/shared/CommentAvatar-V457IgoQ.cjs.map +1 -0
- package/dist/shared/CommentThreadCard-CAJ3oPdr.cjs +2 -0
- package/dist/shared/CommentThreadCard-CAJ3oPdr.cjs.map +1 -0
- package/dist/shared/CommentThreadCard-Cxf8GwHJ.js +213 -0
- package/dist/shared/CommentThreadCard-Cxf8GwHJ.js.map +1 -0
- package/dist/shared/CommentsPanel-BwVVyMOC.js +76 -0
- package/dist/shared/CommentsPanel-BwVVyMOC.js.map +1 -0
- package/dist/shared/CommentsPanel-CES4uzye.cjs +2 -0
- package/dist/shared/CommentsPanel-CES4uzye.cjs.map +1 -0
- package/dist/shared/VersionHistory-Bg6fufP5.js +1120 -0
- package/dist/shared/VersionHistory-Bg6fufP5.js.map +1 -0
- package/dist/shared/VersionHistory-DELa2Wbq.cjs +12 -0
- package/dist/shared/VersionHistory-DELa2Wbq.cjs.map +1 -0
- package/dist/shared/VoiceListeningIndicator-BOfVmLK0.js +338 -0
- package/dist/shared/VoiceListeningIndicator-BOfVmLK0.js.map +1 -0
- package/dist/shared/VoiceListeningIndicator-DNX8JlQM.cjs +2 -0
- package/dist/shared/VoiceListeningIndicator-DNX8JlQM.cjs.map +1 -0
- package/dist/shared/fieldRegistry-BoYyW3GH.cjs +2 -0
- package/dist/shared/fieldRegistry-BoYyW3GH.cjs.map +1 -0
- package/dist/shared/fieldRegistry-PjJWXFoB.js +223 -0
- package/dist/shared/fieldRegistry-PjJWXFoB.js.map +1 -0
- package/dist/shared/icons-C1_s0jKK.js +4269 -0
- package/dist/shared/icons-C1_s0jKK.js.map +1 -0
- package/dist/shared/icons-DtCsXuU6.cjs +3531 -0
- package/dist/shared/icons-DtCsXuU6.cjs.map +1 -0
- package/dist/shared/index-B9jyyL8u.js +2145 -0
- package/dist/shared/index-B9jyyL8u.js.map +1 -0
- package/dist/shared/index-D9WEXpYM.cjs +2 -0
- package/dist/shared/index-D9WEXpYM.cjs.map +1 -0
- package/dist/shared/indexedDbPersistence-BKlGPFTP.js +112 -0
- package/dist/shared/indexedDbPersistence-BKlGPFTP.js.map +1 -0
- package/dist/shared/indexedDbPersistence-BWJ1h5Vp.cjs +2 -0
- package/dist/shared/indexedDbPersistence-BWJ1h5Vp.cjs.map +1 -0
- package/dist/shared/leafBlockFactory-A9eUhSe-.js +335 -0
- package/dist/shared/leafBlockFactory-A9eUhSe-.js.map +1 -0
- package/dist/shared/leafBlockFactory-Dp382eP8.cjs +2 -0
- package/dist/shared/leafBlockFactory-Dp382eP8.cjs.map +1 -0
- package/dist/shared/serialize-DWEfk0vU.cjs +3 -0
- package/dist/shared/serialize-DWEfk0vU.cjs.map +1 -0
- package/dist/shared/serialize-T9Odwx24.js +86 -0
- package/dist/shared/serialize-T9Odwx24.js.map +1 -0
- package/dist/shared/starter-kit-CY5wzYDf.js +4980 -0
- package/dist/shared/starter-kit-CY5wzYDf.js.map +1 -0
- package/dist/shared/starter-kit-lPN-NpJ5.cjs +27 -0
- package/dist/shared/starter-kit-lPN-NpJ5.cjs.map +1 -0
- package/dist/shared/usePopoverEdgeClamp-CDG26jBM.cjs +2 -0
- package/dist/shared/usePopoverEdgeClamp-CDG26jBM.cjs.map +1 -0
- package/dist/shared/usePopoverEdgeClamp-gmFm0CnI.js +109 -0
- package/dist/shared/usePopoverEdgeClamp-gmFm0CnI.js.map +1 -0
- package/dist/shared/useServiceWorkerUpdate-BduabXv6.js +94 -0
- package/dist/shared/useServiceWorkerUpdate-BduabXv6.js.map +1 -0
- package/dist/shared/useServiceWorkerUpdate-DQboGesi.cjs +2 -0
- package/dist/shared/useServiceWorkerUpdate-DQboGesi.cjs.map +1 -0
- package/dist/starter-kit.cjs +2 -0
- package/dist/starter-kit.cjs.map +1 -0
- package/dist/starter-kit.d.ts +9 -0
- package/dist/starter-kit.js +10 -0
- package/dist/starter-kit.js.map +1 -0
- package/dist/style.css +3529 -3283
- package/dist/versions.cjs +2 -0
- package/dist/versions.cjs.map +1 -0
- package/dist/versions.d.ts +11 -0
- package/dist/versions.js +13 -0
- package/dist/versions.js.map +1 -0
- package/dist/voice.cjs +2 -0
- package/dist/voice.cjs.map +1 -0
- package/dist/voice.d.ts +7 -0
- package/dist/voice.js +8 -0
- package/dist/voice.js.map +1 -0
- package/package.json +159 -92
- package/dist/noteloom.cjs +0 -3292
- package/dist/noteloom.cjs.map +0 -1
- package/dist/noteloom.es.js +0 -15047
- package/dist/noteloom.es.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VersionHistory-DELa2Wbq.cjs","sources":["../../src/crdt/textDiff.js","../../src/store/EditorStore.js","../../src/templates/blockTemplates.js","../../src/clipboard/exportDocument.js","../../src/versions/autoVersionHistory.js","../../src/versions/diffVersions.js","../../src/react/useDocumentVersions.js","../../src/react/VersionHistory.jsx"],"sourcesContent":["/**\n * Finds the common-prefix/common-suffix boundary between two strings,\n * operating on Unicode code points (via `Array.from`) rather than raw\n * UTF-16 units, so a surrogate pair can never be split across two\n * character-CRDT slots. Returns the changed region as code-point indices:\n * `oldChars[start, oldEnd)` was removed, `newChars[start, newEnd)` was\n * inserted in its place — everything outside `[start, max(oldEnd,newEnd))`\n * is unchanged. Same algorithm as History's own `diffValueOffsets` (used\n * there purely for caret-position cosmetics on a UTF-16 string), reused\n * here for the actual data-merge boundary, which is why it needs to be\n * code-point aware rather than just close enough.\n */\nexport function diffCodePoints(oldValue, newValue) {\n const oldChars = Array.from(oldValue ?? '');\n const newChars = Array.from(newValue ?? '');\n let start = 0;\n const maxStart = Math.min(oldChars.length, newChars.length);\n while (start < maxStart && oldChars[start] === newChars[start]) start += 1;\n\n let oldEnd = oldChars.length;\n let newEnd = newChars.length;\n while (oldEnd > start && newEnd > start && oldChars[oldEnd - 1] === newChars[newEnd - 1]) {\n oldEnd -= 1;\n newEnd -= 1;\n }\n\n return { start, oldEnd, newEnd, oldChars, newChars };\n}\n","import {\n OP,\n insertBlock,\n removeBlock,\n moveBlock,\n changeBlockType,\n updateBlockProps,\n updateRun,\n editRunChars,\n setBlockContentIds,\n replaceRunSpan,\n setBlockRuns,\n addFieldType,\n updateFieldType,\n removeFieldType,\n addCommentThread,\n removeCommentThread,\n addCommentReply,\n removeCommentReply,\n resolveComment,\n addPerson,\n updatePerson,\n removePerson,\n} from './operations.js';\nimport { ListCrdtState } from '../crdt/listCrdt.js';\nimport { HLC, genPeerId } from '../crdt/clock.js';\nimport { FieldClockRegistry } from '../crdt/fieldRegistry.js';\nimport { diffCodePoints } from '../crdt/textDiff.js';\nimport { genId } from '../utils/idGen.js';\n\n/** Sentinel subscribe/notify key for \"the fieldTypes collection changed\" — see useFieldTypes. */\nconst FIELD_TYPES_KEY = '$fieldTypes';\n\n/** Sentinel subscribe/notify key for \"the comments collection changed\" — see useComments. */\nconst COMMENTS_KEY = '$comments';\n\n/** Sentinel subscribe/notify key for \"the document's people list changed\" — see usePeople. */\nconst PEOPLE_KEY = '$people';\n\n/**\n * Flat, normalized document store with per-id pub-sub.\n *\n * Every write replaces only the object(s) whose data actually changed, so\n * `getBlock(id)`/`getRun(id)` return a referentially stable value across any\n * update that doesn't touch that exact id. That stability is what lets\n * `useSyncExternalStore` (in the React bindings) skip re-rendering anything\n * that wasn't part of a given operation.\n *\n * Whether a given child id in `contentIds` refers to another Block or to a\n * Run is never encoded on the store — it's discovered by membership (ids are\n * unique across both maps), which keeps the store decoupled from the block\n * type registry.\n */\nexport class EditorStore {\n constructor(doc) {\n this.blocks = new Map((doc?.blocks ?? []).map((b) => [b.id, b]));\n this.runs = new Map((doc?.runs ?? []).map((r) => [r.id, r]));\n this.rootId = doc?.rootId ?? null;\n this.fieldTypes = new Map((doc?.fieldTypes ?? []).map((f) => [f.id, f]));\n this._fieldTypesSnapshot = null; // invalidated (set to null) on every fieldTypes mutation — see getFieldTypes\n this.comments = new Map((doc?.comments ?? []).map((c) => [c.id, c]));\n this._commentsSnapshot = null; // invalidated (set to null) on every comments mutation — see getComments\n this.people = new Map((doc?.people ?? []).map((p) => [p.id, p]));\n this._peopleSnapshot = null; // invalidated (set to null) on every people mutation — see getPeople\n this._listeners = new Map(); // id -> Set<() => void>\n this._globalListeners = new Set(); // fired on every mutation regardless of which id(s) changed -- see subscribeAll\n\n // Collaborative-editing merge state. Not yet reachable from any remote\n // transport (that's a later phase) -- for now this only tracks logical\n // clocks and CRDT-safe ordering locally, so `type`/props/run edits and\n // block insert/remove/move are all merge-ready without changing any\n // observable behavior for a single local user. Session-scoped: not\n // persisted by toJSON/fromJSON, since there's no remote peer yet that\n // could need it to survive a reload.\n this._peerId = genPeerId();\n this._clock = new HLC(this._peerId);\n this._fieldClocks = new FieldClockRegistry();\n this._orders = new Map(); // parent block id -> ListCrdtState over its contentIds, lazily seeded on first touch — see _getOrder\n\n // Character-level text merge state — same lazy-seed-from-existing-data\n // relationship to `runs` that `_orders` has to `blocks`. `_runOrders`\n // orders a run's characters (ListCrdtState is fully generic over\n // whatever ids it's given, so it's reused as-is here, just one\n // instance per RUN instead of per parent BLOCK); `_runChars` holds the\n // actual character payload for each slot (ListCrdtState's slots carry\n // no value of their own); `_runValueSnapshots` memoizes the\n // materialized string per run (see _materializeRunValue), the same\n // invalidate-on-mutation convention `getFieldTypes()` already uses for\n // `_fieldTypesSnapshot`.\n this._runOrders = new Map();\n this._runChars = new Map();\n this._runValueSnapshots = new Map();\n }\n\n /** Lazily seeds a block's ordering CRDT state from its current (plain-array) contentIds the first time it's touched. */\n _getOrder(parentId) {\n let order = this._orders.get(parentId);\n if (!order) {\n const block = this.blocks.get(parentId);\n order = ListCrdtState.fromArray(block?.contentIds ?? [], { peerId: 'legacy' });\n this._orders.set(parentId, order);\n }\n return order;\n }\n\n /**\n * Lazily seeds a run's character-ordering CRDT state from its current\n * (plain-string) value the first time it's touched. Unlike blocks,\n * individual characters have no pre-existing stable id of their own —\n * BUT a fresh *random* one (genId()) can't be minted here the way\n * `_getRunOrder`'s block equivalent doesn't need to, because a block's\n * seed ids (its real `.id`s) are already identical on every peer (the\n * document itself was already synced); a run's *characters* aren't\n * separately synced at all, only its plain `value` string is. Two peers\n * independently lazy-seeding the same pre-existing text with random ids\n * would each invent a DIFFERENT id for \"the same\" character, so a\n * remote edit's `afterId` (anchored to the sender's random id) would\n * never resolve on the receiving side. Fix: ids for this initial seed\n * are DETERMINISTIC — `` `${runId}:legacyChar:${index}` `` — so any peer\n * seeding from the same starting string (guaranteed, since a peer only\n * ever needs to seed a run it has already received the full document\n * for) always mints the identical ids independently, with no\n * coordination required. Only ever used for this one-time seed; every\n * character inserted after that (by typing, on any peer) gets a real\n * `genId()`.\n */\n _getRunOrder(runId) {\n let order = this._runOrders.get(runId);\n if (!order) {\n const run = this.runs.get(runId);\n const chars = new Map();\n order = new ListCrdtState();\n let prev = null;\n let index = 0;\n for (const ch of Array.from(run?.value ?? '')) {\n const charId = `${runId}:legacyChar:${index}`;\n chars.set(charId, ch);\n order.insert(charId, prev, { wallTime: 0, counter: 0, peerId: 'legacy' }, 'legacy');\n prev = charId;\n index += 1;\n }\n this._runOrders.set(runId, order);\n this._runChars.set(runId, chars);\n }\n return order;\n }\n\n /** Materializes a run's current text from its character CRDT, memoized until that run's char order next changes. */\n _materializeRunValue(runId) {\n let value = this._runValueSnapshots.get(runId);\n if (value === undefined) {\n const order = this._getRunOrder(runId);\n const chars = this._runChars.get(runId);\n value = order\n .toArray()\n .map((charId) => chars.get(charId))\n .join('');\n this._runValueSnapshots.set(runId, value);\n }\n return value;\n }\n\n /**\n * Diffs `newValue` against the run's current materialized value (common\n * prefix/suffix, code-point aware — see diffCodePoints) and translates\n * only the changed region into character-CRDT insert/delete ops. One\n * shared clock covers the whole edit — matching how a single\n * INSERT_BLOCK/REMOVE_BLOCK op already uses one tick() each — since\n * these characters are never independently reordered relative to each\n * other regardless of how many ticks they'd otherwise get.\n */\n _editRunText(runId, newValue) {\n const oldValue = this._materializeRunValue(runId);\n const { start, oldEnd, newEnd, newChars } = diffCodePoints(oldValue, newValue);\n const order = this._getRunOrder(runId);\n const chars = this._runChars.get(runId);\n const currentIds = order.toArray();\n const clock = this._clock.tick();\n\n const deletedCharIds = [];\n for (let i = start; i < oldEnd; i += 1) {\n const id = currentIds[i];\n order.delete(id, clock);\n deletedCharIds.push({ id, clock });\n }\n\n const insertedChars = [];\n let afterId = start > 0 ? currentIds[start - 1] : null;\n for (let i = start; i < newEnd; i += 1) {\n const id = genId();\n const ch = newChars[i];\n chars.set(id, ch);\n order.insert(id, afterId, clock, this._peerId);\n insertedChars.push({ id, char: ch, afterId, clock });\n afterId = id;\n }\n\n this._runValueSnapshots.delete(runId);\n return { oldValue, insertedChars, deletedCharIds, clock };\n }\n\n /**\n * Replays a previously-resolved text edit's EXACT character ids (from\n * `op._charEdit`, cached on first application — see the UPDATE_RUN case)\n * instead of re-diffing and minting fresh ones. Needed for `History`'s\n * redo, which replays the same op OBJECT a second time: re-diffing would\n * mint a brand-new set of ids rather than restoring the ones the\n * matching undo had only tombstoned, breaking a subsequent undo/redo\n * cycle (mirrors how INSERT_BLOCK's own handler restores an existing\n * slot via `order.restore()` on redo instead of creating a new one,\n * since a block's id is already stable across replay — characters have\n * no such built-in stable id, so this cache is what gives them one).\n */\n _replayRunTextEdit(runId, charEdit) {\n const order = this._getRunOrder(runId);\n const chars = this._runChars.get(runId);\n for (const c of charEdit.insertedChars) {\n if (order.has(c.id)) order.restore(c.id);\n else {\n chars.set(c.id, c.char);\n order.insert(c.id, c.afterId, c.clock, this._peerId);\n }\n }\n for (const d of charEdit.deletedCharIds) order.delete(d.id, d.clock);\n this._runValueSnapshots.delete(runId);\n }\n\n getBlock(id) {\n return this.blocks.get(id);\n }\n\n getRun(id) {\n return this.runs.get(id);\n }\n\n /**\n * Persisted, user-created custom select field types (static only) —\n * insertion order. Returns the SAME array reference across calls unless\n * a fieldTypes op ran in between — required for useSyncExternalStore\n * (see useFieldTypes), same reference-stability contract as\n * getBlock/getRun.\n */\n getFieldTypes() {\n if (!this._fieldTypesSnapshot) this._fieldTypesSnapshot = [...this.fieldTypes.values()];\n return this._fieldTypesSnapshot;\n }\n\n getFieldType(id) {\n return this.fieldTypes.get(id);\n }\n\n /**\n * Every comment thread — insertion order. Returns the SAME array\n * reference across calls unless a comments op ran in between — required\n * for useSyncExternalStore (see useComments), same contract as\n * getFieldTypes.\n */\n getComments() {\n if (!this._commentsSnapshot) this._commentsSnapshot = [...this.comments.values()];\n return this._commentsSnapshot;\n }\n\n getComment(id) {\n return this.comments.get(id);\n }\n\n /**\n * The document's own people list (see src/people/people.js's addPerson —\n * the documented entry point, and createSelectFieldType's \"Assignee\"\n * usage, which sources its options from this instead of any device-local\n * list, so every collaborator on the same document sees the same\n * assignable people). Same reference-stability contract as getFieldTypes/\n * getComments — required for useSyncExternalStore (see usePeople).\n */\n getPeople() {\n if (!this._peopleSnapshot) this._peopleSnapshot = [...this.people.values()];\n return this._peopleSnapshot;\n }\n\n getPerson(id) {\n return this.people.get(id);\n }\n\n /**\n * Every run id in the whole document, regardless of reachability from\n * the root — used by removeCommentMarkEverywhere (see\n * src/comments/commentMarks.js) to strip a deleted comment's id from\n * any run that still carries it, without needing a separate index.\n */\n getAllRunIds() {\n return [...this.runs.keys()];\n }\n\n getRootId() {\n return this.rootId;\n }\n\n subscribe(id, listener) {\n let set = this._listeners.get(id);\n if (!set) {\n set = new Set();\n this._listeners.set(id, set);\n }\n set.add(listener);\n return () => {\n set.delete(listener);\n if (set.size === 0) this._listeners.delete(id);\n };\n }\n\n /**\n * Fires on every mutation, local or remote (applyOperation and\n * applyRemoteOperation both funnel through _notify), regardless of\n * which specific id(s) changed — unlike subscribe(id, ...), which is\n * scoped to one id for render-isolation purposes. Meant for\n * whole-document concerns like auto-persistence, not for UI rendering\n * (a component re-rendering on every edit anywhere defeats the point of\n * per-id subscriptions).\n */\n subscribeAll(listener) {\n this._globalListeners.add(listener);\n return () => this._globalListeners.delete(listener);\n }\n\n _notify(touchedIds) {\n for (const id of touchedIds) {\n const set = this._listeners.get(id);\n if (!set) continue;\n // copy before iterating: a listener may unsubscribe during notification\n for (const listener of [...set]) listener();\n }\n if (this._globalListeners.size > 0) {\n for (const listener of [...this._globalListeners]) listener();\n }\n }\n\n /** Recursively collects a block (or run) and everything reachable under it. */\n _captureSubtree(rootId) {\n const blocks = [];\n const runs = [];\n const walk = (id) => {\n if (this.runs.has(id)) {\n runs.push(this.runs.get(id));\n return;\n }\n const block = this.blocks.get(id);\n if (!block) return;\n blocks.push(block);\n for (const childId of block.contentIds) walk(childId);\n // A block type (e.g. list_item) may hold its own inline runs in\n // props.titleRunIds alongside nested child blocks in contentIds.\n // Walk that too, generically, so nothing gets orphaned on delete.\n for (const runId of block.props?.titleRunIds ?? []) walk(runId);\n };\n walk(rootId);\n return { blocks, runs };\n }\n\n _deleteSubtree(rootId) {\n const walk = (id) => {\n if (this.runs.has(id)) {\n this.runs.delete(id);\n return;\n }\n const block = this.blocks.get(id);\n if (!block) return;\n for (const childId of block.contentIds) walk(childId);\n for (const runId of block.props?.titleRunIds ?? []) walk(runId);\n this.blocks.delete(id);\n };\n walk(rootId);\n }\n\n /**\n * Applies one operation, mutating only the affected map entries, and\n * returns the inverse operation (computed from state captured *before* the\n * mutation, per-op — never reconstructed afterward).\n */\n applyOperation(op) {\n switch (op.type) {\n case OP.UPDATE_RUN: {\n const run = this.runs.get(op.id);\n const patchKeys = Object.keys(op.patch);\n\n // The overwhelmingly common (and, per every real call site in this\n // codebase, the ONLY observed) shape: a lone `value` key, from\n // typing. Routed through this run's own character CRDT instead of\n // whole-value LWW, so concurrent edits to the same run interleave\n // instead of one clobbering the other, and undo can precisely\n // reverse only the characters THIS actor touched (via\n // EDIT_RUN_CHARS below) instead of replaying a stale whole-string\n // snapshot that can clobber a peer's concurrent edit. Any other\n // patch shape (marks, an atomic chip's `data`, or — never observed\n // in practice — `value` mixed with another key) keeps the\n // original whole-field LWW path below.\n if (patchKeys.length === 1 && patchKeys[0] === 'value') {\n let charEdit = op._charEdit;\n if (charEdit) {\n this._replayRunTextEdit(op.id, charEdit); // redo: reuse the exact ids from the first application\n } else {\n const { oldValue, insertedChars, deletedCharIds, clock } = this._editRunText(\n op.id,\n op.patch.value,\n );\n charEdit = { oldValue, insertedChars, deletedCharIds, clock };\n op._charEdit = charEdit; // cached on the op object itself so a future redo replays these same ids -- see _replayRunTextEdit\n }\n const newValue = this._materializeRunValue(op.id);\n this.runs.set(op.id, { ...run, value: newValue });\n this._lastEnvelope = {\n kind: 'runTextEdit',\n runId: op.id,\n insertedChars: charEdit.insertedChars,\n deletedCharIds: charEdit.deletedCharIds,\n clock: charEdit.clock,\n };\n this._notify([op.id]);\n return editRunChars(\n op.id,\n charEdit.insertedChars.map((c) => c.id), // undo: tombstone what was just inserted...\n charEdit.deletedCharIds.map((c) => c.id), // ...and restore what was just deleted\n charEdit.oldValue, // cosmetic-only, for History's caret restoration/change log -- see editRunChars's own doc comment\n );\n }\n\n const previousPatch = {};\n const clocks = {};\n for (const key of patchKeys) {\n previousPatch[key] = run[key];\n clocks[key] = this._clock.tick();\n this._fieldClocks.recordLocal(op.id, key, clocks[key]);\n }\n this.runs.set(op.id, { ...run, ...op.patch });\n this._lastEnvelope = {\n kind: 'fieldWrite',\n target: 'run',\n id: op.id,\n patch: op.patch,\n clocks,\n };\n this._notify([op.id]);\n return updateRun(op.id, previousPatch);\n }\n\n case OP.EDIT_RUN_CHARS: {\n const order = this._getRunOrder(op.id);\n const clock = this._clock.tick();\n for (const charId of op.tombstoneIds) order.delete(charId, clock);\n for (const charId of op.restoreIds) order.restore(charId);\n this._runValueSnapshots.delete(op.id);\n const run = this.runs.get(op.id);\n const newValue = this._materializeRunValue(op.id);\n this.runs.set(op.id, { ...run, value: newValue });\n this._lastEnvelope = {\n kind: 'runCharEdit',\n runId: op.id,\n tombstoneIds: op.tombstoneIds,\n restoreIds: op.restoreIds,\n clock,\n };\n this._notify([op.id]);\n return editRunChars(op.id, op.restoreIds, op.tombstoneIds); // swapped -- this op is its own inverse shape\n }\n\n case OP.UPDATE_BLOCK_PROPS: {\n const block = this.blocks.get(op.id);\n const previousPatch = {};\n const clocks = {};\n for (const key of Object.keys(op.patch)) {\n previousPatch[key] = block.props[key];\n clocks[key] = this._clock.tick();\n this._fieldClocks.recordLocal(op.id, `props.${key}`, clocks[key]);\n }\n this.blocks.set(op.id, { ...block, props: { ...block.props, ...op.patch } });\n this._lastEnvelope = {\n kind: 'fieldWrite',\n target: 'blockProps',\n id: op.id,\n patch: op.patch,\n clocks,\n };\n this._notify([op.id]);\n return updateBlockProps(op.id, previousPatch);\n }\n\n case OP.CHANGE_BLOCK_TYPE: {\n const block = this.blocks.get(op.id);\n const previousType = block.type;\n const previousProps = block.props;\n const clock = this._clock.tick();\n this._fieldClocks.recordLocal(op.id, 'type', clock);\n this.blocks.set(op.id, { ...block, type: op.blockType, props: op.props });\n this._lastEnvelope = {\n kind: 'fieldWrite',\n target: 'blockType',\n id: op.id,\n blockType: op.blockType,\n props: op.props,\n clock,\n };\n this._notify([op.id]);\n return changeBlockType(op.id, previousType, previousProps);\n }\n\n case OP.INSERT_BLOCK: {\n if (op.subtree) {\n for (const b of op.subtree.blocks) this.blocks.set(b.id, b);\n for (const r of op.subtree.runs) this.runs.set(r.id, r);\n } else {\n this.blocks.set(op.block.id, op.block);\n }\n const parent = this.blocks.get(op.parentId);\n const order = this._getOrder(op.parentId);\n if (order.has(op.block.id)) {\n // Already has a slot here (undo of a REMOVE_BLOCK, or duplicate\n // delivery) -- restore its original position instead of trying\n // to create a second slot for the same id.\n order.restore(op.block.id);\n } else {\n const currentArray = order.toArray();\n const index = op.index ?? currentArray.length;\n const afterId = index > 0 ? currentArray[index - 1] : null;\n order.insert(op.block.id, afterId, this._clock.tick(), this._peerId);\n }\n this.blocks.set(op.parentId, { ...parent, contentIds: order.toArray() });\n this._lastEnvelope = {\n kind: 'insertSlot',\n parentId: op.parentId,\n blockId: op.block.id,\n slot: order.getSlot(op.block.id),\n subtree: op.subtree ?? { blocks: [op.block], runs: [] },\n };\n this._notify([op.block.id, op.parentId]);\n return removeBlock(op.block.id);\n }\n\n case OP.REMOVE_BLOCK: {\n const target = this.blocks.get(op.id);\n const parentId = target.parentId;\n const parent = this.blocks.get(parentId);\n const order = this._getOrder(parentId);\n const index = order.toArray().indexOf(op.id);\n const subtree = this._captureSubtree(op.id);\n this._deleteSubtree(op.id);\n const deleteClock = this._clock.tick();\n order.delete(op.id, deleteClock);\n this.blocks.set(parentId, { ...parent, contentIds: order.toArray() });\n this._lastEnvelope = { kind: 'deleteSlot', parentId, blockId: op.id, clock: deleteClock };\n this._notify([parentId]);\n return { type: OP.INSERT_BLOCK, block: target, parentId, index, subtree };\n }\n\n case OP.MOVE_BLOCK: {\n const target = this.blocks.get(op.id);\n const fromParentId = target.parentId;\n const fromOrder = this._getOrder(fromParentId);\n const fromIndex = fromOrder.toArray().indexOf(op.id);\n\n // Tombstone the slot at its old position first -- for a\n // same-parent reorder this is the SAME ListCrdtState as toOrder\n // below, and the array it produces afterward is what toIndex is\n // interpreted against (matches the original index-based\n // contract, where toIndex already meant \"position in the\n // resulting list\").\n fromOrder.delete(op.id, this._clock.tick());\n this.blocks.set(fromParentId, {\n ...this.blocks.get(fromParentId),\n contentIds: fromOrder.toArray(),\n });\n\n const toOrder = this._getOrder(op.toParentId);\n const toArray = toOrder.toArray();\n const toIndex = op.toIndex ?? toArray.length;\n const afterId = toIndex > 0 ? toArray[toIndex - 1] : null;\n const ts = this._clock.tick();\n if (toOrder.has(op.id)) {\n // Reposition the existing slot (same-parent reorder, or moving\n // back to a parent this id was in — and tombstoned — before).\n toOrder.move(op.id, afterId, ts, this._peerId);\n } else {\n toOrder.insert(op.id, afterId, ts, this._peerId);\n }\n this.blocks.set(op.toParentId, {\n ...this.blocks.get(op.toParentId),\n contentIds: toOrder.toArray(),\n });\n\n this.blocks.set(op.id, { ...this.blocks.get(op.id), parentId: op.toParentId });\n\n this._lastEnvelope = {\n kind: 'moveSlot',\n fromParentId,\n toParentId: op.toParentId,\n blockId: op.id,\n slot: toOrder.getSlot(op.id),\n };\n const touched = new Set([op.id, fromParentId, op.toParentId]);\n this._notify(touched);\n return moveBlock(op.id, fromParentId, fromIndex);\n }\n\n case OP.SET_BLOCK_CONTENT_IDS: {\n const block = this.blocks.get(op.blockId);\n const previousContentIds = block.contentIds;\n this.blocks.set(op.blockId, { ...block, contentIds: op.contentIds });\n // This op wholesale-replaces the array (a resync escape hatch, not\n // an incremental edit) -- reseed the ordering CRDT to match rather\n // than leave it stale relative to the new authoritative contents.\n this._orders.set(op.blockId, ListCrdtState.fromArray(op.contentIds, { peerId: 'legacy' }));\n this._lastEnvelope = null; // no CRDT-safe wire representation for a wholesale resync -- not broadcastable in Phase C\n this._notify([op.blockId]);\n return setBlockContentIds(op.blockId, previousContentIds);\n }\n\n case OP.REPLACE_RUN_SPAN: {\n const block = this.blocks.get(op.blockId);\n // The run span lives in contentIds for a plain leaf block (paragraph,\n // heading, tableCell), or in props.titleRunIds for a listItem (whose\n // contentIds instead holds nested child list items).\n const inContentIds = block.contentIds.indexOf(op.oldRunIds[0]) !== -1;\n const sourceArray = inContentIds ? block.contentIds : (block.props?.titleRunIds ?? []);\n const startIndex = sourceArray.indexOf(op.oldRunIds[0]);\n\n const removedRuns = op.oldRunIds.map((id) => this.runs.get(id));\n for (const id of op.oldRunIds) this.runs.delete(id);\n for (const r of op.newRuns) this.runs.set(r.id, r);\n\n const newArray = [...sourceArray];\n newArray.splice(startIndex, op.oldRunIds.length, ...op.newRuns.map((r) => r.id));\n\n if (inContentIds) {\n this.blocks.set(op.blockId, { ...block, contentIds: newArray });\n } else {\n this.blocks.set(op.blockId, {\n ...block,\n props: { ...block.props, titleRunIds: newArray },\n });\n }\n this._lastEnvelope = null; // no CRDT-safe wire representation yet -- not broadcastable in Phase C\n this._notify([op.blockId, ...op.oldRunIds, ...op.newRuns.map((r) => r.id)]);\n return replaceRunSpan(\n op.blockId,\n op.newRuns.map((r) => r.id),\n removedRuns,\n );\n }\n\n case OP.SET_BLOCK_RUNS: {\n const block = this.blocks.get(op.blockId);\n // Same dual-path convention as REPLACE_RUN_SPAN: a listItem's own\n // runs live in props.titleRunIds (contentIds holds nested child\n // items instead); every other run-bearing leaf uses contentIds.\n const usesTitleRunIds = block.props && 'titleRunIds' in block.props;\n const previousRunIds = usesTitleRunIds ? block.props.titleRunIds : block.contentIds;\n const previousRuns = previousRunIds.map((id) => this.runs.get(id)).filter(Boolean);\n\n for (const id of previousRunIds) this.runs.delete(id);\n for (const r of op.runs) this.runs.set(r.id, r);\n const newRunIds = op.runs.map((r) => r.id);\n\n if (usesTitleRunIds) {\n this.blocks.set(op.blockId, {\n ...block,\n props: { ...block.props, titleRunIds: newRunIds },\n });\n } else {\n this.blocks.set(op.blockId, { ...block, contentIds: newRunIds });\n }\n this._lastEnvelope = null; // no CRDT-safe wire representation yet -- not broadcastable in Phase C\n this._notify([op.blockId, ...previousRunIds, ...newRunIds]);\n return setBlockRuns(op.blockId, previousRuns);\n }\n\n case OP.ADD_FIELD_TYPE: {\n this.fieldTypes.set(op.fieldType.id, op.fieldType);\n this._fieldTypesSnapshot = null;\n this._notify([FIELD_TYPES_KEY]);\n return removeFieldType(op.fieldType.id);\n }\n\n case OP.UPDATE_FIELD_TYPE: {\n const existing = this.fieldTypes.get(op.id);\n const previousPatch = {};\n for (const key of Object.keys(op.patch)) previousPatch[key] = existing[key];\n this.fieldTypes.set(op.id, { ...existing, ...op.patch });\n this._fieldTypesSnapshot = null;\n this._notify([FIELD_TYPES_KEY]);\n return updateFieldType(op.id, previousPatch);\n }\n\n case OP.REMOVE_FIELD_TYPE: {\n const existing = this.fieldTypes.get(op.id);\n this.fieldTypes.delete(op.id);\n this._fieldTypesSnapshot = null;\n this._notify([FIELD_TYPES_KEY]);\n return addFieldType(existing);\n }\n\n case OP.ADD_COMMENT_THREAD: {\n this.comments.set(op.thread.id, op.thread);\n this._commentsSnapshot = null;\n this._lastEnvelope = { kind: 'commentWrite', op: 'addThread', thread: op.thread };\n this._notify([COMMENTS_KEY]);\n return removeCommentThread(op.thread.id);\n }\n\n case OP.REMOVE_COMMENT_THREAD: {\n const existing = this.comments.get(op.commentId);\n this.comments.delete(op.commentId);\n this._commentsSnapshot = null;\n this._lastEnvelope = { kind: 'commentWrite', op: 'removeThread', commentId: op.commentId };\n this._notify([COMMENTS_KEY]);\n return addCommentThread(existing);\n }\n\n case OP.ADD_COMMENT_REPLY: {\n const thread = this.comments.get(op.commentId);\n this.comments.set(op.commentId, { ...thread, messages: [...thread.messages, op.message] });\n this._commentsSnapshot = null;\n this._lastEnvelope = {\n kind: 'commentWrite',\n op: 'addReply',\n commentId: op.commentId,\n message: op.message,\n };\n this._notify([COMMENTS_KEY]);\n return removeCommentReply(op.commentId, op.message.id);\n }\n\n case OP.REMOVE_COMMENT_REPLY: {\n const thread = this.comments.get(op.commentId);\n const removedMessage = thread.messages.find((m) => m.id === op.messageId);\n this.comments.set(op.commentId, {\n ...thread,\n messages: thread.messages.filter((m) => m.id !== op.messageId),\n });\n this._commentsSnapshot = null;\n this._lastEnvelope = {\n kind: 'commentWrite',\n op: 'removeReply',\n commentId: op.commentId,\n messageId: op.messageId,\n };\n this._notify([COMMENTS_KEY]);\n return addCommentReply(op.commentId, removedMessage);\n }\n\n case OP.RESOLVE_COMMENT: {\n const thread = this.comments.get(op.commentId);\n const previousResolved = thread.resolved;\n this.comments.set(op.commentId, { ...thread, resolved: op.resolved });\n this._commentsSnapshot = null;\n this._lastEnvelope = {\n kind: 'commentWrite',\n op: 'resolve',\n commentId: op.commentId,\n resolved: op.resolved,\n };\n this._notify([COMMENTS_KEY]);\n return resolveComment(op.commentId, previousResolved);\n }\n\n case OP.ADD_PERSON: {\n this.people.set(op.person.id, op.person);\n this._peopleSnapshot = null;\n this._lastEnvelope = { kind: 'peopleWrite', op: 'add', person: op.person };\n this._notify([PEOPLE_KEY]);\n return removePerson(op.person.id);\n }\n\n case OP.UPDATE_PERSON: {\n const existing = this.people.get(op.id);\n const previousPatch = {};\n for (const key of Object.keys(op.patch)) previousPatch[key] = existing[key];\n this.people.set(op.id, { ...existing, ...op.patch });\n this._peopleSnapshot = null;\n this._lastEnvelope = { kind: 'peopleWrite', op: 'update', id: op.id, patch: op.patch };\n this._notify([PEOPLE_KEY]);\n return updatePerson(op.id, previousPatch);\n }\n\n case OP.REMOVE_PERSON: {\n const existing = this.people.get(op.id);\n this.people.delete(op.id);\n this._peopleSnapshot = null;\n this._lastEnvelope = { kind: 'peopleWrite', op: 'remove', id: op.id };\n this._notify([PEOPLE_KEY]);\n return addPerson(existing);\n }\n\n default:\n throw new Error(`Unknown operation type: ${op.type}`);\n }\n }\n\n /** Applies a batch as one transaction: all mutations first, one notify pass, one combined inverse list. */\n applyOperations(ops) {\n return ops.map((op) => this.applyOperation(op));\n }\n\n /**\n * The CRDT-native wire envelope for whatever `applyOperation` just did —\n * read this immediately after each call to broadcast the change to\n * other peers. `null` for op types with no CRDT-safe representation yet\n * (the coarse resync ops: setBlockContentIds/replaceRunSpan/\n * setBlockRuns/fieldType ops) — those remain local-only in this phase.\n */\n getLastEnvelope() {\n return this._lastEnvelope;\n }\n\n /**\n * Applies a change received from another peer. Deliberately separate\n * from `applyOperation`/`History.perform` — a remote change must never\n * enter the local undo stack (only `perform`/`performBatch` push onto\n * it), so this method is the only way for a remote envelope to reach\n * the store. Idempotent and order-independent per envelope kind: safe\n * to call more than once, or with envelopes arriving out of order.\n */\n applyRemoteOperation(envelope) {\n if (!envelope) return;\n switch (envelope.kind) {\n case 'insertSlot': {\n for (const b of envelope.subtree.blocks)\n if (!this.blocks.has(b.id)) this.blocks.set(b.id, b);\n for (const r of envelope.subtree.runs) if (!this.runs.has(r.id)) this.runs.set(r.id, r);\n const order = this._getOrder(envelope.parentId);\n order.merge([envelope.slot]);\n const parent = this.blocks.get(envelope.parentId);\n this.blocks.set(envelope.parentId, { ...parent, contentIds: order.toArray() });\n this._clock.receive(envelope.slot.clock);\n this._notify([envelope.blockId, envelope.parentId]);\n return;\n }\n\n case 'deleteSlot': {\n const order = this._getOrder(envelope.parentId);\n if (this.blocks.has(envelope.blockId)) this._deleteSubtree(envelope.blockId);\n order.delete(envelope.blockId, envelope.clock);\n if (envelope.clock) this._clock.receive(envelope.clock);\n const parent = this.blocks.get(envelope.parentId);\n this.blocks.set(envelope.parentId, { ...parent, contentIds: order.toArray() });\n this._notify([envelope.parentId]);\n return;\n }\n\n case 'moveSlot': {\n const fromOrder = this._getOrder(envelope.fromParentId);\n // The move's own clock (envelope.slot.clock) is a reasonable proxy\n // for \"when the old position was vacated\" -- there's no separate\n // timestamp for that specific fact, and it's close enough in time\n // to be a safe (if not perfectly precise) tombstone age.\n fromOrder.delete(envelope.blockId, envelope.slot?.clock);\n this.blocks.set(envelope.fromParentId, {\n ...this.blocks.get(envelope.fromParentId),\n contentIds: fromOrder.toArray(),\n });\n\n const toOrder = this._getOrder(envelope.toParentId);\n const hadSlot = toOrder.has(envelope.blockId);\n toOrder.merge([envelope.slot]);\n // merge() only creates a slot or un-deletes one — it never\n // repositions an existing slot (that's not what merging two\n // independently-evolved lists means). A remote MOVE needs the\n // actual reposition, applied only when the slot already existed\n // here before this merge.\n if (hadSlot)\n toOrder.move(\n envelope.blockId,\n envelope.slot.originId,\n envelope.slot.clock,\n envelope.slot.peerId,\n );\n this.blocks.set(envelope.toParentId, {\n ...this.blocks.get(envelope.toParentId),\n contentIds: toOrder.toArray(),\n });\n\n if (this.blocks.has(envelope.blockId)) {\n this.blocks.set(envelope.blockId, {\n ...this.blocks.get(envelope.blockId),\n parentId: envelope.toParentId,\n });\n }\n this._clock.receive(envelope.slot.clock);\n this._notify([envelope.blockId, envelope.fromParentId, envelope.toParentId]);\n return;\n }\n\n case 'fieldWrite': {\n if (envelope.target === 'run') {\n const run = this.runs.get(envelope.id);\n if (run) {\n const patch = {};\n for (const key of Object.keys(envelope.patch)) {\n const remoteClock = envelope.clocks[key];\n if (!this._fieldClocks.shouldApplyRemote(envelope.id, key, remoteClock)) continue;\n patch[key] = envelope.patch[key];\n this._fieldClocks.recordRemote(envelope.id, key, remoteClock);\n }\n if (Object.keys(patch).length > 0) {\n this.runs.set(envelope.id, { ...run, ...patch });\n this._notify([envelope.id]);\n }\n }\n } else if (envelope.target === 'blockProps') {\n const block = this.blocks.get(envelope.id);\n if (block) {\n const patch = {};\n for (const key of Object.keys(envelope.patch)) {\n const remoteClock = envelope.clocks[key];\n if (!this._fieldClocks.shouldApplyRemote(envelope.id, `props.${key}`, remoteClock))\n continue;\n patch[key] = envelope.patch[key];\n this._fieldClocks.recordRemote(envelope.id, `props.${key}`, remoteClock);\n }\n if (Object.keys(patch).length > 0) {\n this.blocks.set(envelope.id, { ...block, props: { ...block.props, ...patch } });\n this._notify([envelope.id]);\n }\n }\n } else if (envelope.target === 'blockType') {\n const block = this.blocks.get(envelope.id);\n if (block && this._fieldClocks.shouldApplyRemote(envelope.id, 'type', envelope.clock)) {\n this._fieldClocks.recordRemote(envelope.id, 'type', envelope.clock);\n this.blocks.set(envelope.id, {\n ...block,\n type: envelope.blockType,\n props: envelope.props,\n });\n this._notify([envelope.id]);\n }\n }\n for (const ts of Object.values(envelope.clocks ?? {})) this._clock.receive(ts);\n if (envelope.clock) this._clock.receive(envelope.clock);\n return;\n }\n\n case 'runTextEdit': {\n const order = this._getRunOrder(envelope.runId);\n const chars = this._runChars.get(envelope.runId);\n for (const c of envelope.insertedChars) {\n if (!order.has(c.id)) chars.set(c.id, c.char);\n order.insert(c.id, c.afterId, c.clock, c.clock?.peerId); // idempotent -- safe on duplicate delivery, same as block inserts\n }\n for (const d of envelope.deletedCharIds) order.delete(d.id, d.clock);\n this._runValueSnapshots.delete(envelope.runId);\n const run = this.runs.get(envelope.runId);\n if (run) {\n this.runs.set(envelope.runId, {\n ...run,\n value: this._materializeRunValue(envelope.runId),\n });\n this._notify([envelope.runId]);\n }\n this._clock.receive(envelope.clock);\n return;\n }\n\n case 'runCharEdit': {\n const order = this._getRunOrder(envelope.runId);\n for (const charId of envelope.tombstoneIds) order.delete(charId, envelope.clock);\n for (const charId of envelope.restoreIds) order.restore(charId);\n this._runValueSnapshots.delete(envelope.runId);\n const run = this.runs.get(envelope.runId);\n if (run) {\n this.runs.set(envelope.runId, {\n ...run,\n value: this._materializeRunValue(envelope.runId),\n });\n this._notify([envelope.runId]);\n }\n this._clock.receive(envelope.clock);\n return;\n }\n\n case 'commentWrite': {\n // Simple, no-per-field-clock handling -- comment thread metadata\n // sees low write concurrency in practice (see the plan's own\n // rationale), so each sub-kind just applies directly rather than\n // comparing HLC clocks the way run/block field writes do above.\n // Existence checks guard only against out-of-order delivery (e.g.\n // a reply arriving before its thread's own add), not against real\n // conflicts -- a later full resync reconciles anything this misses.\n if (envelope.op === 'addThread') {\n if (!this.comments.has(envelope.thread.id)) {\n this.comments.set(envelope.thread.id, envelope.thread);\n this._commentsSnapshot = null;\n this._notify([COMMENTS_KEY]);\n }\n } else if (envelope.op === 'removeThread') {\n if (this.comments.delete(envelope.commentId)) {\n this._commentsSnapshot = null;\n this._notify([COMMENTS_KEY]);\n }\n } else if (envelope.op === 'addReply') {\n const thread = this.comments.get(envelope.commentId);\n if (thread && !thread.messages.some((m) => m.id === envelope.message.id)) {\n this.comments.set(envelope.commentId, {\n ...thread,\n messages: [...thread.messages, envelope.message],\n });\n this._commentsSnapshot = null;\n this._notify([COMMENTS_KEY]);\n }\n } else if (envelope.op === 'removeReply') {\n const thread = this.comments.get(envelope.commentId);\n if (thread && thread.messages.some((m) => m.id === envelope.messageId)) {\n this.comments.set(envelope.commentId, {\n ...thread,\n messages: thread.messages.filter((m) => m.id !== envelope.messageId),\n });\n this._commentsSnapshot = null;\n this._notify([COMMENTS_KEY]);\n }\n } else if (envelope.op === 'resolve') {\n const thread = this.comments.get(envelope.commentId);\n if (thread) {\n this.comments.set(envelope.commentId, { ...thread, resolved: envelope.resolved });\n this._commentsSnapshot = null;\n this._notify([COMMENTS_KEY]);\n }\n }\n return;\n }\n\n case 'peopleWrite': {\n // Same simple existence-check merge as commentWrite above, for the\n // same reason: a document's people list sees low write concurrency\n // in practice (adding/renaming/removing a collaborator's name is\n // not something two people do to the same entry at the same\n // instant), so there's no need for the per-field HLC comparison\n // run/block field writes use.\n if (envelope.op === 'add') {\n if (!this.people.has(envelope.person.id)) {\n this.people.set(envelope.person.id, envelope.person);\n this._peopleSnapshot = null;\n this._notify([PEOPLE_KEY]);\n }\n } else if (envelope.op === 'update') {\n const existing = this.people.get(envelope.id);\n if (existing) {\n this.people.set(envelope.id, { ...existing, ...envelope.patch });\n this._peopleSnapshot = null;\n this._notify([PEOPLE_KEY]);\n }\n } else if (envelope.op === 'remove') {\n if (this.people.delete(envelope.id)) {\n this._peopleSnapshot = null;\n this._notify([PEOPLE_KEY]);\n }\n }\n return;\n }\n\n default:\n throw new Error(`Unknown remote envelope kind: ${envelope.kind}`);\n }\n }\n\n /** Total tombstoned (deleted but still retained) slots across every parent's ordering CRDT and every run's character CRDT — a cheap signal for whether pruneTombstones() is worth calling, or just for observing growth over a long session. */\n getTombstoneCount() {\n let count = 0;\n for (const order of this._orders.values()) count += order.tombstoneCount();\n for (const order of this._runOrders.values()) count += order.tombstoneCount();\n return count;\n }\n\n /**\n * Permanently removes tombstones older than `maxAgeMs` (default 24h)\n * across every parent's ordering CRDT — see ListCrdtState.pruneTombstones\n * for the safety argument this relies on (this package's reconnect model\n * always resyncs via a full snapshot, never a replayed op log, which is\n * what makes a time-based threshold safe here specifically). Opt-in:\n * never called automatically by anything in this store — call it\n * yourself on whatever schedule fits (see createPeriodicTombstoneGC for\n * a ready-made \"just handle it\" helper). Returns the number of slots\n * removed.\n */\n pruneTombstones({ maxAgeMs = 24 * 60 * 60 * 1000, now = Date.now() } = {}) {\n const threshold = { wallTime: now - maxAgeMs, counter: 0, peerId: '' };\n let removed = 0;\n for (const order of this._orders.values()) removed += order.pruneTombstones(threshold);\n // Character payloads for pruned run-char slots (_runChars) are\n // deliberately left in place rather than cleaned up here:\n // ListCrdtState.pruneTombstones only returns a removed *count*, not\n // which ids were removed (a shared contract with the block-level GC\n // above, which has no equivalent payload map to clean), and a few\n // orphaned single-character map entries per prune is a far smaller\n // concern than the whole-subtree leaks tombstone GC exists to prevent\n // in the first place.\n for (const order of this._runOrders.values()) removed += order.pruneTombstones(threshold);\n return removed;\n }\n\n toJSON() {\n return {\n blocks: [...this.blocks.values()],\n runs: [...this.runs.values()],\n rootId: this.rootId,\n fieldTypes: [...this.fieldTypes.values()],\n comments: [...this.comments.values()],\n people: [...this.people.values()],\n };\n }\n\n static fromJSON(doc) {\n return new EditorStore(doc);\n }\n}\n","import { captureSubtree, remapSubtreeIds } from '../clipboard/serialize.js';\nimport { insertBlock, updateRun } from '../store/operations.js';\n\n/** Batches ops if the store supports it (a History instance), else applies them one at a time — same idiom as blocks/shared/mergeCommands.js. */\nfunction applyOps(store, ops) {\n if (typeof store.performBatch === 'function') store.performBatch(ops);\n else for (const op of ops) store.applyOperation(op);\n}\n\n/**\n * Captures one or more sibling blocks (each with its own descendants) as a\n * reusable, storable template — the block-level counterpart to\n * `exportDocumentJSON` for whole documents. Ids are kept as-is (matching the\n * app clipboard's own JSON payload); `insertBlockTemplate` remaps them fresh\n * at insert time, so the same template can be inserted any number of times\n * without ever colliding with existing content.\n */\nexport function captureBlockTemplate(store, blockIds) {\n return { roots: blockIds.map((id) => captureSubtree(store, id)) };\n}\n\n/**\n * Inserts a captured block template as new sibling blocks under `parentId`,\n * starting at `index` — the same \"remap ids, then insert\" loop\n * useClipboardHandlers.js's onPaste uses for multi-block paste, reused here\n * instead of duplicated as a one-off.\n */\nexport function insertBlockTemplate(store, template, { parentId, index }) {\n const ops = [];\n let nextIndex = index;\n for (const root of template.roots) {\n const { block, runs, subtreeBlocks } = remapSubtreeIds(root);\n block.parentId = parentId;\n ops.push(insertBlock(block, parentId, nextIndex, { blocks: [block, ...subtreeBlocks], runs }));\n nextIndex += 1;\n }\n applyOps(store, ops);\n}\n\n/**\n * Wholesale-replaces an already-mounted editor's content with a document\n * template — the \"apply this starter document to a live editor\" counterpart\n * to passing `doc` to `useEditor()` at creation time. Same Map-reassignment\n * approach usePersistedDocument.js uses for loading a persisted document\n * (written fresh here rather than shared, to avoid touching that file).\n */\nexport function applyDocumentTemplate(store, doc) {\n const rawStore = store.store ?? store; // unwrap a History instance to the underlying EditorStore\n rawStore.blocks = new Map((doc.blocks ?? []).map((b) => [b.id, b]));\n rawStore.runs = new Map((doc.runs ?? []).map((r) => [r.id, r]));\n rawStore.rootId = doc.rootId ?? null;\n rawStore.fieldTypes = new Map((doc.fieldTypes ?? []).map((f) => [f.id, f]));\n rawStore._fieldTypesSnapshot = null;\n rawStore.comments = new Map((doc.comments ?? []).map((c) => [c.id, c]));\n rawStore._commentsSnapshot = null;\n rawStore._orders = new Map();\n // '$fieldTypes'/'$comments' are the same sentinel notify keys\n // useFieldTypes/useComments subscribe to -- without them, a restored\n // template/version's field types or comments wouldn't refresh a\n // currently-mounted list for either, even though the underlying Maps did change.\n rawStore._notify([\n ...rawStore.blocks.keys(),\n ...rawStore.runs.keys(),\n '$fieldTypes',\n '$comments',\n ]);\n}\n\n/**\n * Registers block-level templates as slash commands — discoverable and\n * insertable via \"/\" alongside every built-in block, with no changes needed\n * to SlashMenu/useSlashMenuTrigger/BlockRegistry, since those already just\n * read whatever `listSlashCommands()` returns. Each template is registered\n * under a synthetic key that's never used as a real block's `type` (no\n * block of that type is ever inserted — only the template's own captured\n * blocks, which already carry their own real types), so `component`/\n * `isLeaf` here are never actually reached.\n */\nexport function registerBlockTemplates(registry, templates) {\n for (const template of templates) {\n registry.register(`__blockTemplate:${template.id}`, {\n component: () => null,\n isLeaf: true,\n slashCommand: {\n label: template.label,\n icon: template.icon,\n keywords: template.keywords ?? [template.label],\n run(store, { blockId, runId, sliceStart, sliceEnd }) {\n // clear the \"/query\" text that triggered this, same as every other block's slashCommand\n const run = store.getRun(runId);\n const value = run?.value ?? '';\n store.applyOperation(\n updateRun(runId, { value: value.slice(0, sliceStart) + value.slice(sliceEnd) }),\n );\n\n const current = store.getBlock(blockId);\n const parent = store.getBlock(current.parentId);\n const index = parent.contentIds.indexOf(blockId) + 1;\n insertBlockTemplate(store, template, { parentId: current.parentId, index });\n },\n },\n });\n }\n}\n","import { captureSubtree } from './serialize.js';\nimport { serializeBlockRange } from './serialize.js';\n\n/**\n * Whole-document JSON export — the exact `{ rootId, blocks, runs }` shape\n * `new EditorStore({...})` itself accepts, so this round-trips: export a\n * document, and the result can be handed straight back into a fresh\n * EditorStore to reconstruct it. Wraps captureSubtree (already used for\n * duplicate/copy) starting from the document's own root rather than one\n * top-level block, so it walks the *entire* tree in one pass.\n */\nexport function exportDocumentJSON(store, { pretty = true } = {}) {\n const rootId = store.getRootId();\n const { blocks, runs } = captureSubtree(store, rootId);\n const payload = { version: 1, rootId, blocks, runs };\n return JSON.stringify(payload, null, pretty ? 2 : 0);\n}\n\n/** Whole-document HTML export — every top-level block's own toHTML, joined (see serializeBlockRange). */\nexport function exportDocumentHTML(store, registry, inlineRegistry) {\n const root = store.getBlock(store.getRootId());\n if (!root) return '';\n return serializeBlockRange(store, registry, root.contentIds, inlineRegistry).html;\n}\n\n/** Whole-document plain-text export — every top-level block's own toPlainText, joined (see serializeBlockRange). */\nexport function exportDocumentText(store, registry, inlineRegistry) {\n const root = store.getBlock(store.getRootId());\n if (!root) return '';\n return serializeBlockRange(store, registry, root.contentIds, inlineRegistry).text;\n}\n\n/**\n * Whole-document HTML wrapped for Microsoft Word — the well-known trick of\n * giving Word-flavored HTML (an `xmlns:w=\"urn:schemas-microsoft-com:office:\n * word\"` namespace + a small `<!--[if gte mso 9]>` block) a `.doc`\n * extension, which Word opens directly via MIME sniffing without needing a\n * real `.docx` (OOXML zip) writer — no runtime dependency needed for\n * either the zip container or the XML schema a genuine `.docx` would\n * require, staying true to this package's zero-dependency design. The\n * `<body>` content is exactly `exportDocumentHTML`'s own output — nothing\n * about the per-block HTML changes for Word specifically.\n */\nexport function exportDocumentWordHTML(store, registry, inlineRegistry) {\n const body = exportDocumentHTML(store, registry, inlineRegistry);\n return `<html xmlns:o=\"urn:schemas-microsoft-com:office:office\" xmlns:w=\"urn:schemas-microsoft-com:office:word\" xmlns=\"http://www.w3.org/TR/REC-html40\">\n<head>\n<meta charset=\"utf-8\">\n<title>Document</title>\n<!--[if gte mso 9]><xml><w:WordDocument><w:View>Print</w:View><w:DoNotOptimizeForBrowser/></w:WordDocument></xml><![endif]-->\n</head>\n<body>${body}</body>\n</html>`;\n}\n\n/**\n * Whole-document Markdown (CommonMark/GFM) export. Each top-level block\n * calls its own `toMarkdown(block, ctx)`; a block type with no\n * `toMarkdown` of its own (a custom host-registered block type, or one of\n * this package's own types with no meaningful Markdown form — canvas\n * drawings, in particular) falls back to its required `toPlainText`\n * instead, same graceful-degradation choice every per-block `toMarkdown`\n * above makes for ITS OWN children.\n *\n * Consecutive sibling blocks are joined with a blank line EXCEPT between\n * two list items of the same kind (both `listItem`, both `ordered` or both\n * not) or two consecutive `blockquote` lines — those need to stay\n * adjacent, with no blank line between them, or Markdown parses them as\n * separate lists/quotes instead of one continuous one. Mirrors\n * `serializeHTML`'s own consecutive-sibling grouping in `serialize.js`,\n * just without an actual wrapping tag to emit (Markdown lists/quotes need\n * no container syntax, only adjacency).\n */\nexport function exportDocumentMarkdown(store, registry, inlineRegistry) {\n const root = store.getBlock(store.getRootId());\n if (!root) return '';\n const ctx = { store, registry, inlineRegistry };\n const ids = root.contentIds;\n\n let markdown = '';\n let prevBlock = null;\n for (const id of ids) {\n const block = store.getBlock(id);\n const entry = registry.get(block.type);\n const blockMarkdown = (entry.toMarkdown ?? entry.toPlainText)(block, ctx);\n\n if (prevBlock) {\n const sameList =\n block.type === 'listItem' &&\n prevBlock.type === 'listItem' &&\n Boolean(block.props.ordered) === Boolean(prevBlock.props.ordered);\n const sameQuote = block.type === 'blockquote' && prevBlock.type === 'blockquote';\n markdown += sameList || sameQuote ? '\\n' : '\\n\\n';\n }\n markdown += blockMarkdown;\n prevBlock = block;\n }\n return markdown;\n}\n","import { exportDocumentJSON } from '../clipboard/exportDocument.js';\nimport {\n saveDocumentVersion,\n listDocumentVersions,\n deleteDocumentVersion,\n} from '../persistence/indexedDbPersistence.js';\n\nconst DEFAULT_IDLE_MS = 5 * 60 * 1000; // 5 minutes of inactivity closes a version, roughly matching how Google Docs groups edits into one revision\nconst DEFAULT_MAX_VERSIONS = 200;\n\n/**\n * Automatic, Google Docs-style version history — no \"type a label and save\"\n * step. Listens to `store.subscribeToHistory()` (`store` must be a\n * `History` instance, not a plain `EditorStore` — this needs `getHistoryLog()`)\n * and, after `idleMs` of no further edits, closes the \"window\" of edits\n * that just happened and saves one snapshot for it: who made them\n * (`authorId`/`authorIds`, read straight off each entry's `actorId` — see\n * History's `defaultActorId`/`useEditor`'s `currentUserId`, no separate\n * identity plumbing needed here), roughly what changed (`summary`, a\n * lightweight count of distinct blocks touched — not a full diff), and the\n * full document snapshot itself for restore/preview.\n *\n * A version is never named/labeled up front — `DocumentVersion.label`\n * still exists for callers who want to rename one afterward, but nothing\n * in this module asks for one.\n */\nexport function createAutoVersionHistory({\n store,\n docId,\n idleMs = DEFAULT_IDLE_MS,\n maxVersions = DEFAULT_MAX_VERSIONS,\n onSnapshot,\n onError,\n}) {\n let idleTimer = null;\n let windowStart = store.getHistoryLog().length; // index into historyLog where the current open window begins\n let hasPendingActivity = false;\n\n function clearIdleTimer() {\n if (idleTimer) {\n clearTimeout(idleTimer);\n idleTimer = null;\n }\n }\n\n async function finalizeWindow() {\n clearIdleTimer();\n if (!hasPendingActivity) return;\n hasPendingActivity = false;\n\n const log = store.getHistoryLog();\n const entries = log.slice(windowStart);\n windowStart = log.length;\n if (entries.length === 0) return; // e.g. only an undo/redo happened, nothing new was appended to the log\n\n const touchedIds = new Set(entries.map((e) => e.id).filter(Boolean));\n const authorIds = [...new Set(entries.map((e) => e.actorId).filter(Boolean))];\n const authorId = entries[entries.length - 1].actorId ?? null; // whoever made the most recent edit in this window\n\n try {\n const doc = JSON.parse(exportDocumentJSON(store)); // exportDocumentJSON returns a JSON *string* -- parse it into the plain object DocumentVersion.doc expects\n const version = {\n id: crypto.randomUUID(),\n docId,\n timestamp: Date.now(),\n authorId,\n authorIds,\n summary: `${touchedIds.size} block${touchedIds.size === 1 ? '' : 's'} changed`,\n doc,\n };\n await saveDocumentVersion(version);\n onSnapshot?.(version);\n\n const all = await listDocumentVersions(docId); // newest first\n if (all.length > maxVersions) {\n const excess = all.slice(maxVersions);\n await Promise.all(excess.map((v) => deleteDocumentVersion(v.id)));\n }\n } catch (err) {\n onError?.(err);\n }\n }\n\n const unsubscribe = store.subscribeToHistory(() => {\n hasPendingActivity = true;\n clearIdleTimer();\n idleTimer = setTimeout(finalizeWindow, idleMs);\n });\n\n return {\n /** Stops listening. Does NOT flush a final in-progress window -- call `flush()` first if you want that (e.g. right before navigating away). */\n stop() {\n clearIdleTimer();\n unsubscribe();\n },\n /** Closes and saves the current window immediately, without waiting for `idleMs` of inactivity. A no-op if nothing's happened since the last save. */\n flush: finalizeWindow,\n };\n}\n","/**\n * Word-level LCS diff between two strings. Not a full Myers diff, but\n * version-history edits are typically a handful of scattered word changes\n * inside otherwise-unchanged paragraphs, so this is enough to render\n * accurate insertions/deletions instead of just \"this whole block changed.\"\n * Whitespace runs are kept as their own tokens so re-joining segments\n * reproduces the original spacing exactly.\n */\nexport function diffWords(oldText, newText) {\n const oldTokens = tokenize(oldText);\n const newTokens = tokenize(newText);\n const n = oldTokens.length;\n const m = newTokens.length;\n\n const dp = Array.from({ length: n + 1 }, () => new Uint32Array(m + 1));\n for (let i = n - 1; i >= 0; i -= 1) {\n for (let j = m - 1; j >= 0; j -= 1) {\n dp[i][j] =\n oldTokens[i] === newTokens[j] ? dp[i + 1][j + 1] + 1 : Math.max(dp[i + 1][j], dp[i][j + 1]);\n }\n }\n\n const segments = [];\n const push = (type, text) => {\n const last = segments[segments.length - 1];\n if (last && last.type === type) last.text += text;\n else segments.push({ type, text });\n };\n\n let i = 0;\n let j = 0;\n while (i < n && j < m) {\n if (oldTokens[i] === newTokens[j]) {\n push('equal', oldTokens[i]);\n i += 1;\n j += 1;\n } else if (dp[i + 1][j] >= dp[i][j + 1]) {\n push('removed', oldTokens[i]);\n i += 1;\n } else {\n push('added', newTokens[j]);\n j += 1;\n }\n }\n while (i < n) {\n push('removed', oldTokens[i]);\n i += 1;\n }\n while (j < m) {\n push('added', newTokens[j]);\n j += 1;\n }\n return segments;\n}\n\nfunction tokenize(text) {\n return (text ?? '').match(/\\s+|[^\\s]+/g) ?? [];\n}\n\nconst ESCAPE_MAP = { '&': '&', '<': '<', '>': '>', '\"': '"', \"'\": ''' };\nfunction escapeHtml(text) {\n return text.replace(/[&<>\"']/g, (ch) => ESCAPE_MAP[ch]);\n}\n\n/**\n * Flattens a DocumentJSON into an ordered list of its text-bearing blocks\n * (paragraphs, headings, list items, ...), keyed by block id. Only blocks\n * whose content resolves directly to text runs are collected -- container\n * blocks (page, columns, ...) are walked through but not themselves\n * represented, matching how they render (no text of their own to diff).\n */\nfunction extractTextBlocks(doc) {\n const blockById = new Map(doc.blocks.map((b) => [b.id, b]));\n const runById = new Map(doc.runs.map((r) => [r.id, r]));\n const result = [];\n\n const textFromRunIds = (ids) => ids.map((id) => runById.get(id)?.value ?? '').join('');\n\n const walk = (id) => {\n const block = blockById.get(id);\n if (!block) return;\n const titleRunIds = block.props?.titleRunIds;\n if (Array.isArray(titleRunIds) && titleRunIds.length > 0) {\n result.push({ id, text: textFromRunIds(titleRunIds) });\n } else if (block.contentIds.length > 0 && block.contentIds.every((cid) => runById.has(cid))) {\n result.push({ id, text: textFromRunIds(block.contentIds) });\n }\n for (const childId of block.contentIds) {\n if (!runById.has(childId)) walk(childId);\n }\n };\n walk(doc.rootId);\n return result;\n}\n\nconst EMPTY_DOC = {\n rootId: 'root',\n blocks: [{ id: 'root', type: 'page', parentId: null, contentIds: [], props: {} }],\n runs: [],\n};\n\n/**\n * Renders an HTML diff of `nextDoc` against `prevDoc` (Google Docs-style\n * \"show changes\" view) -- blocks that only exist in `nextDoc` render fully\n * highlighted as added, blocks that only existed in `prevDoc` render fully\n * struck-through as removed (appended after the surviving blocks, since\n * this is about surfacing *what* changed, not reproducing exact block\n * reordering), and blocks present in both get word-level diffed. Pass\n * `null`/`undefined` as `prevDoc` for \"this is the first version\" (everything\n * shows as added).\n */\nexport function diffDocumentsHTML(prevDoc, nextDoc) {\n const prevBlocks = extractTextBlocks(prevDoc ?? EMPTY_DOC);\n const nextBlocks = extractTextBlocks(nextDoc ?? EMPTY_DOC);\n const prevById = new Map(prevBlocks.map((b) => [b.id, b]));\n const nextIds = new Set(nextBlocks.map((b) => b.id));\n\n const parts = [];\n\n for (const block of nextBlocks) {\n const prevBlock = prevById.get(block.id);\n if (!prevBlock) {\n const text = escapeHtml(block.text) || ' ';\n parts.push(\n `<p class=\"be-version-diff-block\"><span class=\"be-version-diff-added\">${text}</span></p>`,\n );\n continue;\n }\n if (prevBlock.text === block.text) {\n parts.push(`<p class=\"be-version-diff-block\">${escapeHtml(block.text) || ' '}</p>`);\n continue;\n }\n const segments = diffWords(prevBlock.text, block.text);\n const html = segments\n .map((seg) => {\n const escaped = escapeHtml(seg.text);\n if (seg.type === 'added') return `<span class=\"be-version-diff-added\">${escaped}</span>`;\n if (seg.type === 'removed')\n return `<span class=\"be-version-diff-removed\">${escaped}</span>`;\n return escaped;\n })\n .join('');\n parts.push(`<p class=\"be-version-diff-block\">${html}</p>`);\n }\n\n for (const block of prevBlocks) {\n if (!nextIds.has(block.id)) {\n const text = escapeHtml(block.text) || ' ';\n parts.push(\n `<p class=\"be-version-diff-block\"><span class=\"be-version-diff-removed\">${text}</span></p>`,\n );\n }\n }\n\n if (parts.length === 0) return '<p class=\"be-version-diff-empty\">No text changes.</p>';\n return parts.join('');\n}\n","import { useCallback, useEffect, useState } from 'react';\nimport { listDocumentVersions } from '../persistence/indexedDbPersistence.js';\n\n/**\n * Reactive access to the stored version history for one document (see\n * saveDocumentVersion/loadDocumentVersion/deleteDocumentVersion/\n * listDocumentVersions) — for building a version list UI backed by\n * IndexedDB. Loads on mount and whenever `docId` changes; `refresh()`\n * re-queries on demand (e.g. right after a saveDocumentVersion/\n * deleteDocumentVersion call made elsewhere, since nothing here subscribes\n * to storage writes automatically). Restoring a version is not part of\n * this hook -- pass the loaded version's `doc` to `applyDocumentTemplate`.\n */\nexport function useDocumentVersions(docId) {\n const [versions, setVersions] = useState([]);\n const [isLoaded, setIsLoaded] = useState(false);\n\n const refresh = useCallback(() => {\n if (!docId) return Promise.resolve();\n setIsLoaded(false);\n return listDocumentVersions(docId).then((all) => {\n setVersions(all);\n setIsLoaded(true);\n });\n }, [docId]);\n\n useEffect(() => {\n if (!docId) {\n setVersions([]);\n setIsLoaded(true);\n return undefined;\n }\n let cancelled = false;\n setIsLoaded(false);\n listDocumentVersions(docId).then((all) => {\n if (cancelled) return;\n setVersions(all);\n setIsLoaded(true);\n });\n return () => {\n cancelled = true;\n };\n }, [docId]);\n\n return { versions, isLoaded, refresh };\n}\n","import { useEffect, useMemo, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useEditorStore, useBlockRegistry, useInlineRegistry } from './EditorProvider.jsx';\nimport { useDocumentVersions } from './useDocumentVersions.js';\nimport { createAutoVersionHistory } from '../versions/autoVersionHistory.js';\nimport { diffDocumentsHTML } from '../versions/diffVersions.js';\nimport { applyDocumentTemplate } from '../templates/blockTemplates.js';\nimport { exportDocumentHTML } from '../clipboard/exportDocument.js';\nimport { EditorStore } from '../store/EditorStore.js';\nimport { CommentAvatar } from './CommentAvatar.jsx';\nimport { formatRelativeTime } from './commentFormatting.js';\nimport { ClockHistoryIcon, RestoreIcon, XIcon } from './icons.jsx';\n\nconst FOCUSABLE_SELECTOR =\n 'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])';\n\nfunction formatDayLabel(timestamp) {\n const d = new Date(timestamp);\n const now = new Date();\n const startOfDay = (date) =>\n new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime();\n const diffDays = Math.round((startOfDay(now) - startOfDay(d)) / (24 * 60 * 60 * 1000));\n if (diffDays === 0) return 'Today';\n if (diffDays === 1) return 'Yesterday';\n return d.toLocaleDateString(undefined, {\n month: 'long',\n day: 'numeric',\n year: d.getFullYear() !== now.getFullYear() ? 'numeric' : undefined,\n });\n}\n\n/**\n * Google Docs-style version history — no \"name it and save\" step. Mount\n * this once anywhere under an `<EditorProvider>` (`store` must be a\n * `History` instance, not a plain `EditorStore` — see `createAutoVersionHistory`)\n * and it both quietly captures automatic snapshots (one saved after each\n * burst of edits settles, attributed to whoever made them via History's\n * `defaultActorId`/`useEditor`'s `currentUserId`, no separate identity\n * plumbing needed here) AND renders the \"Version history\" button + drawer\n * UI for browsing/previewing/restoring them.\n *\n * The drawer's preview is a static HTML render (`exportDocumentHTML` against\n * a throwaway `EditorStore` built from that version's snapshot) — read-only\n * by construction, not a second live nested editor.\n */\nexport function VersionHistory({ docId, idleMs, maxVersions }) {\n const store = useEditorStore();\n const registry = useBlockRegistry();\n const inlineRegistry = useInlineRegistry();\n const { versions, isLoaded, refresh } = useDocumentVersions(docId);\n const [isOpen, setIsOpen] = useState(false);\n const [selectedId, setSelectedId] = useState(null);\n const [viewMode, setViewMode] = useState('changes'); // 'changes' | 'preview'\n const drawerRef = useRef(null);\n const previouslyFocusedRef = useRef(null);\n\n useEffect(() => {\n if (typeof store.getHistoryLog !== 'function') return undefined; // needs a History instance, not a plain EditorStore\n const autoHistory = createAutoVersionHistory({\n store,\n docId,\n idleMs,\n maxVersions,\n onSnapshot: refresh,\n });\n return () => autoHistory.stop();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [store, docId]);\n\n function close() {\n setIsOpen(false);\n setSelectedId(null);\n setViewMode('changes');\n }\n\n useEffect(() => {\n if (!isOpen) return undefined;\n const handleKeyDown = (event) => {\n if (event.key === 'Escape') close();\n };\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isOpen]);\n\n // Same one-time move-in-on-open / move-back-out-on-close as Modal.jsx —\n // this drawer is hand-rolled rather than built on Modal (it's a\n // side-drawer, not a centered dialog), so it needs its own copy of the\n // same focus handling instead of inheriting it for free.\n useEffect(() => {\n if (isOpen) {\n previouslyFocusedRef.current = document.activeElement;\n const drawer = drawerRef.current;\n const focusable = drawer?.querySelector(FOCUSABLE_SELECTOR);\n (focusable ?? drawer)?.focus();\n return undefined;\n }\n previouslyFocusedRef.current?.focus?.();\n previouslyFocusedRef.current = null;\n return undefined;\n }, [isOpen]);\n\n const selectedIndex = versions.findIndex((v) => v.id === selectedId);\n const selected = selectedIndex >= 0 ? versions[selectedIndex] : null;\n // versions is newest-first, so the version right before this one chronologically is the next array entry.\n const previousVersion = selectedIndex >= 0 ? (versions[selectedIndex + 1] ?? null) : null;\n\n const previewHtml = useMemo(() => {\n if (!selected) return '';\n const previewStore = new EditorStore(selected.doc);\n return exportDocumentHTML(previewStore, registry, inlineRegistry);\n }, [selected, registry, inlineRegistry]);\n\n const diffHtml = useMemo(() => {\n if (!selected) return '';\n return diffDocumentsHTML(previousVersion?.doc ?? null, selected.doc);\n }, [selected, previousVersion]);\n\n function handleRestore() {\n if (!selected) return;\n if (!window.confirm('Restore this version? This replaces the current document.')) return;\n applyDocumentTemplate(store, selected.doc);\n close();\n }\n\n // Groups by day, preserving useDocumentVersions' own newest-first order.\n const groups = [];\n for (const version of versions) {\n const label = formatDayLabel(version.timestamp);\n let group = groups[groups.length - 1];\n if (!group || group.label !== label) {\n group = { label, versions: [] };\n groups.push(group);\n }\n group.versions.push(version);\n }\n\n return (\n <>\n <button\n type=\"button\"\n className=\"be-version-history-trigger\"\n onClick={() => setIsOpen(true)}\n title=\"Version history\"\n >\n <ClockHistoryIcon size={15} />\n Version history\n </button>\n {isOpen &&\n createPortal(\n <>\n <div className=\"be-version-history-backdrop\" onClick={close} />\n <div\n ref={drawerRef}\n className=\"be-version-history-drawer\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Version history\"\n tabIndex={-1}\n >\n <div className=\"be-version-history-header\">\n <span>{selected ? 'Preview' : 'Version history'}</span>\n <button\n type=\"button\"\n className=\"be-version-history-close\"\n onClick={close}\n aria-label=\"Close\"\n >\n <XIcon size={14} />\n </button>\n </div>\n\n {selected ? (\n <div className=\"be-version-history-preview\">\n <div className=\"be-version-history-preview-meta\">\n <CommentAvatar authorId={selected.authorId} size={24} />\n <div>\n <div className=\"be-version-history-preview-author\">\n {selected.authorId ?? 'Unknown'}\n </div>\n <div className=\"be-version-history-preview-time\">\n {new Date(selected.timestamp).toLocaleString()} · {selected.summary}\n </div>\n </div>\n </div>\n\n <div\n className=\"be-version-history-view-toggle\"\n role=\"tablist\"\n aria-label=\"View mode\"\n >\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={viewMode === 'changes'}\n className={viewMode === 'changes' ? 'is-active' : ''}\n onClick={() => setViewMode('changes')}\n >\n Changes\n </button>\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={viewMode === 'preview'}\n className={viewMode === 'preview' ? 'is-active' : ''}\n onClick={() => setViewMode('preview')}\n >\n Preview\n </button>\n </div>\n\n {viewMode === 'changes' && (\n <>\n <div className=\"be-version-history-diff-legend\">\n <span className=\"be-version-diff-added\">Added</span>\n <span className=\"be-version-diff-removed\">Removed</span>\n {!previousVersion && (\n <span className=\"be-version-history-diff-legend-note\">\n First saved version — everything shown is new.\n </span>\n )}\n </div>\n {/* Word-level diff against the previous version, rendered from plain text -- deliberately simpler than the live editor's own formatting (see diffDocumentsHTML). */}\n <div\n className=\"be-version-history-preview-body be-version-history-diff-body\"\n dangerouslySetInnerHTML={{ __html: diffHtml }}\n />\n </>\n )}\n {viewMode === 'preview' && (\n // Static HTML from a throwaway store (see previewHtml above) -- inherently read-only, not a second live editor.\n <div\n className=\"be-version-history-preview-body\"\n dangerouslySetInnerHTML={{ __html: previewHtml }}\n />\n )}\n\n <div className=\"be-version-history-preview-actions\">\n <button\n type=\"button\"\n onClick={() => {\n setSelectedId(null);\n setViewMode('changes');\n }}\n >\n Back\n </button>\n <button\n type=\"button\"\n className=\"be-version-history-restore\"\n onClick={handleRestore}\n >\n <RestoreIcon size={13} />\n Restore this version\n </button>\n </div>\n </div>\n ) : (\n <div className=\"be-version-history-list\">\n {!isLoaded && <p className=\"be-version-history-empty\">Loading…</p>}\n {isLoaded && versions.length === 0 && (\n <p className=\"be-version-history-empty\">\n No versions yet — one is saved automatically after you make some edits and\n pause.\n </p>\n )}\n {groups.map((group) => (\n <div key={group.label} className=\"be-version-history-group\">\n <div className=\"be-version-history-group-label\">{group.label}</div>\n {group.versions.map((version) => (\n <button\n key={version.id}\n type=\"button\"\n className=\"be-version-history-item\"\n onClick={() => setSelectedId(version.id)}\n >\n <CommentAvatar authorId={version.authorId} size={24} />\n <div className=\"be-version-history-item-body\">\n <div className=\"be-version-history-item-author\">\n {version.authorId ?? 'Unknown'}\n </div>\n <div className=\"be-version-history-item-meta\">\n {formatRelativeTime(version.timestamp)} · {version.summary}\n </div>\n </div>\n </button>\n ))}\n </div>\n ))}\n </div>\n )}\n </div>\n </>,\n document.body,\n )}\n </>\n );\n}\n"],"names":["diffCodePoints","oldValue","newValue","oldChars","newChars","start","maxStart","oldEnd","newEnd","FIELD_TYPES_KEY","COMMENTS_KEY","PEOPLE_KEY","EditorStore","doc","b","f","c","p","genPeerId","HLC","FieldClockRegistry","parentId","order","block","ListCrdtState","runId","run","chars","prev","index","ch","charId","value","currentIds","clock","deletedCharIds","i","id","insertedChars","afterId","genId","charEdit","d","listener","set","touchedIds","rootId","blocks","runs","walk","childId","_a","op","OP","patchKeys","editRunChars","previousPatch","clocks","key","updateRun","updateBlockProps","previousType","previousProps","changeBlockType","r","parent","currentArray","removeBlock","target","subtree","deleteClock","fromParentId","fromOrder","fromIndex","toOrder","toArray","toIndex","ts","touched","moveBlock","previousContentIds","setBlockContentIds","inContentIds","sourceArray","startIndex","removedRuns","newArray","replaceRunSpan","usesTitleRunIds","previousRunIds","previousRuns","newRunIds","setBlockRuns","removeFieldType","existing","updateFieldType","addFieldType","removeCommentThread","addCommentThread","thread","removeCommentReply","removedMessage","m","addCommentReply","previousResolved","resolveComment","removePerson","updatePerson","addPerson","ops","envelope","hadSlot","patch","remoteClock","_b","count","maxAgeMs","now","threshold","removed","applyOps","store","captureBlockTemplate","blockIds","captureSubtree","insertBlockTemplate","template","nextIndex","root","subtreeBlocks","remapSubtreeIds","insertBlock","applyDocumentTemplate","rawStore","registerBlockTemplates","registry","templates","blockId","sliceStart","sliceEnd","current","exportDocumentJSON","pretty","exportDocumentHTML","inlineRegistry","serializeBlockRange","exportDocumentText","exportDocumentWordHTML","exportDocumentMarkdown","ctx","ids","markdown","prevBlock","entry","blockMarkdown","sameList","sameQuote","DEFAULT_IDLE_MS","DEFAULT_MAX_VERSIONS","createAutoVersionHistory","docId","idleMs","maxVersions","onSnapshot","onError","idleTimer","windowStart","hasPendingActivity","clearIdleTimer","finalizeWindow","log","entries","e","authorIds","authorId","version","saveDocumentVersion","all","listDocumentVersions","excess","v","deleteDocumentVersion","err","unsubscribe","diffWords","oldText","newText","oldTokens","tokenize","newTokens","n","dp","j","segments","push","type","text","last","ESCAPE_MAP","escapeHtml","extractTextBlocks","blockById","runById","result","textFromRunIds","titleRunIds","cid","EMPTY_DOC","diffDocumentsHTML","prevDoc","nextDoc","prevBlocks","nextBlocks","prevById","nextIds","parts","html","seg","escaped","useDocumentVersions","versions","setVersions","useState","isLoaded","setIsLoaded","refresh","useCallback","useEffect","cancelled","FOCUSABLE_SELECTOR","formatDayLabel","timestamp","startOfDay","date","diffDays","VersionHistory","useEditorStore","useBlockRegistry","useInlineRegistry","isOpen","setIsOpen","selectedId","setSelectedId","viewMode","setViewMode","drawerRef","useRef","previouslyFocusedRef","autoHistory","close","handleKeyDown","event","drawer","_c","selectedIndex","selected","previousVersion","previewHtml","useMemo","previewStore","diffHtml","handleRestore","groups","label","group","jsxs","Fragment","jsx","ClockHistoryIcon","createPortal","XIcon","CommentAvatar","RestoreIcon","formatRelativeTime"],"mappings":"ySAYO,SAASA,EAAeC,EAAUC,EAAU,CACjD,MAAMC,EAAW,MAAM,KAAKF,GAAY,EAAE,EACpCG,EAAW,MAAM,KAAKF,GAAY,EAAE,EAC1C,IAAIG,EAAQ,EACZ,MAAMC,EAAW,KAAK,IAAIH,EAAS,OAAQC,EAAS,MAAM,EAC1D,KAAOC,EAAQC,GAAYH,EAASE,CAAK,IAAMD,EAASC,CAAK,GAAGA,GAAS,EAEzE,IAAIE,EAASJ,EAAS,OAClBK,EAASJ,EAAS,OACtB,KAAOG,EAASF,GAASG,EAASH,GAASF,EAASI,EAAS,CAAC,IAAMH,EAASI,EAAS,CAAC,GACrFD,GAAU,EACVC,GAAU,EAGZ,MAAO,CAAE,MAAAH,EAAO,OAAAE,EAAQ,OAAAC,EAAQ,SAAAL,EAAU,SAAAC,CAAQ,CACpD,CCIA,MAAMK,EAAkB,cAGlBC,EAAe,YAGfC,EAAa,UAgBZ,MAAMC,CAAY,CACvB,YAAYC,EAAK,CACf,KAAK,OAAS,IAAI,MAAKA,GAAA,YAAAA,EAAK,SAAU,CAAA,GAAI,IAAKC,GAAM,CAACA,EAAE,GAAIA,CAAC,CAAC,CAAC,EAC/D,KAAK,KAAO,IAAI,MAAKD,GAAA,YAAAA,EAAK,OAAQ,CAAA,GAAI,IAAK,GAAM,CAAC,EAAE,GAAI,CAAC,CAAC,CAAC,EAC3D,KAAK,QAASA,GAAA,YAAAA,EAAK,SAAU,KAC7B,KAAK,WAAa,IAAI,MAAKA,GAAA,YAAAA,EAAK,aAAc,CAAA,GAAI,IAAKE,GAAM,CAACA,EAAE,GAAIA,CAAC,CAAC,CAAC,EACvE,KAAK,oBAAsB,KAC3B,KAAK,SAAW,IAAI,MAAKF,GAAA,YAAAA,EAAK,WAAY,CAAA,GAAI,IAAKG,GAAM,CAACA,EAAE,GAAIA,CAAC,CAAC,CAAC,EACnE,KAAK,kBAAoB,KACzB,KAAK,OAAS,IAAI,MAAKH,GAAA,YAAAA,EAAK,SAAU,CAAA,GAAI,IAAKI,GAAM,CAACA,EAAE,GAAIA,CAAC,CAAC,CAAC,EAC/D,KAAK,gBAAkB,KACvB,KAAK,WAAa,IAAI,IACtB,KAAK,iBAAmB,IAAI,IAS5B,KAAK,QAAUC,YAAS,EACxB,KAAK,OAAS,IAAIC,MAAI,KAAK,OAAO,EAClC,KAAK,aAAe,IAAIC,qBACxB,KAAK,QAAU,IAAI,IAYnB,KAAK,WAAa,IAAI,IACtB,KAAK,UAAY,IAAI,IACrB,KAAK,mBAAqB,IAAI,GAChC,CAGA,UAAUC,EAAU,CAClB,IAAIC,EAAQ,KAAK,QAAQ,IAAID,CAAQ,EACrC,GAAI,CAACC,EAAO,CACV,MAAMC,EAAQ,KAAK,OAAO,IAAIF,CAAQ,EACtCC,EAAQE,EAAAA,cAAc,WAAUD,GAAA,YAAAA,EAAO,aAAc,GAAI,CAAE,OAAQ,SAAU,EAC7E,KAAK,QAAQ,IAAIF,EAAUC,CAAK,CAClC,CACA,OAAOA,CACT,CAuBA,aAAaG,EAAO,CAClB,IAAIH,EAAQ,KAAK,WAAW,IAAIG,CAAK,EACrC,GAAI,CAACH,EAAO,CACV,MAAMI,EAAM,KAAK,KAAK,IAAID,CAAK,EACzBE,EAAQ,IAAI,IAClBL,EAAQ,IAAIE,EAAAA,cACZ,IAAII,EAAO,KACPC,EAAQ,EACZ,UAAWC,KAAM,MAAM,MAAKJ,GAAA,YAAAA,EAAK,QAAS,EAAE,EAAG,CAC7C,MAAMK,EAAS,GAAGN,CAAK,eAAeI,CAAK,GAC3CF,EAAM,IAAII,EAAQD,CAAE,EACpBR,EAAM,OAAOS,EAAQH,EAAM,CAAE,SAAU,EAAG,QAAS,EAAG,OAAQ,QAAQ,EAAI,QAAQ,EAClFA,EAAOG,EACPF,GAAS,CACX,CACA,KAAK,WAAW,IAAIJ,EAAOH,CAAK,EAChC,KAAK,UAAU,IAAIG,EAAOE,CAAK,CACjC,CACA,OAAOL,CACT,CAGA,qBAAqBG,EAAO,CAC1B,IAAIO,EAAQ,KAAK,mBAAmB,IAAIP,CAAK,EAC7C,GAAIO,IAAU,OAAW,CACvB,MAAMV,EAAQ,KAAK,aAAaG,CAAK,EAC/BE,EAAQ,KAAK,UAAU,IAAIF,CAAK,EACtCO,EAAQV,EACL,QAAO,EACP,IAAKS,GAAWJ,EAAM,IAAII,CAAM,CAAC,EACjC,KAAK,EAAE,EACV,KAAK,mBAAmB,IAAIN,EAAOO,CAAK,CAC1C,CACA,OAAOA,CACT,CAWA,aAAaP,EAAOvB,EAAU,CAC5B,MAAMD,EAAW,KAAK,qBAAqBwB,CAAK,EAC1C,CAAE,MAAApB,EAAO,OAAAE,EAAQ,OAAAC,EAAQ,SAAAJ,CAAQ,EAAKJ,EAAeC,EAAUC,CAAQ,EACvEoB,EAAQ,KAAK,aAAaG,CAAK,EAC/BE,EAAQ,KAAK,UAAU,IAAIF,CAAK,EAChCQ,EAAaX,EAAM,QAAO,EAC1BY,EAAQ,KAAK,OAAO,KAAI,EAExBC,EAAiB,CAAA,EACvB,QAASC,EAAI/B,EAAO+B,EAAI7B,EAAQ6B,GAAK,EAAG,CACtC,MAAMC,EAAKJ,EAAWG,CAAC,EACvBd,EAAM,OAAOe,EAAIH,CAAK,EACtBC,EAAe,KAAK,CAAE,GAAAE,EAAI,MAAAH,CAAK,CAAE,CACnC,CAEA,MAAMI,EAAgB,CAAA,EACtB,IAAIC,EAAUlC,EAAQ,EAAI4B,EAAW5B,EAAQ,CAAC,EAAI,KAClD,QAAS+B,EAAI/B,EAAO+B,EAAI5B,EAAQ4B,GAAK,EAAG,CACtC,MAAMC,EAAKG,EAAAA,MAAK,EACVV,EAAK1B,EAASgC,CAAC,EACrBT,EAAM,IAAIU,EAAIP,CAAE,EAChBR,EAAM,OAAOe,EAAIE,EAASL,EAAO,KAAK,OAAO,EAC7CI,EAAc,KAAK,CAAE,GAAAD,EAAI,KAAMP,EAAI,QAAAS,EAAS,MAAAL,EAAO,EACnDK,EAAUF,CACZ,CAEA,YAAK,mBAAmB,OAAOZ,CAAK,EAC7B,CAAE,SAAAxB,EAAU,cAAAqC,EAAe,eAAAH,EAAgB,MAAAD,CAAK,CACzD,CAcA,mBAAmBT,EAAOgB,EAAU,CAClC,MAAMnB,EAAQ,KAAK,aAAaG,CAAK,EAC/BE,EAAQ,KAAK,UAAU,IAAIF,CAAK,EACtC,UAAWT,KAAKyB,EAAS,cACnBnB,EAAM,IAAIN,EAAE,EAAE,EAAGM,EAAM,QAAQN,EAAE,EAAE,GAErCW,EAAM,IAAIX,EAAE,GAAIA,EAAE,IAAI,EACtBM,EAAM,OAAON,EAAE,GAAIA,EAAE,QAASA,EAAE,MAAO,KAAK,OAAO,GAGvD,UAAW0B,KAAKD,EAAS,eAAgBnB,EAAM,OAAOoB,EAAE,GAAIA,EAAE,KAAK,EACnE,KAAK,mBAAmB,OAAOjB,CAAK,CACtC,CAEA,SAASY,EAAI,CACX,OAAO,KAAK,OAAO,IAAIA,CAAE,CAC3B,CAEA,OAAOA,EAAI,CACT,OAAO,KAAK,KAAK,IAAIA,CAAE,CACzB,CASA,eAAgB,CACd,OAAK,KAAK,sBAAqB,KAAK,oBAAsB,CAAC,GAAG,KAAK,WAAW,QAAQ,GAC/E,KAAK,mBACd,CAEA,aAAaA,EAAI,CACf,OAAO,KAAK,WAAW,IAAIA,CAAE,CAC/B,CAQA,aAAc,CACZ,OAAK,KAAK,oBAAmB,KAAK,kBAAoB,CAAC,GAAG,KAAK,SAAS,QAAQ,GACzE,KAAK,iBACd,CAEA,WAAWA,EAAI,CACb,OAAO,KAAK,SAAS,IAAIA,CAAE,CAC7B,CAUA,WAAY,CACV,OAAK,KAAK,kBAAiB,KAAK,gBAAkB,CAAC,GAAG,KAAK,OAAO,QAAQ,GACnE,KAAK,eACd,CAEA,UAAUA,EAAI,CACZ,OAAO,KAAK,OAAO,IAAIA,CAAE,CAC3B,CAQA,cAAe,CACb,MAAO,CAAC,GAAG,KAAK,KAAK,KAAI,CAAE,CAC7B,CAEA,WAAY,CACV,OAAO,KAAK,MACd,CAEA,UAAUA,EAAIM,EAAU,CACtB,IAAIC,EAAM,KAAK,WAAW,IAAIP,CAAE,EAChC,OAAKO,IACHA,EAAM,IAAI,IACV,KAAK,WAAW,IAAIP,EAAIO,CAAG,GAE7BA,EAAI,IAAID,CAAQ,EACT,IAAM,CACXC,EAAI,OAAOD,CAAQ,EACfC,EAAI,OAAS,GAAG,KAAK,WAAW,OAAOP,CAAE,CAC/C,CACF,CAWA,aAAaM,EAAU,CACrB,YAAK,iBAAiB,IAAIA,CAAQ,EAC3B,IAAM,KAAK,iBAAiB,OAAOA,CAAQ,CACpD,CAEA,QAAQE,EAAY,CAClB,UAAWR,KAAMQ,EAAY,CAC3B,MAAMD,EAAM,KAAK,WAAW,IAAIP,CAAE,EAClC,GAAKO,EAEL,UAAWD,IAAY,CAAC,GAAGC,CAAG,EAAGD,EAAQ,CAC3C,CACA,GAAI,KAAK,iBAAiB,KAAO,EAC/B,UAAWA,IAAY,CAAC,GAAG,KAAK,gBAAgB,EAAGA,EAAQ,CAE/D,CAGA,gBAAgBG,EAAQ,CACtB,MAAMC,EAAS,CAAA,EACTC,EAAO,CAAA,EACPC,EAAQZ,GAAO,OACnB,GAAI,KAAK,KAAK,IAAIA,CAAE,EAAG,CACrBW,EAAK,KAAK,KAAK,KAAK,IAAIX,CAAE,CAAC,EAC3B,MACF,CACA,MAAMd,EAAQ,KAAK,OAAO,IAAIc,CAAE,EAChC,GAAKd,EACL,CAAAwB,EAAO,KAAKxB,CAAK,EACjB,UAAW2B,KAAW3B,EAAM,WAAY0B,EAAKC,CAAO,EAIpD,UAAWzB,MAAS0B,EAAA5B,EAAM,QAAN,YAAA4B,EAAa,cAAe,CAAA,EAAIF,EAAKxB,CAAK,EAChE,EACA,OAAAwB,EAAKH,CAAM,EACJ,CAAE,OAAAC,EAAQ,KAAAC,CAAI,CACvB,CAEA,eAAeF,EAAQ,CACrB,MAAMG,EAAQZ,GAAO,OACnB,GAAI,KAAK,KAAK,IAAIA,CAAE,EAAG,CACrB,KAAK,KAAK,OAAOA,CAAE,EACnB,MACF,CACA,MAAMd,EAAQ,KAAK,OAAO,IAAIc,CAAE,EAChC,GAAKd,EACL,WAAW2B,KAAW3B,EAAM,WAAY0B,EAAKC,CAAO,EACpD,UAAWzB,MAAS0B,EAAA5B,EAAM,QAAN,YAAA4B,EAAa,cAAe,CAAA,EAAIF,EAAKxB,CAAK,EAC9D,KAAK,OAAO,OAAOY,CAAE,EACvB,EACAY,EAAKH,CAAM,CACb,CAOA,eAAeM,EAAI,OACjB,OAAQA,EAAG,KAAI,CACb,KAAKC,EAAAA,GAAG,WAAY,CAClB,MAAM3B,EAAM,KAAK,KAAK,IAAI0B,EAAG,EAAE,EACzBE,EAAY,OAAO,KAAKF,EAAG,KAAK,EAatC,GAAIE,EAAU,SAAW,GAAKA,EAAU,CAAC,IAAM,QAAS,CACtD,IAAIb,EAAWW,EAAG,UAClB,GAAIX,EACF,KAAK,mBAAmBW,EAAG,GAAIX,CAAQ,MAClC,CACL,KAAM,CAAE,SAAAxC,EAAU,cAAAqC,EAAe,eAAAH,EAAgB,MAAAD,CAAK,EAAK,KAAK,aAC9DkB,EAAG,GACHA,EAAG,MAAM,KACvB,EACYX,EAAW,CAAE,SAAAxC,EAAU,cAAAqC,EAAe,eAAAH,EAAgB,MAAAD,CAAK,EAC3DkB,EAAG,UAAYX,CACjB,CACA,MAAMvC,EAAW,KAAK,qBAAqBkD,EAAG,EAAE,EAChD,YAAK,KAAK,IAAIA,EAAG,GAAI,CAAE,GAAG1B,EAAK,MAAOxB,EAAU,EAChD,KAAK,cAAgB,CACnB,KAAM,cACN,MAAOkD,EAAG,GACV,cAAeX,EAAS,cACxB,eAAgBA,EAAS,eACzB,MAAOA,EAAS,KAC5B,EACU,KAAK,QAAQ,CAACW,EAAG,EAAE,CAAC,EACbG,EAAAA,aACLH,EAAG,GACHX,EAAS,cAAc,IAAKzB,GAAMA,EAAE,EAAE,EACtCyB,EAAS,eAAe,IAAKzB,GAAMA,EAAE,EAAE,EACvCyB,EAAS,QACrB,CACQ,CAEA,MAAMe,EAAgB,CAAA,EAChBC,EAAS,CAAA,EACf,UAAWC,KAAOJ,EAChBE,EAAcE,CAAG,EAAIhC,EAAIgC,CAAG,EAC5BD,EAAOC,CAAG,EAAI,KAAK,OAAO,KAAI,EAC9B,KAAK,aAAa,YAAYN,EAAG,GAAIM,EAAKD,EAAOC,CAAG,CAAC,EAEvD,YAAK,KAAK,IAAIN,EAAG,GAAI,CAAE,GAAG1B,EAAK,GAAG0B,EAAG,MAAO,EAC5C,KAAK,cAAgB,CACnB,KAAM,aACN,OAAQ,MACR,GAAIA,EAAG,GACP,MAAOA,EAAG,MACV,OAAAK,CACV,EACQ,KAAK,QAAQ,CAACL,EAAG,EAAE,CAAC,EACbO,YAAUP,EAAG,GAAII,CAAa,CACvC,CAEA,KAAKH,EAAAA,GAAG,eAAgB,CACtB,MAAM/B,EAAQ,KAAK,aAAa8B,EAAG,EAAE,EAC/BlB,EAAQ,KAAK,OAAO,KAAI,EAC9B,UAAWH,KAAUqB,EAAG,aAAc9B,EAAM,OAAOS,EAAQG,CAAK,EAChE,UAAWH,KAAUqB,EAAG,WAAY9B,EAAM,QAAQS,CAAM,EACxD,KAAK,mBAAmB,OAAOqB,EAAG,EAAE,EACpC,MAAM1B,EAAM,KAAK,KAAK,IAAI0B,EAAG,EAAE,EACzBlD,EAAW,KAAK,qBAAqBkD,EAAG,EAAE,EAChD,YAAK,KAAK,IAAIA,EAAG,GAAI,CAAE,GAAG1B,EAAK,MAAOxB,EAAU,EAChD,KAAK,cAAgB,CACnB,KAAM,cACN,MAAOkD,EAAG,GACV,aAAcA,EAAG,aACjB,WAAYA,EAAG,WACf,MAAAlB,CACV,EACQ,KAAK,QAAQ,CAACkB,EAAG,EAAE,CAAC,EACbG,EAAAA,aAAaH,EAAG,GAAIA,EAAG,WAAYA,EAAG,YAAY,CAC3D,CAEA,KAAKC,EAAAA,GAAG,mBAAoB,CAC1B,MAAM9B,EAAQ,KAAK,OAAO,IAAI6B,EAAG,EAAE,EAC7BI,EAAgB,CAAA,EAChBC,EAAS,CAAA,EACf,UAAWC,KAAO,OAAO,KAAKN,EAAG,KAAK,EACpCI,EAAcE,CAAG,EAAInC,EAAM,MAAMmC,CAAG,EACpCD,EAAOC,CAAG,EAAI,KAAK,OAAO,KAAI,EAC9B,KAAK,aAAa,YAAYN,EAAG,GAAI,SAASM,CAAG,GAAID,EAAOC,CAAG,CAAC,EAElE,YAAK,OAAO,IAAIN,EAAG,GAAI,CAAE,GAAG7B,EAAO,MAAO,CAAE,GAAGA,EAAM,MAAO,GAAG6B,EAAG,KAAK,CAAE,CAAE,EAC3E,KAAK,cAAgB,CACnB,KAAM,aACN,OAAQ,aACR,GAAIA,EAAG,GACP,MAAOA,EAAG,MACV,OAAAK,CACV,EACQ,KAAK,QAAQ,CAACL,EAAG,EAAE,CAAC,EACbQ,mBAAiBR,EAAG,GAAII,CAAa,CAC9C,CAEA,KAAKH,EAAAA,GAAG,kBAAmB,CACzB,MAAM9B,EAAQ,KAAK,OAAO,IAAI6B,EAAG,EAAE,EAC7BS,EAAetC,EAAM,KACrBuC,EAAgBvC,EAAM,MACtBW,EAAQ,KAAK,OAAO,KAAI,EAC9B,YAAK,aAAa,YAAYkB,EAAG,GAAI,OAAQlB,CAAK,EAClD,KAAK,OAAO,IAAIkB,EAAG,GAAI,CAAE,GAAG7B,EAAO,KAAM6B,EAAG,UAAW,MAAOA,EAAG,KAAK,CAAE,EACxE,KAAK,cAAgB,CACnB,KAAM,aACN,OAAQ,YACR,GAAIA,EAAG,GACP,UAAWA,EAAG,UACd,MAAOA,EAAG,MACV,MAAAlB,CACV,EACQ,KAAK,QAAQ,CAACkB,EAAG,EAAE,CAAC,EACbW,EAAAA,gBAAgBX,EAAG,GAAIS,EAAcC,CAAa,CAC3D,CAEA,KAAKT,EAAAA,GAAG,aAAc,CACpB,GAAID,EAAG,QAAS,CACd,UAAWtC,KAAKsC,EAAG,QAAQ,OAAQ,KAAK,OAAO,IAAItC,EAAE,GAAIA,CAAC,EAC1D,UAAWkD,KAAKZ,EAAG,QAAQ,KAAM,KAAK,KAAK,IAAIY,EAAE,GAAIA,CAAC,CACxD,MACE,KAAK,OAAO,IAAIZ,EAAG,MAAM,GAAIA,EAAG,KAAK,EAEvC,MAAMa,EAAS,KAAK,OAAO,IAAIb,EAAG,QAAQ,EACpC9B,EAAQ,KAAK,UAAU8B,EAAG,QAAQ,EACxC,GAAI9B,EAAM,IAAI8B,EAAG,MAAM,EAAE,EAIvB9B,EAAM,QAAQ8B,EAAG,MAAM,EAAE,MACpB,CACL,MAAMc,EAAe5C,EAAM,QAAO,EAC5BO,EAAQuB,EAAG,OAASc,EAAa,OACjC3B,EAAUV,EAAQ,EAAIqC,EAAarC,EAAQ,CAAC,EAAI,KACtDP,EAAM,OAAO8B,EAAG,MAAM,GAAIb,EAAS,KAAK,OAAO,OAAQ,KAAK,OAAO,CACrE,CACA,YAAK,OAAO,IAAIa,EAAG,SAAU,CAAE,GAAGa,EAAQ,WAAY3C,EAAM,QAAO,CAAE,CAAE,EACvE,KAAK,cAAgB,CACnB,KAAM,aACN,SAAU8B,EAAG,SACb,QAASA,EAAG,MAAM,GAClB,KAAM9B,EAAM,QAAQ8B,EAAG,MAAM,EAAE,EAC/B,QAASA,EAAG,SAAW,CAAE,OAAQ,CAACA,EAAG,KAAK,EAAG,KAAM,EAAE,CAC/D,EACQ,KAAK,QAAQ,CAACA,EAAG,MAAM,GAAIA,EAAG,QAAQ,CAAC,EAChCe,cAAYf,EAAG,MAAM,EAAE,CAChC,CAEA,KAAKC,EAAAA,GAAG,aAAc,CACpB,MAAMe,EAAS,KAAK,OAAO,IAAIhB,EAAG,EAAE,EAC9B/B,EAAW+C,EAAO,SAClBH,EAAS,KAAK,OAAO,IAAI5C,CAAQ,EACjCC,EAAQ,KAAK,UAAUD,CAAQ,EAC/BQ,EAAQP,EAAM,QAAO,EAAG,QAAQ8B,EAAG,EAAE,EACrCiB,EAAU,KAAK,gBAAgBjB,EAAG,EAAE,EAC1C,KAAK,eAAeA,EAAG,EAAE,EACzB,MAAMkB,EAAc,KAAK,OAAO,KAAI,EACpC,OAAAhD,EAAM,OAAO8B,EAAG,GAAIkB,CAAW,EAC/B,KAAK,OAAO,IAAIjD,EAAU,CAAE,GAAG4C,EAAQ,WAAY3C,EAAM,QAAO,EAAI,EACpE,KAAK,cAAgB,CAAE,KAAM,aAAc,SAAAD,EAAU,QAAS+B,EAAG,GAAI,MAAOkB,CAAW,EACvF,KAAK,QAAQ,CAACjD,CAAQ,CAAC,EAChB,CAAE,KAAMgC,EAAAA,GAAG,aAAc,MAAOe,EAAQ,SAAA/C,EAAU,MAAAQ,EAAO,QAAAwC,CAAO,CACzE,CAEA,KAAKhB,EAAAA,GAAG,WAAY,CAElB,MAAMkB,EADS,KAAK,OAAO,IAAInB,EAAG,EAAE,EACR,SACtBoB,EAAY,KAAK,UAAUD,CAAY,EACvCE,EAAYD,EAAU,QAAO,EAAG,QAAQpB,EAAG,EAAE,EAQnDoB,EAAU,OAAOpB,EAAG,GAAI,KAAK,OAAO,MAAM,EAC1C,KAAK,OAAO,IAAImB,EAAc,CAC5B,GAAG,KAAK,OAAO,IAAIA,CAAY,EAC/B,WAAYC,EAAU,QAAO,CACvC,CAAS,EAED,MAAME,EAAU,KAAK,UAAUtB,EAAG,UAAU,EACtCuB,EAAUD,EAAQ,QAAO,EACzBE,EAAUxB,EAAG,SAAWuB,EAAQ,OAChCpC,EAAUqC,EAAU,EAAID,EAAQC,EAAU,CAAC,EAAI,KAC/CC,EAAK,KAAK,OAAO,KAAI,EACvBH,EAAQ,IAAItB,EAAG,EAAE,EAGnBsB,EAAQ,KAAKtB,EAAG,GAAIb,EAASsC,EAAI,KAAK,OAAO,EAE7CH,EAAQ,OAAOtB,EAAG,GAAIb,EAASsC,EAAI,KAAK,OAAO,EAEjD,KAAK,OAAO,IAAIzB,EAAG,WAAY,CAC7B,GAAG,KAAK,OAAO,IAAIA,EAAG,UAAU,EAChC,WAAYsB,EAAQ,QAAO,CACrC,CAAS,EAED,KAAK,OAAO,IAAItB,EAAG,GAAI,CAAE,GAAG,KAAK,OAAO,IAAIA,EAAG,EAAE,EAAG,SAAUA,EAAG,WAAY,EAE7E,KAAK,cAAgB,CACnB,KAAM,WACN,aAAAmB,EACA,WAAYnB,EAAG,WACf,QAASA,EAAG,GACZ,KAAMsB,EAAQ,QAAQtB,EAAG,EAAE,CACrC,EACQ,MAAM0B,EAAU,IAAI,IAAI,CAAC1B,EAAG,GAAImB,EAAcnB,EAAG,UAAU,CAAC,EAC5D,YAAK,QAAQ0B,CAAO,EACbC,EAAAA,UAAU3B,EAAG,GAAImB,EAAcE,CAAS,CACjD,CAEA,KAAKpB,EAAAA,GAAG,sBAAuB,CAC7B,MAAM9B,EAAQ,KAAK,OAAO,IAAI6B,EAAG,OAAO,EAClC4B,EAAqBzD,EAAM,WACjC,YAAK,OAAO,IAAI6B,EAAG,QAAS,CAAE,GAAG7B,EAAO,WAAY6B,EAAG,WAAY,EAInE,KAAK,QAAQ,IAAIA,EAAG,QAAS5B,EAAAA,cAAc,UAAU4B,EAAG,WAAY,CAAE,OAAQ,QAAQ,CAAE,CAAC,EACzF,KAAK,cAAgB,KACrB,KAAK,QAAQ,CAACA,EAAG,OAAO,CAAC,EAClB6B,qBAAmB7B,EAAG,QAAS4B,CAAkB,CAC1D,CAEA,KAAK3B,EAAAA,GAAG,iBAAkB,CACxB,MAAM9B,EAAQ,KAAK,OAAO,IAAI6B,EAAG,OAAO,EAIlC8B,EAAe3D,EAAM,WAAW,QAAQ6B,EAAG,UAAU,CAAC,CAAC,IAAM,GAC7D+B,EAAcD,EAAe3D,EAAM,aAAc4B,EAAA5B,EAAM,QAAN,YAAA4B,EAAa,cAAe,GAC7EiC,EAAaD,EAAY,QAAQ/B,EAAG,UAAU,CAAC,CAAC,EAEhDiC,EAAcjC,EAAG,UAAU,IAAKf,GAAO,KAAK,KAAK,IAAIA,CAAE,CAAC,EAC9D,UAAWA,KAAMe,EAAG,UAAW,KAAK,KAAK,OAAOf,CAAE,EAClD,UAAW2B,KAAKZ,EAAG,QAAS,KAAK,KAAK,IAAIY,EAAE,GAAIA,CAAC,EAEjD,MAAMsB,EAAW,CAAC,GAAGH,CAAW,EAChC,OAAAG,EAAS,OAAOF,EAAYhC,EAAG,UAAU,OAAQ,GAAGA,EAAG,QAAQ,IAAKY,GAAMA,EAAE,EAAE,CAAC,EAE3EkB,EACF,KAAK,OAAO,IAAI9B,EAAG,QAAS,CAAE,GAAG7B,EAAO,WAAY+D,EAAU,EAE9D,KAAK,OAAO,IAAIlC,EAAG,QAAS,CAC1B,GAAG7B,EACH,MAAO,CAAE,GAAGA,EAAM,MAAO,YAAa+D,CAAQ,CAC1D,CAAW,EAEH,KAAK,cAAgB,KACrB,KAAK,QAAQ,CAAClC,EAAG,QAAS,GAAGA,EAAG,UAAW,GAAGA,EAAG,QAAQ,IAAKY,GAAMA,EAAE,EAAE,CAAC,CAAC,EACnEuB,EAAAA,eACLnC,EAAG,QACHA,EAAG,QAAQ,IAAKY,GAAMA,EAAE,EAAE,EAC1BqB,CACV,CACM,CAEA,KAAKhC,EAAAA,GAAG,eAAgB,CACtB,MAAM9B,EAAQ,KAAK,OAAO,IAAI6B,EAAG,OAAO,EAIlCoC,EAAkBjE,EAAM,OAAS,gBAAiBA,EAAM,MACxDkE,EAAiBD,EAAkBjE,EAAM,MAAM,YAAcA,EAAM,WACnEmE,EAAeD,EAAe,IAAKpD,GAAO,KAAK,KAAK,IAAIA,CAAE,CAAC,EAAE,OAAO,OAAO,EAEjF,UAAWA,KAAMoD,EAAgB,KAAK,KAAK,OAAOpD,CAAE,EACpD,UAAW2B,KAAKZ,EAAG,KAAM,KAAK,KAAK,IAAIY,EAAE,GAAIA,CAAC,EAC9C,MAAM2B,EAAYvC,EAAG,KAAK,IAAKY,GAAMA,EAAE,EAAE,EAEzC,OAAIwB,EACF,KAAK,OAAO,IAAIpC,EAAG,QAAS,CAC1B,GAAG7B,EACH,MAAO,CAAE,GAAGA,EAAM,MAAO,YAAaoE,CAAS,CAC3D,CAAW,EAED,KAAK,OAAO,IAAIvC,EAAG,QAAS,CAAE,GAAG7B,EAAO,WAAYoE,EAAW,EAEjE,KAAK,cAAgB,KACrB,KAAK,QAAQ,CAACvC,EAAG,QAAS,GAAGqC,EAAgB,GAAGE,CAAS,CAAC,EACnDC,eAAaxC,EAAG,QAASsC,CAAY,CAC9C,CAEA,KAAKrC,EAAAA,GAAG,eACN,YAAK,WAAW,IAAID,EAAG,UAAU,GAAIA,EAAG,SAAS,EACjD,KAAK,oBAAsB,KAC3B,KAAK,QAAQ,CAAC3C,CAAe,CAAC,EACvBoF,kBAAgBzC,EAAG,UAAU,EAAE,EAGxC,KAAKC,EAAAA,GAAG,kBAAmB,CACzB,MAAMyC,EAAW,KAAK,WAAW,IAAI1C,EAAG,EAAE,EACpCI,EAAgB,CAAA,EACtB,UAAWE,KAAO,OAAO,KAAKN,EAAG,KAAK,EAAGI,EAAcE,CAAG,EAAIoC,EAASpC,CAAG,EAC1E,YAAK,WAAW,IAAIN,EAAG,GAAI,CAAE,GAAG0C,EAAU,GAAG1C,EAAG,MAAO,EACvD,KAAK,oBAAsB,KAC3B,KAAK,QAAQ,CAAC3C,CAAe,CAAC,EACvBsF,kBAAgB3C,EAAG,GAAII,CAAa,CAC7C,CAEA,KAAKH,EAAAA,GAAG,kBAAmB,CACzB,MAAMyC,EAAW,KAAK,WAAW,IAAI1C,EAAG,EAAE,EAC1C,YAAK,WAAW,OAAOA,EAAG,EAAE,EAC5B,KAAK,oBAAsB,KAC3B,KAAK,QAAQ,CAAC3C,CAAe,CAAC,EACvBuF,EAAAA,aAAaF,CAAQ,CAC9B,CAEA,KAAKzC,EAAAA,GAAG,mBACN,YAAK,SAAS,IAAID,EAAG,OAAO,GAAIA,EAAG,MAAM,EACzC,KAAK,kBAAoB,KACzB,KAAK,cAAgB,CAAE,KAAM,eAAgB,GAAI,YAAa,OAAQA,EAAG,MAAM,EAC/E,KAAK,QAAQ,CAAC1C,CAAY,CAAC,EACpBuF,sBAAoB7C,EAAG,OAAO,EAAE,EAGzC,KAAKC,EAAAA,GAAG,sBAAuB,CAC7B,MAAMyC,EAAW,KAAK,SAAS,IAAI1C,EAAG,SAAS,EAC/C,YAAK,SAAS,OAAOA,EAAG,SAAS,EACjC,KAAK,kBAAoB,KACzB,KAAK,cAAgB,CAAE,KAAM,eAAgB,GAAI,eAAgB,UAAWA,EAAG,SAAS,EACxF,KAAK,QAAQ,CAAC1C,CAAY,CAAC,EACpBwF,EAAAA,iBAAiBJ,CAAQ,CAClC,CAEA,KAAKzC,EAAAA,GAAG,kBAAmB,CACzB,MAAM8C,EAAS,KAAK,SAAS,IAAI/C,EAAG,SAAS,EAC7C,YAAK,SAAS,IAAIA,EAAG,UAAW,CAAE,GAAG+C,EAAQ,SAAU,CAAC,GAAGA,EAAO,SAAU/C,EAAG,OAAO,CAAC,CAAE,EACzF,KAAK,kBAAoB,KACzB,KAAK,cAAgB,CACnB,KAAM,eACN,GAAI,WACJ,UAAWA,EAAG,UACd,QAASA,EAAG,OACtB,EACQ,KAAK,QAAQ,CAAC1C,CAAY,CAAC,EACpB0F,EAAAA,mBAAmBhD,EAAG,UAAWA,EAAG,QAAQ,EAAE,CACvD,CAEA,KAAKC,EAAAA,GAAG,qBAAsB,CAC5B,MAAM8C,EAAS,KAAK,SAAS,IAAI/C,EAAG,SAAS,EACvCiD,EAAiBF,EAAO,SAAS,KAAMG,GAAMA,EAAE,KAAOlD,EAAG,SAAS,EACxE,YAAK,SAAS,IAAIA,EAAG,UAAW,CAC9B,GAAG+C,EACH,SAAUA,EAAO,SAAS,OAAQG,GAAMA,EAAE,KAAOlD,EAAG,SAAS,CACvE,CAAS,EACD,KAAK,kBAAoB,KACzB,KAAK,cAAgB,CACnB,KAAM,eACN,GAAI,cACJ,UAAWA,EAAG,UACd,UAAWA,EAAG,SACxB,EACQ,KAAK,QAAQ,CAAC1C,CAAY,CAAC,EACpB6F,kBAAgBnD,EAAG,UAAWiD,CAAc,CACrD,CAEA,KAAKhD,EAAAA,GAAG,gBAAiB,CACvB,MAAM8C,EAAS,KAAK,SAAS,IAAI/C,EAAG,SAAS,EACvCoD,EAAmBL,EAAO,SAChC,YAAK,SAAS,IAAI/C,EAAG,UAAW,CAAE,GAAG+C,EAAQ,SAAU/C,EAAG,SAAU,EACpE,KAAK,kBAAoB,KACzB,KAAK,cAAgB,CACnB,KAAM,eACN,GAAI,UACJ,UAAWA,EAAG,UACd,SAAUA,EAAG,QACvB,EACQ,KAAK,QAAQ,CAAC1C,CAAY,CAAC,EACpB+F,iBAAerD,EAAG,UAAWoD,CAAgB,CACtD,CAEA,KAAKnD,EAAAA,GAAG,WACN,YAAK,OAAO,IAAID,EAAG,OAAO,GAAIA,EAAG,MAAM,EACvC,KAAK,gBAAkB,KACvB,KAAK,cAAgB,CAAE,KAAM,cAAe,GAAI,MAAO,OAAQA,EAAG,MAAM,EACxE,KAAK,QAAQ,CAACzC,CAAU,CAAC,EAClB+F,eAAatD,EAAG,OAAO,EAAE,EAGlC,KAAKC,EAAAA,GAAG,cAAe,CACrB,MAAMyC,EAAW,KAAK,OAAO,IAAI1C,EAAG,EAAE,EAChCI,EAAgB,CAAA,EACtB,UAAWE,KAAO,OAAO,KAAKN,EAAG,KAAK,EAAGI,EAAcE,CAAG,EAAIoC,EAASpC,CAAG,EAC1E,YAAK,OAAO,IAAIN,EAAG,GAAI,CAAE,GAAG0C,EAAU,GAAG1C,EAAG,MAAO,EACnD,KAAK,gBAAkB,KACvB,KAAK,cAAgB,CAAE,KAAM,cAAe,GAAI,SAAU,GAAIA,EAAG,GAAI,MAAOA,EAAG,KAAK,EACpF,KAAK,QAAQ,CAACzC,CAAU,CAAC,EAClBgG,eAAavD,EAAG,GAAII,CAAa,CAC1C,CAEA,KAAKH,EAAAA,GAAG,cAAe,CACrB,MAAMyC,EAAW,KAAK,OAAO,IAAI1C,EAAG,EAAE,EACtC,YAAK,OAAO,OAAOA,EAAG,EAAE,EACxB,KAAK,gBAAkB,KACvB,KAAK,cAAgB,CAAE,KAAM,cAAe,GAAI,SAAU,GAAIA,EAAG,EAAE,EACnE,KAAK,QAAQ,CAACzC,CAAU,CAAC,EAClBiG,EAAAA,UAAUd,CAAQ,CAC3B,CAEA,QACE,MAAM,IAAI,MAAM,2BAA2B1C,EAAG,IAAI,EAAE,CAC5D,CACE,CAGA,gBAAgByD,EAAK,CACnB,OAAOA,EAAI,IAAKzD,GAAO,KAAK,eAAeA,CAAE,CAAC,CAChD,CASA,iBAAkB,CAChB,OAAO,KAAK,aACd,CAUA,qBAAqB0D,EAAU,SAC7B,GAAKA,EACL,OAAQA,EAAS,KAAI,CACnB,IAAK,aAAc,CACjB,UAAWhG,KAAKgG,EAAS,QAAQ,OAC1B,KAAK,OAAO,IAAIhG,EAAE,EAAE,GAAG,KAAK,OAAO,IAAIA,EAAE,GAAIA,CAAC,EACrD,UAAWkD,KAAK8C,EAAS,QAAQ,KAAW,KAAK,KAAK,IAAI9C,EAAE,EAAE,GAAG,KAAK,KAAK,IAAIA,EAAE,GAAIA,CAAC,EACtF,MAAM1C,EAAQ,KAAK,UAAUwF,EAAS,QAAQ,EAC9CxF,EAAM,MAAM,CAACwF,EAAS,IAAI,CAAC,EAC3B,MAAM7C,EAAS,KAAK,OAAO,IAAI6C,EAAS,QAAQ,EAChD,KAAK,OAAO,IAAIA,EAAS,SAAU,CAAE,GAAG7C,EAAQ,WAAY3C,EAAM,QAAO,CAAE,CAAE,EAC7E,KAAK,OAAO,QAAQwF,EAAS,KAAK,KAAK,EACvC,KAAK,QAAQ,CAACA,EAAS,QAASA,EAAS,QAAQ,CAAC,EAClD,MACF,CAEA,IAAK,aAAc,CACjB,MAAMxF,EAAQ,KAAK,UAAUwF,EAAS,QAAQ,EAC1C,KAAK,OAAO,IAAIA,EAAS,OAAO,GAAG,KAAK,eAAeA,EAAS,OAAO,EAC3ExF,EAAM,OAAOwF,EAAS,QAASA,EAAS,KAAK,EACzCA,EAAS,OAAO,KAAK,OAAO,QAAQA,EAAS,KAAK,EACtD,MAAM7C,EAAS,KAAK,OAAO,IAAI6C,EAAS,QAAQ,EAChD,KAAK,OAAO,IAAIA,EAAS,SAAU,CAAE,GAAG7C,EAAQ,WAAY3C,EAAM,QAAO,CAAE,CAAE,EAC7E,KAAK,QAAQ,CAACwF,EAAS,QAAQ,CAAC,EAChC,MACF,CAEA,IAAK,WAAY,CACf,MAAMtC,EAAY,KAAK,UAAUsC,EAAS,YAAY,EAKtDtC,EAAU,OAAOsC,EAAS,SAAS3D,EAAA2D,EAAS,OAAT,YAAA3D,EAAe,KAAK,EACvD,KAAK,OAAO,IAAI2D,EAAS,aAAc,CACrC,GAAG,KAAK,OAAO,IAAIA,EAAS,YAAY,EACxC,WAAYtC,EAAU,QAAO,CACvC,CAAS,EAED,MAAME,EAAU,KAAK,UAAUoC,EAAS,UAAU,EAC5CC,EAAUrC,EAAQ,IAAIoC,EAAS,OAAO,EAC5CpC,EAAQ,MAAM,CAACoC,EAAS,IAAI,CAAC,EAMzBC,GACFrC,EAAQ,KACNoC,EAAS,QACTA,EAAS,KAAK,SACdA,EAAS,KAAK,MACdA,EAAS,KAAK,MAC1B,EACQ,KAAK,OAAO,IAAIA,EAAS,WAAY,CACnC,GAAG,KAAK,OAAO,IAAIA,EAAS,UAAU,EACtC,WAAYpC,EAAQ,QAAO,CACrC,CAAS,EAEG,KAAK,OAAO,IAAIoC,EAAS,OAAO,GAClC,KAAK,OAAO,IAAIA,EAAS,QAAS,CAChC,GAAG,KAAK,OAAO,IAAIA,EAAS,OAAO,EACnC,SAAUA,EAAS,UAC/B,CAAW,EAEH,KAAK,OAAO,QAAQA,EAAS,KAAK,KAAK,EACvC,KAAK,QAAQ,CAACA,EAAS,QAASA,EAAS,aAAcA,EAAS,UAAU,CAAC,EAC3E,MACF,CAEA,IAAK,aAAc,CACjB,GAAIA,EAAS,SAAW,MAAO,CAC7B,MAAMpF,EAAM,KAAK,KAAK,IAAIoF,EAAS,EAAE,EACrC,GAAIpF,EAAK,CACP,MAAMsF,EAAQ,CAAA,EACd,UAAWtD,KAAO,OAAO,KAAKoD,EAAS,KAAK,EAAG,CAC7C,MAAMG,EAAcH,EAAS,OAAOpD,CAAG,EAClC,KAAK,aAAa,kBAAkBoD,EAAS,GAAIpD,EAAKuD,CAAW,IACtED,EAAMtD,CAAG,EAAIoD,EAAS,MAAMpD,CAAG,EAC/B,KAAK,aAAa,aAAaoD,EAAS,GAAIpD,EAAKuD,CAAW,EAC9D,CACI,OAAO,KAAKD,CAAK,EAAE,OAAS,IAC9B,KAAK,KAAK,IAAIF,EAAS,GAAI,CAAE,GAAGpF,EAAK,GAAGsF,EAAO,EAC/C,KAAK,QAAQ,CAACF,EAAS,EAAE,CAAC,EAE9B,CACF,SAAWA,EAAS,SAAW,aAAc,CAC3C,MAAMvF,EAAQ,KAAK,OAAO,IAAIuF,EAAS,EAAE,EACzC,GAAIvF,EAAO,CACT,MAAMyF,EAAQ,CAAA,EACd,UAAWtD,KAAO,OAAO,KAAKoD,EAAS,KAAK,EAAG,CAC7C,MAAMG,EAAcH,EAAS,OAAOpD,CAAG,EAClC,KAAK,aAAa,kBAAkBoD,EAAS,GAAI,SAASpD,CAAG,GAAIuD,CAAW,IAEjFD,EAAMtD,CAAG,EAAIoD,EAAS,MAAMpD,CAAG,EAC/B,KAAK,aAAa,aAAaoD,EAAS,GAAI,SAASpD,CAAG,GAAIuD,CAAW,EACzE,CACI,OAAO,KAAKD,CAAK,EAAE,OAAS,IAC9B,KAAK,OAAO,IAAIF,EAAS,GAAI,CAAE,GAAGvF,EAAO,MAAO,CAAE,GAAGA,EAAM,MAAO,GAAGyF,CAAK,CAAE,CAAE,EAC9E,KAAK,QAAQ,CAACF,EAAS,EAAE,CAAC,EAE9B,CACF,SAAWA,EAAS,SAAW,YAAa,CAC1C,MAAMvF,EAAQ,KAAK,OAAO,IAAIuF,EAAS,EAAE,EACrCvF,GAAS,KAAK,aAAa,kBAAkBuF,EAAS,GAAI,OAAQA,EAAS,KAAK,IAClF,KAAK,aAAa,aAAaA,EAAS,GAAI,OAAQA,EAAS,KAAK,EAClE,KAAK,OAAO,IAAIA,EAAS,GAAI,CAC3B,GAAGvF,EACH,KAAMuF,EAAS,UACf,MAAOA,EAAS,KAC9B,CAAa,EACD,KAAK,QAAQ,CAACA,EAAS,EAAE,CAAC,EAE9B,CACA,UAAWjC,KAAM,OAAO,OAAOiC,EAAS,QAAU,CAAA,CAAE,EAAG,KAAK,OAAO,QAAQjC,CAAE,EACzEiC,EAAS,OAAO,KAAK,OAAO,QAAQA,EAAS,KAAK,EACtD,MACF,CAEA,IAAK,cAAe,CAClB,MAAMxF,EAAQ,KAAK,aAAawF,EAAS,KAAK,EACxCnF,EAAQ,KAAK,UAAU,IAAImF,EAAS,KAAK,EAC/C,UAAW9F,KAAK8F,EAAS,cAClBxF,EAAM,IAAIN,EAAE,EAAE,GAAGW,EAAM,IAAIX,EAAE,GAAIA,EAAE,IAAI,EAC5CM,EAAM,OAAON,EAAE,GAAIA,EAAE,QAASA,EAAE,OAAOkG,EAAAlG,EAAE,QAAF,YAAAkG,EAAS,MAAM,EAExD,UAAWxE,KAAKoE,EAAS,eAAgBxF,EAAM,OAAOoB,EAAE,GAAIA,EAAE,KAAK,EACnE,KAAK,mBAAmB,OAAOoE,EAAS,KAAK,EAC7C,MAAMpF,EAAM,KAAK,KAAK,IAAIoF,EAAS,KAAK,EACpCpF,IACF,KAAK,KAAK,IAAIoF,EAAS,MAAO,CAC5B,GAAGpF,EACH,MAAO,KAAK,qBAAqBoF,EAAS,KAAK,CAC3D,CAAW,EACD,KAAK,QAAQ,CAACA,EAAS,KAAK,CAAC,GAE/B,KAAK,OAAO,QAAQA,EAAS,KAAK,EAClC,MACF,CAEA,IAAK,cAAe,CAClB,MAAMxF,EAAQ,KAAK,aAAawF,EAAS,KAAK,EAC9C,UAAW/E,KAAU+E,EAAS,aAAcxF,EAAM,OAAOS,EAAQ+E,EAAS,KAAK,EAC/E,UAAW/E,KAAU+E,EAAS,WAAYxF,EAAM,QAAQS,CAAM,EAC9D,KAAK,mBAAmB,OAAO+E,EAAS,KAAK,EAC7C,MAAMpF,EAAM,KAAK,KAAK,IAAIoF,EAAS,KAAK,EACpCpF,IACF,KAAK,KAAK,IAAIoF,EAAS,MAAO,CAC5B,GAAGpF,EACH,MAAO,KAAK,qBAAqBoF,EAAS,KAAK,CAC3D,CAAW,EACD,KAAK,QAAQ,CAACA,EAAS,KAAK,CAAC,GAE/B,KAAK,OAAO,QAAQA,EAAS,KAAK,EAClC,MACF,CAEA,IAAK,eAAgB,CAQnB,GAAIA,EAAS,KAAO,YACb,KAAK,SAAS,IAAIA,EAAS,OAAO,EAAE,IACvC,KAAK,SAAS,IAAIA,EAAS,OAAO,GAAIA,EAAS,MAAM,EACrD,KAAK,kBAAoB,KACzB,KAAK,QAAQ,CAACpG,CAAY,CAAC,WAEpBoG,EAAS,KAAO,eACrB,KAAK,SAAS,OAAOA,EAAS,SAAS,IACzC,KAAK,kBAAoB,KACzB,KAAK,QAAQ,CAACpG,CAAY,CAAC,WAEpBoG,EAAS,KAAO,WAAY,CACrC,MAAMX,EAAS,KAAK,SAAS,IAAIW,EAAS,SAAS,EAC/CX,GAAU,CAACA,EAAO,SAAS,KAAMG,GAAMA,EAAE,KAAOQ,EAAS,QAAQ,EAAE,IACrE,KAAK,SAAS,IAAIA,EAAS,UAAW,CACpC,GAAGX,EACH,SAAU,CAAC,GAAGA,EAAO,SAAUW,EAAS,OAAO,CAC7D,CAAa,EACD,KAAK,kBAAoB,KACzB,KAAK,QAAQ,CAACpG,CAAY,CAAC,EAE/B,SAAWoG,EAAS,KAAO,cAAe,CACxC,MAAMX,EAAS,KAAK,SAAS,IAAIW,EAAS,SAAS,EAC/CX,GAAUA,EAAO,SAAS,KAAMG,GAAMA,EAAE,KAAOQ,EAAS,SAAS,IACnE,KAAK,SAAS,IAAIA,EAAS,UAAW,CACpC,GAAGX,EACH,SAAUA,EAAO,SAAS,OAAQG,GAAMA,EAAE,KAAOQ,EAAS,SAAS,CACjF,CAAa,EACD,KAAK,kBAAoB,KACzB,KAAK,QAAQ,CAACpG,CAAY,CAAC,EAE/B,SAAWoG,EAAS,KAAO,UAAW,CACpC,MAAMX,EAAS,KAAK,SAAS,IAAIW,EAAS,SAAS,EAC/CX,IACF,KAAK,SAAS,IAAIW,EAAS,UAAW,CAAE,GAAGX,EAAQ,SAAUW,EAAS,SAAU,EAChF,KAAK,kBAAoB,KACzB,KAAK,QAAQ,CAACpG,CAAY,CAAC,EAE/B,CACA,MACF,CAEA,IAAK,cAAe,CAOlB,GAAIoG,EAAS,KAAO,MACb,KAAK,OAAO,IAAIA,EAAS,OAAO,EAAE,IACrC,KAAK,OAAO,IAAIA,EAAS,OAAO,GAAIA,EAAS,MAAM,EACnD,KAAK,gBAAkB,KACvB,KAAK,QAAQ,CAACnG,CAAU,CAAC,WAElBmG,EAAS,KAAO,SAAU,CACnC,MAAMhB,EAAW,KAAK,OAAO,IAAIgB,EAAS,EAAE,EACxChB,IACF,KAAK,OAAO,IAAIgB,EAAS,GAAI,CAAE,GAAGhB,EAAU,GAAGgB,EAAS,MAAO,EAC/D,KAAK,gBAAkB,KACvB,KAAK,QAAQ,CAACnG,CAAU,CAAC,EAE7B,MAAWmG,EAAS,KAAO,UACrB,KAAK,OAAO,OAAOA,EAAS,EAAE,IAChC,KAAK,gBAAkB,KACvB,KAAK,QAAQ,CAACnG,CAAU,CAAC,GAG7B,MACF,CAEA,QACE,MAAM,IAAI,MAAM,iCAAiCmG,EAAS,IAAI,EAAE,CACxE,CACE,CAGA,mBAAoB,CAClB,IAAIK,EAAQ,EACZ,UAAW7F,KAAS,KAAK,QAAQ,OAAM,EAAI6F,GAAS7F,EAAM,eAAc,EACxE,UAAWA,KAAS,KAAK,WAAW,OAAM,EAAI6F,GAAS7F,EAAM,eAAc,EAC3E,OAAO6F,CACT,CAaA,gBAAgB,CAAE,SAAAC,EAAW,GAAK,GAAK,GAAK,IAAM,IAAAC,EAAM,KAAK,IAAG,CAAE,EAAK,CAAA,EAAI,CACzE,MAAMC,EAAY,CAAE,SAAUD,EAAMD,EAAU,QAAS,EAAG,OAAQ,EAAE,EACpE,IAAIG,EAAU,EACd,UAAWjG,KAAS,KAAK,QAAQ,OAAM,EAAIiG,GAAWjG,EAAM,gBAAgBgG,CAAS,EASrF,UAAWhG,KAAS,KAAK,WAAW,OAAM,EAAIiG,GAAWjG,EAAM,gBAAgBgG,CAAS,EACxF,OAAOC,CACT,CAEA,QAAS,CACP,MAAO,CACL,OAAQ,CAAC,GAAG,KAAK,OAAO,OAAM,CAAE,EAChC,KAAM,CAAC,GAAG,KAAK,KAAK,OAAM,CAAE,EAC5B,OAAQ,KAAK,OACb,WAAY,CAAC,GAAG,KAAK,WAAW,OAAM,CAAE,EACxC,SAAU,CAAC,GAAG,KAAK,SAAS,OAAM,CAAE,EACpC,OAAQ,CAAC,GAAG,KAAK,OAAO,OAAM,CAAE,CACtC,CACE,CAEA,OAAO,SAAS1G,EAAK,CACnB,OAAO,IAAID,EAAYC,CAAG,CAC5B,CACF,CCjlCA,SAAS2G,EAASC,EAAOZ,EAAK,CAC5B,GAAI,OAAOY,EAAM,cAAiB,WAAYA,EAAM,aAAaZ,CAAG,MAC/D,WAAWzD,KAAMyD,EAAKY,EAAM,eAAerE,CAAE,CACpD,CAUO,SAASsE,GAAqBD,EAAOE,EAAU,CACpD,MAAO,CAAE,MAAOA,EAAS,IAAKtF,GAAOuF,iBAAeH,EAAOpF,CAAE,CAAC,CAAC,CACjE,CAQO,SAASwF,EAAoBJ,EAAOK,EAAU,CAAE,SAAAzG,EAAU,MAAAQ,CAAK,EAAI,CACxE,MAAMgF,EAAM,CAAA,EACZ,IAAIkB,EAAYlG,EAChB,UAAWmG,KAAQF,EAAS,MAAO,CACjC,KAAM,CAAE,MAAAvG,EAAO,KAAAyB,EAAM,cAAAiF,CAAa,EAAKC,EAAAA,gBAAgBF,CAAI,EAC3DzG,EAAM,SAAWF,EACjBwF,EAAI,KAAKsB,EAAAA,YAAY5G,EAAOF,EAAU0G,EAAW,CAAE,OAAQ,CAACxG,EAAO,GAAG0G,CAAa,EAAG,KAAAjF,CAAI,CAAE,CAAC,EAC7F+E,GAAa,CACf,CACAP,EAASC,EAAOZ,CAAG,CACrB,CASO,SAASuB,EAAsBX,EAAO5G,EAAK,CAChD,MAAMwH,EAAWZ,EAAM,OAASA,EAChCY,EAAS,OAAS,IAAI,KAAKxH,EAAI,QAAU,CAAA,GAAI,IAAKC,GAAM,CAACA,EAAE,GAAIA,CAAC,CAAC,CAAC,EAClEuH,EAAS,KAAO,IAAI,KAAKxH,EAAI,MAAQ,CAAA,GAAI,IAAKmD,GAAM,CAACA,EAAE,GAAIA,CAAC,CAAC,CAAC,EAC9DqE,EAAS,OAASxH,EAAI,QAAU,KAChCwH,EAAS,WAAa,IAAI,KAAKxH,EAAI,YAAc,CAAA,GAAI,IAAKE,GAAM,CAACA,EAAE,GAAIA,CAAC,CAAC,CAAC,EAC1EsH,EAAS,oBAAsB,KAC/BA,EAAS,SAAW,IAAI,KAAKxH,EAAI,UAAY,CAAA,GAAI,IAAKG,GAAM,CAACA,EAAE,GAAIA,CAAC,CAAC,CAAC,EACtEqH,EAAS,kBAAoB,KAC7BA,EAAS,QAAU,IAAI,IAKvBA,EAAS,QAAQ,CACf,GAAGA,EAAS,OAAO,KAAI,EACvB,GAAGA,EAAS,KAAK,KAAI,EACrB,cACA,WACJ,CAAG,CACH,CAYO,SAASC,GAAuBC,EAAUC,EAAW,CAC1D,UAAWV,KAAYU,EACrBD,EAAS,SAAS,mBAAmBT,EAAS,EAAE,GAAI,CAClD,UAAW,IAAM,KACjB,OAAQ,GACR,aAAc,CACZ,MAAOA,EAAS,MAChB,KAAMA,EAAS,KACf,SAAUA,EAAS,UAAY,CAACA,EAAS,KAAK,EAC9C,IAAIL,EAAO,CAAE,QAAAgB,EAAS,MAAAhH,EAAO,WAAAiH,EAAY,SAAAC,GAAY,CAEnD,MAAMjH,EAAM+F,EAAM,OAAOhG,CAAK,EACxBO,GAAQN,GAAA,YAAAA,EAAK,QAAS,GAC5B+F,EAAM,eACJ9D,EAAAA,UAAUlC,EAAO,CAAE,MAAOO,EAAM,MAAM,EAAG0G,CAAU,EAAI1G,EAAM,MAAM2G,CAAQ,CAAC,CAAE,CAC1F,EAEU,MAAMC,EAAUnB,EAAM,SAASgB,CAAO,EAEhC5G,EADS4F,EAAM,SAASmB,EAAQ,QAAQ,EACzB,WAAW,QAAQH,CAAO,EAAI,EACnDZ,EAAoBJ,EAAOK,EAAU,CAAE,SAAUc,EAAQ,SAAU,MAAA/G,EAAO,CAC5E,CACR,CACA,CAAK,CAEL,CC5FO,SAASgH,EAAmBpB,EAAO,CAAE,OAAAqB,EAAS,EAAI,EAAK,CAAA,EAAI,CAChE,MAAMhG,EAAS2E,EAAM,UAAS,EACxB,CAAE,OAAA1E,EAAQ,KAAAC,CAAI,EAAK4E,EAAAA,eAAeH,EAAO3E,CAAM,EAErD,OAAO,KAAK,UADI,CAAE,QAAS,EAAG,OAAAA,EAAQ,OAAAC,EAAQ,KAAAC,CAAI,EACnB,KAAM8F,EAAS,EAAI,CAAC,CACrD,CAGO,SAASC,EAAmBtB,EAAOc,EAAUS,EAAgB,CAClE,MAAMhB,EAAOP,EAAM,SAASA,EAAM,UAAS,CAAE,EAC7C,OAAKO,EACEiB,EAAAA,oBAAoBxB,EAAOc,EAAUP,EAAK,WAAYgB,CAAc,EAAE,KAD3D,EAEpB,CAGO,SAASE,GAAmBzB,EAAOc,EAAUS,EAAgB,CAClE,MAAMhB,EAAOP,EAAM,SAASA,EAAM,UAAS,CAAE,EAC7C,OAAKO,EACEiB,EAAAA,oBAAoBxB,EAAOc,EAAUP,EAAK,WAAYgB,CAAc,EAAE,KAD3D,EAEpB,CAaO,SAASG,GAAuB1B,EAAOc,EAAUS,EAAgB,CAEtE,MAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QADMD,EAAmBtB,EAAOc,EAAUS,CAAc,CAOrD;AAAA,QAEZ,CAoBO,SAASI,GAAuB3B,EAAOc,EAAUS,EAAgB,CACtE,MAAMhB,EAAOP,EAAM,SAASA,EAAM,UAAS,CAAE,EAC7C,GAAI,CAACO,EAAM,MAAO,GAClB,MAAMqB,EAAM,CAAE,MAAA5B,EAAO,SAAAc,EAAU,eAAAS,CAAc,EACvCM,EAAMtB,EAAK,WAEjB,IAAIuB,EAAW,GACXC,EAAY,KAChB,UAAWnH,KAAMiH,EAAK,CACpB,MAAM/H,EAAQkG,EAAM,SAASpF,CAAE,EACzBoH,EAAQlB,EAAS,IAAIhH,EAAM,IAAI,EAC/BmI,GAAiBD,EAAM,YAAcA,EAAM,aAAalI,EAAO8H,CAAG,EAExE,GAAIG,EAAW,CACb,MAAMG,EACJpI,EAAM,OAAS,YACfiI,EAAU,OAAS,YACnB,EAAQjI,EAAM,MAAM,SAAa,EAAQiI,EAAU,MAAM,QACrDI,EAAYrI,EAAM,OAAS,cAAgBiI,EAAU,OAAS,aACpED,GAAYI,GAAYC,EAAY;AAAA,EAAO;AAAA;AAAA,CAC7C,CACAL,GAAYG,EACZF,EAAYjI,CACd,CACA,OAAOgI,CACT,CC3FA,MAAMM,GAAkB,EAAI,GAAK,IAC3BC,GAAuB,IAkBtB,SAASC,EAAyB,CACvC,MAAAtC,EACA,MAAAuC,EACA,OAAAC,EAASJ,GACT,YAAAK,EAAcJ,GACd,WAAAK,EACA,QAAAC,CACF,EAAG,CACD,IAAIC,EAAY,KACZC,EAAc7C,EAAM,cAAa,EAAG,OACpC8C,EAAqB,GAEzB,SAASC,GAAiB,CACpBH,IACF,aAAaA,CAAS,EACtBA,EAAY,KAEhB,CAEA,eAAeI,GAAiB,CAE9B,GADAD,EAAc,EACV,CAACD,EAAoB,OACzBA,EAAqB,GAErB,MAAMG,EAAMjD,EAAM,cAAa,EACzBkD,EAAUD,EAAI,MAAMJ,CAAW,EAErC,GADAA,EAAcI,EAAI,OACdC,EAAQ,SAAW,EAAG,OAE1B,MAAM9H,EAAa,IAAI,IAAI8H,EAAQ,IAAKC,GAAMA,EAAE,EAAE,EAAE,OAAO,OAAO,CAAC,EAC7DC,EAAY,CAAC,GAAG,IAAI,IAAIF,EAAQ,IAAKC,GAAMA,EAAE,OAAO,EAAE,OAAO,OAAO,CAAC,CAAC,EACtEE,EAAWH,EAAQA,EAAQ,OAAS,CAAC,EAAE,SAAW,KAExD,GAAI,CACF,MAAM9J,EAAM,KAAK,MAAMgI,EAAmBpB,CAAK,CAAC,EAC1CsD,EAAU,CACd,GAAI,OAAO,WAAU,EACrB,MAAAf,EACA,UAAW,KAAK,IAAG,EACnB,SAAAc,EACA,UAAAD,EACA,QAAS,GAAGhI,EAAW,IAAI,SAASA,EAAW,OAAS,EAAI,GAAK,GAAG,WACpE,IAAAhC,CACR,EACM,MAAMmK,EAAAA,oBAAoBD,CAAO,EACjCZ,GAAA,MAAAA,EAAaY,GAEb,MAAME,EAAM,MAAMC,uBAAqBlB,CAAK,EAC5C,GAAIiB,EAAI,OAASf,EAAa,CAC5B,MAAMiB,EAASF,EAAI,MAAMf,CAAW,EACpC,MAAM,QAAQ,IAAIiB,EAAO,IAAKC,GAAMC,wBAAsBD,EAAE,EAAE,CAAC,CAAC,CAClE,CACF,OAASE,EAAK,CACZlB,GAAA,MAAAA,EAAUkB,EACZ,CACF,CAEA,MAAMC,EAAc9D,EAAM,mBAAmB,IAAM,CACjD8C,EAAqB,GACrBC,EAAc,EACdH,EAAY,WAAWI,EAAgBR,CAAM,CAC/C,CAAC,EAED,MAAO,CAEL,MAAO,CACLO,EAAc,EACde,EAAW,CACb,EAEA,MAAOd,CACX,CACA,CC1FO,SAASe,GAAUC,EAASC,EAAS,CAC1C,MAAMC,EAAYC,EAASH,CAAO,EAC5BI,EAAYD,EAASF,CAAO,EAC5BI,EAAIH,EAAU,OACdrF,EAAIuF,EAAU,OAEdE,EAAK,MAAM,KAAK,CAAE,OAAQD,EAAI,CAAC,EAAI,IAAM,IAAI,YAAYxF,EAAI,CAAC,CAAC,EACrE,QAASlE,EAAI0J,EAAI,EAAG1J,GAAK,EAAGA,GAAK,EAC/B,QAAS4J,EAAI1F,EAAI,EAAG0F,GAAK,EAAGA,GAAK,EAC/BD,EAAG3J,CAAC,EAAE4J,CAAC,EACLL,EAAUvJ,CAAC,IAAMyJ,EAAUG,CAAC,EAAID,EAAG3J,EAAI,CAAC,EAAE4J,EAAI,CAAC,EAAI,EAAI,KAAK,IAAID,EAAG3J,EAAI,CAAC,EAAE4J,CAAC,EAAGD,EAAG3J,CAAC,EAAE4J,EAAI,CAAC,CAAC,EAIhG,MAAMC,EAAW,CAAA,EACXC,EAAO,CAACC,EAAMC,IAAS,CAC3B,MAAMC,EAAOJ,EAASA,EAAS,OAAS,CAAC,EACrCI,GAAQA,EAAK,OAASF,EAAME,EAAK,MAAQD,EACxCH,EAAS,KAAK,CAAE,KAAAE,EAAM,KAAAC,CAAI,CAAE,CACnC,EAEA,IAAIhK,EAAI,EACJ4J,EAAI,EACR,KAAO5J,EAAI0J,GAAKE,EAAI1F,GACdqF,EAAUvJ,CAAC,IAAMyJ,EAAUG,CAAC,GAC9BE,EAAK,QAASP,EAAUvJ,CAAC,CAAC,EAC1BA,GAAK,EACL4J,GAAK,GACID,EAAG3J,EAAI,CAAC,EAAE4J,CAAC,GAAKD,EAAG3J,CAAC,EAAE4J,EAAI,CAAC,GACpCE,EAAK,UAAWP,EAAUvJ,CAAC,CAAC,EAC5BA,GAAK,IAEL8J,EAAK,QAASL,EAAUG,CAAC,CAAC,EAC1BA,GAAK,GAGT,KAAO5J,EAAI0J,GACTI,EAAK,UAAWP,EAAUvJ,CAAC,CAAC,EAC5BA,GAAK,EAEP,KAAO4J,EAAI1F,GACT4F,EAAK,QAASL,EAAUG,CAAC,CAAC,EAC1BA,GAAK,EAEP,OAAOC,CACT,CAEA,SAASL,EAASQ,EAAM,CACtB,OAAQA,GAAQ,IAAI,MAAM,aAAa,GAAK,CAAA,CAC9C,CAEA,MAAME,GAAa,CAAE,IAAK,QAAS,IAAK,OAAQ,IAAK,OAAQ,IAAK,SAAU,IAAK,OAAO,EACxF,SAASC,EAAWH,EAAM,CACxB,OAAOA,EAAK,QAAQ,WAAatK,GAAOwK,GAAWxK,CAAE,CAAC,CACxD,CASA,SAAS0K,EAAkB3L,EAAK,CAC9B,MAAM4L,EAAY,IAAI,IAAI5L,EAAI,OAAO,IAAKC,GAAM,CAACA,EAAE,GAAIA,CAAC,CAAC,CAAC,EACpD4L,EAAU,IAAI,IAAI7L,EAAI,KAAK,IAAKmD,GAAM,CAACA,EAAE,GAAIA,CAAC,CAAC,CAAC,EAChD2I,EAAS,CAAA,EAETC,EAAkBtD,GAAQA,EAAI,IAAKjH,GAAE,OAAK,QAAAc,EAAAuJ,EAAQ,IAAIrK,CAAE,IAAd,YAAAc,EAAiB,QAAS,GAAE,EAAE,KAAK,EAAE,EAE/EF,EAAQZ,GAAO,OACnB,MAAMd,EAAQkL,EAAU,IAAIpK,CAAE,EAC9B,GAAI,CAACd,EAAO,OACZ,MAAMsL,GAAc1J,EAAA5B,EAAM,QAAN,YAAA4B,EAAa,YAC7B,MAAM,QAAQ0J,CAAW,GAAKA,EAAY,OAAS,EACrDF,EAAO,KAAK,CAAE,GAAAtK,EAAI,KAAMuK,EAAeC,CAAW,EAAG,EAC5CtL,EAAM,WAAW,OAAS,GAAKA,EAAM,WAAW,MAAOuL,GAAQJ,EAAQ,IAAII,CAAG,CAAC,GACxFH,EAAO,KAAK,CAAE,GAAAtK,EAAI,KAAMuK,EAAerL,EAAM,UAAU,EAAG,EAE5D,UAAW2B,KAAW3B,EAAM,WACrBmL,EAAQ,IAAIxJ,CAAO,GAAGD,EAAKC,CAAO,CAE3C,EACA,OAAAD,EAAKpC,EAAI,MAAM,EACR8L,CACT,CAEA,MAAMI,EAAY,CAChB,OAAQ,OACR,OAAQ,CAAC,CAAE,GAAI,OAAQ,KAAM,OAAQ,SAAU,KAAM,WAAY,CAAA,EAAI,MAAO,CAAA,CAAE,CAAE,EAChF,KAAM,CAAA,CACR,EAYO,SAASC,EAAkBC,EAASC,EAAS,CAClD,MAAMC,EAAaX,EAAkBS,GAAWF,CAAS,EACnDK,EAAaZ,EAAkBU,GAAWH,CAAS,EACnDM,EAAW,IAAI,IAAIF,EAAW,IAAKrM,GAAM,CAACA,EAAE,GAAIA,CAAC,CAAC,CAAC,EACnDwM,EAAU,IAAI,IAAIF,EAAW,IAAKtM,GAAMA,EAAE,EAAE,CAAC,EAE7CyM,EAAQ,CAAA,EAEd,UAAWhM,KAAS6L,EAAY,CAC9B,MAAM5D,EAAY6D,EAAS,IAAI9L,EAAM,EAAE,EACvC,GAAI,CAACiI,EAAW,CACd,MAAM4C,EAAOG,EAAWhL,EAAM,IAAI,GAAK,SACvCgM,EAAM,KACJ,wEAAwEnB,CAAI,aACpF,EACM,QACF,CACA,GAAI5C,EAAU,OAASjI,EAAM,KAAM,CACjCgM,EAAM,KAAK,oCAAoChB,EAAWhL,EAAM,IAAI,GAAK,QAAQ,MAAM,EACvF,QACF,CAEA,MAAMiM,EADWhC,GAAUhC,EAAU,KAAMjI,EAAM,IAAI,EAElD,IAAKkM,GAAQ,CACZ,MAAMC,EAAUnB,EAAWkB,EAAI,IAAI,EACnC,OAAIA,EAAI,OAAS,QAAgB,uCAAuCC,CAAO,UAC3ED,EAAI,OAAS,UACR,yCAAyCC,CAAO,UAClDA,CACT,CAAC,EACA,KAAK,EAAE,EACVH,EAAM,KAAK,oCAAoCC,CAAI,MAAM,CAC3D,CAEA,UAAWjM,KAAS4L,EAClB,GAAI,CAACG,EAAQ,IAAI/L,EAAM,EAAE,EAAG,CAC1B,MAAM6K,EAAOG,EAAWhL,EAAM,IAAI,GAAK,SACvCgM,EAAM,KACJ,0EAA0EnB,CAAI,aACtF,CACI,CAGF,OAAImB,EAAM,SAAW,EAAU,wDACxBA,EAAM,KAAK,EAAE,CACtB,CC/IO,SAASI,EAAoB3D,EAAO,CACzC,KAAM,CAAC4D,EAAUC,CAAW,EAAIC,EAAAA,SAAS,CAAA,CAAE,EACrC,CAACC,EAAUC,CAAW,EAAIF,EAAAA,SAAS,EAAK,EAExCG,EAAUC,EAAAA,YAAY,IACrBlE,GACLgE,EAAY,EAAK,EACV9C,EAAAA,qBAAqBlB,CAAK,EAAE,KAAMiB,GAAQ,CAC/C4C,EAAY5C,CAAG,EACf+C,EAAY,EAAI,CAClB,CAAC,GALkB,QAAQ,QAAO,EAMjC,CAAChE,CAAK,CAAC,EAEVmE,OAAAA,EAAAA,UAAU,IAAM,CACd,GAAI,CAACnE,EAAO,CACV6D,EAAY,CAAA,CAAE,EACdG,EAAY,EAAI,EAChB,MACF,CACA,IAAII,EAAY,GAChB,OAAAJ,EAAY,EAAK,EACjB9C,EAAAA,qBAAqBlB,CAAK,EAAE,KAAMiB,GAAQ,CACpCmD,IACJP,EAAY5C,CAAG,EACf+C,EAAY,EAAI,EAClB,CAAC,EACM,IAAM,CACXI,EAAY,EACd,CACF,EAAG,CAACpE,CAAK,CAAC,EAEH,CAAE,SAAA4D,EAAU,SAAAG,EAAU,QAAAE,CAAO,CACtC,CChCA,MAAMI,GACJ,2EAEF,SAASC,GAAeC,EAAW,CACjC,MAAM7L,EAAI,IAAI,KAAK6L,CAAS,EACtBlH,MAAU,KACVmH,EAAcC,GAClB,IAAI,KAAKA,EAAK,YAAA,EAAeA,EAAK,WAAYA,EAAK,QAAA,CAAS,EAAE,QAAA,EAC1DC,EAAW,KAAK,OAAOF,EAAWnH,CAAG,EAAImH,EAAW9L,CAAC,IAAM,GAAK,GAAK,GAAK,IAAK,EACrF,OAAIgM,IAAa,EAAU,QACvBA,IAAa,EAAU,YACpBhM,EAAE,mBAAmB,OAAW,CACrC,MAAO,OACP,IAAK,UACL,KAAMA,EAAE,YAAA,IAAkB2E,EAAI,YAAA,EAAgB,UAAY,MAAA,CAC3D,CACH,CAgBO,SAASsH,GAAe,CAAE,MAAA3E,EAAO,OAAAC,EAAQ,YAAAC,GAAe,CAC7D,MAAMzC,EAAQmH,EAAAA,eAAA,EACRrG,EAAWsG,EAAAA,iBAAA,EACX7F,EAAiB8F,EAAAA,kBAAA,EACjB,CAAE,SAAAlB,EAAU,SAAAG,EAAU,QAAAE,CAAA,EAAYN,EAAoB3D,CAAK,EAC3D,CAAC+E,EAAQC,CAAS,EAAIlB,EAAAA,SAAS,EAAK,EACpC,CAACmB,EAAYC,CAAa,EAAIpB,EAAAA,SAAS,IAAI,EAC3C,CAACqB,EAAUC,CAAW,EAAItB,EAAAA,SAAS,SAAS,EAC5CuB,EAAYC,EAAAA,OAAO,IAAI,EACvBC,EAAuBD,EAAAA,OAAO,IAAI,EAExCnB,EAAAA,UAAU,IAAM,CACd,GAAI,OAAO1G,EAAM,eAAkB,WAAY,OAC/C,MAAM+H,EAAczF,EAAyB,CAC3C,MAAAtC,EACA,MAAAuC,EACA,OAAAC,EACA,YAAAC,EACA,WAAY+D,CAAA,CACb,EACD,MAAO,IAAMuB,EAAY,KAAA,CAE3B,EAAG,CAAC/H,EAAOuC,CAAK,CAAC,EAEjB,SAASyF,GAAQ,CACfT,EAAU,EAAK,EACfE,EAAc,IAAI,EAClBE,EAAY,SAAS,CACvB,CAEAjB,EAAAA,UAAU,IAAM,CACd,GAAI,CAACY,EAAQ,OACb,MAAMW,EAAiBC,GAAU,CAC3BA,EAAM,MAAQ,UAAUF,EAAA,CAC9B,EACA,gBAAS,iBAAiB,UAAWC,CAAa,EAC3C,IAAM,SAAS,oBAAoB,UAAWA,CAAa,CAEpE,EAAG,CAACX,CAAM,CAAC,EAMXZ,EAAAA,UAAU,IAAM,WACd,GAAIY,EAAQ,CACVQ,EAAqB,QAAU,SAAS,cACxC,MAAMK,EAASP,EAAU,SAExBlM,GADiByM,GAAA,YAAAA,EAAQ,cAAcvB,MAC1BuB,IAAb,MAAAzM,EAAsB,QACvB,MACF,EACA0M,GAAA3I,EAAAqI,EAAqB,UAArB,YAAArI,EAA8B,QAA9B,MAAA2I,EAAA,KAAA3I,GACAqI,EAAqB,QAAU,IAEjC,EAAG,CAACR,CAAM,CAAC,EAEX,MAAMe,EAAgBlC,EAAS,UAAWxC,GAAMA,EAAE,KAAO6D,CAAU,EAC7Dc,EAAWD,GAAiB,EAAIlC,EAASkC,CAAa,EAAI,KAE1DE,EAAkBF,GAAiB,EAAKlC,EAASkC,EAAgB,CAAC,GAAK,KAAQ,KAE/EG,EAAcC,EAAAA,QAAQ,IAAM,CAChC,GAAI,CAACH,EAAU,MAAO,GACtB,MAAMI,EAAe,IAAIvP,EAAYmP,EAAS,GAAG,EACjD,OAAOhH,EAAmBoH,EAAc5H,EAAUS,CAAc,CAClE,EAAG,CAAC+G,EAAUxH,EAAUS,CAAc,CAAC,EAEjCoH,EAAWF,EAAAA,QAAQ,IAClBH,EACE/C,GAAkBgD,GAAA,YAAAA,EAAiB,MAAO,KAAMD,EAAS,GAAG,EAD7C,GAErB,CAACA,EAAUC,CAAe,CAAC,EAE9B,SAASK,GAAgB,CAClBN,GACA,OAAO,QAAQ,2DAA2D,IAC/E3H,EAAsBX,EAAOsI,EAAS,GAAG,EACzCN,EAAA,EACF,CAGA,MAAMa,EAAS,CAAA,EACf,UAAWvF,KAAW6C,EAAU,CAC9B,MAAM2C,EAAQjC,GAAevD,EAAQ,SAAS,EAC9C,IAAIyF,EAAQF,EAAOA,EAAO,OAAS,CAAC,GAChC,CAACE,GAASA,EAAM,QAAUD,KAC5BC,EAAQ,CAAE,MAAAD,EAAO,SAAU,EAAC,EAC5BD,EAAO,KAAKE,CAAK,GAEnBA,EAAM,SAAS,KAAKzF,CAAO,CAC7B,CAEA,OACE0F,EAAAA,KAAAC,WAAA,CACE,SAAA,CAAAD,EAAAA,KAAC,SAAA,CACC,KAAK,SACL,UAAU,6BACV,QAAS,IAAMzB,EAAU,EAAI,EAC7B,MAAM,kBAEN,SAAA,CAAA2B,EAAAA,IAACC,EAAAA,iBAAA,CAAiB,KAAM,EAAA,CAAI,EAAE,iBAAA,CAAA,CAAA,EAG/B7B,GACC8B,EAAAA,aACEJ,OAAAC,EAAAA,SAAA,CACE,SAAA,CAAAC,EAAAA,IAAC,MAAA,CAAI,UAAU,8BAA8B,QAASlB,EAAO,EAC7DgB,EAAAA,KAAC,MAAA,CACC,IAAKpB,EACL,UAAU,4BACV,KAAK,SACL,aAAW,OACX,aAAW,kBACX,SAAU,GAEV,SAAA,CAAAoB,EAAAA,KAAC,MAAA,CAAI,UAAU,4BACb,SAAA,CAAAE,EAAAA,IAAC,OAAA,CAAM,SAAAZ,EAAW,UAAY,kBAAkB,EAChDY,EAAAA,IAAC,SAAA,CACC,KAAK,SACL,UAAU,2BACV,QAASlB,EACT,aAAW,QAEX,SAAAkB,EAAAA,IAACG,EAAAA,MAAA,CAAM,KAAM,EAAA,CAAI,CAAA,CAAA,CACnB,EACF,EAECf,EACCU,EAAAA,KAAC,MAAA,CAAI,UAAU,6BACb,SAAA,CAAAA,EAAAA,KAAC,MAAA,CAAI,UAAU,kCACb,SAAA,CAAAE,EAAAA,IAACI,EAAAA,cAAA,CAAc,SAAUhB,EAAS,SAAU,KAAM,GAAI,SACrD,MAAA,CACC,SAAA,CAAAY,MAAC,MAAA,CAAI,UAAU,oCACZ,SAAAZ,EAAS,UAAY,UACxB,EACAU,EAAAA,KAAC,MAAA,CAAI,UAAU,kCACZ,SAAA,CAAA,IAAI,KAAKV,EAAS,SAAS,EAAE,eAAA,EAAiB,MAAIA,EAAS,OAAA,CAAA,CAC9D,CAAA,CAAA,CACF,CAAA,EACF,EAEAU,EAAAA,KAAC,MAAA,CACC,UAAU,iCACV,KAAK,UACL,aAAW,YAEX,SAAA,CAAAE,EAAAA,IAAC,SAAA,CACC,KAAK,SACL,KAAK,MACL,gBAAexB,IAAa,UAC5B,UAAWA,IAAa,UAAY,YAAc,GAClD,QAAS,IAAMC,EAAY,SAAS,EACrC,SAAA,SAAA,CAAA,EAGDuB,EAAAA,IAAC,SAAA,CACC,KAAK,SACL,KAAK,MACL,gBAAexB,IAAa,UAC5B,UAAWA,IAAa,UAAY,YAAc,GAClD,QAAS,IAAMC,EAAY,SAAS,EACrC,SAAA,SAAA,CAAA,CAED,CAAA,CAAA,EAGDD,IAAa,WACZsB,EAAAA,KAAAC,EAAAA,SAAA,CACE,SAAA,CAAAD,EAAAA,KAAC,MAAA,CAAI,UAAU,iCACb,SAAA,CAAAE,EAAAA,IAAC,OAAA,CAAK,UAAU,wBAAwB,SAAA,QAAK,EAC7CA,EAAAA,IAAC,OAAA,CAAK,UAAU,0BAA0B,SAAA,UAAO,EAChD,CAACX,GACAW,EAAAA,IAAC,OAAA,CAAK,UAAU,sCAAsC,SAAA,gDAAA,CAEtD,CAAA,EAEJ,EAEAA,EAAAA,IAAC,MAAA,CACC,UAAU,+DACV,wBAAyB,CAAE,OAAQP,CAAA,CAAS,CAAA,CAC9C,EACF,EAEDjB,IAAa,WAEZwB,EAAAA,IAAC,MAAA,CACC,UAAU,kCACV,wBAAyB,CAAE,OAAQV,CAAA,CAAY,CAAA,EAInDQ,EAAAA,KAAC,MAAA,CAAI,UAAU,qCACb,SAAA,CAAAE,EAAAA,IAAC,SAAA,CACC,KAAK,SACL,QAAS,IAAM,CACbzB,EAAc,IAAI,EAClBE,EAAY,SAAS,CACvB,EACD,SAAA,MAAA,CAAA,EAGDqB,EAAAA,KAAC,SAAA,CACC,KAAK,SACL,UAAU,6BACV,QAASJ,EAET,SAAA,CAAAM,EAAAA,IAACK,EAAAA,YAAA,CAAY,KAAM,EAAA,CAAI,EAAE,sBAAA,CAAA,CAAA,CAE3B,CAAA,CACF,CAAA,CAAA,CACF,EAEAP,EAAAA,KAAC,MAAA,CAAI,UAAU,0BACZ,SAAA,CAAA,CAAC1C,GAAY4C,EAAAA,IAAC,IAAA,CAAE,UAAU,2BAA2B,SAAA,WAAQ,EAC7D5C,GAAYH,EAAS,SAAW,SAC9B,IAAA,CAAE,UAAU,2BAA2B,SAAA,mFAAA,CAGxC,EAED0C,EAAO,IAAKE,GACXC,EAAAA,KAAC,MAAA,CAAsB,UAAU,2BAC/B,SAAA,CAAAE,EAAAA,IAAC,MAAA,CAAI,UAAU,iCAAkC,SAAAH,EAAM,MAAM,EAC5DA,EAAM,SAAS,IAAKzF,GACnB0F,EAAAA,KAAC,SAAA,CAEC,KAAK,SACL,UAAU,0BACV,QAAS,IAAMvB,EAAcnE,EAAQ,EAAE,EAEvC,SAAA,CAAA4F,EAAAA,IAACI,EAAAA,cAAA,CAAc,SAAUhG,EAAQ,SAAU,KAAM,GAAI,EACrD0F,EAAAA,KAAC,MAAA,CAAI,UAAU,+BACb,SAAA,CAAAE,MAAC,MAAA,CAAI,UAAU,iCACZ,SAAA5F,EAAQ,UAAY,UACvB,EACA0F,EAAAA,KAAC,MAAA,CAAI,UAAU,+BACZ,SAAA,CAAAQ,EAAAA,mBAAmBlG,EAAQ,SAAS,EAAE,MAAIA,EAAQ,OAAA,CAAA,CACrD,CAAA,CAAA,CACF,CAAA,CAAA,EAbKA,EAAQ,EAAA,CAehB,CAAA,CAAA,EAnBOyF,EAAM,KAoBhB,CACD,CAAA,CAAA,CACH,CAAA,CAAA,CAAA,CAEJ,EACF,EACA,SAAS,IAAA,CACX,EACJ,CAEJ"}
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
import { useState as S, useRef as R, useEffect as E, useCallback as m } from "react";
|
|
2
|
+
import { flushSync as F, createPortal as Q } from "react-dom";
|
|
3
|
+
import { a as W, l as V, M as X } from "./icons-C1_s0jKK.js";
|
|
4
|
+
import { f as Y, a as Z, i as ee, b as te, c as ne, r as q, s as H } from "./leafBlockFactory-A9eUhSe-.js";
|
|
5
|
+
import { c as re, M as se, u as oe } from "./usePopoverEdgeClamp-gmFm0CnI.js";
|
|
6
|
+
import { jsxs as z, jsx as L } from "react/jsx-runtime";
|
|
7
|
+
function U(e) {
|
|
8
|
+
var c, a;
|
|
9
|
+
const s = (c = e.getPendingSelection) == null ? void 0 : c.call(e);
|
|
10
|
+
if (s) {
|
|
11
|
+
Y(s.runId, s.offset);
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
const i = (((a = e.getPendingAffectedBlockIds) == null ? void 0 : a.call(e)) ?? []).find((l) => e.getBlock(l));
|
|
15
|
+
i && Z(e, i);
|
|
16
|
+
}
|
|
17
|
+
const G = [
|
|
18
|
+
{
|
|
19
|
+
phrases: ["new paragraph", "next paragraph"],
|
|
20
|
+
description: "Start a new paragraph",
|
|
21
|
+
action: { type: "insertParagraph" }
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
phrases: ["heading one", "heading 1"],
|
|
25
|
+
description: "Convert the current block to a heading 1",
|
|
26
|
+
action: { type: "convertBlock", blockType: "heading", props: { level: 1 } }
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
phrases: ["heading two", "heading 2"],
|
|
30
|
+
description: "Convert the current block to a heading 2",
|
|
31
|
+
action: { type: "convertBlock", blockType: "heading", props: { level: 2 } }
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
phrases: ["heading three", "heading 3"],
|
|
35
|
+
description: "Convert the current block to a heading 3",
|
|
36
|
+
action: { type: "convertBlock", blockType: "heading", props: { level: 3 } }
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
phrases: ["bulleted list", "bullet point", "bullet list"],
|
|
40
|
+
description: "Convert the current block to a bulleted list item",
|
|
41
|
+
action: {
|
|
42
|
+
type: "convertBlock",
|
|
43
|
+
blockType: "listItem",
|
|
44
|
+
props: { ordered: !1, titleRunIds: [] }
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
phrases: ["numbered list", "ordered list"],
|
|
49
|
+
description: "Convert the current block to a numbered list item",
|
|
50
|
+
action: {
|
|
51
|
+
type: "convertBlock",
|
|
52
|
+
blockType: "listItem",
|
|
53
|
+
props: { ordered: !0, titleRunIds: [] }
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
phrases: ["checklist", "to-do", "to do", "to-do list", "to do list"],
|
|
58
|
+
description: "Convert the current block to a to-do item",
|
|
59
|
+
action: {
|
|
60
|
+
type: "convertBlock",
|
|
61
|
+
blockType: "listItem",
|
|
62
|
+
props: { ordered: !1, checked: !1, titleRunIds: [] }
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
phrases: ["quote"],
|
|
67
|
+
description: "Convert the current block to a quote",
|
|
68
|
+
action: { type: "convertBlock", blockType: "blockquote", props: {} }
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
phrases: ["code block", "code"],
|
|
72
|
+
description: "Convert the current block to a code block",
|
|
73
|
+
action: { type: "convertBlock", blockType: "code", props: { language: "plaintext" } }
|
|
74
|
+
},
|
|
75
|
+
{ phrases: ["undo"], description: "Undo the last edit", action: { type: "undo" } },
|
|
76
|
+
{ phrases: ["redo"], description: "Redo the last undone edit", action: { type: "redo" } },
|
|
77
|
+
{
|
|
78
|
+
phrases: ["stop dictation", "stop listening", "stop"],
|
|
79
|
+
description: "Stop dictation",
|
|
80
|
+
action: { type: "stopDictation" }
|
|
81
|
+
}
|
|
82
|
+
], J = /* @__PURE__ */ new Map();
|
|
83
|
+
for (const { phrases: e, action: s } of G)
|
|
84
|
+
for (const n of e) J.set(n, s);
|
|
85
|
+
function ie(e) {
|
|
86
|
+
return (e ?? "").toLowerCase().trim().replace(/\s+/g, " ").replace(/[.,!?]+$/, "");
|
|
87
|
+
}
|
|
88
|
+
function ce(e) {
|
|
89
|
+
return J.get(ie(e)) ?? null;
|
|
90
|
+
}
|
|
91
|
+
function ke() {
|
|
92
|
+
return G.map(({ phrases: e, description: s }) => ({ phrases: [...e], description: s }));
|
|
93
|
+
}
|
|
94
|
+
function ae(e, s) {
|
|
95
|
+
if (typeof e.performBatch == "function") e.performBatch(s);
|
|
96
|
+
else for (const n of s) e.applyOperation(n);
|
|
97
|
+
}
|
|
98
|
+
function le(e) {
|
|
99
|
+
var s;
|
|
100
|
+
return ((s = e == null ? void 0 : e.props) == null ? void 0 : s.titleRunIds) ?? (e == null ? void 0 : e.contentIds) ?? [];
|
|
101
|
+
}
|
|
102
|
+
function ue(e, s, n) {
|
|
103
|
+
var i, c;
|
|
104
|
+
if (n.type === "insertParagraph") {
|
|
105
|
+
ee(e, s, ne("paragraph"));
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (n.type === "convertBlock") {
|
|
109
|
+
const a = e.getBlock(s);
|
|
110
|
+
if (!a) return;
|
|
111
|
+
const l = le(a), { ops: O } = re(e, s, n.blockType, n.props, l);
|
|
112
|
+
ae(e, O), l[0] && te(l[0]);
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
if (n.type === "undo") {
|
|
116
|
+
(i = e.undo) != null && i.call(e) && U(e);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
n.type === "redo" && (c = e.redo) != null && c.call(e) && U(e);
|
|
120
|
+
}
|
|
121
|
+
function $() {
|
|
122
|
+
return typeof window > "u" ? null : window.SpeechRecognition ?? window.webkitSpeechRecognition ?? null;
|
|
123
|
+
}
|
|
124
|
+
const de = "Microphone access is blocked. Enable it in your browser's site settings, then try again.";
|
|
125
|
+
function ye({ shortcut: e = !0, engine: s } = {}) {
|
|
126
|
+
const n = W(), [i, c] = S(!1), [a, l] = S("idle"), [O, b] = S("unknown"), [x, I] = S(null), p = R(null), u = R(null), g = R(null), h = R(null), B = R(0), v = s != null || $() !== null;
|
|
127
|
+
E(() => {
|
|
128
|
+
var o;
|
|
129
|
+
if (!((o = navigator.permissions) != null && o.query)) return;
|
|
130
|
+
let t, r = !1;
|
|
131
|
+
return navigator.permissions.query({ name: "microphone" }).then((d) => {
|
|
132
|
+
r || (t = d, b(d.state), t.onchange = () => b(t.state));
|
|
133
|
+
}).catch(() => {
|
|
134
|
+
}), () => {
|
|
135
|
+
r = !0, t && (t.onchange = null);
|
|
136
|
+
};
|
|
137
|
+
}, []);
|
|
138
|
+
const A = m(() => {
|
|
139
|
+
if (!u.current) {
|
|
140
|
+
const t = q();
|
|
141
|
+
if (!t) return null;
|
|
142
|
+
u.current = t;
|
|
143
|
+
}
|
|
144
|
+
return {
|
|
145
|
+
runId: u.current.runId,
|
|
146
|
+
blockId: u.current.blockId,
|
|
147
|
+
startOffset: u.current.offset,
|
|
148
|
+
insertedLength: 0
|
|
149
|
+
};
|
|
150
|
+
}, []), M = m(
|
|
151
|
+
(t, r) => {
|
|
152
|
+
const o = n.getRun(t.runId);
|
|
153
|
+
if (!o || o.type !== "text") return;
|
|
154
|
+
const d = o.value ?? "", k = d.slice(0, t.startOffset);
|
|
155
|
+
if (t.needsLeadingSpace === void 0) {
|
|
156
|
+
const C = k[k.length - 1];
|
|
157
|
+
t.needsLeadingSpace = t.startOffset > 0 && C !== void 0 && !/\s/.test(C);
|
|
158
|
+
}
|
|
159
|
+
const y = (t.needsLeadingSpace ? " " : "") + r, f = d.slice(t.startOffset + t.insertedLength);
|
|
160
|
+
F(
|
|
161
|
+
() => n.applyOperation(V(t.runId, { value: k + y + f }))
|
|
162
|
+
), t.insertedLength = y.length;
|
|
163
|
+
const w = t.startOffset + y.length;
|
|
164
|
+
H(t.runId, w), u.current = { runId: t.runId, blockId: t.blockId, offset: w }, g.current = { runId: t.runId, offset: w };
|
|
165
|
+
},
|
|
166
|
+
[n]
|
|
167
|
+
), K = m(
|
|
168
|
+
(t) => {
|
|
169
|
+
const r = n.getRun(t.runId);
|
|
170
|
+
if (!r || r.type !== "text") return;
|
|
171
|
+
const o = r.value ?? "", d = o.slice(0, t.startOffset) + o.slice(t.startOffset + t.insertedLength);
|
|
172
|
+
F(() => n.applyOperation(V(t.runId, { value: d }))), H(t.runId, t.startOffset), u.current = {
|
|
173
|
+
runId: t.runId,
|
|
174
|
+
blockId: t.blockId,
|
|
175
|
+
offset: t.startOffset
|
|
176
|
+
}, g.current = { runId: t.runId, offset: t.startOffset };
|
|
177
|
+
},
|
|
178
|
+
[n]
|
|
179
|
+
), _ = m(
|
|
180
|
+
(t) => {
|
|
181
|
+
const r = n.getRun(t.runId);
|
|
182
|
+
if (!r || r.type !== "text") return;
|
|
183
|
+
const o = r.value ?? "", d = o.slice(0, t.startOffset) + o.slice(t.startOffset + t.insertedLength);
|
|
184
|
+
n.applyOperation(V(t.runId, { value: d }));
|
|
185
|
+
},
|
|
186
|
+
[n]
|
|
187
|
+
), j = m(
|
|
188
|
+
(t) => {
|
|
189
|
+
var k, y;
|
|
190
|
+
let r = "", o = !1;
|
|
191
|
+
const d = Math.max(t.resultIndex, B.current);
|
|
192
|
+
for (let f = d; f < t.results.length; f += 1) {
|
|
193
|
+
const w = t.results[f], C = ((k = w[0]) == null ? void 0 : k.transcript) ?? "";
|
|
194
|
+
if (!w.isFinal) {
|
|
195
|
+
r += (r ? " " : "") + C, o = !0;
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
const T = h.current ?? A();
|
|
199
|
+
if (h.current = null, B.current = f + 1, !T) continue;
|
|
200
|
+
const D = ce(C);
|
|
201
|
+
D ? (K(T), D.type === "stopDictation" ? (y = p.current) == null || y.stop() : (ue(n, T.blockId, D), u.current = null, g.current = null, l("listening"))) : (M(T, C), l("listening"));
|
|
202
|
+
}
|
|
203
|
+
if (o) {
|
|
204
|
+
const f = h.current ?? A();
|
|
205
|
+
f && (h.current = f, M(f, r));
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
[n, A, M, K]
|
|
209
|
+
);
|
|
210
|
+
E(() => {
|
|
211
|
+
if (!i) return;
|
|
212
|
+
const t = () => {
|
|
213
|
+
const r = g.current;
|
|
214
|
+
if (!r) return;
|
|
215
|
+
const o = q();
|
|
216
|
+
o && (o.runId === r.runId && o.offset === r.offset || (h.current && (_(h.current), h.current = null), u.current = o, g.current = { runId: o.runId, offset: o.offset }));
|
|
217
|
+
};
|
|
218
|
+
return document.addEventListener("selectionchange", t), () => document.removeEventListener("selectionchange", t);
|
|
219
|
+
}, [i, _]);
|
|
220
|
+
const N = m(() => {
|
|
221
|
+
if (!v || p.current) return;
|
|
222
|
+
I(null);
|
|
223
|
+
const t = q();
|
|
224
|
+
u.current = t, g.current = t ? { runId: t.runId, offset: t.offset } : null, h.current = null, B.current = 0;
|
|
225
|
+
let r;
|
|
226
|
+
if (s)
|
|
227
|
+
r = s();
|
|
228
|
+
else {
|
|
229
|
+
const o = $();
|
|
230
|
+
r = new o();
|
|
231
|
+
}
|
|
232
|
+
r.continuous = !0, r.interimResults = !0, r.onresult = j, r.onstart = () => l("listening"), r.onspeechstart = () => l("listening"), r.onspeechend = () => l("processing"), r.onerror = (o) => {
|
|
233
|
+
o.error === "not-allowed" || o.error === "service-not-allowed" ? (b("denied"), I(de)) : I(o.error ?? "Voice typing stopped unexpectedly.");
|
|
234
|
+
}, r.onend = () => {
|
|
235
|
+
p.current = null, u.current = null, g.current = null, h.current = null, B.current = 0, c(!1), l("idle");
|
|
236
|
+
}, p.current = r, r.start(), c(!0);
|
|
237
|
+
}, [v, j, s]), P = m(() => {
|
|
238
|
+
var t;
|
|
239
|
+
(t = p.current) == null || t.stop();
|
|
240
|
+
}, []);
|
|
241
|
+
return E(() => () => {
|
|
242
|
+
var t;
|
|
243
|
+
return (t = p.current) == null ? void 0 : t.stop();
|
|
244
|
+
}, []), E(() => {
|
|
245
|
+
if (!e || !v) return;
|
|
246
|
+
const t = (r) => {
|
|
247
|
+
!(r.metaKey || r.ctrlKey) || !r.shiftKey || r.key.toLowerCase() !== "m" || (r.preventDefault(), p.current ? P() : N());
|
|
248
|
+
};
|
|
249
|
+
return document.addEventListener("keydown", t), () => document.removeEventListener("keydown", t);
|
|
250
|
+
}, [e, v, N, P]), { isSupported: v, isListening: i, status: a, permissionState: O, error: x, start: N, stop: P };
|
|
251
|
+
}
|
|
252
|
+
function we({ voice: e }) {
|
|
253
|
+
const [s, n] = S(!1);
|
|
254
|
+
E(() => {
|
|
255
|
+
n(!1);
|
|
256
|
+
}, [e == null ? void 0 : e.error]);
|
|
257
|
+
const i = (e == null ? void 0 : e.permissionState) === "denied" && !s;
|
|
258
|
+
return /* @__PURE__ */ z(se, { isOpen: i, onClose: () => n(!0), title: "Microphone access blocked", children: [
|
|
259
|
+
/* @__PURE__ */ L("p", { children: (e == null ? void 0 : e.error) || "Microphone access is blocked. Enable it in your browser's site settings, then try again." }),
|
|
260
|
+
/* @__PURE__ */ z("div", { className: "be-modal-actions", children: [
|
|
261
|
+
/* @__PURE__ */ L("button", { type: "button", className: "be-modal-cancel", onClick: () => n(!0), children: "Dismiss" }),
|
|
262
|
+
/* @__PURE__ */ L("button", { type: "button", className: "be-modal-save", onClick: () => {
|
|
263
|
+
var c;
|
|
264
|
+
return (c = e == null ? void 0 : e.start) == null ? void 0 : c.call(e);
|
|
265
|
+
}, children: "Try again" })
|
|
266
|
+
] })
|
|
267
|
+
] });
|
|
268
|
+
}
|
|
269
|
+
function pe(e) {
|
|
270
|
+
const [s, n] = S(null);
|
|
271
|
+
return E(() => {
|
|
272
|
+
if (!e) {
|
|
273
|
+
n(null);
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
const i = () => {
|
|
277
|
+
var b, x, I, p;
|
|
278
|
+
const c = (b = window.getSelection) == null ? void 0 : b.call(window);
|
|
279
|
+
if (!c || c.rangeCount === 0 || !c.isCollapsed) {
|
|
280
|
+
n(null);
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
const a = c.anchorNode, l = (a == null ? void 0 : a.nodeType) === 1 ? a : a == null ? void 0 : a.parentElement;
|
|
284
|
+
if (!((x = l == null ? void 0 : l.closest) != null && x.call(l, "[data-run-id]"))) {
|
|
285
|
+
n(null);
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
const O = ((p = (I = c.getRangeAt(0)).getBoundingClientRect) == null ? void 0 : p.call(I)) ?? {
|
|
289
|
+
top: 0,
|
|
290
|
+
left: 0,
|
|
291
|
+
right: 0,
|
|
292
|
+
bottom: 0,
|
|
293
|
+
width: 0,
|
|
294
|
+
height: 0
|
|
295
|
+
};
|
|
296
|
+
n(O);
|
|
297
|
+
};
|
|
298
|
+
return i(), document.addEventListener("selectionchange", i), window.addEventListener("scroll", i, !0), window.addEventListener("resize", i), () => {
|
|
299
|
+
document.removeEventListener("selectionchange", i), window.removeEventListener("scroll", i, !0), window.removeEventListener("resize", i);
|
|
300
|
+
};
|
|
301
|
+
}, [e]), s;
|
|
302
|
+
}
|
|
303
|
+
function Ce({ voice: e }) {
|
|
304
|
+
const s = !!(e != null && e.isListening), n = pe(s), i = R(null), c = oe(i, !!(s && n), n == null ? void 0 : n.left);
|
|
305
|
+
if (!s || !n || c == null) return null;
|
|
306
|
+
const a = e.status === "processing";
|
|
307
|
+
return Q(
|
|
308
|
+
/* @__PURE__ */ z(
|
|
309
|
+
"div",
|
|
310
|
+
{
|
|
311
|
+
ref: i,
|
|
312
|
+
className: `be-voice-indicator${a ? " be-voice-indicator-processing" : ""}`,
|
|
313
|
+
contentEditable: !1,
|
|
314
|
+
style: {
|
|
315
|
+
position: "fixed",
|
|
316
|
+
top: n.top - 8,
|
|
317
|
+
left: c,
|
|
318
|
+
transform: "translate(-50%, -100%)"
|
|
319
|
+
},
|
|
320
|
+
children: [
|
|
321
|
+
/* @__PURE__ */ L("span", { className: "be-voice-indicator-dot" }),
|
|
322
|
+
/* @__PURE__ */ L(X, { size: 12 }),
|
|
323
|
+
/* @__PURE__ */ L("span", { className: "be-voice-indicator-label", children: a ? "Processing…" : "Listening…" })
|
|
324
|
+
]
|
|
325
|
+
}
|
|
326
|
+
),
|
|
327
|
+
document.body
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
export {
|
|
331
|
+
Ce as V,
|
|
332
|
+
we as a,
|
|
333
|
+
pe as b,
|
|
334
|
+
ke as l,
|
|
335
|
+
U as r,
|
|
336
|
+
ye as u
|
|
337
|
+
};
|
|
338
|
+
//# sourceMappingURL=VoiceListeningIndicator-BOfVmLK0.js.map
|