bsky-richtext-react 1.1.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,50 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ---
9
9
 
10
+ ## [2.0.0] — 2026-02-18
11
+
12
+ ### Breaking Changes
13
+
14
+ - **Upgraded all `@tiptap/*` dependencies from v2 to v3** (`^3.20.0`). Consumers must update their installed `@tiptap/*` packages to v3.
15
+ - **Replaced `tippy.js` with `@floating-ui/dom`** for mention suggestion popup positioning, aligning with the tiptap v3 ecosystem. The `tippy.js` peer dependency has been removed.
16
+ - **Peer dependency requirements changed**: consumers must install `@tiptap/*@^3.20.0` and `@floating-ui/dom@^1.6.0`. The `tippy.js` peer dependency is no longer required.
17
+
18
+ ### Why
19
+
20
+ - Fixes Turbopack build failures in Next.js 16+ when the consumer's dependency tree includes tiptap v3 packages (e.g., via `@tiptap/starter-kit@3.x`). Turbopack's strict static export analysis caught that `@tiptap/extension-list@3.x` imports symbols from `@tiptap/core` that don't exist in v2.
21
+ - Aligns with the tiptap v3 ecosystem (`tippy.js` → `@floating-ui/dom`).
22
+
23
+ ### Migration
24
+
25
+ ```diff
26
+ - "@tiptap/core": "^2.x.x",
27
+ + "@tiptap/core": "^3.20.0",
28
+ // repeat for all @tiptap/* packages
29
+
30
+ - "tippy.js": "^6.x.x",
31
+ + "@floating-ui/dom": "^1.6.0",
32
+ ```
33
+
34
+ ---
35
+
36
+ ## [2.0.0] — 2026-02-18
37
+
38
+ ### Breaking Changes
39
+
40
+ - **tiptap upgraded from v2 to v3** — all `@tiptap/*` peer dependencies must be updated to `^3.20.0`.
41
+ - **`tippy.js` replaced with `@floating-ui/dom`** — the mention suggestion popup now uses `@floating-ui/dom` for positioning. Remove `tippy.js` from your dependencies and install `@floating-ui/dom` instead.
42
+
43
+ ### Migration
44
+
45
+ ```diff
46
+ - bun add @tiptap/core@^2 @tiptap/react@^2 ... tippy.js
47
+ + bun add @tiptap/core@^3.20.0 @tiptap/react@^3.20.0 ... @floating-ui/dom
48
+ ```
49
+
50
+ Update all `@tiptap/*` peer dependencies to `^3.20.0` and replace `tippy.js` with `@floating-ui/dom`.
51
+
52
+ ---
53
+
10
54
  ## [1.1.0] — 2026-02-17
11
55
 
12
56
  ### Changed
package/README.md CHANGED
@@ -36,7 +36,16 @@ pnpm add bsky-richtext-react
36
36
  Peer dependencies (if not already installed):
37
37
 
38
38
  ```bash
39
- bun add react react-dom
39
+ bun add react react-dom @floating-ui/dom \
40
+ @tiptap/core@^3.20.0 \
41
+ @tiptap/extension-document@^3.20.0 \
42
+ @tiptap/extension-hard-break@^3.20.0 \
43
+ @tiptap/extension-history@^3.20.0 \
44
+ @tiptap/extension-mention@^3.20.0 \
45
+ @tiptap/extension-paragraph@^3.20.0 \
46
+ @tiptap/extension-placeholder@^3.20.0 \
47
+ @tiptap/extension-text@^3.20.0 \
48
+ @tiptap/react@^3.20.0
40
49
  ```
41
50
 
42
51
  ---
@@ -224,7 +233,7 @@ import { RichTextEditor } from 'bsky-richtext-react'
224
233
  | `onMentionQuery` | `(query: string) => Promise<MentionSuggestion[]>` | **Bluesky public API** | Custom mention search. Overrides the built-in search. |
225
234
  | `mentionSearchDebounceMs` | `number` | `300` | Debounce delay (ms) for the built-in search. No effect when `onMentionQuery` is set. |
226
235
  | `disableDefaultMentionSearch` | `boolean` | `false` | Disable the built-in Bluesky API search entirely |
227
- | `renderMentionSuggestion` | `SuggestionOptions['render']` | tippy.js popup | Custom TipTap suggestion renderer factory |
236
+ | `renderMentionSuggestion` | `SuggestionOptions['render']` | @floating-ui/dom popup | Custom TipTap suggestion renderer factory |
228
237
  | `mentionSuggestionOptions` | `DefaultSuggestionRendererOptions` | — | Options forwarded to the default renderer |
229
238
  | `editorRef` | `Ref<RichTextEditorRef>` | — | Imperative ref |
230
239
  | `editable` | `boolean` | `true` | Toggle read-only mode |
@@ -281,7 +290,7 @@ The editor searches Bluesky actors **by default** when the user types `@`:
281
290
 
282
291
  ### `<MentionSuggestionList>`
283
292
 
284
- The default suggestion dropdown rendered inside the tippy.js popup. Exported so you can reuse or reference it in your own popup implementation.
293
+ The default suggestion dropdown rendered inside the @floating-ui/dom popup. Exported so you can reuse or reference it in your own popup implementation.
285
294
 
