docblocks-react-ui 0.4.3 → 0.4.5

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/CHANGELOG.md CHANGED
@@ -1,5 +1,68 @@
1
1
  # docblocks-react-ui
2
2
 
3
+ ## 0.4.5
4
+
5
+ ### Patch Changes
6
+
7
+ - 468f457: The callout's custom color picker commits the last scrubbed value when
8
+ the picker section closes without an explicit commit (the former close
9
+ discarded the draft); an untouched picker still commits nothing. The
10
+ swatch grid's custom swatch carries the current color when it matches
11
+ no preset (a small dot over the rainbow swatch).
12
+ - 55f51fc: A DOM selection outside a text-editable inside the canvas view maps to
13
+ none over the page's selection mapping. The engine's focus move over a
14
+ canvas item (the mousedown's default focuses the non-editable — the
15
+ firefox's behavior) fires a selectionchange whose blocks mapping would
16
+ flag the focused item: the stray selection tinted the picked shape
17
+ over the canvas' own selection state (the two-click pick's first
18
+ pick). The canvas manages its selection over the explicit press; the
19
+ page card's editable keeps the mapping.
20
+ - 745f1d7: The redo of a remounting step (a type change) restores the pre-change
21
+ selection seat: the redo's stack item carries the pre-undo snapshot,
22
+ which over a remount is the lost-caret residue (none/blocks) rather
23
+ than the pre-change seat. The redo falls back to the seat the matching
24
+ undo restored when the item's own snapshot is not a text selection and
25
+ the undo itself restored a text seat (the remount's case); a non-text
26
+ undo restoration (the canvas' blocks selection) is a legitimate
27
+ pre-undo selection and the redo restores its own snapshot. The view's
28
+ history reseat window suppresses the remount's transient selection loss
29
+ over the undo/redo, and the reseat re-runs when the restoration's
30
+ emission lands.
31
+ - 7bc9512: The shared popover's enter and exit animations now run: the classes were
32
+ keyed on `data-open` / `data-closed` attributes that Radix does not set
33
+ (it sets `data-state="open" | "closed"`), so the animations never applied
34
+ and the content teleported in. The closed content now gets
35
+ `pointer-events-none` for the exit animation, so a fading popover does
36
+ not swallow the press landing over its area.
37
+ - 00d4596: The canvas connector's line is clickable in webkit (Safari): the wide
38
+ invisible hit path renders in its own svg sized to the path's bounding
39
+ box over the 1x1 center-anchor draw layer. The webkit hit-tests only
40
+ inside an svg's own box (the overflow-visible content of the 1x1 layer
41
+ is draw-only there), so the line was not selectable by a click over
42
+ there. The chromium and the firefox reach the overflow, so the box
43
+ change alters no behavior over them.
44
+ - 4e1bee5: The cross-block selection stands over the engines that clamp the DOM
45
+ selection across contenteditable boundaries (webkit / Safari): the
46
+ selection writes (the keyboard extension, the drag's seat) use a
47
+ document-ordered Range instead of the Selection endpoint setters (the
48
+ clamping writes), and the cross-block reads (the arrow at the text's
49
+ edge, the range's extension) use the range's far endpoint when the
50
+ selection's focus reads clamped into the anchor's editable. The
51
+ selection's mapping reads the cross-editable range from its endpoints
52
+ instead of the anchor / focus nodes.
53
+ - Updated dependencies [745f1d7]
54
+ - docblocks-core@0.2.2
55
+
56
+ ## 0.4.4
57
+
58
+ ### Patch Changes
59
+
60
+ - ae88381: The motion drag's pointer-Y helper no longer tests the event against the
61
+ global `TouchEvent` (the `instanceof` stand): the global is absent on the
62
+ no-touch Safari (a desktop Safari on macOS), so every drag callback threw
63
+ a `ReferenceError` and the block drag-reorder failed there. The touch's
64
+ stand is duck-typed over the event's own `changedTouches` property.
65
+
3
66
  ## 0.4.3
4
67
 
5
68
  ### Patch Changes
@@ -850,6 +850,42 @@ function selectionOrphaned() {
850
850
  const node = selection.getRangeAt(0).startContainer;
851
851
  return node !== document && !document.contains(node);
852
852
  }
853
+ /**
854
+ * The selection's focus end as the editor reads it: the engine's
855
+ * `focusNode` / `focusOffset` — except when the range crosses a
856
+ * contenteditable boundary and the focus reads back inside the anchor's
857
+ * own editable (the webkit's clamped focus read-back: the engine clamps
858
+ * the far endpoint there, so the anchor/focus pair cannot express the
859
+ * cross range). The range's endpoints stand the derivation then: the
860
+ * engine's range is faithful across the boundary even when the
861
+ * anchor/focus read-back is not. The direction is the range's (the
862
+ * clamped engine's anchor reads as the range's start) — the focus end is
863
+ * the range's far endpoint over the anchor's, whatever its order.
864
+ */
865
+ function effectiveFocusEnd(domSelection) {
866
+ if (domSelection.rangeCount === 0) return null;
867
+ const { anchorNode, anchorOffset, focusNode, focusOffset } = domSelection;
868
+ if (focusNode === null || anchorNode === null) return null;
869
+ const range = domSelection.getRangeAt(0);
870
+ const anchorEditable = editableOfNode$1(anchorNode);
871
+ const startEditable = editableOfNode$1(range.startContainer);
872
+ const endEditable = range.startContainer === range.endContainer ? startEditable : editableOfNode$1(range.endContainer);
873
+ if (startEditable !== null && endEditable !== null && startEditable !== endEditable && anchorEditable !== null && anchorEditable.contains(focusNode)) return range.startContainer === anchorNode && range.startOffset === anchorOffset ? {
874
+ node: range.endContainer,
875
+ offset: range.endOffset
876
+ } : {
877
+ node: range.startContainer,
878
+ offset: range.startOffset
879
+ };
880
+ return {
881
+ node: focusNode,
882
+ offset: focusOffset
883
+ };
884
+ }
885
+ /** The contenteditable that owns a node (the node's element or its parent's), or null. */
886
+ function editableOfNode$1(node) {
887
+ return (node === null ? null : node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement)?.closest("[contenteditable=\"true\"]") ?? null;
888
+ }
853
889
  //#endregion
854
890
  //#region src/editing/block-commands/utils/focus.ts
855
891
  /** Run `fn` in the next animation frame (setTimeout where frames do not exist). */
@@ -957,9 +993,13 @@ function seatedIn(el) {
957
993
  * the user's and stops the watch — it is never clobbered. The offsets are
958
994
  * the gesture's pre-move ones: a structural gesture never edits the
959
995
  * block's text, so they remain valid. `scope` confines the lookup to one
960
- * editor root (a page can render the same doc in several).
996
+ * editor root (a page can render the same doc in several). The deadline
997
+ * stands the remount's commit window over the engine's scheduling (the
998
+ * firefox's engine commits the remount slower over the load) — the watch
999
+ * stops at the first seated attempt or the user's selection, so the
1000
+ * length is the residue's watch lifetime only.
961
1001
  */
962
- const RESTORE_DEADLINE_MS = 600;
1002
+ const RESTORE_DEADLINE_MS = 2e3;
963
1003
  function restoreSelectionIn(doc, blockId, from, to, scope = document, exclude = null) {
964
1004
  const selector = `[data-block-id="${CSS.escape(blockId)}"][data-slot="docblocks/block-content"]`;
965
1005
  const json = doc.toJSON();
@@ -1028,6 +1068,40 @@ function reseatHistorySelection(doc, view, scope = document) {
1028
1068
  restoreSelectionIn(doc, from.blockId, from.offset, to === null ? null : to.offset, scope);
1029
1069
  }
1030
1070
  /**
1071
+ * Stand a DOM selection over (base, focus) — across the contenteditable
1072
+ * boundary included: the selection is built as one document-ordered Range
1073
+ * and added whole. The engine's `setBaseAndExtent` / `extend` cannot put an
1074
+ * endpoint in ANOTHER editable — the webkit clamps the far endpoint to the
1075
+ * anchor's own editable (the call stands, the range does not cross); the
1076
+ * Range's endpoints are faithful across the boundary. The anchor/focus
1077
+ * READ-BACK may still be clamped in that engine — the mapping's stand
1078
+ * (`selection-mapping`'s cross-editable branch) reads the range there.
1079
+ * The direction's read-back stands the range's (the anchor reads as the
1080
+ * range's start): the core model is document-ordered, so the direction
1081
+ * carries no behavior.
1082
+ */
1083
+ function applyDomSelection(baseNode, baseOffset, focusNode, focusOffset) {
1084
+ const selection = window.getSelection();
1085
+ if (selection === null) return;
1086
+ const baseProbe = document.createRange();
1087
+ baseProbe.setStart(baseNode, baseOffset);
1088
+ baseProbe.collapse(true);
1089
+ const focusProbe = document.createRange();
1090
+ focusProbe.setStart(focusNode, focusOffset);
1091
+ focusProbe.collapse(true);
1092
+ const baseFirst = baseProbe.compareBoundaryPoints(Range.END_TO_START, focusProbe) <= 0;
1093
+ const range = document.createRange();
1094
+ if (baseFirst) {
1095
+ range.setStart(baseNode, baseOffset);
1096
+ range.setEnd(focusNode, focusOffset);
1097
+ } else {
1098
+ range.setStart(focusNode, focusOffset);
1099
+ range.setEnd(baseNode, baseOffset);
1100
+ }
1101
+ selection.removeAllRanges();
1102
+ selection.addRange(range);
1103
+ }
1104
+ /**
1031
1105
  * Re-base the browser's selection anchor at (anchorNode, anchorOffset) and
1032
1106
  * put the focus end at the flat offset in the target block (DOM-only: the
1033
1107
  * doc is untouched). The browser's shift+arrow cannot cross a contenteditable
@@ -1039,12 +1113,10 @@ function reseatHistorySelection(doc, view, scope = document) {
1039
1113
  * selection, not the focus. A no-op when the target element is not rendered.
1040
1114
  */
1041
1115
  function extendSelectionTo(anchorNode, anchorOffset, blockId, offset) {
1042
- const domSelection = window.getSelection();
1043
- if (domSelection === null) return;
1044
1116
  const el = editorRootOf(anchorNode).querySelector(`[data-block-id="${CSS.escape(blockId)}"][data-slot="docblocks/block-content"]`);
1045
1117
  if (el === null) return;
1046
1118
  const target = locatePosition(el, offset);
1047
- domSelection.setBaseAndExtent(anchorNode, anchorOffset, target.node, target.offset);
1119
+ applyDomSelection(anchorNode, anchorOffset, target.node, target.offset);
1048
1120
  }
1049
1121
  //#endregion
1050
1122
  //#region src/editing/slash/context.ts
@@ -5041,12 +5113,14 @@ function DocblocksI18nProvider({ children }) {
5041
5113
  /**
5042
5114
  * The custom color's picker body (the callout menu's custom swatch opens it
5043
5115
  * as an inline section): the native `input type="color"` (the live scrub —
5044
- * no doc write) and the hex field (the strict `#rrggbb`). The doc write
5045
- * stands one `onCommit` per pick (one undo step, one wire update — the
5046
- * swatch pick's parity): the native dialog's commit (`change`), the field's
5047
- * valid Enter / blur. An invalid field value resets to the draft on blur
5048
- * (the picker stands the last valid stand). The close without a commit
5049
- * (the cancel) discards the draft — the menu's unmount stands it.
5116
+ * no doc write over the scrub) and the hex field (the strict `#rrggbb`).
5117
+ * The doc write stands one `onCommit` per pick (one undo step, one wire
5118
+ * update — the swatch pick's parity): the native dialog's commit (`change`),
5119
+ * the field's valid Enter / blur. An invalid field value resets to the
5120
+ * draft on blur (the picker stands the last valid stand). The close without
5121
+ * an explicit commit (the Esc / the toggle / the menu's dismiss) commits the
5122
+ * last scrubbed value (the picker's unmount commits it); an untouched
5123
+ * picker commits nothing.
5050
5124
  */
5051
5125
  /** The absent value's stand: the native input's neutral default. */
5052
5126
  const DEFAULT_HEX = "#808080";
@@ -5062,11 +5136,24 @@ function ColorPickerInner({ value, onCommit, onClose }) {
5062
5136
  onCommitRef.current = onCommit;
5063
5137
  const onCloseRef = useRef(onClose);
5064
5138
  onCloseRef.current = onClose;
5139
+ const draftRef = useRef(draft);
5140
+ draftRef.current = draft;
5141
+ const touchedRef = useRef(false);
5142
+ const committedRef = useRef(false);
5143
+ useEffect(() => {
5144
+ return () => {
5145
+ if (!touchedRef.current || committedRef.current) return;
5146
+ const committed = normalizeHex$1(draftRef.current);
5147
+ const current = valueRef.current === null ? null : normalizeHex$1(valueRef.current);
5148
+ if (committed !== null && committed !== current) onCommitRef.current(committed);
5149
+ };
5150
+ }, []);
5065
5151
  const nativeRef = useRef(null);
5066
5152
  useEffect(() => {
5067
5153
  const el = nativeRef.current;
5068
5154
  if (el === null) return;
5069
5155
  const onChange = (event) => {
5156
+ committedRef.current = true;
5070
5157
  const committed = normalizeHex$1(event.target.value);
5071
5158
  const current = valueRef.current === null ? null : normalizeHex$1(valueRef.current);
5072
5159
  if (committed !== null && committed !== current) onCommitRef.current(committed);
@@ -5079,6 +5166,7 @@ function ColorPickerInner({ value, onCommit, onClose }) {
5079
5166
  const commitField = (raw) => {
5080
5167
  const match = raw.trim().match(STRICT_HEX_RE);
5081
5168
  if (match === null) return false;
5169
+ committedRef.current = true;
5082
5170
  const hex = `#${match[1].toLowerCase()}`;
5083
5171
  setDraft(hex);
5084
5172
  setField(hex);
@@ -5092,7 +5180,10 @@ function ColorPickerInner({ value, onCommit, onClose }) {
5092
5180
  ref: nativeRef,
5093
5181
  type: "color",
5094
5182
  value: draft,
5095
- onInput: (event) => setDraft(event.currentTarget.value),
5183
+ onInput: (event) => {
5184
+ touchedRef.current = true;
5185
+ setDraft(event.currentTarget.value);
5186
+ },
5096
5187
  "aria-label": t("colorPicker.aria"),
5097
5188
  className: "h-8 w-8 cursor-pointer rounded-xs border border-(--border) bg-transparent p-0.5"
5098
5189
  }), /* @__PURE__ */ jsx(Input, {
@@ -5135,7 +5226,10 @@ function ColorPicker(props) {
5135
5226
  * Two opt-in extras (off by default): the transparent ("no color") swatch
5136
5227
  * (a theme-background circle crossed by a thin `--destructive` line —
5137
5228
  * reports `onSelectNone`) and the custom swatch (a rainbow circle that
5138
- * reports `onCustom`; the full picker it opens is built on first use).
5229
+ * reports `onCustom`; the full picker it opens is built on first use). A
5230
+ * current value that matches no entry (a non-preset custom color) shows a
5231
+ * small dot of its own over the custom swatch — the row's highlight shows
5232
+ * a preset's match only, so the dot is the custom value's marker.
5139
5233
  */
5140
5234
  /** The palette's i18n scope: the package's instance stands the provider's
5141
5235
  * seat over the palette (the primitive stands also outside the editor's
@@ -5161,6 +5255,8 @@ function ColorSwatchesInner({ colors, current, onSelect, label, allowNone = fals
5161
5255
  if (currentHex === null) return false;
5162
5256
  return (normalizeHex$1(entry) ?? resolved[index] ?? null) === currentHex;
5163
5257
  };
5258
+ const currentHex = current === null || current === void 0 ? null : normalizeHex$1(current);
5259
+ const customCarriesCurrent = allowCustom && currentHex !== null && !colors.some((entry, index) => (normalizeHex$1(entry) ?? resolved[index] ?? null) === currentHex);
5164
5260
  const selectSwatch = (entry) => (event) => {
5165
5261
  const hex = resolveColorToHex(entry, event.currentTarget);
5166
5262
  if (hex !== null) onSelect(hex);
@@ -5214,9 +5310,15 @@ function ColorSwatchesInner({ colors, current, onSelect, label, allowNone = fals
5214
5310
  "data-color": "custom",
5215
5311
  "aria-label": t("common:color.custom"),
5216
5312
  title: t("common:color.custom"),
5217
- className: "size-5 rounded-full border border-(--border) transition-none",
5313
+ className: "relative size-5 rounded-full border border-(--border) transition-none",
5218
5314
  style: { background: "conic-gradient(red, orange, yellow, green, cyan, blue, magenta, red)" },
5219
- onClick: onCustom
5315
+ onClick: onCustom,
5316
+ children: customCarriesCurrent && currentHex !== null && /* @__PURE__ */ jsx("span", {
5317
+ "aria-hidden": true,
5318
+ "data-slot": "docblocks/palette-custom-current",
5319
+ className: "\n absolute top-1/2 left-1/2 size-3 -translate-x-1/2 -translate-y-1/2 rounded-full border border-(--border)\n ",
5320
+ style: { background: currentHex }
5321
+ })
5220
5322
  })
5221
5323
  ]
5222
5324
  });
@@ -5244,12 +5346,13 @@ function PopoverContent({ className, align = "center", sideOffset = 4, ...props
5244
5346
  pointer-events-auto z-modal flex w-72 origin-(--radix-popover-content-transform-origin) flex-col gap-2.5
5245
5347
  rounded-lg bg-popover p-2.5 text-sm text-popover-foreground shadow-md ring-1 ring-foreground/10
5246
5348
  outline-hidden duration-100
5247
- data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95
5248
- data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95
5249
5349
  data-[side=bottom]:slide-in-from-top-2
5250
5350
  data-[side=left]:slide-in-from-right-2
5251
5351
  data-[side=right]:slide-in-from-left-2
5252
5352
  data-[side=top]:slide-in-from-bottom-2
5353
+ data-[state=closed]:pointer-events-none data-[state=closed]:animate-out data-[state=closed]:fade-out-0
5354
+ data-[state=closed]:zoom-out-95
5355
+ data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95
5253
5356
  `, className),
5254
5357
  ...props
5255
5358
  }) });
@@ -11993,7 +12096,10 @@ function EditorProviderStand({ doc, provider, blockRenderers, blobResolver, blob
11993
12096
  const [store] = useState(() => createEditorStore(doc, rootId));
11994
12097
  const docRef = useRef(doc);
11995
12098
  const rootIdRef = useRef(rootId);
11996
- const selectionRef = useRef({ view: null });
12099
+ const selectionRef = useRef({
12100
+ view: null,
12101
+ reseatUntil: { current: 0 }
12102
+ });
11997
12103
  const parentContext = useContext(EditorContext);
11998
12104
  const effectiveAccessLevel = accessLevel ?? parentContext?.accessLevel ?? "editor";
11999
12105
  const effectiveMode = effectiveAccessLevel === "viewer" ? "published" : mode ?? parentContext?.mode ?? "edit";
@@ -16029,8 +16135,12 @@ function extendRangeFocusEnd(doc, selection, key) {
16029
16135
  if (selection.kind !== "text" || selection.to === null) return false;
16030
16136
  const domSelection = window.getSelection();
16031
16137
  if (domSelection === null || domSelection.rangeCount === 0) return false;
16032
- const { anchorNode, anchorOffset, focusNode, focusOffset } = domSelection;
16033
- if (anchorNode === null || focusNode === null) return false;
16138
+ const { anchorNode, anchorOffset } = domSelection;
16139
+ if (anchorNode === null) return false;
16140
+ const effective = effectiveFocusEnd(domSelection);
16141
+ if (effective === null) return false;
16142
+ const focusNode = effective.node;
16143
+ const focusOffset = effective.offset;
16034
16144
  const scope = editorRootOf(focusNode);
16035
16145
  const focusBlock = textBlockOfNode(focusNode);
16036
16146
  if (focusBlock === null) return false;
@@ -16079,7 +16189,7 @@ function extendRangeFocusEnd(doc, selection, key) {
16079
16189
  const target = scope.querySelector(`[data-block-id="${CSS.escape(next.blockId)}"][data-slot="docblocks/block-content"]`);
16080
16190
  if (target === null) return false;
16081
16191
  const position = locatePosition(target, next.offset);
16082
- domSelection.setBaseAndExtent(anchorNode, anchorOffset, position.node, position.offset);
16192
+ applyDomSelection(anchorNode, anchorOffset, position.node, position.offset);
16083
16193
  return true;
16084
16194
  }
16085
16195
  //#endregion
@@ -16123,6 +16233,36 @@ function mapDomSelection(root, domSelection, doc) {
16123
16233
  const range = domSelection.getRangeAt(0);
16124
16234
  const anchorBlock = textBlockOf(anchorNode, root);
16125
16235
  const focusBlock = textBlockOf(focusNode, root);
16236
+ if ((anchorNode instanceof Element ? anchorNode : anchorNode.parentElement ?? null)?.closest("[data-slot=\"docblocks/canvas-view\"]") !== null && anchorBlock === null && editableOfNode(anchorNode) === null) return { kind: "none" };
16237
+ const startEditable = editableOfNode(range.startContainer);
16238
+ const endEditable = range.startContainer === range.endContainer ? startEditable : editableOfNode(range.endContainer);
16239
+ if (startEditable !== null && endEditable !== null && startEditable !== endEditable) {
16240
+ const first = {
16241
+ node: range.startContainer,
16242
+ offset: range.startOffset,
16243
+ textBlock: textBlockOf(range.startContainer, root)
16244
+ };
16245
+ const last = {
16246
+ node: range.endContainer,
16247
+ offset: range.endOffset,
16248
+ textBlock: textBlockOf(range.endContainer, root)
16249
+ };
16250
+ if (first.textBlock === null && last.textBlock === null && !rangeTouchesTextBlock(root, range)) return mapBlocksSelection(root, domSelection, anchorBlock);
16251
+ const from = resolveEndpoint(doc, root, first, "first");
16252
+ const to = resolveEndpoint(doc, root, last, "last");
16253
+ if (from === null || to === null) return mapBlocksSelection(root, domSelection, anchorBlock);
16254
+ if (from.blockId === to.blockId && from.offset === to.offset) return {
16255
+ kind: "text",
16256
+ from,
16257
+ to: null
16258
+ };
16259
+ return {
16260
+ kind: "text",
16261
+ from,
16262
+ to,
16263
+ ...!(range.startContainer === anchorNode && range.startOffset === anchorOffset) ? { reverse: true } : {}
16264
+ };
16265
+ }
16126
16266
  if (anchorBlock !== null && focusBlock === anchorBlock) return mapTextSelection(anchorBlock, anchorNode, anchorOffset, focusNode, focusOffset);
16127
16267
  const anchorIsFirst = range.startContainer === anchorNode && range.startOffset === anchorOffset;
16128
16268
  const first = {
@@ -16340,11 +16480,13 @@ function syncDomSelection(root, doc, view) {
16340
16480
  * not — the mapping must not clobber a `blocks` view there.
16341
16481
  */
16342
16482
  function domSelectionInEditable(domSelection) {
16343
- if (domSelection === null || domSelection.rangeCount === 0) return false;
16344
- const elementOf = (node) => node instanceof Element ? node : node === null ? null : node.parentElement;
16345
- const anchor = elementOf(domSelection.anchorNode);
16346
- const focus = elementOf(domSelection.focusNode);
16347
- return anchor?.closest("[contenteditable=\"true\"]") !== null && focus?.closest("[contenteditable=\"true\"]") !== null;
16483
+ const anchor = editableOfNode(domSelection?.anchorNode ?? null);
16484
+ const focus = editableOfNode(domSelection?.focusNode ?? null);
16485
+ return anchor !== null && focus !== null;
16486
+ }
16487
+ /** The contenteditable that owns a node (the node's element or its parent's), or null. */
16488
+ function editableOfNode(node) {
16489
+ return (node === null ? null : node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement)?.closest("[contenteditable=\"true\"]") ?? null;
16348
16490
  }
16349
16491
  //#endregion
16350
16492
  //#region src/editing/cross-range-keys.ts
@@ -16376,6 +16518,13 @@ function handleCrossRangeKey(doc, view, selection, root, event) {
16376
16518
  if (moved) syncDomSelection(root, doc, view);
16377
16519
  return true;
16378
16520
  }
16521
+ if (event.key === "ArrowLeft" || event.key === "ArrowRight") {
16522
+ const domSelection = window.getSelection();
16523
+ if (domSelection === null || domSelection.rangeCount === 0 || domSelection.focusNode === null) return false;
16524
+ event.preventDefault();
16525
+ domSelection.collapse(domSelection.focusNode, domSelection.focusOffset);
16526
+ return true;
16527
+ }
16379
16528
  if (event.key === "Delete" || event.key === "Backspace") {
16380
16529
  event.preventDefault();
16381
16530
  const result = doc.deleteTextRange(selection.from, selection.to);
@@ -17002,7 +17151,9 @@ function useBlockInput({ id, blockType, context, innerRef, wrapperRef, declareLo
17002
17151
  const domSelection = window.getSelection();
17003
17152
  if (selection.kind !== "blocks" && mappedRoot instanceof HTMLElement && domSelection !== null) {
17004
17153
  const fresh = mapDomSelection(mappedRoot, domSelection, doc);
17005
- if (!selectionsEqual(fresh, selection)) view.set(fresh);
17154
+ if (!selectionsEqual(fresh, selection)) {
17155
+ if (!(fresh.kind !== "text" && Date.now() < selectionRef.reseatUntil.current)) view.set(fresh);
17156
+ }
17006
17157
  selection = view.get();
17007
17158
  root = mappedRoot;
17008
17159
  }
@@ -17152,7 +17303,17 @@ function useBlockInput({ id, blockType, context, innerRef, wrapperRef, declareLo
17152
17303
  const domSelection = window.getSelection();
17153
17304
  if (domSelection === null || domSelection.rangeCount === 0 || !domSelection.isCollapsed) return;
17154
17305
  if (domSelection.anchorNode === null || !inner.contains(domSelection.anchorNode)) return;
17155
- if (caretOffsetIn(inner, domSelection.anchorNode, domSelection.anchorOffset) !== 0) return;
17306
+ const offset = caretOffsetIn(inner, domSelection.anchorNode, domSelection.anchorOffset);
17307
+ if (offset !== 0) {
17308
+ const text = doc.getText(id);
17309
+ if (offset === text.length && text.endsWith("\n")) {
17310
+ event.preventDefault();
17311
+ doc.deleteText(id, offset - 1, offset);
17312
+ focusCaretIn(id, offset - 1, editorRootOf(inner));
17313
+ return;
17314
+ }
17315
+ return;
17316
+ }
17156
17317
  if (inCell) return;
17157
17318
  if ((blockType === "quote" || blockType === "callout" || blockType === "code") && doc.getTextLength(id) > 0) return;
17158
17319
  const merged = mergeWithPrevious(doc, id, context.parentId);
@@ -17388,8 +17549,12 @@ function useBlockKeyboard({ id, blockType, context, innerRef }) {
17388
17549
  if (selectionRef.view?.get().kind === "blocks") return;
17389
17550
  const domSelection = window.getSelection();
17390
17551
  if (domSelection === null || domSelection.rangeCount === 0) return;
17391
- const { anchorNode, anchorOffset, focusNode, focusOffset } = domSelection;
17392
- if (anchorNode === null || focusNode === null) return;
17552
+ const { anchorNode, anchorOffset } = domSelection;
17553
+ if (anchorNode === null) return;
17554
+ const effective = effectiveFocusEnd(domSelection);
17555
+ if (effective === null) return;
17556
+ const focusNode = effective.node;
17557
+ const focusOffset = effective.offset;
17393
17558
  const focusBlock = textBlockOfNode(focusNode);
17394
17559
  if (focusBlock === null) return;
17395
17560
  const focusBlockId = focusBlock.dataset.blockId;
@@ -17580,11 +17745,14 @@ function useTextInner({ id, block, blockType, context, wrapperRef }) {
17580
17745
  if (!startInside && !endInside) return;
17581
17746
  const from = caretOffsetIn(el, range.startContainer, range.startOffset);
17582
17747
  const to = caretOffsetIn(el, range.endContainer, range.endOffset);
17748
+ const farContainer = startInside ? range.endContainer : range.startContainer;
17749
+ const farBlockId = (farContainer.nodeType === Node.TEXT_NODE ? farContainer.parentElement : farContainer)?.closest("[data-block-id]")?.getAttribute("data-block-id") ?? null;
17583
17750
  const crossCapture = () => ({
17584
17751
  startIsLocal: startInside,
17585
17752
  localOffset: startInside ? from : to,
17586
- farNode: startInside ? range.endContainer : range.startContainer,
17587
- farOffset: startInside ? range.endOffset : range.startOffset
17753
+ farNode: farContainer,
17754
+ farOffset: startInside ? range.endOffset : range.startOffset,
17755
+ farBlockId
17588
17756
  });
17589
17757
  if (nextText === prevText) {
17590
17758
  if (startInside && endInside) {
@@ -17638,16 +17806,26 @@ function useTextInner({ id, block, blockType, context, wrapperRef }) {
17638
17806
  renderRunsInto(pending.runs, el);
17639
17807
  appliedRef.current = block;
17640
17808
  if ("cross" in pending) {
17809
+ const cross = pending.cross;
17810
+ let farNode = cross.farNode;
17811
+ let farOffset = cross.farOffset;
17812
+ if (!document.contains(farNode) && cross.farBlockId !== null) {
17813
+ const farInner = (el.closest("[data-slot=\"docblocks/editor\"]") ?? document).querySelector(`[data-block-id="${CSS.escape(cross.farBlockId)}"][data-slot="docblocks/block-content"]`);
17814
+ if (farInner !== null) {
17815
+ const remap = locatePosition(farInner, cross.farOffset);
17816
+ farNode = remap.node;
17817
+ farOffset = remap.offset;
17818
+ }
17819
+ }
17641
17820
  const selection = window.getSelection();
17642
- if (selection !== null && selection.rangeCount > 0 && (selection.containsNode(pending.cross.farNode, true) || selectionOrphaned()) && document.contains(pending.cross.farNode)) {
17643
- const local = locatePosition(el, pending.cross.localOffset);
17644
- const cross = pending.cross;
17821
+ if (selection !== null && selection.rangeCount > 0 && (selection.containsNode(farNode, true) || selectionOrphaned()) && document.contains(farNode)) {
17822
+ const local = locatePosition(el, cross.localOffset);
17645
17823
  const range = document.createRange();
17646
17824
  if (cross.startIsLocal) {
17647
17825
  range.setStart(local.node, local.offset);
17648
- range.setEnd(cross.farNode, cross.farOffset);
17826
+ range.setEnd(farNode, farOffset);
17649
17827
  } else {
17650
- range.setStart(cross.farNode, cross.farOffset);
17828
+ range.setStart(farNode, farOffset);
17651
17829
  range.setEnd(local.node, local.offset);
17652
17830
  }
17653
17831
  selection.removeAllRanges();
@@ -18336,8 +18514,10 @@ function calloutIconName(icon, variant) {
18336
18514
  * focus stands the gesture). The pick's stand closes the menu over the
18337
18515
  * color and the icon's apply (the type preset stays open). The custom
18338
18516
  * swatch's press toggles the picker's inline section over the menu's
18339
- * background row; the close without a commit (the cancel) discards the
18340
- * draft — the menu's unmount stands it.
18517
+ * background row; a close without an explicit commit (the Esc / the
18518
+ * dismiss) applies the last scrubbed value (the picker's unmount commits
18519
+ * it; the grid's custom swatch carries a non-preset current value as its
18520
+ * own dot).
18341
18521
  */
18342
18522
  function CalloutBlockMenu({ id, block }) {
18343
18523
  const { t } = useTranslation("editor");
@@ -19378,7 +19558,11 @@ const CanvasSessionContext = createContext({
19378
19558
  * `interactive` toggles the hit path: the canvas view is interactive
19379
19559
  * (the line is selectable, the endpoints draggable), the page view's
19380
19560
  * embedded surface stands it inert (no selection / dragging there — the
19381
- * bands must not intercept the content's clicks).
19561
+ * bands must not intercept the content's clicks). The hit path's `d`
19562
+ * is returned alongside the content: the hit path renders in its own
19563
+ * bbox-sized svg — the webkit does not hit-test the overflow-visible
19564
+ * content over the 1x1 svg's box, so the line is not clickable from
19565
+ * there without the box.
19382
19566
  */
19383
19567
  function connectorLineOf(surfaceId, connectorId, block, childIds, blocks, selected, interactive, session) {
19384
19568
  const attrs = block.attrs;
@@ -19530,8 +19714,8 @@ function connectorLineOf(surfaceId, connectorId, block, childIds, blocks, select
19530
19714
  })]
19531
19715
  }) : null;
19532
19716
  const pathStyle = { stroke };
19533
- return /* @__PURE__ */ jsxs(Fragment$1, { children: [
19534
- /* @__PURE__ */ jsx("path", {
19717
+ return {
19718
+ content: /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("path", {
19535
19719
  "data-connector-id": connectorId,
19536
19720
  "data-selected": selected || void 0,
19537
19721
  d: path,
@@ -19542,18 +19726,36 @@ function connectorLineOf(surfaceId, connectorId, block, childIds, blocks, select
19542
19726
  strokeDasharray: dash,
19543
19727
  strokeLinecap: attrs.strokeStyle === "dot" ? "round" : void 0,
19544
19728
  style: pathStyle
19545
- }),
19546
- interactive && /* @__PURE__ */ jsx("path", {
19547
- "data-connector-hit": connectorId,
19548
- d: path,
19549
- stroke: "transparent",
19550
- strokeWidth: 12,
19551
- fill: "none",
19552
- pointerEvents: "stroke",
19553
- className: "cursor-pointer"
19554
- }),
19555
- snapBadge
19556
- ] });
19729
+ }), snapBadge] }),
19730
+ hitD: interactive ? path : null
19731
+ };
19732
+ }
19733
+ /** The path's points' bounding box (the surface's center-anchor space):
19734
+ * the `d`'s M/L's coordinates (the plain numbers' parse — the builder's
19735
+ * template's format). The hit path's svg box must contain the stroke:
19736
+ * the webkit hit-tests only inside the svg's own box, so the hit path
19737
+ * needs a bbox-sized svg over the 1x1 draw layer (draw-only there). */
19738
+ function hitBoxOf(d) {
19739
+ const numbers = d.replace(/[A-Za-z]/g, " ").split(/\s+/).map(Number.parseFloat).filter((value) => Number.isFinite(value));
19740
+ if (numbers.length < 4) return null;
19741
+ let minX = Infinity;
19742
+ let minY = Infinity;
19743
+ let maxX = -Infinity;
19744
+ let maxY = -Infinity;
19745
+ for (let i = 0; i < numbers.length; i += 2) {
19746
+ const x = numbers[i] ?? 0;
19747
+ const y = numbers[i + 1] ?? 0;
19748
+ minX = Math.min(minX, x);
19749
+ minY = Math.min(minY, y);
19750
+ maxX = Math.max(maxX, x);
19751
+ maxY = Math.max(maxY, y);
19752
+ }
19753
+ return {
19754
+ x: minX,
19755
+ y: minY,
19756
+ w: maxX - minX,
19757
+ h: maxY - minY
19758
+ };
19557
19759
  }
19558
19760
  /**
19559
19761
  * One connector's line, the surface's Z-ORDER stand (the explicit zIndex):
@@ -19565,9 +19767,12 @@ function connectorLineOf(surfaceId, connectorId, block, childIds, blocks, select
19565
19767
  * CanvasItem's wrapper stands at the surface's origin), the shared
19566
19768
  * arrowhead defs (the surface's hidden defs svg) stand the markers.
19567
19769
  *
19568
- * The SVG itself is pointer-events none; the per-line hit path (the wide
19569
- * transparent stroke) is pointer-events stroke — the line is
19570
- * click-selectable, the empty canvas around it is not.
19770
+ * The SVG is pointer-events none: the visible path is draw-only. The
19771
+ * per-line hit path (the wide transparent stroke, pointer-events stroke)
19772
+ * renders in its own bbox-sized svg — the webkit hit-tests only inside
19773
+ * the svg's own box, so the 1x1 overflow-visible layer is not
19774
+ * click-selectable there; the chromium and the firefox reach the
19775
+ * overflow, so the box change alters no behavior there.
19571
19776
  */
19572
19777
  function ConnectorLine({ id, interactive = true }) {
19573
19778
  const { store } = useEditorContext();
@@ -19588,7 +19793,8 @@ function ConnectorLine({ id, interactive = true }) {
19588
19793
  store
19589
19794
  ]);
19590
19795
  if (content === null) return null;
19591
- return /* @__PURE__ */ jsx("svg", {
19796
+ const hitBox = content.hitD !== null ? hitBoxOf(content.hitD) : null;
19797
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("svg", {
19592
19798
  "data-slot": "docblocks/connector-layer",
19593
19799
  "data-block-id": id,
19594
19800
  style: {
@@ -19600,8 +19806,32 @@ function ConnectorLine({ id, interactive = true }) {
19600
19806
  overflow: "visible",
19601
19807
  pointerEvents: "none"
19602
19808
  },
19603
- children: content
19604
- });
19809
+ children: content.content
19810
+ }), content.hitD !== null && hitBox !== null && /* @__PURE__ */ jsx("svg", {
19811
+ "data-slot": "docblocks/connector-hit-layer",
19812
+ "data-block-id": id,
19813
+ style: {
19814
+ position: "absolute",
19815
+ left: `calc(50% + ${hitBox.x - 16}px)`,
19816
+ top: `calc(50% + ${hitBox.y - 16}px)`,
19817
+ width: hitBox.w + 32,
19818
+ height: hitBox.h + 32,
19819
+ overflow: "visible",
19820
+ pointerEvents: "none"
19821
+ },
19822
+ children: /* @__PURE__ */ jsx("g", {
19823
+ transform: `translate(${16 - hitBox.x}, ${16 - hitBox.y})`,
19824
+ children: /* @__PURE__ */ jsx("path", {
19825
+ "data-connector-hit": id,
19826
+ d: content.hitD,
19827
+ stroke: "transparent",
19828
+ strokeWidth: 12,
19829
+ fill: "none",
19830
+ pointerEvents: "stroke",
19831
+ className: "cursor-pointer"
19832
+ })
19833
+ })
19834
+ })] });
19605
19835
  }
19606
19836
  //#endregion
19607
19837
  //#region src/blocks/PlaceholderBlock.tsx
@@ -28034,7 +28264,7 @@ function crossRangeClipboardContent(doc, selection) {
28034
28264
  function seatCrossSelection(anchor, position) {
28035
28265
  const base = (anchor.node.compareDocumentPosition(position.node) & Node.DOCUMENT_POSITION_FOLLOWING) !== 0 || anchor.offset !== 0 ? anchor : position;
28036
28266
  const focus = base === anchor ? position : anchor;
28037
- window.getSelection()?.setBaseAndExtent(base.node, base.offset, focus.node, focus.offset);
28267
+ applyDomSelection(base.node, base.offset, focus.node, focus.offset);
28038
28268
  }
28039
28269
  /**
28040
28270
  * The text position under (x, y) inside the editor's own scope: the
@@ -28229,6 +28459,43 @@ function useCrossDrag(rootRef, doc) {
28229
28459
  //#endregion
28230
28460
  //#region src/editing/use-editing.ts
28231
28461
  /**
28462
+ * The history reseat's window over the undo/redo (the remount's transient
28463
+ * selection loss's stand): the window's end stands the mapping's none's
28464
+ * suppression. The engine's remount commit + the selectionchange's settle
28465
+ * stands the sub-second over the load, so the window stands a margin over
28466
+ * it (the staleness is bounded by the window's end; the explicit paths —
28467
+ * the Escape, the gutter's reset — stand the real clear).
28468
+ */
28469
+ const RESEAT_WINDOW_MS = 2e3;
28470
+ /**
28471
+ * The undo/redo's reseat over the engine's event ordering: the fast path
28472
+ * re-reads the view over the synchronous read (the restoration's stand
28473
+ * lands inside the undo/redo call), and the window's stand re-runs the
28474
+ * reseat when the restoration's emission lands over the transaction's
28475
+ * settle (the engine's ordering stands the popped's event after the
28476
+ * handler's return — the reseat then reads the restored state). The
28477
+ * reseat's own stands (the user's live selection's stop, the seated's
28478
+ * short-circuit) keep the re-runs from clobbering.
28479
+ */
28480
+ function scheduleHistoryReseat(doc, view, root) {
28481
+ if (view === null) return;
28482
+ const scope = root ?? document;
28483
+ const run = () => {
28484
+ reseatHistorySelection(doc, view, scope);
28485
+ };
28486
+ run();
28487
+ let alive = true;
28488
+ const unsubscribe = view.onChange((selection) => {
28489
+ if (!alive) return;
28490
+ if (selection.kind !== "text") return;
28491
+ run();
28492
+ });
28493
+ window.setTimeout(() => {
28494
+ alive = false;
28495
+ unsubscribe();
28496
+ }, RESEAT_WINDOW_MS);
28497
+ }
28498
+ /**
28232
28499
  * Document-level wiring owned by the editor root: `selectionchange` maps
28233
28500
  * the DOM selection to the core Selection view, the mod+z / mod+shift+z /
28234
28501
  * mod+y hotkeys drive doc.undo()/doc.redo(), and the copy event carries
@@ -28254,6 +28521,7 @@ function useEditing() {
28254
28521
  if (view.get().kind === "blocks" && !domSelectionInEditable(window.getSelection())) return;
28255
28522
  const anchorNode = window.getSelection()?.anchorNode ?? null;
28256
28523
  if ((anchorNode instanceof Element ? anchorNode : anchorNode?.parentElement ?? null)?.closest("[data-slot=\"docblocks/page-card\"]") !== null) return;
28524
+ if (next.kind !== "text" && Date.now() < selectionRef.reseatUntil.current) return;
28257
28525
  if (!selectionsEqual(next, view.get())) view.set(next);
28258
28526
  };
28259
28527
  document.addEventListener("selectionchange", onSelectionChange);
@@ -28308,11 +28576,13 @@ function useEditing() {
28308
28576
  if (key === "z" && !event.shiftKey) {
28309
28577
  event.preventDefault();
28310
28578
  doc.undo();
28311
- if (view !== null) reseatHistorySelection(doc, view, root ?? document);
28579
+ selectionRef.reseatUntil.current = Date.now() + RESEAT_WINDOW_MS;
28580
+ scheduleHistoryReseat(doc, view, root);
28312
28581
  } else if (key === "z" && event.shiftKey || key === "y") {
28313
28582
  event.preventDefault();
28314
28583
  doc.redo();
28315
- if (view !== null) reseatHistorySelection(doc, view, root ?? document);
28584
+ selectionRef.reseatUntil.current = Date.now() + RESEAT_WINDOW_MS;
28585
+ scheduleHistoryReseat(doc, view, root);
28316
28586
  }
28317
28587
  };
28318
28588
  const onCopy = (event) => {
@@ -29115,11 +29385,15 @@ function clampTailSeatCrossing(next, draggedId, seatId) {
29115
29385
  * event's clientY, or the last changed touch's (the touch release event
29116
29386
  * carries no coordinate of its own). Null when the event stands no
29117
29387
  * usable coordinate (the measurement is stale — the caller keeps the
29118
- * preview or skips the commit).
29388
+ * preview or skips the commit). The touch's stand is duck-typed over
29389
+ * `changedTouches`: the global `TouchEvent` is absent on the no-touch
29390
+ * Safari (a desktop Safari on macOS), so the `instanceof` stand throws a
29391
+ * ReferenceError over every drag callback.
29119
29392
  */
29120
29393
  function pointerYOf(event) {
29121
- if (event instanceof TouchEvent) {
29122
- const touch = event.changedTouches[event.changedTouches.length - 1];
29394
+ if ("changedTouches" in event) {
29395
+ const touches = event.changedTouches;
29396
+ const touch = touches[touches.length - 1];
29123
29397
  return touch === null || touch === void 0 ? null : touch.clientY;
29124
29398
  }
29125
29399
  return event.clientY;
@@ -997,6 +997,16 @@ interface MentionProvider {
997
997
  /** The per-instance selection view; null before the mount effect ran and after unmount. */
998
998
  interface SelectionRef {
999
999
  view: SelectionView | null;
1000
+ /**
1001
+ * The history reseat's window end (the epoch ms): the undo/redo's remount
1002
+ * stands the engine's transient selection loss, and the gesture-time and
1003
+ * event-based mappings' none push stands the remount's residue over the
1004
+ * window (not the user's clear — the real clear stands the explicit
1005
+ * paths: the Escape, the editor's outside's focus).
1006
+ */
1007
+ reseatUntil: {
1008
+ current: number;
1009
+ };
1000
1010
  }
1001
1011
  /**
1002
1012
  * The local user's presence identity and the selection-sharing cipher
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { n as BlockRendererMap, r as BlockRendererProps, t as BlockRenderer } from "./index-YJcgf8Hh.mjs";
2
- import { $ as ProtocolLimits, A as filterIsComplete, B as DatabaseBridge, C as DatabaseTableView, Ct as BlobSubtype, D as DatabaseTableRow, E as DatabaseTablePhase, F as BridgeTableDescription, G as IsoInstant, H as FilterConditionInput, I as BridgeValueInput, J as OperationStatus, K as MutationContext, L as CellMap, M as BatchOp, N as BridgeColumn, O as UseDatabaseTable, P as BridgeColumnAnnotation, Q as ProtocolDescriptor, R as CellValueParse, S as DatabaseTableProps, St as BlobStore, T as useDatabaseTable, Tt as createMemoryBlobStore, U as FilterInput, V as DomainEvent, W as Id, X as PageSnapshot, Y as PageQuery, Z as ProtocolCapability, _ as PresencePeer, _t as isBridgeError, a as EditorContextValue, at as SortInput, b as useTableList, bt as BlobMeta, c as EmbedSandboxPolicy, ct as SubscriptionStatus, d as PdfPreview, dt as TableEvent, et as QueryOperator, f as PdfPreviewProps, ft as TableRef, g as PresenceIdentity, gt as BridgeErrorCode, h as PresenceCrypto, ht as BridgeError, i as AccessLevel, it as RowWire, j as FilterBuilder, k as emptyFilter, l as MentionEntry, lt as TableDescription, m as SyncEmbedResolver, mt as BRIDGE_ERROR_CODES, n as DEFAULT_EMBED_SANDBOX, nt as Revision, o as EditorMode, ot as SubscriptionHandle, p as PresenceConfig, pt as TableSnapshot, q as MutationReceipt, r as EditorProvider, rt as RowPage, s as EditorProviderProps, st as SubscriptionObserver, t as useEditorContext, tt as QuerySemantics, u as MentionProvider, ut as TableEnvelopeBase, v as PresenceSharing, vt as isBridgeErrorCode, w as UseTableList, wt as blobSubtypeOf, x as DatabaseTable, xt as BlobRef, y as PresenceSharingMode, yt as toBridgeError, z as Column } from "./index-BQRTt8x2.mjs";
2
+ import { $ as ProtocolLimits, A as filterIsComplete, B as DatabaseBridge, C as DatabaseTableView, Ct as BlobSubtype, D as DatabaseTableRow, E as DatabaseTablePhase, F as BridgeTableDescription, G as IsoInstant, H as FilterConditionInput, I as BridgeValueInput, J as OperationStatus, K as MutationContext, L as CellMap, M as BatchOp, N as BridgeColumn, O as UseDatabaseTable, P as BridgeColumnAnnotation, Q as ProtocolDescriptor, R as CellValueParse, S as DatabaseTableProps, St as BlobStore, T as useDatabaseTable, Tt as createMemoryBlobStore, U as FilterInput, V as DomainEvent, W as Id, X as PageSnapshot, Y as PageQuery, Z as ProtocolCapability, _ as PresencePeer, _t as isBridgeError, a as EditorContextValue, at as SortInput, b as useTableList, bt as BlobMeta, c as EmbedSandboxPolicy, ct as SubscriptionStatus, d as PdfPreview, dt as TableEvent, et as QueryOperator, f as PdfPreviewProps, ft as TableRef, g as PresenceIdentity, gt as BridgeErrorCode, h as PresenceCrypto, ht as BridgeError, i as AccessLevel, it as RowWire, j as FilterBuilder, k as emptyFilter, l as MentionEntry, lt as TableDescription, m as SyncEmbedResolver, mt as BRIDGE_ERROR_CODES, n as DEFAULT_EMBED_SANDBOX, nt as Revision, o as EditorMode, ot as SubscriptionHandle, p as PresenceConfig, pt as TableSnapshot, q as MutationReceipt, r as EditorProvider, rt as RowPage, s as EditorProviderProps, st as SubscriptionObserver, t as useEditorContext, tt as QuerySemantics, u as MentionProvider, ut as TableEnvelopeBase, v as PresenceSharing, vt as isBridgeErrorCode, w as UseTableList, wt as blobSubtypeOf, x as DatabaseTable, xt as BlobRef, y as PresenceSharingMode, yt as toBridgeError, z as Column } from "./index-CZEO5s2i.mjs";
3
3
  import * as React from "react";
4
4
  import { ComponentType, ReactNode } from "react";
5
5
  import { Block, BlockId, BlockType, Doc, DocMeta, PresenceState, Selection, SelectionView, SyncEmbedRef, TextRun } from "docblocks-core";
@@ -294,7 +294,7 @@ declare function AlertDescription({ className, ...props }: React.ComponentProps<
294
294
  //#endregion
295
295
  //#region src/shared/ui/Badge.d.ts
296
296
  declare const badgeVariants: (props?: ({
297
- variant?: "default" | "custom" | "secondary" | "destructive" | "outline" | null | undefined;
297
+ variant?: "default" | "destructive" | "outline" | "secondary" | "custom" | null | undefined;
298
298
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
299
299
  declare function Badge({ className, variant, asChild, ...props }: React.ComponentProps<"span"> & VariantProps<typeof badgeVariants> & {
300
300
  asChild?: boolean;
@@ -305,7 +305,7 @@ declare function BareSelect({ className, children, ...props }: React.ComponentPr
305
305
  //#endregion
306
306
  //#region src/shared/ui/Button.d.ts
307
307
  declare const buttonVariants: (props?: ({
308
- variant?: "link" | "default" | "secondary" | "destructive" | "outline" | "ghost" | null | undefined;
308
+ variant?: "link" | "default" | "destructive" | "outline" | "secondary" | "ghost" | null | undefined;
309
309
  size?: "default" | "icon" | "sm" | "lg" | "xl" | null | undefined;
310
310
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
311
311
  declare function Button({ className, variant, size, asChild, type, ...props }: React.ComponentProps<"button"> & VariantProps<typeof buttonVariants> & {
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as PopoverHeader, A as SelectTrigger, At as isBridgeErrorCode, B as DropdownMenuRadioGroup, Bt as useMeta, C as SelectContent, Ct as BASELINE_CAPABILITIES, D as SelectScrollDownButton, Dt as BRIDGE_ERROR_CODES, E as SelectLabel, Et as validateProtocolDescriptor, F as DropdownMenuContent, Ft as columnAnnotation, G as DropdownMenuSubContent, Gt as useText, H as DropdownMenuSeparator, Ht as usePresenceSharing, I as DropdownMenuGroup, It as ScrollArea, J as Separator, Jt as blobSubtypeOf, K as DropdownMenuSubTrigger, L as DropdownMenuItem, Lt as Input, M as Label, Mt as conditionMatches, N as DropdownMenu, Nt as parseCellValue, O as SelectScrollUpButton, Ot as BridgeError, P as DropdownMenuCheckboxItem, Pt as TEXT_TYPES, Q as PopoverDescription, R as DropdownMenuLabel, Rt as useBlock, S as Select, St as AlertTitle, T as SelectItem, Tt as isDatabaseBridge, U as DropdownMenuShortcut, Ut as useSelection, V as DropdownMenuRadioItem, Vt as usePresence, W as DropdownMenuSub, Wt as useSelectionView, X as PopoverAnchor, Y as Popover, Yt as createMemoryBlobStore, Z as PopoverContent, _ as FilterBuilder, _t as BareSelect, a as SHAPE_FONT_STACKS, at as CardAction, b as Skeleton, bt as Alert, ct as CardFooter, d as useEditorContext, dt as Pen, et as PopoverTitle, f as DEFAULT_EMBED_SANDBOX, ft as Eye, g as newMutationContext, gt as buttonVariants, h as cellValueEqual, ht as Button, i as SHAPE_FONT_OPTIONS, it as Card, j as SelectValue, jt as toBridgeError, k as SelectSeparator, kt as isBridgeError, l as markToggleAction, lt as CardHeader, m as useDatabaseTable, mt as BookOpen, nt as DocblocksI18nProvider, ot as CardContent, p as GridBody, q as DropdownMenuTrigger, qt as renderRuns, rt as Checkbox, s as FORMAT_PALETTE, st as CardDescription, t as Editor, tt as PopoverTrigger, u as EditorProvider, ut as CardTitle, v as emptyFilter, vt as Badge, w as SelectGroup, wt as PROTOCOL_VERSION, x as SegmentSelector, xt as AlertDescription, y as filterIsComplete, yt as badgeVariants, z as DropdownMenuPortal, zt as useDoc } from "./Editor-BHXnrEJ1.mjs";
1
+ import { $ as PopoverHeader, A as SelectTrigger, At as isBridgeErrorCode, B as DropdownMenuRadioGroup, Bt as useMeta, C as SelectContent, Ct as BASELINE_CAPABILITIES, D as SelectScrollDownButton, Dt as BRIDGE_ERROR_CODES, E as SelectLabel, Et as validateProtocolDescriptor, F as DropdownMenuContent, Ft as columnAnnotation, G as DropdownMenuSubContent, Gt as useText, H as DropdownMenuSeparator, Ht as usePresenceSharing, I as DropdownMenuGroup, It as ScrollArea, J as Separator, Jt as blobSubtypeOf, K as DropdownMenuSubTrigger, L as DropdownMenuItem, Lt as Input, M as Label, Mt as conditionMatches, N as DropdownMenu, Nt as parseCellValue, O as SelectScrollUpButton, Ot as BridgeError, P as DropdownMenuCheckboxItem, Pt as TEXT_TYPES, Q as PopoverDescription, R as DropdownMenuLabel, Rt as useBlock, S as Select, St as AlertTitle, T as SelectItem, Tt as isDatabaseBridge, U as DropdownMenuShortcut, Ut as useSelection, V as DropdownMenuRadioItem, Vt as usePresence, W as DropdownMenuSub, Wt as useSelectionView, X as PopoverAnchor, Y as Popover, Yt as createMemoryBlobStore, Z as PopoverContent, _ as FilterBuilder, _t as BareSelect, a as SHAPE_FONT_STACKS, at as CardAction, b as Skeleton, bt as Alert, ct as CardFooter, d as useEditorContext, dt as Pen, et as PopoverTitle, f as DEFAULT_EMBED_SANDBOX, ft as Eye, g as newMutationContext, gt as buttonVariants, h as cellValueEqual, ht as Button, i as SHAPE_FONT_OPTIONS, it as Card, j as SelectValue, jt as toBridgeError, k as SelectSeparator, kt as isBridgeError, l as markToggleAction, lt as CardHeader, m as useDatabaseTable, mt as BookOpen, nt as DocblocksI18nProvider, ot as CardContent, p as GridBody, q as DropdownMenuTrigger, qt as renderRuns, rt as Checkbox, s as FORMAT_PALETTE, st as CardDescription, t as Editor, tt as PopoverTrigger, u as EditorProvider, ut as CardTitle, v as emptyFilter, vt as Badge, w as SelectGroup, wt as PROTOCOL_VERSION, x as SegmentSelector, xt as AlertDescription, y as filterIsComplete, yt as badgeVariants, z as DropdownMenuPortal, zt as useDoc } from "./Editor-B1T7ytNQ.mjs";
2
2
  import { d as cn, l as preventDefault } from "./constants-BaAj3jDA.mjs";
3
3
  import { useCallback, useEffect, useRef, useState } from "react";
4
4
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -1,4 +1,4 @@
1
- import { Kt as INLINE_CODE_CLASS, St as AlertTitle, b as Skeleton, bt as Alert, c as textOf, d as useEditorContext, ft as Eye, n as childrenSlot, o as TextBlock, pt as CodeXml, r as CodeHeader, x as SegmentSelector, xt as AlertDescription } from "../Editor-BHXnrEJ1.mjs";
1
+ import { Kt as INLINE_CODE_CLASS, St as AlertTitle, b as Skeleton, bt as Alert, c as textOf, d as useEditorContext, ft as Eye, n as childrenSlot, o as TextBlock, pt as CodeXml, r as CodeHeader, x as SegmentSelector, xt as AlertDescription } from "../Editor-B1T7ytNQ.mjs";
2
2
  import { r as TriangleAlert } from "../constants-BaAj3jDA.mjs";
3
3
  import { t as LoaderCircle } from "../LoaderCircle-AGVFE4IP.mjs";
4
4
  import { useEffect, useRef, useState } from "react";
@@ -1,4 +1,4 @@
1
- import { f as PdfPreviewProps } from "../index-BQRTt8x2.mjs";
1
+ import { f as PdfPreviewProps } from "../index-CZEO5s2i.mjs";
2
2
  //#region src/pdf/PdfFirstPage.d.ts
3
3
  declare function PdfFirstPage({ id, url, name }: PdfPreviewProps): import("react").JSX.Element;
4
4
  //#endregion
package/dist/styles.css CHANGED
@@ -2394,17 +2394,6 @@
2394
2394
  .aria-selected\:text-muted-foreground[aria-selected="true"] {
2395
2395
  color: var(--muted-foreground);
2396
2396
  }
2397
- .data-closed\:animate-out[data-closed] {
2398
- animation: exit var(--tw-animation-duration,var(--tw-duration,.15s))var(--tw-ease,ease)var(--tw-animation-delay,0s)var(--tw-animation-iteration-count,1)var(--tw-animation-direction,normal)var(--tw-animation-fill-mode,none);
2399
- }
2400
- .data-closed\:fade-out-0[data-closed] {
2401
- --tw-exit-opacity: calc(0/100);
2402
- --tw-exit-opacity: 0;
2403
- }
2404
- .data-closed\:zoom-out-95[data-closed] {
2405
- --tw-exit-scale: calc(95*1%);
2406
- --tw-exit-scale: .95;
2407
- }
2408
2397
  .data-disabled\:pointer-events-none[data-disabled] {
2409
2398
  pointer-events: none;
2410
2399
  }
@@ -2417,17 +2406,6 @@
2417
2406
  .data-inset\:pl-8[data-inset] {
2418
2407
  padding-left: calc(var(--spacing) * 8);
2419
2408
  }
2420
- .data-open\:animate-in[data-open] {
2421
- animation: enter var(--tw-animation-duration,var(--tw-duration,.15s))var(--tw-ease,ease)var(--tw-animation-delay,0s)var(--tw-animation-iteration-count,1)var(--tw-animation-direction,normal)var(--tw-animation-fill-mode,none);
2422
- }
2423
- .data-open\:fade-in-0[data-open] {
2424
- --tw-enter-opacity: calc(0/100);
2425
- --tw-enter-opacity: 0;
2426
- }
2427
- .data-open\:zoom-in-95[data-open] {
2428
- --tw-enter-scale: calc(95*1%);
2429
- --tw-enter-scale: .95;
2430
- }
2431
2409
  .data-placeholder\:text-muted-foreground[data-placeholder] {
2432
2410
  color: var(--muted-foreground);
2433
2411
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "docblocks-react-ui",
3
- "version": "0.4.3",
3
+ "version": "0.4.5",
4
4
  "description": "React rendering + editing layer for docblocks: hooks, block renderers, caret/selection, keyboard, clipboard.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -34,7 +34,7 @@
34
34
  "access": "public"
35
35
  },
36
36
  "peerDependencies": {
37
- "docblocks-core": "^0.2.1",
37
+ "docblocks-core": "^0.2.2",
38
38
  "framer-motion": "^11.0.0 || ^12.0.0 || ^13.0.0 || ^14.0.0",
39
39
  "mermaid": "^12.0.0",
40
40
  "pdfjs-dist": "^6.0.0",