@plannotator/ui 0.46.0 → 0.46.1

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/HANDOFF.md CHANGED
@@ -1527,6 +1527,7 @@ The guide chain's engine plumbing (Claude/Codex/marker commands, output parsing,
1527
1527
 
1528
1528
  ## Publishing & versioning
1529
1529
 
1530
+ - **ui 0.46.1 (fix, ui only, core pin unchanged at `0.25.6`):** `useVimSelection` (mounted by every `Viewer`) now only clears a page selection whose anchor or focus lies inside the viewer's own container; with vim off it used to clear the WHOLE page's selection on every mount and `contentVersion` change, so a selection in another host panel vanished whenever the document behind it loaded or changed.
1530
1531
  - **ui 0.45.0 (annotation card header slot + mentions on the card's edit box): `@plannotator/ui` only — `@plannotator/core` is UNCHANGED at `0.25.5`, so this publishes alone** (core 0.25.5 must already be published). Purely additive over 0.44.0, both props on `AnnotationPanel`: `renderCardHeader` (the header-row twin of `renderCardFooter`, wrapper `[data-annotation-card-header]`, renders under `readOnly`, open-document cards only in the All-files view) and `mentionSource` (the 0.43.0 type, applied to the card's EDIT box, saving `onEdit(id, { text, mentions })` only when a source was supplied and a pick survived). Nothing is removed, no new supported imports (`components/MentionAutocomplete` is internal glue), no export-, share- or archive-visible change, and Plannotator passes neither — `packages/editor` and `packages/review-editor` have zero source diff, and the panel is byte-identical to 0.44.0. Known difference from `CommentPopover`: no chips in the card's edit box (follow-up named in the section). See "Annotation card header slot and mentions on the edit box (0.45.0)".
1531
1532
  - **ui 0.44.0 (mention token chips in the composer): `@plannotator/ui` only — `@plannotator/core` is UNCHANGED at `0.25.5`, so this publishes alone** (core 0.25.5 must already be published). Purely additive over 0.43.2: the `@Label` tokens a `mentionSource` composer inserted render as chips in the composer's existing highlight overlay, `MentionSource.tokenClassName?` lets a host restyle them (under the metric rule), `useMentionAutocomplete` also returns the surviving `mentions`, and `utils/composerTokens` joins the supported-import list. Nothing is removed, no export-, share- or archive-visible change, and Plannotator passes none of it — with neither `mentionSource` nor `skillReferences` the composer is byte-identical to 0.43.2. See "Mention token chips in the composer (0.44.0)".
1532
1533
  - **ui 0.43.1 (`mentionSource` on the viewers): `@plannotator/ui` only — `@plannotator/core` is UNCHANGED at `0.25.5`, so this publishes alone** (core 0.25.5 must already be published). Purely additive over 0.43.0: `mentionSource` on `Viewer` and `HtmlViewer` (forwarded to every comment composer each mounts) and the optional `Annotation.mentions` field the picked ids land on, set only when a source was supplied and a token survived. Nothing is removed, no new modules, no export-, share- or archive-visible change, and Plannotator passes none of it. See "`mentionSource` on the viewers (0.43.1)".
@@ -1548,7 +1549,7 @@ The guide chain's engine plumbing (Claude/Codex/marker commands, output parsing,
1548
1549
 
1549
1550
  ---
1550
1551
 
1551
- ## `Settings` `annotateParity` (unreleased, after 0.46.0)
1552
+ ## `Settings` `annotateParity` (shipped in 0.46.0)
1552
1553
 
1553
1554
  `<Settings mode="annotate">` takes a new optional `annotateParity?: boolean`,
1554
1555
  default `false`. **A host that omits it sees exactly the annotate Settings it
package/README.md CHANGED
@@ -367,7 +367,7 @@ npm install @plannotator/ui @plannotator/core
367
367
  - `@plannotator/core` — pure utils + types, zero deps, browser-safe (CI enforces no `node:` imports). Published.
368
368
  - `@plannotator/ui` — React components/hooks + theme + `configure()`. Depends on an exact published `@plannotator/core` version. Published.
369
369
  - `@plannotator/shared`, `@plannotator/ai` — stay private to the monorepo; `shared` re-exports `core`'s modules via shims so Plannotator's internals are untouched.
