bible-note 0.5.0 → 0.6.2

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 (32) hide show
  1. package/README.md +349 -293
  2. package/dist/bible-note.cjs +100 -101
  3. package/dist/bible-note.css +1 -1
  4. package/dist/bible-note.mjs +7799 -7717
  5. package/dist/chunks/{ContentEditable-C_wyHFh1.mjs → ContentEditable-BaXBKC3m.mjs} +1 -1
  6. package/dist/chunks/{ContentEditable-DgthEFHJ.cjs → ContentEditable-Ce294XLd.cjs} +2 -2
  7. package/dist/chunks/{ExcalidrawComponent-bEqDGYRW.cjs → ExcalidrawComponent-DdmtbuXc.cjs} +1 -1
  8. package/dist/chunks/{ExcalidrawComponent-iTobN_Hf.mjs → ExcalidrawComponent-OMjYgJCL.mjs} +2 -2
  9. package/dist/chunks/{ExcalidrawModal-DAEdxIBk.mjs → ExcalidrawModal-DSotOBGc.mjs} +2 -2
  10. package/dist/chunks/{ExcalidrawModal-Bbez9U5x.cjs → ExcalidrawModal-Db1LI01l.cjs} +2 -2
  11. package/dist/chunks/LexicalUtils.prod-CYv8J7Gq.cjs +3 -0
  12. package/dist/chunks/{LexicalUtils.prod-5zbJxaQa.mjs → LexicalUtils.prod-D2Igim2c.mjs} +28 -32
  13. package/dist/chunks/{MediaComponent-BTaaADsV.mjs → MediaComponent-D-AMKM9e.mjs} +3 -3
  14. package/dist/chunks/{MediaComponent-BhjGu3D-.cjs → MediaComponent-D69mEyrJ.cjs} +1 -1
  15. package/dist/chunks/{MediaResizer-C7UGQ3Kl.mjs → MediaResizer-C_ZJbHAU.mjs} +1 -1
  16. package/dist/chunks/{MediaResizer-DGw5LvDR.cjs → MediaResizer-Dzro5TVg.cjs} +1 -1
  17. package/dist/chunks/{StickyComponent-B8skHBRs.mjs → StickyComponent-B1GQ5G8T.mjs} +2 -2
  18. package/dist/chunks/{StickyComponent-C6xBrvrK.cjs → StickyComponent-DsQhvYHJ.cjs} +1 -1
  19. package/dist/chunks/{StickyNode-GgIn3-zY.cjs → StickyNode-B7sXOkJV.cjs} +1 -1
  20. package/dist/chunks/{StickyNode-B2B6di-N.mjs → StickyNode-C5dwEb8E.mjs} +3 -3
  21. package/dist/chunks/{TreeViewPlugin-DkUjU27t.cjs → TreeViewPlugin-8-uPZF17.cjs} +3 -3
  22. package/dist/chunks/{TreeViewPlugin-B0UnxNiM.mjs → TreeViewPlugin-Cd1KNBRW.mjs} +18 -18
  23. package/knowledge/development.md +222 -7
  24. package/knowledge/ui-rag.md +185 -135
  25. package/package.json +1 -1
  26. package/types/AppComp.d.ts +4 -2
  27. package/types/BibleNote.d.ts +31 -5
  28. package/types/actionButtonList.d.ts +23 -0
  29. package/types/bibleNoteHelpers.d.ts +3 -1
  30. package/types/floatingActionButtons.d.ts +118 -0
  31. package/types/lib.d.ts +1 -0
  32. package/dist/chunks/LexicalUtils.prod-W-Xb5dGB.cjs +0 -3