286
295
  ```tsx
287
296
  import { MentionSuggestionList } from 'bsky-richtext-react'
@@ -507,6 +516,24 @@ bun run format
507
516
 
508
517
  ---
509
518
 
519
+ ## Migration
520
+
521
+ ### v2.0.0 — tiptap v3 upgrade
522
+
523
+ **v2.0.0 upgrades tiptap from v2 to v3.** If you are upgrading from v1.x, you must:
524
+
525
+ 1. Update all `@tiptap/*` peer dependencies to `^3.20.0`.
526
+ 2. Replace `tippy.js` with `@floating-ui/dom`.
527
+
528
+ ```diff
529
+ - bun add @tiptap/core@^2 @tiptap/react@^2 tippy.js
530
+ + bun add @tiptap/core@^3.20.0 @tiptap/react@^3.20.0 @floating-ui/dom
531
+ ```
532
+
533
+ See [CHANGELOG.md](./CHANGELOG.md) for the full list of changes.
534
+
535
+ ---
536
+
510
537
  ## Changelog
511
538
 
512
539
  See [CHANGELOG.md](./CHANGELOG.md).
package/dist/index.cjs CHANGED
@@ -11,15 +11,11 @@ var extensionHardBreak = require('@tiptap/extension-hard-break');
11
11
  var extensionPlaceholder = require('@tiptap/extension-placeholder');
12
12
  var api = require('@atproto/api');
13
13
  var extensionMention = require('@tiptap/extension-mention');
14
- var tippy = require('tippy.js');
14
+ var dom = require('@floating-ui/dom');
15
15
  var core = require('@tiptap/core');
16
16
  var state = require('@tiptap/pm/state');
17
17
  var view = require('@tiptap/pm/view');
18
18
 
19
- function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
20
-
21
- var tippy__default = /*#__PURE__*/_interopDefault(tippy);
22
-
23
19
  // src/components/RichTextDisplay/RichTextDisplay.tsx
24
20
 
25
21
  // src/types/facets.ts
@@ -455,12 +451,6 @@ function createDefaultSuggestionRenderer(options = {}) {
455
451
  return () => {
456
452
  let renderer;
457
453
  let popup;
458
- const destroy = () => {
459
- popup?.[0]?.destroy();
460
- renderer?.destroy();
461
- renderer = void 0;
462
- popup = void 0;
463
- };
464
454
  const buildProps = (props) => ({
465
455
  ...props,
466
456
  showAvatars: options.showAvatars ?? true,
@@ -475,33 +465,49 @@ function createDefaultSuggestionRenderer(options = {}) {
475
465
  });
476
466
  if (!props.clientRect) return;
477
467
  const clientRect = props.clientRect;
478
- popup = tippy__default.default("body", {
479
- getReferenceClientRect: () => clientRect?.() ?? new DOMRect(),
480
- appendTo: () => document.body,
481
- content: renderer.element,
482
- showOnCreate: true,
483
- interactive: true,
484
- trigger: "manual",
485
- placement: "bottom-start"
468
+ popup = document.createElement("div");
469
+ popup.style.position = "fixed";
470
+ popup.style.zIndex = "9999";
471
+ popup.appendChild(renderer.element);
472
+ document.body.appendChild(popup);
473
+ const virtualEl = { getBoundingClientRect: () => clientRect?.() ?? new DOMRect() };
474
+ void dom.computePosition(virtualEl, popup, {
475
+ placement: "bottom-start",
476
+ middleware: [dom.offset(8), dom.flip(), dom.shift({ padding: 8 })]
477
+ }).then(({ x, y }) => {
478
+ if (popup) {
479
+ popup.style.left = `${x}px`;
480
+ popup.style.top = `${y}px`;
481
+ }
486
482
  });
487
483
  },
488
484
  onUpdate(props) {
489
485
  renderer?.updateProps(buildProps(props));
490
- if (!props.clientRect) return;
486
+ if (!props.clientRect || !popup) return;
491
487
  const clientRect = props.clientRect;
492
- popup?.[0]?.setProps({
493
- getReferenceClientRect: () => clientRect?.() ?? new DOMRect()
488
+ const virtualEl = { getBoundingClientRect: () => clientRect?.() ?? new DOMRect() };
489
+ void dom.computePosition(virtualEl, popup, {
490
+ placement: "bottom-start",
491
+ middleware: [dom.offset(8), dom.flip(), dom.shift({ padding: 8 })]
492
+ }).then(({ x, y }) => {
493
+ if (popup) {
494
+ popup.style.left = `${x}px`;
495
+ popup.style.top = `${y}px`;
496
+ }
494
497
  });
495
498
  },
496
499
  onKeyDown(props) {
497
500
  if (props.event.key === "Escape") {
498
- popup?.[0]?.hide();
501
+ if (popup) popup.style.display = "none";
499
502
  return true;
500
503
  }
501
504
  return renderer?.ref?.onKeyDown(props) ?? false;
502
505
  },
503
506
  onExit() {
504
- destroy();
507
+ popup?.remove();
508
+ renderer?.destroy();
509
+ popup = void 0;
510
+ renderer = void 0;
505
511
  }
506
512
  };
507
513
  };