bible-note 0.4.7 → 0.6.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/README.md CHANGED
@@ -1,253 +1,349 @@
1
- # Bible Note
2
-
3
- A Bible study tool for taking notes and organizing your thoughts.
4
-
5
- It extends the [Lexical playground](https://playground.lexical.dev/): the
6
- playground editor packaged as a drop-in component and built out with
7
- Bible-specific features — name and location lookup, sticky notes, footer action
8
- buttons and pluggable storage. The MIT license and Meta's copyright carry over
9
- from upstream Lexical.
10
-
11
- MIT license
12
-
13
- ```bash
14
- npm install bible-note react react-dom bootstrap bootstrap-icons
15
- ```
16
-
17
- The peer dependencies are React ^19.2.8, React DOM, and Bootstrap ^5.3.8 with
18
- its icon font. React has to be the host's copy so there is only one of it;
19
- Bootstrap and bootstrap-icons are global stylesheets the host imports itself, so
20
- it keeps control of cascade order and can theme or pin its own version.
21
- Everything else the editor needs — Lexical, Excalidraw, KaTeX, Shiki — is
22
- bundled.
23
-
24
- ### Releasing to npm
25
-
26
- For maintainers, from a clean `main`:
27
-
28
- ```bash
29
- npm test
30
- npm pack --dry-run # check which files go in the package
31
- npm whoami # run `npm login` if this fails
32
- npm version patch --tag-version-prefix="" # or minor / major
33
- npm publish
34
- git push origin main --follow-tags
35
- npm view bible-note version # confirm the new version is live
36
- ```
37
-
38
- ## Import
39
-
40
- ```js
41
- const { BibleNote } = require("bible-note");
42
- // or module
43
- import { BibleNote } from "bible-note";
44
- ```
45
-
46
- ```typescript
47
- import { BibleNote } from "bible-note";
48
- import type {
49
- BibleNoteFooterActionButton,
50
- FilePathResolver,
51
- FileRevealer,
52
- ExtraFontFamilyOption,
53
- MentionNameMatch,
54
- MentionLocationMatch,
55
- } from "bible-note";
56
- ```
57
-
58
- ## Stylesheets
59
-
60
- Three, in this order — Bootstrap first, then the icon font, then the editor's
61
- own stylesheet last so its overrides win:
62
-
63
- ```js
64
- import "bootstrap/dist/css/bootstrap.min.css";
65
- import "bootstrap-icons/font/bootstrap-icons.css";
66
- import "bible-note/styles.css";
67
- ```
68
-
69
- Skipping the first two does not throw — it renders a broken editor: the toolbar
70
- and footer lose their layout, and with no `@font-face` for the icon font every
71
- `bi bi-*` glyph falls back to tofu. `bible-note/styles.css` carries the
72
- editor, KaTeX and Excalidraw rules, and needs no configuration.
73
-
74
- ## Usage
75
-
76
- ```typescript
77
- import {
78
- BibleNote,
79
- createBrowserStorageManager,
80
- LocationsLookupManager,
81
- NamesLookupManager,
82
- } from "bible-note";
83
- import "bootstrap/dist/css/bootstrap.min.css";
84
- import "bootstrap-icons/font/bootstrap-icons.css";
85
- import "bible-note/styles.css";
86
-
87
- // fromRawDataset takes the generated dataset files exactly as fetched. Use the
88
- // plain constructors when you already hold MentionNameMatch/MentionLocationMatch
89
- // records.
90
- const namesLookupManager = NamesLookupManager.fromRawDataset(
91
- { en: namesMap },
92
- "en",
93
- );
94
- const locationsLookupManager = LocationsLookupManager.fromRawDataset(
95
- { en: locationsMap },
96
- "en",
97
- );
98
-
99
- const bibleNote = new BibleNote({
100
- namesLookupManager,
101
- locationsLookupManager,
102
- getLangCode: (text) => (/[\u1780-\u17FF]/u.test(text) ? "km" : "en"),
103
- editorExtraFontFamilies: [],
104
- stickyNoteExtraFontFamilies: [],
105
- storageManager: createBrowserStorageManager(),
106
- loadData: () => localStorage.getItem("bible-note") ?? "",
107
- saveData: (data) => localStorage.setItem("bible-note", data),
108
- });
109
-
110
- bibleNote.render(document.getElementById("root")!);
111
- ```
112
-
113
- ### Microsoft Word round trips
114
-
115
- The editor footer has separate Word import and export buttons. Export creates a
116
- standard `.docx` that opens in Microsoft Word and includes a private BibleNote
117
- round-trip copy of the editor state. Importing that file back restores the full
118
- editable document, including editor-specific content that Word cannot represent
119
- natively. If Word has removed that private data, or the file came from another
120
- application, BibleNote falls back to Word-content conversion and preserves the
121
- document's text, headings, emphasis, lists, tables, links, and embedded images;
122
- Word-only layout details may be simplified.
123
-
124
- Because a Word document has no hover cards, the export spells out what they
125
- show. Every person, place and Bible-verse mention links to an entry in a
126
- **References** appendix after the note: the name or location record from
127
- `namesMap` / `locationsMap` (description, family, locations, links,
128
- coordinates) and the verse text, with verse references resolved through
129
- `shortToVerseData` and related people and places through
130
- `verseFullTextToListShorts`. Each mention also carries a short screen tip.
131
- Equations become editable Word equations. Sticky notes, drawings and embed
132
- thumbnails are packaged as pictures. Checklists, collapsibles, column layouts,
133
- highlights and code blocks are rewritten into forms Word renders. Re-importing
134
- the file leaves the appendix out.
135
-
136
- The existing Import and Export buttons remain the lossless JSON backup path.
137
- In the Electron app, both Word and lossless editor files use native Open and
138
- Save dialogs; browser builds continue to use the browser picker and download.
139
-
140
- `namesMap` and `locationsMap` are the host's own datasets — the package bundles
141
- none of its own.
142
-
143
- The two managers own every search, ranking and index the built-in mention and
144
- lookup UI uses, and they carry no editor dependency. To build your own mention
145
- or lookup UI, construct them and call their methods directly — no `BibleNote`
146
- import required:
147
-
148
- ```typescript
149
- import { NamesLookupManager } from "bible-note";
150
-
151
- const names = NamesLookupManager.fromRawDataset({ en: namesMap }, "en");
152
-
153
- names.searchNames("Mos", { limit: 20 }); // ranked MentionNameMatch[]
154
- names.searchNamesPagination({ query: "Mos", page: 2, pageSize: 20 });
155
- names.getRecordById("name-moses");
156
- names.searchByShortVerse("EXO 6:23"); // the names that verse mentions
157
- names.nameTypes; // types present in the data, most common first
158
- ```
159
-
160
- ### Translated datasets
161
-
162
- A record in a translated dataset carries the KJV English name in `kjvName`
163
- alongside its own translated `name`. The managers index both, so the same
164
- manager answers a query in either language, ranking an English hit exactly the
165
- way it ranks a native-language one:
166
-
167
- ```typescript
168
- const names = NamesLookupManager.fromRawDataset({ km: khmerNamesMap }, "km");
169
-
170
- names.searchNames("Genesis"); // finds the record named "លោកុប្បត្តិ"
171
- names.searchNames("លោកុប្បត្តិ"); // and so does its own name
172
- ```
173
-
174
- The built-in UI shows the English name beside the translated one — in the
175
- lookup panel, the mention typeahead, the hover card and the advanced panel.
176
- `getMentionKjvName(record)` is the rule it follows: the English name, or `null`
177
- when there is nothing to add (an untranslated dataset, or a record whose
178
- translated name is the English one anyway).
179
-
180
- ```typescript
181
- import { getMentionKjvName } from "bible-note";
182
-
183
- getMentionKjvName(record); // "Genesis" | null
184
- ```
185
-
186
- An untranslated dataset such as the KJV one carries no `kjvName` at all, and
187
- everything above is a no-op for it.
188
-
189
- ### Styling a dataset
190
-
191
- Both managers take an optional third argument: a plain CSS style object, merged
192
- into every surface the built-in UI renders that dataset on — the mention
193
- typeahead popup, the hover card, the advanced panel, and the lookup panel's list
194
- and search box. A dataset in a script the editor's own font does not cover can
195
- therefore carry its own `fontFamily`:
196
-
197
- ```typescript
198
- const locations = LocationsLookupManager.fromRawDataset(
199
- { km: khmerLocationsMap },
200
- "km",
201
- { fontFamily: "Battambang, serif" },
202
- );
203
-
204
- locations.style; // read it back; assignable, too
205
- ```
206
-
207
- The two managers are styled independently, so a Khmer location dataset can sit
208
- beside an English name one. Anything a React `style` prop accepts works, but a
209
- hover card's own positioning always wins over the style. Plugins read `style` as
210
- they render, so replacing it after the editor is mounted only shows up on the
211
- next render.
212
-
213
- `BibleNote.getAllShortVersesFromText` bridges the two: it reads every verse a
214
- note refers to — Bible verse mentions and references written in the prose alike
215
- — and returns them as the short keys the managers index by. It is static, so it
216
- also works on plain text such as a pasted passage:
217
-
218
- ```typescript
219
- BibleNote.getAllShortVersesFromText(bibleNote.content);
220
- // ["GEN 1:1", "GEN 1:2", "GEN 1:3", "JHN 3:16"]
221
- ```
222
-
223
- References are returned in document order without duplicates. A range inside
224
- one chapter is expanded verse by verse; a range crossing a chapter boundary
225
- (`Genesis 1:31-2:3`) keeps only its two endpoints, since the package bundles no
226
- per-chapter verse counts.
227
-
228
- ## Exports
229
-
230
- | Export | Kind | Purpose |
231
- | --- | --- | --- |
232
- | `BibleNote` | class | The editor: `render`, `unmount`, `addText`, `searchText`, `content`, `isReadOnly`, footer action buttons, colour scheme, and the static `getAllShortVersesFromText` |
233
- | `BibleNoteSettings` | component | Settings panel, passed through `render(el, { settings })` |
234
- | `createBrowserStorageManager` | function | `localStorage`-backed `BibleNoteStorageManager` |
235
- | `applyBibleNoteColorScheme` / `clearBibleNoteColorScheme` | function | Toggle the `light`/`dark` body classes |
236
- | `EDITOR_STATE_LOCAL_STORAGE_KEY` | constant | Storage key the editor state is saved under |
237
- | `BibleNoteProps`, `BibleNoteRenderOptions` | type | Constructor and `render` options |
238
- | `BibleNoteFooterActionButton`, `BibleNoteFooterActionButtons` | type | Footer action button descriptors |
239
- | `NamesLookupManager`, `LocationsLookupManager` | class | Own the name/location datasets: ranked search, id/name lookup, pagination, verse lookup |
240
- | `parseMentionNameMatch(es)`, `parseMentionLocationMatch(es)`, `getLookupRecordValues`, `normalizeMentionNameType` | function | Dataset normalization helpers the managers use |
241
- | `getMentionKjvName` | function | The KJV English name to show beside a translated record's name, or `null` |
242
- | `MentionNameMatch`, `MentionLocationMatch`, `MentionNamePreview`, `MentionLocationPreview` | type | Name/location record shapes |
243
- | `NamesLookupManagerDataMap`, `LocationsLookupManagerDataMap`, `LookupPaginationResult` | type | Manager constructor input and search results |
244
- | `LookupManagerStyle` | type | The extra CSS style a manager renders its dataset with |
245
- | `FilePathResolver`, `FileRevealer`, `FilePathResolverContext` | type | Media file path hooks |
246
- | `ExtraFontFamilyOption`, `FontFamilyOption` | type | Extra font families for the editor and sticky notes |
247
- | `BibleNoteStorageManager` | type | Storage adapter contract |
248
- | `BibleNoteColorScheme` | type | `'light' | 'dark'` |
249
-
250
- `dist/` and `types/` here are generated by `npm run pack` from the sources under
251
- `src/` — edit those, not the build output. This file, `package.json` and
252
- `LICENSE` are maintained by hand and are the only files in this folder that git
253
- tracks.
1
+ # Bible Note
2
+
3
+ A Bible study tool for taking notes and organizing your thoughts.
4
+
5
+ It extends the [Lexical playground](https://playground.lexical.dev/): the
6
+ playground editor packaged as a drop-in component and built out with
7
+ Bible-specific features — name and location lookup, sticky notes, footer action
8
+ buttons and pluggable storage. The MIT license and Meta's copyright carry over
9
+ from upstream Lexical.
10
+
11
+ MIT license
12
+
13
+ ```bash
14
+ npm install bible-note react react-dom bootstrap bootstrap-icons
15
+ ```
16
+
17
+ The peer dependencies are React ^19.2.8, React DOM, and Bootstrap ^5.3.8 with
18
+ its icon font. React has to be the host's copy so there is only one of it;
19
+ Bootstrap and bootstrap-icons are global stylesheets the host imports itself, so
20
+ it keeps control of cascade order and can theme or pin its own version.
21
+ Everything else the editor needs — Lexical, Excalidraw, KaTeX, Shiki — is
22
+ bundled.
23
+
24
+ ### Releasing to npm
25
+
26
+ For maintainers, from a clean `main`:
27
+
28
+ ```bash
29
+ npm test
30
+ npm pack --dry-run # check which files go in the package
31
+ npm whoami # run `npm login` if this fails
32
+ npm version patch --tag-version-prefix="" # or minor / major
33
+ npm publish
34
+ git push origin main --follow-tags
35
+ npm view bible-note version # confirm the new version is live
36
+ ```
37
+
38
+ ## Import
39
+
40
+ ```js
41
+ const { BibleNote } = require("bible-note");
42
+ // or module
43
+ import { BibleNote } from "bible-note";
44
+ ```
45
+
46
+ ```typescript
47
+ import { BibleNote } from "bible-note";
48
+ import type {
49
+ BibleNoteFooterActionButton,
50
+ FilePathResolver,
51
+ FileRevealer,
52
+ ExtraFontFamilyOption,
53
+ MentionNameMatch,
54
+ MentionLocationMatch,
55
+ } from "bible-note";
56
+ ```
57
+
58
+ ## Stylesheets
59
+
60
+ Three, in this order — Bootstrap first, then the icon font, then the editor's
61
+ own stylesheet last so its overrides win:
62
+
63
+ ```js
64
+ import "bootstrap/dist/css/bootstrap.min.css";
65
+ import "bootstrap-icons/font/bootstrap-icons.css";
66
+ import "bible-note/styles.css";
67
+ ```
68
+
69
+ Skipping the first two does not throw — it renders a broken editor: the toolbar
70
+ and footer lose their layout, and with no `@font-face` for the icon font every
71
+ `bi bi-*` glyph falls back to tofu. `bible-note/styles.css` carries the
72
+ editor, KaTeX and Excalidraw rules, and needs no configuration.
73
+
74
+ ## Usage
75
+
76
+ ```typescript
77
+ import {
78
+ BibleNote,
79
+ createBrowserStorageManager,
80
+ LocationsLookupManager,
81
+ NamesLookupManager,
82
+ } from "bible-note";
83
+ import "bootstrap/dist/css/bootstrap.min.css";
84
+ import "bootstrap-icons/font/bootstrap-icons.css";
85
+ import "bible-note/styles.css";
86
+
87
+ // fromRawDataset takes the generated dataset files exactly as fetched. Use the
88
+ // plain constructors when you already hold MentionNameMatch/MentionLocationMatch
89
+ // records.
90
+ const namesLookupManager = NamesLookupManager.fromRawDataset(
91
+ { en: namesMap },
92
+ "en",
93
+ );
94
+ const locationsLookupManager = LocationsLookupManager.fromRawDataset(
95
+ { en: locationsMap },
96
+ "en",
97
+ );
98
+
99
+ const bibleNote = new BibleNote({
100
+ namesLookupManager,
101
+ locationsLookupManager,
102
+ getLangCode: (text) => (/[\u1780-\u17FF]/u.test(text) ? "km" : "en"),
103
+ editorExtraFontFamilies: [],
104
+ stickyNoteExtraFontFamilies: [],
105
+ storageManager: createBrowserStorageManager(),
106
+ loadData: () => localStorage.getItem("bible-note") ?? "",
107
+ saveData: (data) => localStorage.setItem("bible-note", data),
108
+ });
109
+
110
+ bibleNote.render(document.getElementById("root")!);
111
+ ```
112
+
113
+ ### Buttons on the selected-text toolbar
114
+
115
+ Selecting text in the note pops up a small toolbar over it — Bold, Italic,
116
+ Underline, …, Insert comment. A host adds its own buttons to it with
117
+ `appendFloatingActionButton` (after the built-in buttons) or
118
+ `prependFloatingActionButton` (before them). The editor renders the `<button>`
119
+ itself, so it matches the built-in ones: `children` is only its content, and
120
+ `description` is its tooltip and accessible name. Give a Bootstrap icon the
121
+ `format` class to size and tint it like the others.
122
+
123
+ ```tsx
124
+ bibleNote.appendFloatingActionButton({
125
+ id: "copy-selected-text",
126
+ description: "Copy selected text",
127
+ children: <i className="bi bi-clipboard format" />,
128
+ onClick: async ({ selection }) => {
129
+ await navigator.clipboard.writeText(selection.text);
130
+ },
131
+ });
132
+
133
+ bibleNote.appendFloatingActionButton({
134
+ id: "uppercase-selected-text",
135
+ description: "Make selected text uppercase",
136
+ isHiddenWhenReadOnly: true,
137
+ children: <i className="bi bi-alphabet-uppercase format" />,
138
+ onClick: ({ selection, replaceText }) => {
139
+ replaceText(selection.text.toUpperCase());
140
+ },
141
+ });
142
+
143
+ bibleNote.getFloatingActionButton("copy-selected-text"); // the descriptor, or null
144
+ bibleNote.removeFloatingActionButton("copy-selected-text"); // false when absent
145
+ ```
146
+
147
+ `onClick` receives a `BibleNoteFloatingActionButtonClickEvent`, captured at the
148
+ click:
149
+
150
+ | Field | What it holds |
151
+ | --- | --- |
152
+ | `id` | The clicked button's `id` |
153
+ | `selection.text` | The selected text as plain text, paragraphs separated by `\n` — what Copy puts on the clipboard as `text/plain` |
154
+ | `selection.html` | The selection as HTML, formatting included — what Copy puts on the clipboard as `text/html` |
155
+ | `selection.start`, `selection.end` | The selection's two ends in document order, each `{ key, offset, type }`: the editor's node key, the character offset in a `'text'` node or the child index in an `'element'` node. Keys identify nodes of the note as it is open now; they are not saved with `content` |
156
+ | `selection.isBackward` | `true` when the user selected from the end back to the start |
157
+ | `selection.domRange` | A copy of the browser's DOM `Range` for the selection, or `null`. Measure the text on screen with `domRange.getBoundingClientRect()`; it stops matching once the note changes |
158
+ | `replaceText(text)` | Replaces the captured range with `text`, inserted the way `addText` inserts it — plain text, paste rules applied, `\n` starts a paragraph; `""` deletes the selected text. It restores the range first, so it works after an `await` or after the user clicked elsewhere. Returns `false`, changing nothing, when the note is read-only or the range no longer holds `selection.text` |
159
+ | `mouseEvent` | The React click event |
160
+
161
+ Buttons show in a read-only note too, as Insert comment does, unless
162
+ `isHiddenWhenReadOnly` is set. Ids are unique per editor: re-adding an `id`
163
+ replaces that button in place. Like footer buttons, they can be added before
164
+ `render` and are kept across `unmount`. Unlike footer buttons, they take no
165
+ `shortcutKey`.
166
+
167
+ ### Microsoft Word round trips
168
+
169
+ The editor footer has separate Word import and export buttons. Export creates a
170
+ standard `.docx` that opens in Microsoft Word and includes a private BibleNote
171
+ round-trip copy of the editor state. Importing that file back restores the full
172
+ editable document, including editor-specific content that Word cannot represent
173
+ natively. If Word has removed that private data, or the file came from another
174
+ application, BibleNote falls back to Word-content conversion and preserves the
175
+ document's text, headings, emphasis, lists, tables, links, and embedded images;
176
+ Word-only layout details may be simplified.
177
+
178
+ Because a Word document has no hover cards, the export spells out what they
179
+ show. Every person, place and Bible-verse mention links to an entry in a
180
+ **References** appendix after the note: the name or location record from
181
+ `namesMap` / `locationsMap` (description, family, locations, links,
182
+ coordinates) and the verse text, with verse references resolved through
183
+ `shortToVerseData` and related people and places through
184
+ `verseFullTextToListShorts`. Each mention also carries a short screen tip.
185
+ Equations become editable Word equations. Sticky notes, drawings and embed
186
+ thumbnails are packaged as pictures. Checklists, collapsibles, column layouts,
187
+ highlights and code blocks are rewritten into forms Word renders. Re-importing
188
+ the file leaves the appendix out.
189
+
190
+ The existing Import and Export buttons remain the lossless JSON backup path.
191
+ In the Electron app, both Word and lossless editor files use native Open and
192
+ Save dialogs; browser builds continue to use the browser picker and download.
193
+
194
+ `namesMap` and `locationsMap` are the host's own datasets — the package bundles
195
+ none of its own.
196
+
197
+ The two managers own every search, ranking and index the built-in mention and
198
+ lookup UI uses, and they carry no editor dependency. To build your own mention
199
+ or lookup UI, construct them and call their methods directly — no `BibleNote`
200
+ import required:
201
+
202
+ ```typescript
203
+ import { NamesLookupManager } from "bible-note";
204
+
205
+ const names = NamesLookupManager.fromRawDataset({ en: namesMap }, "en");
206
+
207
+ names.searchNames("Mos", { limit: 20 }); // ranked MentionNameMatch[]
208
+ names.searchNamesPagination({ query: "Mos", page: 2, pageSize: 20 });
209
+ names.getRecordById("name-moses");
210
+ names.searchByShortVerse("EXO 6:23"); // the names that verse mentions
211
+ names.nameTypes; // types present in the data, most common first
212
+ ```
213
+
214
+ ### Translated datasets
215
+
216
+ A record in a translated dataset carries the KJV English name in `kjvName`
217
+ alongside its own translated `name`. The managers index both, so the same
218
+ manager answers a query in either language, ranking an English hit exactly the
219
+ way it ranks a native-language one:
220
+
221
+ ```typescript
222
+ const names = NamesLookupManager.fromRawDataset({ km: khmerNamesMap }, "km");
223
+
224
+ names.searchNames("Genesis"); // finds the record named "លោកុប្បត្តិ"
225
+ names.searchNames("លោកុប្បត្តិ"); // and so does its own name
226
+ ```
227
+
228
+ The built-in UI shows the English name beside the translated one — in the
229
+ lookup panel, the mention typeahead, the hover card and the advanced panel.
230
+ `getMentionKjvName(record)` is the rule it follows: the English name, or `null`
231
+ when there is nothing to add (an untranslated dataset, or a record whose
232
+ translated name is the English one anyway).
233
+
234
+ ```typescript
235
+ import { getMentionKjvName } from "bible-note";
236
+
237
+ getMentionKjvName(record); // "Genesis" | null
238
+ ```
239
+
240
+ An untranslated dataset such as the KJV one carries no `kjvName` at all, and
241
+ everything above is a no-op for it.
242
+
243
+ ### Styling a dataset
244
+
245
+ Both managers take an optional third argument: a plain CSS style object, merged
246
+ into every surface the built-in UI renders that dataset on — the mention
247
+ typeahead popup, the hover card, the advanced panel, and the lookup panel's list
248
+ and search box. A dataset in a script the editor's own font does not cover can
249
+ therefore carry its own `fontFamily`:
250
+
251
+ ```typescript
252
+ const locations = LocationsLookupManager.fromRawDataset(
253
+ { km: khmerLocationsMap },
254
+ "km",
255
+ { fontFamily: "Battambang, serif" },
256
+ );
257
+
258
+ locations.style; // read it back; assignable, too
259
+ ```
260
+
261
+ The two managers are styled independently, so a Khmer location dataset can sit
262
+ beside an English name one. Anything a React `style` prop accepts works, but a
263
+ hover card's own positioning always wins over the style. Plugins read `style` as
264
+ they render, so replacing it after the editor is mounted only shows up on the
265
+ next render.
266
+
267
+ `BibleNote.getAllShortVersesFromText` bridges the two: it reads every verse a
268
+ note refers to — Bible verse mentions and references written in the prose alike
269
+ — and returns them as the short keys the managers index by. It is static, so it
270
+ also works on plain text such as a pasted passage:
271
+
272
+ ```typescript
273
+ BibleNote.getAllShortVersesFromText(bibleNote.content);
274
+ // ["GEN 1:1", "GEN 1:2", "GEN 1:3", "JHN 3:16"]
275
+ ```
276
+
277
+ References are returned in document order without duplicates. A range inside
278
+ one chapter is expanded verse by verse; a range crossing a chapter boundary
279
+ (`Genesis 1:31-2:3`) keeps only its two endpoints, since the package bundles no
280
+ per-chapter verse counts.
281
+
282
+ ## Exports
283
+
284
+ | Export | Kind | Purpose |
285
+ | --- | --- | --- |
286
+ | `BibleNote` | class | The editor: `render`, `unmount`, `addText`, `searchText`, `content`, `isReadOnly`, footer action buttons, selected-text toolbar buttons, colour scheme, and the static `getAllShortVersesFromText` |
287
+ | `BibleNoteSettings` | component | Settings panel, passed through `render(el, { settings })` |
288
+ | `createBrowserStorageManager` | function | `localStorage`-backed `BibleNoteStorageManager` |
289
+ | `applyBibleNoteColorScheme` / `clearBibleNoteColorScheme` | function | Toggle the `light`/`dark` body classes |
290
+ | `EDITOR_STATE_LOCAL_STORAGE_KEY` | constant | Storage key the editor state is saved under |
291
+ | `BibleNoteProps`, `BibleNoteRenderOptions` | type | Constructor and `render` options |
292
+ | `BibleNoteFooterActionButton`, `BibleNoteFooterActionButtons` | type | Footer action button descriptors |
293
+ | `BibleNoteFloatingActionButton`, `BibleNoteFloatingActionButtons` | type | Selected-text toolbar button descriptors |
294
+ | `BibleNoteFloatingActionButtonClickEvent`, `BibleNoteTextSelection`, `BibleNoteSelectionPoint` | type | What a selected-text toolbar button's `onClick` receives: the selection's text, HTML and range, and `replaceText` |
295
+ | `NamesLookupManager`, `LocationsLookupManager` | class | Own the name/location datasets: ranked search, id/name lookup, pagination, verse lookup |
296
+ | `parseMentionNameMatch(es)`, `parseMentionLocationMatch(es)`, `getLookupRecordValues`, `normalizeMentionNameType` | function | Dataset normalization helpers the managers use |
297
+ | `getMentionKjvName` | function | The KJV English name to show beside a translated record's name, or `null` |
298
+ | `MentionNameMatch`, `MentionLocationMatch`, `MentionNamePreview`, `MentionLocationPreview` | type | Name/location record shapes |
299
+ | `NamesLookupManagerDataMap`, `LocationsLookupManagerDataMap`, `LookupPaginationResult` | type | Manager constructor input and search results |
300
+ | `LookupManagerStyle` | type | The extra CSS style a manager renders its dataset with |
301
+ | `FilePathResolver`, `FileRevealer`, `FilePathResolverContext` | type | Media file path hooks |
302
+ | `ExtraFontFamilyOption`, `FontFamilyOption` | type | Extra font families for the editor and sticky notes |
303
+ | `BibleNoteStorageManager` | type | Storage adapter contract |
304
+ | `BibleNoteColorScheme` | type | `'light' | 'dark'` |
305
+
306
+ ## Knowledge files
307
+
308
+ The package ships two markdown files describing itself, generated on every
309
+ build:
310
+
311
+ | File | For |
312
+ | --- | --- |
313
+ | `bible-note/knowledge/development.md` | Developers: architecture, installation, every prop and hook grouped by feature, datasets and lookup managers, persistence, Electron integration, working on the editor, and a full API reference generated from the type declarations |
314
+ | `bible-note/knowledge/ui-rag.md` | A retrieval (RAG) pipeline behind an in-app assistant: end-user help for the editor UI — formatting, the slash menu, mentions, Bible verses, the lookup panel, inserting content, shortcuts, import/export, comments, settings |
315
+
316
+ Both are exposed through `exports`, so they resolve like any other subpath:
317
+
318
+ ```js
319
+ import { readFile } from "node:fs/promises";
320
+ import { fileURLToPath } from "node:url";
321
+
322
+ const ragPath = fileURLToPath(import.meta.resolve("bible-note/knowledge/ui-rag.md"));
323
+ // CommonJS: require.resolve("bible-note/knowledge/ui-rag.md")
324
+ const corpus = await readFile(ragPath, "utf8");
325
+ ```
326
+
327
+ `ui-rag.md` is pre-chunked. It opens with YAML front matter (`package`,
328
+ `version`, `chunks`), and every `## ` heading starts one self-contained chunk.
329
+ The heading is a breadcrumb (`## Mentions › Mention a person with @`), and the
330
+ line under it is an HTML comment holding the chunk's metadata as JSON:
331
+
332
+ ```markdown
333
+ ## Mentions › Mention a person with @
334
+
335
+ <!-- chunk {"id":"ui/mentions/mention-a-person-with","section":"Mentions","title":"Mention a person with @","tags":["mentions","names"],"source":"knowledge/ui/04-mentions.md","package":"bible-note@0.5.0"} -->
336
+
337
+ Type @ followed by a few letters of the name…
338
+ ```
339
+
340
+ Split on `^## ` (a markdown-header splitter does this out of the box), parse
341
+ `<!-- chunk (.*) -->` for metadata, and index the rest. Chunk `id`s are stable
342
+ across releases as long as the section heading is unchanged; every chunk is
343
+ under 4,000 characters. The text is written for the person using the editor and
344
+ names buttons as they appear on screen.
345
+
346
+ `dist/`, `types/` and `knowledge/` here are generated by `npm run pack` from the
347
+ sources under `src/` and `knowledge/` — edit those, not the build output. This
348
+ file, `package.json` and `LICENSE` are maintained by hand and are the only files
349
+ in this folder that git tracks.