noteloom 0.3.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/README.md +344 -53
  2. package/bin/noteloom.mjs +139 -0
  3. package/dist/canvas.cjs +2 -0
  4. package/dist/canvas.cjs.map +1 -0
  5. package/dist/canvas.d.ts +2 -0
  6. package/dist/canvas.js +5 -0
  7. package/dist/canvas.js.map +1 -0
  8. package/dist/collab.cjs +2 -0
  9. package/dist/collab.cjs.map +1 -0
  10. package/dist/collab.d.ts +19 -0
  11. package/dist/collab.js +379 -0
  12. package/dist/collab.js.map +1 -0
  13. package/dist/comments.cjs +2 -0
  14. package/dist/comments.cjs.map +1 -0
  15. package/dist/comments.d.ts +17 -0
  16. package/dist/comments.js +19 -0
  17. package/dist/comments.js.map +1 -0
  18. package/dist/index.cjs +2 -0
  19. package/dist/index.cjs.map +1 -0
  20. package/dist/index.d.ts +392 -32
  21. package/dist/index.js +3983 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/persistence.cjs +2 -0
  24. package/dist/persistence.cjs.map +1 -0
  25. package/dist/persistence.d.ts +11 -0
  26. package/dist/persistence.js +12 -0
  27. package/dist/persistence.js.map +1 -0
  28. package/dist/shared/CommentAvatar-TKqsM8vG.js +53 -0
  29. package/dist/shared/CommentAvatar-TKqsM8vG.js.map +1 -0
  30. package/dist/shared/CommentAvatar-V457IgoQ.cjs +2 -0
  31. package/dist/shared/CommentAvatar-V457IgoQ.cjs.map +1 -0
  32. package/dist/shared/CommentThreadCard-CAJ3oPdr.cjs +2 -0
  33. package/dist/shared/CommentThreadCard-CAJ3oPdr.cjs.map +1 -0
  34. package/dist/shared/CommentThreadCard-Cxf8GwHJ.js +213 -0
  35. package/dist/shared/CommentThreadCard-Cxf8GwHJ.js.map +1 -0
  36. package/dist/shared/CommentsPanel-BwVVyMOC.js +76 -0
  37. package/dist/shared/CommentsPanel-BwVVyMOC.js.map +1 -0
  38. package/dist/shared/CommentsPanel-CES4uzye.cjs +2 -0
  39. package/dist/shared/CommentsPanel-CES4uzye.cjs.map +1 -0
  40. package/dist/shared/VersionHistory-Bg6fufP5.js +1120 -0
  41. package/dist/shared/VersionHistory-Bg6fufP5.js.map +1 -0
  42. package/dist/shared/VersionHistory-DELa2Wbq.cjs +12 -0
  43. package/dist/shared/VersionHistory-DELa2Wbq.cjs.map +1 -0
  44. package/dist/shared/VoiceListeningIndicator-BOfVmLK0.js +338 -0
  45. package/dist/shared/VoiceListeningIndicator-BOfVmLK0.js.map +1 -0
  46. package/dist/shared/VoiceListeningIndicator-DNX8JlQM.cjs +2 -0
  47. package/dist/shared/VoiceListeningIndicator-DNX8JlQM.cjs.map +1 -0
  48. package/dist/shared/fieldRegistry-BoYyW3GH.cjs +2 -0
  49. package/dist/shared/fieldRegistry-BoYyW3GH.cjs.map +1 -0
  50. package/dist/shared/fieldRegistry-PjJWXFoB.js +223 -0
  51. package/dist/shared/fieldRegistry-PjJWXFoB.js.map +1 -0
  52. package/dist/shared/icons-C1_s0jKK.js +4269 -0
  53. package/dist/shared/icons-C1_s0jKK.js.map +1 -0
  54. package/dist/shared/icons-DtCsXuU6.cjs +3531 -0
  55. package/dist/shared/icons-DtCsXuU6.cjs.map +1 -0
  56. package/dist/shared/index-B9jyyL8u.js +2145 -0
  57. package/dist/shared/index-B9jyyL8u.js.map +1 -0
  58. package/dist/shared/index-D9WEXpYM.cjs +2 -0
  59. package/dist/shared/index-D9WEXpYM.cjs.map +1 -0
  60. package/dist/shared/indexedDbPersistence-BKlGPFTP.js +112 -0
  61. package/dist/shared/indexedDbPersistence-BKlGPFTP.js.map +1 -0
  62. package/dist/shared/indexedDbPersistence-BWJ1h5Vp.cjs +2 -0
  63. package/dist/shared/indexedDbPersistence-BWJ1h5Vp.cjs.map +1 -0
  64. package/dist/shared/leafBlockFactory-A9eUhSe-.js +335 -0
  65. package/dist/shared/leafBlockFactory-A9eUhSe-.js.map +1 -0
  66. package/dist/shared/leafBlockFactory-Dp382eP8.cjs +2 -0
  67. package/dist/shared/leafBlockFactory-Dp382eP8.cjs.map +1 -0
  68. package/dist/shared/serialize-DWEfk0vU.cjs +3 -0
  69. package/dist/shared/serialize-DWEfk0vU.cjs.map +1 -0
  70. package/dist/shared/serialize-T9Odwx24.js +86 -0
  71. package/dist/shared/serialize-T9Odwx24.js.map +1 -0
  72. package/dist/shared/starter-kit-CY5wzYDf.js +4980 -0
  73. package/dist/shared/starter-kit-CY5wzYDf.js.map +1 -0
  74. package/dist/shared/starter-kit-lPN-NpJ5.cjs +27 -0
  75. package/dist/shared/starter-kit-lPN-NpJ5.cjs.map +1 -0
  76. package/dist/shared/usePopoverEdgeClamp-CDG26jBM.cjs +2 -0
  77. package/dist/shared/usePopoverEdgeClamp-CDG26jBM.cjs.map +1 -0
  78. package/dist/shared/usePopoverEdgeClamp-gmFm0CnI.js +109 -0
  79. package/dist/shared/usePopoverEdgeClamp-gmFm0CnI.js.map +1 -0
  80. package/dist/shared/useServiceWorkerUpdate-BduabXv6.js +94 -0
  81. package/dist/shared/useServiceWorkerUpdate-BduabXv6.js.map +1 -0
  82. package/dist/shared/useServiceWorkerUpdate-DQboGesi.cjs +2 -0
  83. package/dist/shared/useServiceWorkerUpdate-DQboGesi.cjs.map +1 -0
  84. package/dist/starter-kit.cjs +2 -0
  85. package/dist/starter-kit.cjs.map +1 -0
  86. package/dist/starter-kit.d.ts +9 -0
  87. package/dist/starter-kit.js +10 -0
  88. package/dist/starter-kit.js.map +1 -0
  89. package/dist/style.css +3529 -3200
  90. package/dist/versions.cjs +2 -0
  91. package/dist/versions.cjs.map +1 -0
  92. package/dist/versions.d.ts +11 -0
  93. package/dist/versions.js +13 -0
  94. package/dist/versions.js.map +1 -0
  95. package/dist/voice.cjs +2 -0
  96. package/dist/voice.cjs.map +1 -0
  97. package/dist/voice.d.ts +7 -0
  98. package/dist/voice.js +8 -0
  99. package/dist/voice.js.map +1 -0
  100. package/package.json +159 -92
  101. package/dist/noteloom.cjs +0 -3209
  102. package/dist/noteloom.cjs.map +0 -1
  103. package/dist/noteloom.es.js +0 -14622
  104. package/dist/noteloom.es.js.map +0 -1