@@ -1,6 +1,6 @@
1
1
  import { $ as e, $n as t, A as n, Ar as r, B as i, Bn as a, C as o, Cr as s, Ct as c, D as l, Dn as u, Dr as d, E as f, En as p, Er as m, Et as h, F as g, Fr as _, Ft as v, Gn as y, Gr as b, Gt as x, H as S, Hn as C, Hr as w, Ht as T, I as E, It as D, J as ee, Jt as O, K as te, Kt as ne, Ln as k, M as re, Nr as ie, Nt as ae, O as oe, P as se, Pn as ce, Pt as le, Q as ue, Qn as de, Qr as fe, R as pe, Rr as me, Rt as he, S as ge, Sn as _e, Tn as ve, Tr as ye, Un as be, Ut as xe, V as Se, Vn as Ce, Vr as A, W as we, Wn as Te, Wt as Ee, X as De, Xn as Oe, Y as ke, Yn as Ae, Yr as je, Yt as Me, Z as Ne, Zn as Pe, Zr as Fe, Zt as Ie, _ as Le, _r as Re, _t as ze, a as Be, ar as Ve, b as He, bn as j, br as Ue, bt as We, cn as Ge, cr as Ke, dn as qe, dr as Je, en as Ye, et as Xe, f as Ze, fn as Qe, gn as $e, gr as et, h as tt, i as nt, ii as rt, jn as it, jt as at, kn as ot, kr as st, l as ct, ln as lt, lr as ut, m as dt, mr as ft, mt as pt, n as mt, ni as ht, o as gt, oi as _t, on as vt, or as yt, p as bt, pr as xt, q as St, qn as Ct, qr as wt, qt as M, ri as Tt, rn as Et, rr as Dt, s as Ot, sr as kt, t as At, ti as jt, tn as Mt, tr as Nt, tt as N, un as Pt, ur as Ft, vn as It, vr as Lt, vt as P, w as Rt, wn as zt, wr as Bt, wt as Vt, x as Ht, xn as Ut, xr as Wt, xt as Gt, yn as Kt, yt as qt, zn as Jt, zt as Yt } from "./Lexical.prod-DYDuARMX.mjs";
2
- import { C as Xt, I as Zt, N as Qt, T as $t, a as en, f as tn, g as nn, i as rn, k as an, n as on, o as sn, s as cn, t as ln } from "./LexicalUtils.prod-5zbJxaQa.mjs";
3
- import { B as un, H as dn, I as fn, K as pn, M as mn, R as hn, V as gn, c as _n, d as vn, f as yn, h as bn, j as xn, l as Sn, m as Cn, n as wn, s as Tn, u as En, v as Dn, x as On, y as kn } from "./ContentEditable-C_wyHFh1.mjs";
2
+ import { C as Xt, F as Zt, M as Qt, O as $t, a as en, f as tn, g as nn, i as rn, n as an, o as on, s as sn, t as cn, w as ln } from "./LexicalUtils.prod-D2Igim2c.mjs";
3
+ import { B as un, H as dn, I as fn, K as pn, M as mn, R as hn, V as gn, c as _n, d as vn, f as yn, h as bn, j as xn, l as Sn, m as Cn, n as wn, s as Tn, u as En, v as Dn, x as On, y as kn } from "./ContentEditable-BaXBKC3m.mjs";
4
4
  import { t as An } from "./useLexicalEditable.prod-CgMasHPY.mjs";
5
5
  import * as jn from "react";
6
6
  import { Suspense as Mn, createContext as Nn, forwardRef as Pn, startTransition as Fn, useCallback as F, useContext as In, useEffect as I, useLayoutEffect as Ln, useMemo as Rn, useRef as L, useState as R } from "react";