370
- - Currently `@plannotator/ui` 0.46.0 depends exactly on `@plannotator/core` 0.25.6. `core` is bumped only when something under `packages/core` changes, so `ui` can advance alone. Keep the published core version exact in `packages/ui/package.json`; do not use a `workspace:` protocol there, because a directly published manifest must remain installable outside this monorepo. Bun still links the matching local workspace during development. When both packages change, publish `core` first, then build and publish the UI tarball. See HANDOFF.md "Publishing & versioning" for the verification command.
370
+ - Currently `@plannotator/ui` 0.46.1 depends exactly on `@plannotator/core` 0.25.6. `core` is bumped only when something under `packages/core` changes, so `ui` can advance alone. Keep the published core version exact in `packages/ui/package.json`; do not use a `workspace:` protocol there, because a directly published manifest must remain installable outside this monorepo. Bun still links the matching local workspace during development. When both packages change, publish `core` first, then build and publish the UI tarball. See HANDOFF.md "Publishing & versioning" for the verification command.
371
371
 
372
372
  ## The one rule
373
373
 
@@ -227,6 +227,27 @@ function applyVisualBlockSelection(
227
227
  if (points) applyNativeTextSelection(graph.container, points.cursor, points.anchor);
228
228
  }
229
229
 
230
+ /**
231
+ * Clear the page selection only when it touches the viewer's own document.
232
+ *
233
+ * A page has ONE selection, so an unconditional `removeAllRanges()` also kills
234
+ * a selection the user just made somewhere else (another panel of a host app,
235
+ * the annotation sidebar). A selection belongs to the viewer when its anchor or
236
+ * focus lies inside the container; with no container nothing is cleared.
237
+ */
238
+ function clearSelectionWithin(container: HTMLElement | null | undefined): void {
239
+ if (!container) return;
240
+ const selection = window.getSelection();
241
+ if (!selection || selection.rangeCount === 0) return;
242
+ const { anchorNode, focusNode } = selection;
243
+ if (
244
+ (anchorNode && container.contains(anchorNode))
245
+ || (focusNode && container.contains(focusNode))
246
+ ) {
247
+ selection.removeAllRanges();
248
+ }
249
+ }
250
+
230
251
  /**
231
252
  * Own semantic block navigation and precise text selection while the rendered
232
253
  * document has focus.
@@ -291,7 +312,7 @@ export function useVimSelection({
291
312
  if (!initial) return null;
292
313
  const next: VimBlockState = { phase: 'block', targetKey: initial.key };
293
314
  setState(next);
294
- window.getSelection()?.removeAllRanges();
315
+ clearSelectionWithin(container);
295
316
  scrollVimTargetIntoView(initial.element, scrollViewportRef.current);
296
317
  return next;
297
318
  }, [containerRef, setState]);
@@ -302,7 +323,7 @@ export function useVimSelection({
302
323
  setFocused(false);
303
324
  setHelpOpen(false);
304
325
  setHudCommand(null);
305
- window.getSelection()?.removeAllRanges();
326
+ clearSelectionWithin(containerRef.current);
306
327
  return;
307
328
  }
308
329
  if (!focused) return;
@@ -366,9 +387,9 @@ export function useVimSelection({
366
387
 
367
388
  const setSemanticTarget = useCallback((target: SemanticTarget) => {
368
389
  setState(semanticStateForTarget(target));
369
- window.getSelection()?.removeAllRanges();
390
+ clearSelectionWithin(containerRef.current);
370
391
  scrollVimTargetIntoView(target.element, scrollViewportRef.current);
371
- }, [setState]);
392
+ }, [containerRef, setState]);
372
393
 
373
394
  const updateTextState = useCallback((
374
395
  graph: SemanticTargetGraph,
@@ -816,13 +837,13 @@ export function useVimSelection({
816
837
  setSemanticTarget(parent);
817
838
  } else {
818
839
  setState(createInitialVimSelectionState());
819
- window.getSelection()?.removeAllRanges();
840
+ clearSelectionWithin(graph.container);
820
841
  }
821
842
  return;
822
843
  }
823
844
  case 'block':
824
845
  setState(createInitialVimSelectionState());
825
- window.getSelection()?.removeAllRanges();
846
+ clearSelectionWithin(graph.container);
826
847
  }
827
848
  }, [setSemanticTarget, setState, updateTextState]);
828
849
 
@@ -1041,7 +1062,7 @@ export function useVimSelection({
1041
1062
  const onMouseDown = useCallback((event: ReactMouseEvent<HTMLElement>) => {
1042
1063
  if (!enabled || isDocumentKeyboardControl(event.target)) return;
1043
1064
  setState(createInitialVimSelectionState());
1044
- window.getSelection()?.removeAllRanges();
1065
+ clearSelectionWithin(event.currentTarget);
1045
1066
  if (document.activeElement !== event.currentTarget) {
1046
1067
  pointerFocusRef.current = true;
1047
1068
  event.currentTarget.focus({ preventScroll: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plannotator/ui",
3
- "version": "0.46.0",
3
+ "version": "0.46.1",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  "./components/*": "./components/*.tsx",