@@ -0,0 +1,2 @@
1
+ "use strict";const x=require("react/jsx-runtime"),r=require("react"),L=require("./icons-DtCsXuU6.cjs"),v='button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';function y({isOpen:t,onClose:e,title:o,size:n="default",variant:s="dialog",children:u}){const c=r.useRef(null),a=r.useRef(null);if(r.useEffect(()=>{if(!t)return;const l=d=>{d.key==="Escape"&&e()};return document.addEventListener("keydown",l),()=>document.removeEventListener("keydown",l)},[t,e]),r.useEffect(()=>{var l,d,m;if(t){a.current=document.activeElement;const f=c.current;(l=(f==null?void 0:f.querySelector(v))??f)==null||l.focus();return}(m=(d=a.current)==null?void 0:d.focus)==null||m.call(d),a.current=null},[t]),!t)return null;const i=s==="sheet";return x.jsx("div",{className:`be-modal-overlay${i?" be-modal-overlay-sheet":""}`,onMouseDown:l=>{l.target===l.currentTarget&&e()},children:x.jsxs("div",{ref:c,className:`be-modal${n==="large"?" be-modal-large":""}${i?" be-modal-sheet":""}`,role:"dialog","aria-modal":"true","aria-label":o,tabIndex:-1,children:[o&&x.jsx("div",{className:"be-modal-title",children:o}),u]})})}const p=8;function g(t,e){const o=Math.max(p,window.innerWidth-e-p);return Math.min(Math.max(t,p),o)}function A(t,e){const o=Math.max(p,window.innerHeight-e-p);return Math.min(Math.max(t,p),o)}function B(t,e,o,n,s,u){const c=t.getBlock(e),i=t.getBlock(c.parentId).contentIds.indexOf(e),l="titleRunIds"in n,d="titleRunIds"in(c.props??{}),m=u?!u.isLeaf(c.type)&&c.contentIds.length>0:!1,f=u?!u.isLeaf(o):!1,h=[];if(m&&!f&&c.contentIds.forEach((E,w)=>h.push(L.moveBlock(E,c.parentId,i+1+w))),h.push(L.changeBlockType(e,o,n)),l)h.push(L.updateBlockProps(e,{titleRunIds:s})),!d&&!m&&h.push(L.setBlockContentIds(e,[]));else{const E=m&&f?c.contentIds:[];h.push(L.setBlockContentIds(e,[...E,...s]))}return{newBlockId:e,ops:h}}function T(t,e,o){const[n,s]=r.useState(null);return r.useLayoutEffect(()=>{s(o??null)},[o]),r.useLayoutEffect(()=>{if(!e||!t.current||n==null)return;const u=t.current.getBoundingClientRect(),c=g(n,u.width);c!==n&&s(c)},[e,t,n]),n}function C(t,e,o){const[n,s]=r.useState(null);return r.useLayoutEffect(()=>{s(o??null)},[o]),r.useLayoutEffect(()=>{if(!e||!t.current||n==null)return;const u=t.current.getBoundingClientRect(),c=u.width/2,i=g(n-c,u.width)+c;i!==n&&s(i)},[e,t,n]),n}function R(t,e,o){const[n,s]=r.useState(null);return r.useLayoutEffect(()=>{s(o??null)},[o]),r.useLayoutEffect(()=>{if(!e||!t.current||n==null)return;const u=t.current.getBoundingClientRect(),a=g(n-u.width,u.width)+u.width;a!==n&&s(a)},[e,t,n]),n}exports.Modal=y;exports.clampLeftToViewport=g;exports.clampTopToViewport=A;exports.convertBlockType=B;exports.useAutoAdjustedCenteredLeft=C;exports.useAutoAdjustedRightLeft=R;exports.useHorizontalAutoAdjustedLeft=T;
2
+ //# sourceMappingURL=usePopoverEdgeClamp-CDG26jBM.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePopoverEdgeClamp-CDG26jBM.cjs","sources":["../../src/react/Modal.jsx","../../src/react/popoverPosition.js","../../src/blocks/shared/convertBlockType.js","../../src/react/usePopoverEdgeClamp.js"],"sourcesContent":["import { useEffect, useRef } from 'react';\n\nconst FOCUSABLE_SELECTOR =\n 'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])';\n\n/**\n * Minimal, dependency-free modal dialog: a fixed backdrop + centered panel.\n * Closes on Escape or a click directly on the backdrop (not bubbled up from\n * inside the panel, which is why the backdrop's onMouseDown checks\n * `event.target === event.currentTarget`). No focus trap — the whole\n * editor package is deliberately zero-dependency, and dialogs here are\n * short, single-purpose forms, not deep navigable UI.\n *\n * Does move focus IN (to the first focusable element inside the panel, or\n * the panel itself as a fallback) on open, and OUT (back to whatever had\n * focus right before the modal opened — typically the button that opened\n * it) on close — distinct from a focus trap: it's a one-time move each\n * way, not a loop that prevents Tab from ever leaving the panel.\n */\nexport function Modal({ isOpen, onClose, title, size = 'default', variant = 'dialog', children }) {\n const panelRef = useRef(null);\n const previouslyFocusedRef = useRef(null);\n\n useEffect(() => {\n if (!isOpen) return undefined;\n const handleKeyDown = (event) => {\n if (event.key === 'Escape') onClose();\n };\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [isOpen, onClose]);\n\n useEffect(() => {\n if (isOpen) {\n previouslyFocusedRef.current = document.activeElement;\n const panel = panelRef.current;\n const focusable = panel?.querySelector(FOCUSABLE_SELECTOR);\n (focusable ?? panel)?.focus();\n return undefined;\n }\n previouslyFocusedRef.current?.focus?.();\n previouslyFocusedRef.current = null;\n return undefined;\n }, [isOpen]);\n\n if (!isOpen) return null;\n const isSheet = variant === 'sheet';\n\n return (\n <div\n className={`be-modal-overlay${isSheet ? ' be-modal-overlay-sheet' : ''}`}\n onMouseDown={(event) => {\n if (event.target === event.currentTarget) onClose();\n }}\n >\n <div\n ref={panelRef}\n className={`be-modal${size === 'large' ? ' be-modal-large' : ''}${isSheet ? ' be-modal-sheet' : ''}`}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={title}\n tabIndex={-1}\n >\n {title && <div className=\"be-modal-title\">{title}</div>}\n {children}\n </div>\n </div>\n );\n}\n","const MARGIN = 8;\n\n/**\n * Shifts `left`/`top` back inside the viewport (never past the opposite\n * edge either) for a box of the given size — the \"shift\" strategy antd's\n * `autoAdjustOverflow` uses, not a side-flip. Shared by every popover-\n * positioning hook in this file so the margin/clamp math lives in exactly\n * one place.\n */\nexport function clampLeftToViewport(left, width) {\n const maxLeft = Math.max(MARGIN, window.innerWidth - width - MARGIN);\n return Math.min(Math.max(left, MARGIN), maxLeft);\n}\n\nexport function clampTopToViewport(top, height) {\n const maxTop = Math.max(MARGIN, window.innerHeight - height - MARGIN);\n return Math.min(Math.max(top, MARGIN), maxTop);\n}\n","import {\n changeBlockType,\n moveBlock,\n setBlockContentIds,\n updateBlockProps,\n} from '../../store/operations.js';\n\n/**\n * Builds the ops that convert `blockId` to a different type IN PLACE — same\n * id, same parentId, same position among siblings — carrying over `runIds`\n * (reusing the existing Run objects — never recreated) rather than creating\n * new ones, so any marks/text already typed survive the conversion. `props`\n * may include `titleRunIds` (for a listItem-shaped target) — `runIds` is\n * threaded into whichever of contentIds/props.titleRunIds the target type\n * actually uses (and whichever the *source* type used, when detaching).\n *\n * Keeping the same id (rather than deleting the old block and inserting a\n * new one) matters beyond just simplicity: it's what lets a future\n * multi-peer merge treat two concurrent conversions of the same block as\n * one field-level conflict on that id (last-write-wins) instead of two\n * unrelated structural edits that would otherwise leave both resulting\n * blocks sitting side by side after merging.\n *\n * `registry` is optional and additive — this function's two original\n * callers (markdownShortcuts.js, applyVoiceAction.js) never pass one, and\n * only ever call this on a fresh, childless, single-run paragraph, so their\n * behavior is completely unaffected by anything below. When `registry` IS\n * supplied (the \"Turn into\" feature), the *source* block's own nested\n * children — real child blocks in `contentIds`, distinct from a leaf's own\n * runs, true for `listItem`/`toggleHeading`/`callout` (`!registry.isLeaf`)\n * — are handled instead of being silently orphaned:\n * - If the *target* type can also hold children (`!registry.isLeaf(type)`,\n * e.g. listItem -> toggleHeading), the children simply stay parented to\n * this same block id — nothing needs to move.\n * - If the target is a pure leaf (e.g. toggleHeading -> heading) and can't\n * hold them, they're promoted to sibling blocks inserted immediately\n * after this block instead — content is never silently dropped.\n *\n * Returns `{ ops, newBlockId }` rather than applying anything itself —\n * `newBlockId` is always `blockId` (kept for backward compatibility with\n * callers written when this returned a freshly generated id). The caller\n * folds `ops` into its own batch (e.g. alongside an `updateRun` that strips\n * a matched markdown-shortcut prefix from the first run), so the whole\n * thing is one atomic undo step.\n */\nexport function convertBlockType(store, blockId, type, props, runIds, registry) {\n const block = store.getBlock(blockId);\n const parent = store.getBlock(block.parentId);\n const index = parent.contentIds.indexOf(blockId);\n const targetUsesTitleRunIds = 'titleRunIds' in props;\n const sourceUsesTitleRunIds = 'titleRunIds' in (block.props ?? {});\n const sourceHasChildren = registry\n ? !registry.isLeaf(block.type) && block.contentIds.length > 0\n : false;\n const targetCanHoldChildren = registry ? !registry.isLeaf(type) : false;\n\n const ops = [];\n\n // Children only need to move when the target can't hold them (promoted\n // to siblings). When the target can also hold children, they're already\n // correctly parented to this same block id — nothing to do.\n if (sourceHasChildren && !targetCanHoldChildren) {\n block.contentIds.forEach((childId, i) =>\n ops.push(moveBlock(childId, block.parentId, index + 1 + i)),\n );\n }\n\n ops.push(changeBlockType(blockId, type, props));\n\n if (targetUsesTitleRunIds) {\n ops.push(updateBlockProps(blockId, { titleRunIds: runIds }));\n // A leaf source's old contentIds held its own runs, now superseded by\n // titleRunIds — clear it so those ids aren't misread as child blocks.\n // A container source that already used titleRunIds (or had its\n // children promoted to siblings above) already has the right\n // contentIds and needs no clearing.\n if (!sourceUsesTitleRunIds && !sourceHasChildren) {\n ops.push(setBlockContentIds(blockId, []));\n }\n } else {\n // Target keeps its own runs directly in contentIds. Any children still\n // sitting in contentIds at this point are ones the target can also\n // hold (handled above) and must be kept alongside the transferred\n // runIds, not replaced by them.\n const keepChildren = sourceHasChildren && targetCanHoldChildren ? block.contentIds : [];\n ops.push(setBlockContentIds(blockId, [...keepChildren, ...runIds]));\n }\n\n return { newBlockId: blockId, ops };\n}\n","import { useLayoutEffect, useState } from 'react';\nimport { clampLeftToViewport } from './popoverPosition.js';\n\n// All three hooks below share the exact two-phase shape\n// useAutoAdjustedPosition.js documents in full (snap to the raw anchor\n// first so nothing jumps, then measure + clamp once real layout exists,\n// both as useLayoutEffects so the whole chain settles before the browser\n// ever paints) — only the *anchor math* differs per popover's own CSS\n// convention, so each is kept as its own tiny hook rather than forcing one\n// generic shape to cover every transform variant.\n\n/**\n * For a popover that's LEFT-anchored (plain `left: <value>`, no transform)\n * but already owns its own vertical placement (Select/SlashMenu both flip\n * between `top`/`bottom` to dodge the on-screen keyboard) — this only ever\n * touches the horizontal axis, leaving the caller's vertical decision alone.\n */\nexport function useHorizontalAutoAdjustedLeft(menuRef, isOpen, rawLeft) {\n const [left, setLeft] = useState(null);\n\n useLayoutEffect(() => {\n setLeft(rawLeft ?? null);\n }, [rawLeft]);\n\n useLayoutEffect(() => {\n if (!isOpen || !menuRef.current || left == null) return;\n const rect = menuRef.current.getBoundingClientRect();\n const clamped = clampLeftToViewport(left, rect.width);\n if (clamped !== left) setLeft(clamped);\n }, [isOpen, menuRef, left]);\n\n return left;\n}\n\n/**\n * For a popover CENTERED on an x-coordinate via `left: <centerX>;\n * transform: translateX(-50%)` (FloatingToolbar's own bubble, centered over\n * the text selection it's formatting) — clamps the box's actual left/right\n * edges (accounting for the -50% shift) and returns an adjusted `centerX`\n * for that same `left` + `transform: translateX(-50%)` pairing, so the\n * caller's JSX doesn't need to change anything but the number.\n */\nexport function useAutoAdjustedCenteredLeft(menuRef, isOpen, rawCenterLeft) {\n const [centerLeft, setCenterLeft] = useState(null);\n\n useLayoutEffect(() => {\n setCenterLeft(rawCenterLeft ?? null);\n }, [rawCenterLeft]);\n\n useLayoutEffect(() => {\n if (!isOpen || !menuRef.current || centerLeft == null) return;\n const rect = menuRef.current.getBoundingClientRect();\n const half = rect.width / 2;\n const clampedEdge = clampLeftToViewport(centerLeft - half, rect.width);\n const nextCenter = clampedEdge + half;\n if (nextCenter !== centerLeft) setCenterLeft(nextCenter);\n }, [isOpen, menuRef, centerLeft]);\n\n return centerLeft;\n}\n\n/**\n * For a popover RIGHT-anchored on an x-coordinate via `left: <rightEdgeX>;\n * transform: translateX(-100%)` (TableHeaderRow's column menu, whose right\n * edge lines up with the header cell's own right edge and grows leftward)\n * — clamps the box's actual left edge and returns an adjusted `rightEdgeX`\n * for that same `left` + `transform: translateX(-100%)` pairing.\n */\nexport function useAutoAdjustedRightLeft(menuRef, isOpen, rawRightEdgeLeft) {\n const [rightLeft, setRightLeft] = useState(null);\n\n useLayoutEffect(() => {\n setRightLeft(rawRightEdgeLeft ?? null);\n }, [rawRightEdgeLeft]);\n\n useLayoutEffect(() => {\n if (!isOpen || !menuRef.current || rightLeft == null) return;\n const rect = menuRef.current.getBoundingClientRect();\n const clampedEdge = clampLeftToViewport(rightLeft - rect.width, rect.width);\n const nextRightLeft = clampedEdge + rect.width;\n if (nextRightLeft !== rightLeft) setRightLeft(nextRightLeft);\n }, [isOpen, menuRef, rightLeft]);\n\n return rightLeft;\n}\n"],"names":["FOCUSABLE_SELECTOR","Modal","isOpen","onClose","title","size","variant","children","panelRef","useRef","previouslyFocusedRef","useEffect","handleKeyDown","event","panel","_a","_c","_b","isSheet","jsx","jsxs","MARGIN","clampLeftToViewport","left","width","maxLeft","clampTopToViewport","top","height","maxTop","convertBlockType","store","blockId","type","props","runIds","registry","block","index","targetUsesTitleRunIds","sourceUsesTitleRunIds","sourceHasChildren","targetCanHoldChildren","ops","childId","i","moveBlock","changeBlockType","updateBlockProps","setBlockContentIds","keepChildren","useHorizontalAutoAdjustedLeft","menuRef","rawLeft","setLeft","useState","useLayoutEffect","rect","clamped","useAutoAdjustedCenteredLeft","rawCenterLeft","centerLeft","setCenterLeft","half","nextCenter","useAutoAdjustedRightLeft","rawRightEdgeLeft","rightLeft","setRightLeft","nextRightLeft"],"mappings":"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"}
@@ -0,0 +1,109 @@
1
+ import { jsx as v, jsxs as M } from "react/jsx-runtime";
2
+ import { useRef as w, useEffect as E, useState as x, useLayoutEffect as p } from "react";
3
+ import { m as T, i as b, j as R, s as B } from "./icons-C1_s0jKK.js";
4
+ const y = 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';
5
+ function j({ isOpen: t, onClose: e, title: o, size: n = "default", variant: s = "dialog", children: r }) {
6
+ const c = w(null), u = w(null);
7
+ if (E(() => {
8
+ if (!t) return;
9
+ const a = (l) => {
10
+ l.key === "Escape" && e();
11
+ };
12
+ return document.addEventListener("keydown", a), () => document.removeEventListener("keydown", a);
13
+ }, [t, e]), E(() => {
14
+ var a, l, h;
15
+ if (t) {
16
+ u.current = document.activeElement;
17
+ const d = c.current;
18
+ (a = (d == null ? void 0 : d.querySelector(y)) ?? d) == null || a.focus();
19
+ return;
20
+ }
21
+ (h = (l = u.current) == null ? void 0 : l.focus) == null || h.call(l), u.current = null;
22
+ }, [t]), !t) return null;
23
+ const i = s === "sheet";
24
+ return /* @__PURE__ */ v(
25
+ "div",
26
+ {
27
+ className: `be-modal-overlay${i ? " be-modal-overlay-sheet" : ""}`,
28
+ onMouseDown: (a) => {
29
+ a.target === a.currentTarget && e();
30
+ },
31
+ children: /* @__PURE__ */ M(
32
+ "div",
33
+ {
34
+ ref: c,
35
+ className: `be-modal${n === "large" ? " be-modal-large" : ""}${i ? " be-modal-sheet" : ""}`,
36
+ role: "dialog",
37
+ "aria-modal": "true",
38
+ "aria-label": o,
39
+ tabIndex: -1,
40
+ children: [
41
+ o && /* @__PURE__ */ v("div", { className: "be-modal-title", children: o }),
42
+ r
43
+ ]
44
+ }
45
+ )
46
+ }
47
+ );
48
+ }
49
+ const m = 8;
50
+ function L(t, e) {
51
+ const o = Math.max(m, window.innerWidth - e - m);
52
+ return Math.min(Math.max(t, m), o);
53
+ }
54
+ function S(t, e) {
55
+ const o = Math.max(m, window.innerHeight - e - m);
56
+ return Math.min(Math.max(t, m), o);
57
+ }
58
+ function H(t, e, o, n, s, r) {
59
+ const c = t.getBlock(e), i = t.getBlock(c.parentId).contentIds.indexOf(e), a = "titleRunIds" in n, l = "titleRunIds" in (c.props ?? {}), h = r ? !r.isLeaf(c.type) && c.contentIds.length > 0 : !1, d = r ? !r.isLeaf(o) : !1, f = [];
60
+ if (h && !d && c.contentIds.forEach(
61
+ (g, C) => f.push(T(g, c.parentId, i + 1 + C))
62
+ ), f.push(b(e, o, n)), a)
63
+ f.push(R(e, { titleRunIds: s })), !l && !h && f.push(B(e, []));
64
+ else {
65
+ const g = h && d ? c.contentIds : [];
66
+ f.push(B(e, [...g, ...s]));
67
+ }
68
+ return { newBlockId: e, ops: f };
69
+ }
70
+ function N(t, e, o) {
71
+ const [n, s] = x(null);
72
+ return p(() => {
73
+ s(o ?? null);
74
+ }, [o]), p(() => {
75
+ if (!e || !t.current || n == null) return;
76
+ const r = t.current.getBoundingClientRect(), c = L(n, r.width);
77
+ c !== n && s(c);
78
+ }, [e, t, n]), n;
79
+ }
80
+ function U(t, e, o) {
81
+ const [n, s] = x(null);
82
+ return p(() => {
83
+ s(o ?? null);
84
+ }, [o]), p(() => {
85
+ if (!e || !t.current || n == null) return;
86
+ const r = t.current.getBoundingClientRect(), c = r.width / 2, i = L(n - c, r.width) + c;
87
+ i !== n && s(i);
88
+ }, [e, t, n]), n;
89
+ }
90
+ function $(t, e, o) {
91
+ const [n, s] = x(null);
92
+ return p(() => {
93
+ s(o ?? null);
94
+ }, [o]), p(() => {
95
+ if (!e || !t.current || n == null) return;
96
+ const r = t.current.getBoundingClientRect(), u = L(n - r.width, r.width) + r.width;
97
+ u !== n && s(u);
98
+ }, [e, t, n]), n;
99
+ }
100
+ export {
101
+ j as M,
102
+ N as a,
103
+ L as b,
104
+ H as c,
105
+ S as d,
106
+ $ as e,
107
+ U as u
108
+ };
109
+ //# sourceMappingURL=usePopoverEdgeClamp-gmFm0CnI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePopoverEdgeClamp-gmFm0CnI.js","sources":["../../src/react/Modal.jsx","../../src/react/popoverPosition.js","../../src/blocks/shared/convertBlockType.js","../../src/react/usePopoverEdgeClamp.js"],"sourcesContent":["import { useEffect, useRef } from 'react';\n\nconst FOCUSABLE_SELECTOR =\n 'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])';\n\n/**\n * Minimal, dependency-free modal dialog: a fixed backdrop + centered panel.\n * Closes on Escape or a click directly on the backdrop (not bubbled up from\n * inside the panel, which is why the backdrop's onMouseDown checks\n * `event.target === event.currentTarget`). No focus trap — the whole\n * editor package is deliberately zero-dependency, and dialogs here are\n * short, single-purpose forms, not deep navigable UI.\n *\n * Does move focus IN (to the first focusable element inside the panel, or\n * the panel itself as a fallback) on open, and OUT (back to whatever had\n * focus right before the modal opened — typically the button that opened\n * it) on close — distinct from a focus trap: it's a one-time move each\n * way, not a loop that prevents Tab from ever leaving the panel.\n */\nexport function Modal({ isOpen, onClose, title, size = 'default', variant = 'dialog', children }) {\n const panelRef = useRef(null);\n const previouslyFocusedRef = useRef(null);\n\n useEffect(() => {\n if (!isOpen) return undefined;\n const handleKeyDown = (event) => {\n if (event.key === 'Escape') onClose();\n };\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [isOpen, onClose]);\n\n useEffect(() => {\n if (isOpen) {\n previouslyFocusedRef.current = document.activeElement;\n const panel = panelRef.current;\n const focusable = panel?.querySelector(FOCUSABLE_SELECTOR);\n (focusable ?? panel)?.focus();\n return undefined;\n }\n previouslyFocusedRef.current?.focus?.();\n previouslyFocusedRef.current = null;\n return undefined;\n }, [isOpen]);\n\n if (!isOpen) return null;\n const isSheet = variant === 'sheet';\n\n return (\n <div\n className={`be-modal-overlay${isSheet ? ' be-modal-overlay-sheet' : ''}`}\n onMouseDown={(event) => {\n if (event.target === event.currentTarget) onClose();\n }}\n >\n <div\n ref={panelRef}\n className={`be-modal${size === 'large' ? ' be-modal-large' : ''}${isSheet ? ' be-modal-sheet' : ''}`}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={title}\n tabIndex={-1}\n >\n {title && <div className=\"be-modal-title\">{title}</div>}\n {children}\n </div>\n </div>\n );\n}\n","const MARGIN = 8;\n\n/**\n * Shifts `left`/`top` back inside the viewport (never past the opposite\n * edge either) for a box of the given size — the \"shift\" strategy antd's\n * `autoAdjustOverflow` uses, not a side-flip. Shared by every popover-\n * positioning hook in this file so the margin/clamp math lives in exactly\n * one place.\n */\nexport function clampLeftToViewport(left, width) {\n const maxLeft = Math.max(MARGIN, window.innerWidth - width - MARGIN);\n return Math.min(Math.max(left, MARGIN), maxLeft);\n}\n\nexport function clampTopToViewport(top, height) {\n const maxTop = Math.max(MARGIN, window.innerHeight - height - MARGIN);\n return Math.min(Math.max(top, MARGIN), maxTop);\n}\n","import {\n changeBlockType,\n moveBlock,\n setBlockContentIds,\n updateBlockProps,\n} from '../../store/operations.js';\n\n/**\n * Builds the ops that convert `blockId` to a different type IN PLACE — same\n * id, same parentId, same position among siblings — carrying over `runIds`\n * (reusing the existing Run objects — never recreated) rather than creating\n * new ones, so any marks/text already typed survive the conversion. `props`\n * may include `titleRunIds` (for a listItem-shaped target) — `runIds` is\n * threaded into whichever of contentIds/props.titleRunIds the target type\n * actually uses (and whichever the *source* type used, when detaching).\n *\n * Keeping the same id (rather than deleting the old block and inserting a\n * new one) matters beyond just simplicity: it's what lets a future\n * multi-peer merge treat two concurrent conversions of the same block as\n * one field-level conflict on that id (last-write-wins) instead of two\n * unrelated structural edits that would otherwise leave both resulting\n * blocks sitting side by side after merging.\n *\n * `registry` is optional and additive — this function's two original\n * callers (markdownShortcuts.js, applyVoiceAction.js) never pass one, and\n * only ever call this on a fresh, childless, single-run paragraph, so their\n * behavior is completely unaffected by anything below. When `registry` IS\n * supplied (the \"Turn into\" feature), the *source* block's own nested\n * children — real child blocks in `contentIds`, distinct from a leaf's own\n * runs, true for `listItem`/`toggleHeading`/`callout` (`!registry.isLeaf`)\n * — are handled instead of being silently orphaned:\n * - If the *target* type can also hold children (`!registry.isLeaf(type)`,\n * e.g. listItem -> toggleHeading), the children simply stay parented to\n * this same block id — nothing needs to move.\n * - If the target is a pure leaf (e.g. toggleHeading -> heading) and can't\n * hold them, they're promoted to sibling blocks inserted immediately\n * after this block instead — content is never silently dropped.\n *\n * Returns `{ ops, newBlockId }` rather than applying anything itself —\n * `newBlockId` is always `blockId` (kept for backward compatibility with\n * callers written when this returned a freshly generated id). The caller\n * folds `ops` into its own batch (e.g. alongside an `updateRun` that strips\n * a matched markdown-shortcut prefix from the first run), so the whole\n * thing is one atomic undo step.\n */\nexport function convertBlockType(store, blockId, type, props, runIds, registry) {\n const block = store.getBlock(blockId);\n const parent = store.getBlock(block.parentId);\n const index = parent.contentIds.indexOf(blockId);\n const targetUsesTitleRunIds = 'titleRunIds' in props;\n const sourceUsesTitleRunIds = 'titleRunIds' in (block.props ?? {});\n const sourceHasChildren = registry\n ? !registry.isLeaf(block.type) && block.contentIds.length > 0\n : false;\n const targetCanHoldChildren = registry ? !registry.isLeaf(type) : false;\n\n const ops = [];\n\n // Children only need to move when the target can't hold them (promoted\n // to siblings). When the target can also hold children, they're already\n // correctly parented to this same block id — nothing to do.\n if (sourceHasChildren && !targetCanHoldChildren) {\n block.contentIds.forEach((childId, i) =>\n ops.push(moveBlock(childId, block.parentId, index + 1 + i)),\n );\n }\n\n ops.push(changeBlockType(blockId, type, props));\n\n if (targetUsesTitleRunIds) {\n ops.push(updateBlockProps(blockId, { titleRunIds: runIds }));\n // A leaf source's old contentIds held its own runs, now superseded by\n // titleRunIds — clear it so those ids aren't misread as child blocks.\n // A container source that already used titleRunIds (or had its\n // children promoted to siblings above) already has the right\n // contentIds and needs no clearing.\n if (!sourceUsesTitleRunIds && !sourceHasChildren) {\n ops.push(setBlockContentIds(blockId, []));\n }\n } else {\n // Target keeps its own runs directly in contentIds. Any children still\n // sitting in contentIds at this point are ones the target can also\n // hold (handled above) and must be kept alongside the transferred\n // runIds, not replaced by them.\n const keepChildren = sourceHasChildren && targetCanHoldChildren ? block.contentIds : [];\n ops.push(setBlockContentIds(blockId, [...keepChildren, ...runIds]));\n }\n\n return { newBlockId: blockId, ops };\n}\n","import { useLayoutEffect, useState } from 'react';\nimport { clampLeftToViewport } from './popoverPosition.js';\n\n// All three hooks below share the exact two-phase shape\n// useAutoAdjustedPosition.js documents in full (snap to the raw anchor\n// first so nothing jumps, then measure + clamp once real layout exists,\n// both as useLayoutEffects so the whole chain settles before the browser\n// ever paints) — only the *anchor math* differs per popover's own CSS\n// convention, so each is kept as its own tiny hook rather than forcing one\n// generic shape to cover every transform variant.\n\n/**\n * For a popover that's LEFT-anchored (plain `left: <value>`, no transform)\n * but already owns its own vertical placement (Select/SlashMenu both flip\n * between `top`/`bottom` to dodge the on-screen keyboard) — this only ever\n * touches the horizontal axis, leaving the caller's vertical decision alone.\n */\nexport function useHorizontalAutoAdjustedLeft(menuRef, isOpen, rawLeft) {\n const [left, setLeft] = useState(null);\n\n useLayoutEffect(() => {\n setLeft(rawLeft ?? null);\n }, [rawLeft]);\n\n useLayoutEffect(() => {\n if (!isOpen || !menuRef.current || left == null) return;\n const rect = menuRef.current.getBoundingClientRect();\n const clamped = clampLeftToViewport(left, rect.width);\n if (clamped !== left) setLeft(clamped);\n }, [isOpen, menuRef, left]);\n\n return left;\n}\n\n/**\n * For a popover CENTERED on an x-coordinate via `left: <centerX>;\n * transform: translateX(-50%)` (FloatingToolbar's own bubble, centered over\n * the text selection it's formatting) — clamps the box's actual left/right\n * edges (accounting for the -50% shift) and returns an adjusted `centerX`\n * for that same `left` + `transform: translateX(-50%)` pairing, so the\n * caller's JSX doesn't need to change anything but the number.\n */\nexport function useAutoAdjustedCenteredLeft(menuRef, isOpen, rawCenterLeft) {\n const [centerLeft, setCenterLeft] = useState(null);\n\n useLayoutEffect(() => {\n setCenterLeft(rawCenterLeft ?? null);\n }, [rawCenterLeft]);\n\n useLayoutEffect(() => {\n if (!isOpen || !menuRef.current || centerLeft == null) return;\n const rect = menuRef.current.getBoundingClientRect();\n const half = rect.width / 2;\n const clampedEdge = clampLeftToViewport(centerLeft - half, rect.width);\n const nextCenter = clampedEdge + half;\n if (nextCenter !== centerLeft) setCenterLeft(nextCenter);\n }, [isOpen, menuRef, centerLeft]);\n\n return centerLeft;\n}\n\n/**\n * For a popover RIGHT-anchored on an x-coordinate via `left: <rightEdgeX>;\n * transform: translateX(-100%)` (TableHeaderRow's column menu, whose right\n * edge lines up with the header cell's own right edge and grows leftward)\n * — clamps the box's actual left edge and returns an adjusted `rightEdgeX`\n * for that same `left` + `transform: translateX(-100%)` pairing.\n */\nexport function useAutoAdjustedRightLeft(menuRef, isOpen, rawRightEdgeLeft) {\n const [rightLeft, setRightLeft] = useState(null);\n\n useLayoutEffect(() => {\n setRightLeft(rawRightEdgeLeft ?? null);\n }, [rawRightEdgeLeft]);\n\n useLayoutEffect(() => {\n if (!isOpen || !menuRef.current || rightLeft == null) return;\n const rect = menuRef.current.getBoundingClientRect();\n const clampedEdge = clampLeftToViewport(rightLeft - rect.width, rect.width);\n const nextRightLeft = clampedEdge + rect.width;\n if (nextRightLeft !== rightLeft) setRightLeft(nextRightLeft);\n }, [isOpen, menuRef, rightLeft]);\n\n return rightLeft;\n}\n"],"names":["FOCUSABLE_SELECTOR","Modal","isOpen","onClose","title","size","variant","children","panelRef","useRef","previouslyFocusedRef","useEffect","handleKeyDown","event","panel","_a","_c","_b","isSheet","jsx","jsxs","MARGIN","clampLeftToViewport","left","width","maxLeft","clampTopToViewport","top","height","maxTop","convertBlockType","store","blockId","type","props","runIds","registry","block","index","targetUsesTitleRunIds","sourceUsesTitleRunIds","sourceHasChildren","targetCanHoldChildren","ops","childId","i","moveBlock","changeBlockType","updateBlockProps","setBlockContentIds","keepChildren","useHorizontalAutoAdjustedLeft","menuRef","rawLeft","setLeft","useState","useLayoutEffect","rect","clamped","useAutoAdjustedCenteredLeft","rawCenterLeft","centerLeft","setCenterLeft","half","nextCenter","useAutoAdjustedRightLeft","rawRightEdgeLeft","rightLeft","setRightLeft","nextRightLeft"],"mappings":"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"}
@@ -0,0 +1,94 @@
1
+ import { useState as w, useRef as h, useEffect as k, useCallback as g } from "react";
2
+ import { s as v, a as W } from "./indexedDbPersistence-BKlGPFTP.js";
3
+ const b = 500;
4
+ function L({ store: r, docId: c, debounceMs: f = b, onError: s }) {
5
+ let e = null;
6
+ function t() {
7
+ return v(c, r.toJSON()).catch((i) => s == null ? void 0 : s(i));
8
+ }
9
+ function m() {
10
+ return e ? (clearTimeout(e), e = null, t()) : Promise.resolve();
11
+ }
12
+ const n = r.subscribeAll(() => {
13
+ e && clearTimeout(e), e = setTimeout(() => {
14
+ e = null, t();
15
+ }, f);
16
+ });
17
+ function l() {
18
+ e && clearTimeout(e), e = null, n();
19
+ }
20
+ return { stop: l, flush: m };
21
+ }
22
+ function D({
23
+ store: r,
24
+ docId: c,
25
+ debounceMs: f,
26
+ onError: s,
27
+ saveShortcut: e = !0,
28
+ onSave: t
29
+ }) {
30
+ const [m, n] = w(!1), l = h(() => Promise.resolve());
31
+ k(() => {
32
+ let p = !1;
33
+ n(!1), W(c).then((d) => {
34
+ if (!p && d) {
35
+ const a = r.store ?? r;
36
+ a.blocks = new Map((d.blocks ?? []).map((o) => [o.id, o])), a.runs = new Map((d.runs ?? []).map((o) => [o.id, o])), a.rootId = d.rootId ?? null, a.fieldTypes = new Map((d.fieldTypes ?? []).map((o) => [o.id, o])), a._fieldTypesSnapshot = null, a._orders = /* @__PURE__ */ new Map(), a._notify([...a.blocks.keys(), ...a.runs.keys()]);
37
+ }
38
+ }).catch((d) => s == null ? void 0 : s(d)).finally(() => {
39
+ p || n(!0);
40
+ });
41
+ const { stop: u, flush: y } = L({ store: r, docId: c, debounceMs: f, onError: s });
42
+ return l.current = y, () => {
43
+ p = !0, y(), u(), l.current = () => Promise.resolve();
44
+ };
45
+ }, [c]);
46
+ const i = g(async () => {
47
+ await l.current(), t == null || t();
48
+ }, [t]);
49
+ return k(() => {
50
+ if (!e) return;
51
+ const p = (u) => {
52
+ !(u.metaKey || u.ctrlKey) || u.shiftKey || u.altKey || u.key.toLowerCase() !== "s" || (u.preventDefault(), i());
53
+ };
54
+ return document.addEventListener("keydown", p), () => document.removeEventListener("keydown", p);
55
+ }, [e, i]), { isLoaded: m, save: i };
56
+ }
57
+ function A() {
58
+ const [r, c] = w(!1), [f, s] = w(null);
59
+ k(() => {
60
+ if (!navigator.serviceWorker) return;
61
+ let t = !1;
62
+ function m(n) {
63
+ if (!n) return;
64
+ const l = () => {
65
+ n.waiting && (s(n.waiting), c(!0));
66
+ };
67
+ l(), n.addEventListener("updatefound", () => {
68
+ const i = n.installing;
69
+ i && i.addEventListener("statechange", () => {
70
+ i.state === "installed" && navigator.serviceWorker.controller && l();
71
+ });
72
+ });
73
+ }
74
+ return navigator.serviceWorker.getRegistration().then((n) => {
75
+ t || m(n);
76
+ }), () => {
77
+ t = !0;
78
+ };
79
+ }, []);
80
+ const e = g(() => {
81
+ if (!f) return;
82
+ const t = () => window.location.reload();
83
+ navigator.serviceWorker.addEventListener("controllerchange", t, {
84
+ once: !0
85
+ }), f.postMessage({ type: "SKIP_WAITING" });
86
+ }, [f]);
87
+ return { updateAvailable: r, applyUpdate: e };
88
+ }
89
+ export {
90
+ A as a,
91
+ L as c,
92
+ D as u
93
+ };
94
+ //# sourceMappingURL=useServiceWorkerUpdate-BduabXv6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useServiceWorkerUpdate-BduabXv6.js","sources":["../../src/persistence/autoPersist.js","../../src/react/usePersistedDocument.js","../../src/react/useServiceWorkerUpdate.js"],"sourcesContent":["import { savePersistedDocument } from './indexedDbPersistence.js';\n\nconst DEFAULT_DEBOUNCE_MS = 500;\n\n/**\n * Wires a store (an `EditorStore`, or a `History` wrapping one — anything\n * with `subscribeAll`/`toJSON`) up to debounced auto-save into IndexedDB\n * under `docId`. Fires on every mutation, local or remote (subscribeAll\n * doesn't distinguish), so a document being live-collaborated on stays\n * persisted the same as one edited solo.\n *\n * Debounced rather than saving on every single keystroke: `toJSON()`\n * serializes the whole document, and typing already fires a store\n * mutation per keystroke — saving synchronously on each one would mean a\n * full-document IndexedDB write per character typed, which gets\n * expensive fast on a larger document.\n *\n * Returns a `stop()` function — call it when the store is no longer in\n * use (e.g. navigating away from this document) to unsubscribe and\n * cancel any pending debounced save. `stop()` does NOT flush a pending\n * save first; call `flush()` (also returned) beforehand if the most\n * recent edit must be persisted before tearing down.\n *\n * `flush()` returns a Promise that resolves once the write actually lands\n * (or resolves immediately if there was nothing pending — the document was\n * already fully saved) — used by `usePersistedDocument`'s Ctrl/Cmd+S\n * shortcut to know when it's safe to report \"saved\" back to the host app.\n */\nexport function createAutoPersistence({ store, docId, debounceMs = DEFAULT_DEBOUNCE_MS, onError }) {\n let timer = null;\n\n function saveNow() {\n return savePersistedDocument(docId, store.toJSON()).catch((err) => onError?.(err));\n }\n\n function flush() {\n if (timer) {\n clearTimeout(timer);\n timer = null;\n return saveNow();\n }\n return Promise.resolve();\n }\n\n const unsubscribe = store.subscribeAll(() => {\n if (timer) clearTimeout(timer);\n timer = setTimeout(() => {\n timer = null;\n saveNow();\n }, debounceMs);\n });\n\n function stop() {\n if (timer) clearTimeout(timer);\n timer = null;\n unsubscribe();\n }\n\n return { stop, flush };\n}\n","import { useCallback, useEffect, useRef, useState } from 'react';\nimport { loadPersistedDocument } from '../persistence/indexedDbPersistence.js';\nimport { createAutoPersistence } from '../persistence/autoPersist.js';\n\n/**\n * Ties a store to IndexedDB persistence for React usage: loads whatever\n * was last saved under `docId` (if anything) into the store on mount, and\n * auto-saves on every change from then on — the \"lightweight editor,\n * works fully offline, no server required\" building block.\n *\n * `store` must already exist (created via `useMemo`, same as every\n * example in this package) — this hook does not construct one. If a\n * persisted document is found, the store's content is REPLACED with it\n * (the same direct-swap pattern `CollabSession` uses to adopt a peer's\n * snapshot); if nothing was found, the store is left exactly as its\n * caller initialized it (e.g. with a starter document).\n *\n * Returns `{ isLoaded, save }` — `isLoaded` is `false` until the initial\n * IndexedDB read resolves, so callers can show a loading state instead of\n * briefly flashing default content that's about to be replaced. `save()`\n * forces an immediate write (skipping the rest of any debounce window) and\n * returns a Promise that resolves once it's actually persisted — call it\n * yourself for a manual \"Save\" button, in addition to whatever the\n * Ctrl/Cmd+S shortcut below already covers.\n *\n * `saveShortcut` (default `true`) wires one document-level Ctrl/Cmd+S\n * keydown listener that calls `save()` and blocks the browser's own \"Save\n * Page\" dialog — everything here already auto-saves on every edit\n * (debounced), so there's nothing Ctrl+S needs to do that hasn't already\n * happened within `debounceMs`, but the shortcut still matters: it's the\n * muscle-memory reflex every user already has, and without intercepting it\n * the browser's native save-page prompt pops up instead, which reads as\n * \"did that just NOT save?\" even though it did. `onSave` (optional) fires\n * every time `save()` resolves — e.g. to flash a brief \"Saved\" toast — for\n * both the shortcut and any manual `save()` call a host app makes itself.\n * Pass `{ saveShortcut: false }` to opt out and wire your own binding.\n *\n * Known edge case: an edit made in the narrow window between mount and\n * the initial load resolving can be discarded once the load applies\n * (whatever was actually persisted always wins) — acceptable for a\n * hydrate-on-mount pattern, and not reachable in practice outside\n * deliberately racing it.\n */\nexport function usePersistedDocument({\n store,\n docId,\n debounceMs,\n onError,\n saveShortcut = true,\n onSave,\n}) {\n const [isLoaded, setIsLoaded] = useState(false);\n // The current burst's own flush(), refreshed every time the docId effect\n // below re-runs — save() always goes through this ref rather than\n // closing over one particular createAutoPersistence call, since docId\n // (and so this whole setup) can change across the hook's lifetime.\n const flushRef = useRef(() => Promise.resolve());\n\n useEffect(() => {\n let cancelled = false;\n setIsLoaded(false);\n\n loadPersistedDocument(docId)\n .then((doc) => {\n if (cancelled) return;\n if (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._orders = new Map();\n rawStore._notify([...rawStore.blocks.keys(), ...rawStore.runs.keys()]);\n }\n })\n .catch((err) => onError?.(err))\n .finally(() => {\n if (!cancelled) setIsLoaded(true);\n });\n\n const { stop, flush } = createAutoPersistence({ store, docId, debounceMs, onError });\n flushRef.current = flush;\n\n return () => {\n cancelled = true;\n flush();\n stop();\n flushRef.current = () => Promise.resolve();\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [docId]);\n\n const save = useCallback(async () => {\n await flushRef.current();\n onSave?.();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [onSave]);\n\n useEffect(() => {\n if (!saveShortcut) return undefined;\n const handleKeyDown = (event) => {\n const mod = event.metaKey || event.ctrlKey;\n // Windows/Linux: Ctrl+S. Mac: Cmd+S (event.metaKey). Same physical\n // gesture, same browser-native \"Save Page\" dialog to intercept either\n // way — no separate handling needed per platform.\n if (!mod || event.shiftKey || event.altKey || event.key.toLowerCase() !== 's') return;\n event.preventDefault();\n save();\n };\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [saveShortcut, save]);\n\n return { isLoaded, save };\n}\n","import { useEffect, useState, useCallback } from 'react';\n\n/**\n * Watches for a new, already-installed-but-waiting service worker (the\n * standard signal that a fresh build is available) and exposes a way to\n * activate it. Generic — works with any service worker registration,\n * however it got there (vite-plugin-pwa, a hand-written registration,\n * Workbox, ...); this hook doesn't register one itself, only observes.\n *\n * This is what makes \"the app shell loads with no internet\" (an offline-\n * capable service worker, set up at the host app's build level — see\n * README's \"Offline app shell (PWA)\" section) safe to combine with\n * \"actually ship updates to users\": without surfacing that a new version\n * is waiting, a service-worker-cached app can silently keep serving a\n * stale build indefinitely once installed.\n *\n * Returns `{ updateAvailable, applyUpdate }` — `applyUpdate()` tells the\n * waiting worker to activate and reloads the page once it has. No-ops\n * harmlessly (updateAvailable stays false) in a browser/context with no\n * service worker support, or when no registration exists yet.\n */\nexport function useServiceWorkerUpdate() {\n const [updateAvailable, setUpdateAvailable] = useState(false);\n const [waitingWorker, setWaitingWorker] = useState(null);\n\n useEffect(() => {\n if (!navigator.serviceWorker) return undefined;\n let cancelled = false;\n\n function watchRegistration(registration) {\n if (!registration) return;\n const noteWaiting = () => {\n if (registration.waiting) {\n setWaitingWorker(registration.waiting);\n setUpdateAvailable(true);\n }\n };\n noteWaiting(); // a worker may already be waiting by the time this hook mounts\n registration.addEventListener('updatefound', () => {\n const installing = registration.installing;\n if (!installing) return;\n installing.addEventListener('statechange', () => {\n if (installing.state === 'installed' && navigator.serviceWorker.controller) noteWaiting();\n });\n });\n }\n\n navigator.serviceWorker.getRegistration().then((registration) => {\n if (!cancelled) watchRegistration(registration);\n });\n\n return () => {\n cancelled = true;\n };\n }, []);\n\n const applyUpdate = useCallback(() => {\n if (!waitingWorker) return;\n const reloadOnceControllerChanges = () => window.location.reload();\n navigator.serviceWorker.addEventListener('controllerchange', reloadOnceControllerChanges, {\n once: true,\n });\n waitingWorker.postMessage({ type: 'SKIP_WAITING' });\n }, [waitingWorker]);\n\n return { updateAvailable, applyUpdate };\n}\n"],"names":["DEFAULT_DEBOUNCE_MS","createAutoPersistence","store","docId","debounceMs","onError","timer","saveNow","savePersistedDocument","err","flush","unsubscribe","stop","usePersistedDocument","saveShortcut","onSave","isLoaded","setIsLoaded","useState","flushRef","useRef","useEffect","cancelled","loadPersistedDocument","doc","rawStore","b","r","f","save","useCallback","handleKeyDown","event","useServiceWorkerUpdate","updateAvailable","setUpdateAvailable","waitingWorker","setWaitingWorker","watchRegistration","registration","noteWaiting","installing","applyUpdate","reloadOnceControllerChanges"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ "use strict";const u=require("react"),w=require("./indexedDbPersistence-BWJ1h5Vp.cjs"),v=500;function g({store:a,docId:f,debounceMs:d=v,onError:s}){let e=null;function t(){return w.savePersistedDocument(f,a.toJSON()).catch(i=>s==null?void 0:s(i))}function k(){return e?(clearTimeout(e),e=null,t()):Promise.resolve()}const n=a.subscribeAll(()=>{e&&clearTimeout(e),e=setTimeout(()=>{e=null,t()},d)});function l(){e&&clearTimeout(e),e=null,n()}return{stop:l,flush:k}}function h({store:a,docId:f,debounceMs:d,onError:s,saveShortcut:e=!0,onSave:t}){const[k,n]=u.useState(!1),l=u.useRef(()=>Promise.resolve());u.useEffect(()=>{let m=!1;n(!1),w.loadPersistedDocument(f).then(p=>{if(!m&&p){const r=a.store??a;r.blocks=new Map((p.blocks??[]).map(o=>[o.id,o])),r.runs=new Map((p.runs??[]).map(o=>[o.id,o])),r.rootId=p.rootId??null,r.fieldTypes=new Map((p.fieldTypes??[]).map(o=>[o.id,o])),r._fieldTypesSnapshot=null,r._orders=new Map,r._notify([...r.blocks.keys(),...r.runs.keys()])}}).catch(p=>s==null?void 0:s(p)).finally(()=>{m||n(!0)});const{stop:c,flush:y}=g({store:a,docId:f,debounceMs:d,onError:s});return l.current=y,()=>{m=!0,y(),c(),l.current=()=>Promise.resolve()}},[f]);const i=u.useCallback(async()=>{await l.current(),t==null||t()},[t]);return u.useEffect(()=>{if(!e)return;const m=c=>{!(c.metaKey||c.ctrlKey)||c.shiftKey||c.altKey||c.key.toLowerCase()!=="s"||(c.preventDefault(),i())};return document.addEventListener("keydown",m),()=>document.removeEventListener("keydown",m)},[e,i]),{isLoaded:k,save:i}}function b(){const[a,f]=u.useState(!1),[d,s]=u.useState(null);u.useEffect(()=>{if(!navigator.serviceWorker)return;let t=!1;function k(n){if(!n)return;const l=()=>{n.waiting&&(s(n.waiting),f(!0))};l(),n.addEventListener("updatefound",()=>{const i=n.installing;i&&i.addEventListener("statechange",()=>{i.state==="installed"&&navigator.serviceWorker.controller&&l()})})}return navigator.serviceWorker.getRegistration().then(n=>{t||k(n)}),()=>{t=!0}},[]);const e=u.useCallback(()=>{if(!d)return;const t=()=>window.location.reload();navigator.serviceWorker.addEventListener("controllerchange",t,{once:!0}),d.postMessage({type:"SKIP_WAITING"})},[d]);return{updateAvailable:a,applyUpdate:e}}exports.createAutoPersistence=g;exports.usePersistedDocument=h;exports.useServiceWorkerUpdate=b;
2
+ //# sourceMappingURL=useServiceWorkerUpdate-DQboGesi.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useServiceWorkerUpdate-DQboGesi.cjs","sources":["../../src/persistence/autoPersist.js","../../src/react/usePersistedDocument.js","../../src/react/useServiceWorkerUpdate.js"],"sourcesContent":["import { savePersistedDocument } from './indexedDbPersistence.js';\n\nconst DEFAULT_DEBOUNCE_MS = 500;\n\n/**\n * Wires a store (an `EditorStore`, or a `History` wrapping one — anything\n * with `subscribeAll`/`toJSON`) up to debounced auto-save into IndexedDB\n * under `docId`. Fires on every mutation, local or remote (subscribeAll\n * doesn't distinguish), so a document being live-collaborated on stays\n * persisted the same as one edited solo.\n *\n * Debounced rather than saving on every single keystroke: `toJSON()`\n * serializes the whole document, and typing already fires a store\n * mutation per keystroke — saving synchronously on each one would mean a\n * full-document IndexedDB write per character typed, which gets\n * expensive fast on a larger document.\n *\n * Returns a `stop()` function — call it when the store is no longer in\n * use (e.g. navigating away from this document) to unsubscribe and\n * cancel any pending debounced save. `stop()` does NOT flush a pending\n * save first; call `flush()` (also returned) beforehand if the most\n * recent edit must be persisted before tearing down.\n *\n * `flush()` returns a Promise that resolves once the write actually lands\n * (or resolves immediately if there was nothing pending — the document was\n * already fully saved) — used by `usePersistedDocument`'s Ctrl/Cmd+S\n * shortcut to know when it's safe to report \"saved\" back to the host app.\n */\nexport function createAutoPersistence({ store, docId, debounceMs = DEFAULT_DEBOUNCE_MS, onError }) {\n let timer = null;\n\n function saveNow() {\n return savePersistedDocument(docId, store.toJSON()).catch((err) => onError?.(err));\n }\n\n function flush() {\n if (timer) {\n clearTimeout(timer);\n timer = null;\n return saveNow();\n }\n return Promise.resolve();\n }\n\n const unsubscribe = store.subscribeAll(() => {\n if (timer) clearTimeout(timer);\n timer = setTimeout(() => {\n timer = null;\n saveNow();\n }, debounceMs);\n });\n\n function stop() {\n if (timer) clearTimeout(timer);\n timer = null;\n unsubscribe();\n }\n\n return { stop, flush };\n}\n","import { useCallback, useEffect, useRef, useState } from 'react';\nimport { loadPersistedDocument } from '../persistence/indexedDbPersistence.js';\nimport { createAutoPersistence } from '../persistence/autoPersist.js';\n\n/**\n * Ties a store to IndexedDB persistence for React usage: loads whatever\n * was last saved under `docId` (if anything) into the store on mount, and\n * auto-saves on every change from then on — the \"lightweight editor,\n * works fully offline, no server required\" building block.\n *\n * `store` must already exist (created via `useMemo`, same as every\n * example in this package) — this hook does not construct one. If a\n * persisted document is found, the store's content is REPLACED with it\n * (the same direct-swap pattern `CollabSession` uses to adopt a peer's\n * snapshot); if nothing was found, the store is left exactly as its\n * caller initialized it (e.g. with a starter document).\n *\n * Returns `{ isLoaded, save }` — `isLoaded` is `false` until the initial\n * IndexedDB read resolves, so callers can show a loading state instead of\n * briefly flashing default content that's about to be replaced. `save()`\n * forces an immediate write (skipping the rest of any debounce window) and\n * returns a Promise that resolves once it's actually persisted — call it\n * yourself for a manual \"Save\" button, in addition to whatever the\n * Ctrl/Cmd+S shortcut below already covers.\n *\n * `saveShortcut` (default `true`) wires one document-level Ctrl/Cmd+S\n * keydown listener that calls `save()` and blocks the browser's own \"Save\n * Page\" dialog — everything here already auto-saves on every edit\n * (debounced), so there's nothing Ctrl+S needs to do that hasn't already\n * happened within `debounceMs`, but the shortcut still matters: it's the\n * muscle-memory reflex every user already has, and without intercepting it\n * the browser's native save-page prompt pops up instead, which reads as\n * \"did that just NOT save?\" even though it did. `onSave` (optional) fires\n * every time `save()` resolves — e.g. to flash a brief \"Saved\" toast — for\n * both the shortcut and any manual `save()` call a host app makes itself.\n * Pass `{ saveShortcut: false }` to opt out and wire your own binding.\n *\n * Known edge case: an edit made in the narrow window between mount and\n * the initial load resolving can be discarded once the load applies\n * (whatever was actually persisted always wins) — acceptable for a\n * hydrate-on-mount pattern, and not reachable in practice outside\n * deliberately racing it.\n */\nexport function usePersistedDocument({\n store,\n docId,\n debounceMs,\n onError,\n saveShortcut = true,\n onSave,\n}) {\n const [isLoaded, setIsLoaded] = useState(false);\n // The current burst's own flush(), refreshed every time the docId effect\n // below re-runs — save() always goes through this ref rather than\n // closing over one particular createAutoPersistence call, since docId\n // (and so this whole setup) can change across the hook's lifetime.\n const flushRef = useRef(() => Promise.resolve());\n\n useEffect(() => {\n let cancelled = false;\n setIsLoaded(false);\n\n loadPersistedDocument(docId)\n .then((doc) => {\n if (cancelled) return;\n if (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._orders = new Map();\n rawStore._notify([...rawStore.blocks.keys(), ...rawStore.runs.keys()]);\n }\n })\n .catch((err) => onError?.(err))\n .finally(() => {\n if (!cancelled) setIsLoaded(true);\n });\n\n const { stop, flush } = createAutoPersistence({ store, docId, debounceMs, onError });\n flushRef.current = flush;\n\n return () => {\n cancelled = true;\n flush();\n stop();\n flushRef.current = () => Promise.resolve();\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [docId]);\n\n const save = useCallback(async () => {\n await flushRef.current();\n onSave?.();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [onSave]);\n\n useEffect(() => {\n if (!saveShortcut) return undefined;\n const handleKeyDown = (event) => {\n const mod = event.metaKey || event.ctrlKey;\n // Windows/Linux: Ctrl+S. Mac: Cmd+S (event.metaKey). Same physical\n // gesture, same browser-native \"Save Page\" dialog to intercept either\n // way — no separate handling needed per platform.\n if (!mod || event.shiftKey || event.altKey || event.key.toLowerCase() !== 's') return;\n event.preventDefault();\n save();\n };\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [saveShortcut, save]);\n\n return { isLoaded, save };\n}\n","import { useEffect, useState, useCallback } from 'react';\n\n/**\n * Watches for a new, already-installed-but-waiting service worker (the\n * standard signal that a fresh build is available) and exposes a way to\n * activate it. Generic — works with any service worker registration,\n * however it got there (vite-plugin-pwa, a hand-written registration,\n * Workbox, ...); this hook doesn't register one itself, only observes.\n *\n * This is what makes \"the app shell loads with no internet\" (an offline-\n * capable service worker, set up at the host app's build level — see\n * README's \"Offline app shell (PWA)\" section) safe to combine with\n * \"actually ship updates to users\": without surfacing that a new version\n * is waiting, a service-worker-cached app can silently keep serving a\n * stale build indefinitely once installed.\n *\n * Returns `{ updateAvailable, applyUpdate }` — `applyUpdate()` tells the\n * waiting worker to activate and reloads the page once it has. No-ops\n * harmlessly (updateAvailable stays false) in a browser/context with no\n * service worker support, or when no registration exists yet.\n */\nexport function useServiceWorkerUpdate() {\n const [updateAvailable, setUpdateAvailable] = useState(false);\n const [waitingWorker, setWaitingWorker] = useState(null);\n\n useEffect(() => {\n if (!navigator.serviceWorker) return undefined;\n let cancelled = false;\n\n function watchRegistration(registration) {\n if (!registration) return;\n const noteWaiting = () => {\n if (registration.waiting) {\n setWaitingWorker(registration.waiting);\n setUpdateAvailable(true);\n }\n };\n noteWaiting(); // a worker may already be waiting by the time this hook mounts\n registration.addEventListener('updatefound', () => {\n const installing = registration.installing;\n if (!installing) return;\n installing.addEventListener('statechange', () => {\n if (installing.state === 'installed' && navigator.serviceWorker.controller) noteWaiting();\n });\n });\n }\n\n navigator.serviceWorker.getRegistration().then((registration) => {\n if (!cancelled) watchRegistration(registration);\n });\n\n return () => {\n cancelled = true;\n };\n }, []);\n\n const applyUpdate = useCallback(() => {\n if (!waitingWorker) return;\n const reloadOnceControllerChanges = () => window.location.reload();\n navigator.serviceWorker.addEventListener('controllerchange', reloadOnceControllerChanges, {\n once: true,\n });\n waitingWorker.postMessage({ type: 'SKIP_WAITING' });\n }, [waitingWorker]);\n\n return { updateAvailable, applyUpdate };\n}\n"],"names":["DEFAULT_DEBOUNCE_MS","createAutoPersistence","store","docId","debounceMs","onError","timer","saveNow","savePersistedDocument","err","flush","unsubscribe","stop","usePersistedDocument","saveShortcut","onSave","isLoaded","setIsLoaded","useState","flushRef","useRef","useEffect","cancelled","loadPersistedDocument","doc","rawStore","b","r","f","save","useCallback","handleKeyDown","event","useServiceWorkerUpdate","updateAvailable","setUpdateAvailable","waitingWorker","setWaitingWorker","watchRegistration","registration","noteWaiting","installing","applyUpdate","reloadOnceControllerChanges"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./shared/index-D9WEXpYM.cjs"),i=require("./shared/starter-kit-lPN-NpJ5.cjs");exports.defineBlock=e.defineBlock;exports.defineExtension=e.defineExtension;exports.defineInline=e.defineInline;exports.registerExtensions=e.registerExtensions;exports.starterKit=i.starterKit;
2
+ //# sourceMappingURL=starter-kit.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"starter-kit.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":""}
@@ -0,0 +1,9 @@
1
+ // noteloom/starter-kit — types re-exported from the main declaration file.
2
+ export {
3
+ starterKit,
4
+ defineBlock,
5
+ defineInline,
6
+ defineExtension,
7
+ registerExtensions,
8
+ Extension,
9
+ } from './index';
@@ -0,0 +1,10 @@
1
+ import { b as n, d as a, e as i, a as r } from "./shared/index-B9jyyL8u.js";
2
+ import { am as o } from "./shared/starter-kit-CY5wzYDf.js";
3
+ export {
4
+ n as defineBlock,
5
+ a as defineExtension,
6
+ i as defineInline,
7
+ r as registerExtensions,
8
+ o as starterKit
9
+ };
10
+ //# sourceMappingURL=starter-kit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"starter-kit.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}