@@ -446,10 +446,10 @@ function fr(t, r = un(rr)) {
446
446
  }, 0), t.registerCommand(ce, () => {
447
447
  let e = st(), t = N();
448
448
  return j(t) && (e.setFormat(t.format), e.setStyle(t.style)), we([e]), !0;
449
- }, 0), t.registerCommand(vt, () => ln((e) => {
449
+ }, 0), t.registerCommand(vt, () => cn((e) => {
450
450
  let t = e.getIndent();
451
451
  e.setIndent(t + 1);
452
- }), 0), t.registerCommand(xt, () => ln((e) => {
452
+ }), 0), t.registerCommand(xt, () => cn((e) => {
453
453
  let t = e.getIndent();
454
454
  t > 0 && e.setIndent(Math.max(0, t - 1));
455
455
  }), 0), t.registerCommand(s, (e) => {
@@ -473,10 +473,10 @@ function fr(t, r = un(rr)) {
473
473
  let t = N();
474
474
  if (_(t)) {
475
475
  let n = t.getNodes();
476
- if (n.length > 0) return e.preventDefault(), ur(n[0], an(n[0]) ? "next" : "previous"), !0;
476
+ if (n.length > 0) return e.preventDefault(), ur(n[0], $t(n[0]) ? "next" : "previous"), !0;
477
477
  }
478
478
  if (!j(t)) return !1;
479
- if (!e.shiftKey && ir(t, an(t.anchor.getNode()) ? "next" : "previous")) return e.preventDefault(), !0;
479
+ if (!e.shiftKey && ir(t, $t(t.anchor.getNode()) ? "next" : "previous")) return e.preventDefault(), !0;
480
480
  if (e.shiftKey || nr(t, "arrow", "start", r.peek()), Zt(t, !0)) {
481
481
  let n = e.shiftKey;
482
482
  return e.preventDefault(), Qt(t, n, !0), !0;
@@ -486,10 +486,10 @@ function fr(t, r = un(rr)) {
486
486
  let t = N();
487
487
  if (_(t)) {
488
488
  let n = t.getNodes();
489
- if (n.length > 0) return e.preventDefault(), ur(n[0], an(n[0]) ? "previous" : "next"), !0;
489
+ if (n.length > 0) return e.preventDefault(), ur(n[0], $t(n[0]) ? "previous" : "next"), !0;
490
490
  }
491
491
  if (!j(t)) return !1;
492
- if (!e.shiftKey && ir(t, an(t.anchor.getNode()) ? "previous" : "next")) return e.preventDefault(), !0;
492
+ if (!e.shiftKey && ir(t, $t(t.anchor.getNode()) ? "previous" : "next")) return e.preventDefault(), !0;
493
493
  if (e.shiftKey || nr(t, "arrow", "end", r.peek()), Zt(t, !1)) {
494
494
  let n = e.shiftKey;
495
495
  return e.preventDefault(), Qt(t, n, !1), !0;
@@ -505,7 +505,7 @@ function fr(t, r = un(rr)) {
505
505
  if (t.offset !== 0) return !1;
506
506
  let n = t.getNode();
507
507
  if (Tt(n)) return !1;
508
- let r = sn(n);
508
+ let r = on(n);
509
509
  return r.getIndent() > 0 && (r.is(n) || n.is(r.getFirstDescendant()));
510
510
  }(n)) return e.preventDefault(), t.dispatchCommand(xt, void 0);
511
511
  if (Oe && Wt) return !1;
@@ -557,8 +557,8 @@ function fr(t, r = un(rr)) {
557
557
  }, 0), t.registerCommand(Ct, () => {
558
558
  let e = N();
559
559
  return Fe(j(e) && ye(e.anchor.getNode()) !== null ? e : null), !0;
560
- }, 0), t.registerCommand(me, (e) => (_n(t, cn(e, ClipboardEvent) ? e : null), !0), 0), t.registerCommand(ae, (e) => (async function(e, t) {
561
- await _n(t, cn(e, ClipboardEvent) ? e : null), t.update(() => {
560
+ }, 0), t.registerCommand(me, (e) => (_n(t, sn(e, ClipboardEvent) ? e : null), !0), 0), t.registerCommand(ae, (e) => (async function(e, t) {
561
+ await _n(t, sn(e, ClipboardEvent) ? e : null), t.update(() => {
562
562
  let e = N();
563
563
  j(e) ? e.removeText() : _(e) && e.getNodes().forEach((e) => e.remove());
564
564
  }, { tag: "cut" });
@@ -566,7 +566,7 @@ function fr(t, r = un(rr)) {
566
566
  let [, n, r] = rn(e);
567
567
  return n.length > 0 && !r ? (t.dispatchCommand(Wn, n), !0) : k(e.target) && b(e.target) ? !1 : N() !== null && (function(e, t) {
568
568
  e.preventDefault(), t.update(() => {
569
- let n = N(), r = cn(e, InputEvent) || cn(e, KeyboardEvent) ? null : e.clipboardData;
569
+ let n = N(), r = sn(e, InputEvent) || sn(e, KeyboardEvent) ? null : e.clipboardData;
570
570
  r != null && n !== null && bn(r, n, t);
571
571
  }, { tag: "paste" });
572
572
  }(e, t), !0);
@@ -1860,7 +1860,7 @@ function ui(e, t, r, a, o) {
1860
1860
  let t = N();
1861
1861
  if (t) {
1862
1862
  if (!J(t) && !j(t)) return !1;
1863
- _n(r, cn(e, ClipboardEvent) ? e : null, En(t));
1863
+ _n(r, sn(e, ClipboardEvent) ? e : null, En(t));
1864
1864
  let n = p(e);
1865
1865
  return j(t) ? (t.removeText(), !0) : n;
1866
1866
  }
@@ -2634,10 +2634,10 @@ function Ki(e) {
2634
2634
  G(e.getParent()) ? e.isEmpty() && e.append(r()) : e.remove();
2635
2635
  }
2636
2636
  function qi(e) {
2637
- Y(e.getParent()) ? $t(e, U) : e.remove();
2637
+ Y(e.getParent()) ? ln(e, U) : e.remove();
2638
2638
  }
2639
2639
  function Ji(e) {
2640
- $t(e, G);
2640
+ ln(e, G);
2641
2641
  let [t] = Br(e, null, null), n = t.reduce((e, t) => Math.max(e, t.length), 0), i = e.getChildren();
2642
2642
  for (let e = 0; e < t.length; ++e) {
2643
2643
  let a = i[e];
@@ -2730,7 +2730,7 @@ function $i(e, t) {
2730
2730
  let i = N() || ke();
2731
2731
  if (!i || !j(i) || !r && ki(i.anchor.getNode())) return !1;
2732
2732
  let a = xr(Number(e), Number(t), n);
2733
- on(a);
2733
+ an(a);
2734
2734
  let o = a.getFirstDescendant();
2735
2735
  return O(o) && o.select(), !0;
2736
2736
  }(e, n.peek()), 0), e.registerCommand(ue, (t, r) => e === r && function(e, t) {
@@ -3580,7 +3580,7 @@ function Za(e, t) {
3580
3580
  let r = t.attributes.value;
3581
3581
  return e.registerCommand(Te, (t) => {
3582
3582
  let i = N();
3583
- if (!j(i) || i.isCollapsed() || !cn(t, ClipboardEvent) || t.clipboardData === null) return !1;
3583
+ if (!j(i) || i.isCollapsed() || !sn(t, ClipboardEvent) || t.clipboardData === null) return !1;
3584
3584
  let a = t.clipboardData.getData("text");
3585
3585
  return n(a) ? !i.getNodes().some((e) => P(e) || O(e) && !e.isSimpleText()) && (e.dispatchCommand(Ka, {
3586
3586
  ...r,
@@ -4329,7 +4329,7 @@ function Os(e, t, n, r, i) {
4329
4329
  }
4330
4330
  //#endregion
4331
4331
  //#region src/nodes/MediaNode.tsx
4332
- var ks = jn.lazy(() => import("./MediaComponent-BTaaADsV.mjs"));
4332
+ var ks = jn.lazy(() => import("./MediaComponent-D-AMKM9e.mjs"));
4333
4333
  function As(e) {
4334
4334
  return e.parentElement != null && e.parentElement.tagName === "LI" && e.previousSibling === null && e.getAttribute("aria-roledescription") === "checkbox";
4335
4335
  }
@@ -1,6 +1,6 @@
1
1
  # BibleNote — development guide
2
2
 
3
- > Generated by `npm run pack` for **bible-note@0.5.0** from the hand-written topics in `knowledge/development/` and the package's own type declarations. Do not edit this file — edit the sources and re-run the pack. End-user help for the editor UI lives in `ui-rag.md` next to it.
3
+ > Generated by `npm run pack` for **bible-note@0.6.2** from the hand-written topics in `knowledge/development/` and the package's own type declarations. Do not edit this file — edit the sources and re-run the pack. End-user help for the editor UI lives in `ui-rag.md` next to it.
4
4
 
5
5
  ## Contents
6
6
 
@@ -233,11 +233,48 @@ tooltip when the element has no `title`; `shortcutKey` clicks the button from
233
233
  anywhere in the page and is shown in the tooltip. Give the button the
234
234
  `action-button` class to match the built-in ones.
235
235
 
236
+ ### Host buttons on the selected-text toolbar
237
+
238
+ The toolbar that pops up over selected text (Bold, Italic, …, Insert comment)
239
+ takes host buttons too. Here the editor renders the `<button>`, and `onClick`
240
+ receives the selection it was clicked on:
241
+
242
+ ```tsx
243
+ bibleNote.appendFloatingActionButton({
244
+ id: 'copy-selected-text',
245
+ description: 'Copy selected text', // tooltip and accessible name
246
+ children: <i className="bi bi-clipboard format" />,
247
+ onClick: async ({ selection }) => {
248
+ await navigator.clipboard.writeText(selection.text);
249
+ },
250
+ });
251
+ bibleNote.appendFloatingActionButton({
252
+ id: 'uppercase-selected-text',
253
+ description: 'Make selected text uppercase',
254
+ isHiddenWhenReadOnly: true,
255
+ children: <i className="bi bi-alphabet-uppercase format" />,
256
+ onClick: ({ selection, replaceText }) => {
257
+ replaceText(selection.text.toUpperCase());
258
+ },
259
+ });
260
+ bibleNote.removeFloatingActionButton('copy-selected-text');
261
+ ```
262
+
263
+ `selection` holds the plain `text`, the `html` Copy would produce, the `start`
264
+ and `end` points in document order, `isBackward`, and a copy of the DOM
265
+ `domRange`. `replaceText(text)` writes back into that captured range the way
266
+ `addText` inserts text, even after an `await`; it returns `false` and changes
267
+ nothing when the note is read-only or the range no longer holds
268
+ `selection.text`. `prepend…` places a button before Bold, `append…` after
269
+ Insert comment; re-adding an `id` replaces that button in place. The buttons
270
+ show in read-only mode unless `isHiddenWhenReadOnly` is set.
271
+
236
272
  ### Mounting without auto-mount
237
273
 
238
274
  `render` can be called any time after construction and again later — each call
239
275
  unmounts the previous root first. Call `unmount()` when the host view goes away;
240
- the instance keeps its props and footer buttons for the next `render`.
276
+ the instance keeps its props, footer buttons and selected-text toolbar
277
+ buttons for the next `render`.
241
278
 
242
279
  <a id="dev-datasets-and-lookup-managers"></a>
243
280
 
@@ -541,7 +578,10 @@ instance's `colorScheme` follows the Dark Mode switch.
541
578
  selected page size and opens the print dialog).
542
579
 
543
580
  Host buttons go before or after the built-in ones with
544
- `prependFooterActionButton` / `appendFooterActionButton`.
581
+ `prependFooterActionButton` / `appendFooterActionButton`. Buttons for the
582
+ toolbar over selected text use `prependFloatingActionButton` /
583
+ `appendFloatingActionButton`; their `onClick` receives the selection and a
584
+ `replaceText` that writes back into it.
545
585
 
546
586
  ### Electron: native file dialogs
547
587
 
@@ -596,7 +636,7 @@ This topic is for changing the editor itself, in its source repository.
596
636
  | -------------------------------------------- | -------------------------------------------------------------------------------------- |
597
637
  | `src/lib.ts` | the package's public entry — only re-exports; everything it reaches is library code |
598
638
  | `src/index.tsx` | the demo host (fetches datasets, wires every prop, mounts) — not part of the package |
599
- | `src/BibleNote.ts` | the `BibleNote` class: queued editor actions, footer buttons, colour scheme |
639
+ | `src/BibleNote.ts` | the `BibleNote` class: queued editor actions, host buttons, colour scheme |
600
640
  | `src/bibleNoteHelpers.tsx` | `BibleNoteProps`, the storage split, `renderEditor` |
601
641
  | `src/AppComp.tsx` | providers, storage hydration, the editor controller behind `BibleNote`'s methods |
602
642
  | `src/Editor.tsx` | the plugin tree, zoom and the full-view layout |
@@ -676,9 +716,9 @@ settings panel.
676
716
  | `AutocompletePlugin` | `src/plugins/AutocompletePlugin` | `isAutocomplete` |
677
717
  | `PageSizePreviewPlugin` | `src/plugins/PageSizePreviewPlugin` | always |
678
718
  | `PaperPageNavigationPlugin` | `src/plugins/PaperPageNavigationPlugin` | always |
679
- | `TableOfContentsPlugin` | `src/plugins/TableOfContentsPlugin` | `showTableOfContents` |
680
719
  | `ContextMenuPlugin` | `src/plugins/ContextMenuPlugin` | `shouldUseLexicalContextMenu` |
681
720
  | `SpecialTextPlugin` | `src/plugins/SpecialTextPlugin` | `shouldAllowHighlightingWithBrackets` |
721
+ | `ScrollToTopPlugin` | `src/plugins/ScrollToTopPlugin` | always |
682
722
  | `ActionsPlugin` | `src/plugins/ActionsPlugin` | always |
683
723
  | `TreeViewPlugin` | `src/plugins/TreeViewPlugin` | `showTreeView` |
684
724
 
@@ -960,6 +1000,45 @@ removeFooterActionButton(id: string): boolean;
960
1000
 
961
1001
  Removes the host footer button with this `id`; `false` when there was none.
962
1002
 
1003
+ ##### `appendFloatingActionButton()`
1004
+
1005
+ ```ts
1006
+ appendFloatingActionButton(actionButton: BibleNoteFloatingActionButton): void;
1007
+ ```
1008
+
1009
+ Adds a host button to the floating toolbar that appears over selected
1010
+ text, after its built-in buttons (after Insert comment). Its `onClick`
1011
+ receives the selection — text, HTML and range — and can replace the
1012
+ selected text. A button whose `id` is already present is replaced in
1013
+ place, keeping its position.
1014
+
1015
+ ##### `prependFloatingActionButton()`
1016
+
1017
+ ```ts
1018
+ prependFloatingActionButton(actionButton: BibleNoteFloatingActionButton): void;
1019
+ ```
1020
+
1021
+ Adds a host button to the floating toolbar before its built-in buttons
1022
+ (before Bold), ahead of any prepended earlier. A button whose `id` is
1023
+ already present is replaced in place, keeping its position.
1024
+
1025
+ ##### `getFloatingActionButton()`
1026
+
1027
+ ```ts
1028
+ getFloatingActionButton(id: string): BibleNoteFloatingActionButton | null;
1029
+ ```
1030
+
1031
+ The host floating toolbar button with this `id`, or `null`.
1032
+
1033
+ ##### `removeFloatingActionButton()`
1034
+
1035
+ ```ts
1036
+ removeFloatingActionButton(id: string): boolean;
1037
+ ```
1038
+
1039
+ Removes the host floating toolbar button with this `id`; `false` when there
1040
+ was none.
1041
+
963
1042
  ##### `searchText()`
964
1043
 
965
1044
  ```ts
@@ -986,8 +1065,8 @@ ever mounted once.
986
1065
  unmount(): void;
987
1066
  ```
988
1067
 
989
- Unmounts the editor. The instance keeps its props and footer buttons and
990
- can be rendered again.
1068
+ Unmounts the editor. The instance keeps its props, footer buttons and
1069
+ floating toolbar buttons and can be rendered again.
991
1070
 
992
1071
  <a id="api-locationslookupmanager"></a>
993
1072
 
@@ -1444,6 +1523,64 @@ The editor's two colour schemes.
1444
1523
  type BibleNoteColorScheme = 'dark' | 'light';
1445
1524
  ```
1446
1525
 
1526
+ <a id="api-biblenotefloatingactionbutton"></a>
1527
+
1528
+ #### `BibleNoteFloatingActionButton`
1529
+
1530
+ A host-supplied button in the floating toolbar that appears over selected
1531
+ text — the bar with Bold, Italic, Underline, … and Insert comment.
1532
+
1533
+ Unlike a footer button, the editor renders the `<button>` itself, so it
1534
+ matches the built-in ones; `children` is only what goes inside it.
1535
+
1536
+ | Property | Type | Required | Description |
1537
+ | --- | --- | --- | --- |
1538
+ | `id` | `string` | yes | Unique per editor; adding a button with an existing id replaces it in place. |
1539
+ | `description` | `string` | yes | What the button does: its tooltip and its accessible name. |
1540
+ | `children` | `ReactNode` | yes | The content of the button, normally a Bootstrap icon given the `format` class so it is sized and tinted like the built-in icons: `<i className="bi bi-clipboard format" />`. |
1541
+ | `onClick` | `(event: BibleNoteFloatingActionButtonClickEvent) => void` | yes | Called on click with the selection the toolbar is showing for. Not called when the selection has collapsed to a caret by the time of the click. |
1542
+ | `isHiddenWhenReadOnly` | `boolean` | no | `true` shows the button only while the note can be edited, like the built-in formatting buttons. By default it shows in read-only mode too, like Insert comment — right for actions that only read the selection. |
1543
+
1544
+ <a id="api-biblenotefloatingactionbuttonclickevent"></a>
1545
+
1546
+ #### `BibleNoteFloatingActionButtonClickEvent`
1547
+
1548
+ What a floating action button's `onClick` receives.
1549
+
1550
+ ```ts
1551
+ type BibleNoteFloatingActionButtonClickEvent = Readonly<{
1552
+ /** The `id` of the button that was clicked. */
1553
+ id: string;
1554
+ /** The selection the button was clicked on. */
1555
+ selection: BibleNoteTextSelection;
1556
+ /**
1557
+ * Replaces the text of the captured selection with `text`, inserted the way
1558
+ * `BibleNote.addText` inserts it: as plain text, as if pasted, so the paste
1559
+ * rules apply and `\n` starts a new paragraph. An empty string deletes the
1560
+ * selected text. The selection is restored from `selection.start` and
1561
+ * `selection.end` first, so this still works after the user has clicked
1562
+ * elsewhere or after an `await`.
1563
+ *
1564
+ * Returns `false`, and changes nothing, when the note is read-only or when
1565
+ * that range no longer holds `selection.text` — because the note was edited
1566
+ * since the click, or the text was already replaced.
1567
+ */
1568
+ replaceText: (text: string) => boolean;
1569
+ /** The React click event of the button. */
1570
+ mouseEvent: ReactMouseEvent<HTMLButtonElement>;
1571
+ }>;
1572
+ ```
1573
+
1574
+ <a id="api-biblenotefloatingactionbuttons"></a>
1575
+
1576
+ #### `BibleNoteFloatingActionButtons`
1577
+
1578
+ The host floating toolbar buttons on each side of the built-in ones, in order.
1579
+
1580
+ ```ts
1581
+ type BibleNoteFloatingActionButtons = PlacedActionButtons<BibleNoteFloatingActionButton>;
1582
+ ```
1583
+
1447
1584
  <a id="api-biblenotefooteractionbutton"></a>
1448
1585
 
1449
1586
  #### `BibleNoteFooterActionButton`
@@ -1520,6 +1657,34 @@ Options for `BibleNote#render`.
1520
1657
  | `settings` | `ReactNode` | no | The settings panel to mount, normally `<BibleNoteSettings />`. Omit it and the editor has no settings panel. |
1521
1658
  | `settingsContainerElement` | `Element \| DocumentFragment` | no | Where to portal the `settings` panel. Without it the panel renders inside the editor's own layout. |
1522
1659
 
1660
+ <a id="api-biblenoteselectionpoint"></a>
1661
+
1662
+ #### `BibleNoteSelectionPoint`
1663
+
1664
+ A position in the open note, addressed the way the editor addresses it: a
1665
+ node, and an offset inside that node.
1666
+
1667
+ ```ts
1668
+ type BibleNoteSelectionPoint = Readonly<{
1669
+ /**
1670
+ * The editor's key for the node the point sits in. Keys identify nodes of
1671
+ * the note as it is open right now: they are not saved with `content`, and
1672
+ * they change when the note is loaded again.
1673
+ */
1674
+ key: string;
1675
+ /**
1676
+ * For a `'text'` point, the character offset inside that text node. For an
1677
+ * `'element'` point, the index of the child the point sits before.
1678
+ */
1679
+ offset: number;
1680
+ /**
1681
+ * `'text'` when `key` names a text node; `'element'` when it names an element
1682
+ * node such as a paragraph or a list item.
1683
+ */
1684
+ type: 'text' | 'element';
1685
+ }>;
1686
+ ```
1687
+
1523
1688
  <a id="api-biblenotesettingsprops"></a>
1524
1689
 
1525
1690
  #### `BibleNoteSettingsProps`
@@ -1546,6 +1711,45 @@ first renders; writes are fire-and-forget.
1546
1711
  | `getSetting` | `getSetting<T = unknown>(key: string): Promise<T \| null>` | yes | The value stored under `key`, or `null` when there is none. |
1547
1712
  | `deleteSetting` | `deleteSetting(key: string): Promise<void>` | yes | Removes `key`. |
1548
1713
 
1714
+ <a id="api-biblenotetextselection"></a>
1715
+
1716
+ #### `BibleNoteTextSelection`
1717
+
1718
+ The text selection a floating action button was clicked on. It is a snapshot
1719
+ taken at the click: it does not follow later edits or selection changes.
1720
+
1721
+ ```ts
1722
+ type BibleNoteTextSelection = Readonly<{
1723
+ /**
1724
+ * The selected text as plain text — what Copy puts on the clipboard as
1725
+ * `text/plain`. Paragraphs are separated by `\n`. Never empty: the toolbar
1726
+ * only appears over a selection that contains text.
1727
+ */
1728
+ text: string;
1729
+ /**
1730
+ * The selected content as HTML, formatting included — what Copy puts on the
1731
+ * clipboard as `text/html`.
1732
+ */
1733
+ html: string;
1734
+ /** Where the selection begins, in document order. */
1735
+ start: BibleNoteSelectionPoint;
1736
+ /** Where the selection ends, in document order. */
1737
+ end: BibleNoteSelectionPoint;
1738
+ /**
1739
+ * `true` when the user selected from the end back toward the start, so the
1740
+ * caret sits at `start`; `false` when the caret sits at `end`.
1741
+ */
1742
+ isBackward: boolean;
1743
+ /**
1744
+ * A copy of the browser's DOM `Range` for the selection, or `null` when the
1745
+ * browser had no selection inside the editor at the click. Use it to measure
1746
+ * the text on screen (`domRange.getBoundingClientRect()`); it stops matching
1747
+ * the page once the note changes.
1748
+ */
1749
+ domRange: Range | null;
1750
+ }>;
1751
+ ```
1752
+
1549
1753
  <a id="api-extrafontfamilyoption"></a>
1550
1754
 
1551
1755
  #### `ExtraFontFamilyOption`
@@ -1925,3 +2129,14 @@ A Bible verse as the host renders it: a title line plus the full text.
1925
2129
  | `title` | `string` | yes | The verse reference as displayed, e.g. `(KJV) Genesis 1:1`. |
1926
2130
  | `fullText` | `string` | yes | The title line followed by the verse lines, in the same shape the editor accepts when Bible text is pasted after `^`: `(KJV) Genesis 1:1\n(1): In the beginning…`. |
1927
2131
  | `style` | `CSSProperties` | no | Extra CSS for this verse's text, e.g. a font for a non-Latin version. |
2132
+
2133
+ #### `PlacedActionButtons`
2134
+
2135
+ Host buttons on each side of an editor's built-in buttons, in order.
2136
+
2137
+ ```ts
2138
+ type PlacedActionButtons<T> = Readonly<{
2139
+ before: ReadonlyArray<T>;
2140
+ after: ReadonlyArray<T>;
2141
+ }>;
2142
+ ```