bookish-press 0.9.4 → 0.10.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.
Files changed (154) hide show
  1. package/dist/components/Auth.svelte +37 -21
  2. package/dist/components/BookPreview.svelte +4 -4
  3. package/dist/components/BookPreview.svelte.d.ts +1 -1
  4. package/dist/components/Link.svelte +19 -12
  5. package/dist/components/app/Button.svelte +1 -8
  6. package/dist/components/app/Link.svelte +1 -7
  7. package/dist/components/app/Options.svelte +1 -6
  8. package/dist/components/app/TextInput.svelte +2 -8
  9. package/dist/components/chapter/Atom.svelte +2 -1
  10. package/dist/components/chapter/Atom.svelte.d.ts +1 -1
  11. package/dist/components/chapter/Block.svelte +9 -9
  12. package/dist/components/chapter/Block.svelte.d.ts +1 -1
  13. package/dist/components/chapter/Callout.svelte.d.ts +1 -1
  14. package/dist/components/chapter/CaptionedCode.svelte +1 -0
  15. package/dist/components/chapter/CaptionedCode.svelte.d.ts +1 -1
  16. package/dist/components/chapter/ChapterBody.svelte +5 -2
  17. package/dist/components/chapter/ChapterBody.svelte.d.ts +1 -1
  18. package/dist/components/chapter/ChapterBody.test.js +3 -3
  19. package/dist/components/chapter/Citations.svelte +17 -16
  20. package/dist/components/chapter/Citations.svelte.d.ts +1 -1
  21. package/dist/components/chapter/Code.svelte +8 -14
  22. package/dist/components/chapter/Comment.svelte +7 -12
  23. package/dist/components/chapter/Comment.svelte.d.ts +1 -1
  24. package/dist/components/chapter/Definition.svelte +8 -9
  25. package/dist/components/chapter/Definition.svelte.d.ts +1 -1
  26. package/dist/components/chapter/Embed.svelte +41 -61
  27. package/dist/components/chapter/Embed.svelte.d.ts +1 -1
  28. package/dist/components/chapter/ErrorMessage.svelte.d.ts +1 -1
  29. package/dist/components/chapter/Figure.svelte +14 -14
  30. package/dist/components/chapter/Figure.svelte.d.ts +4 -4
  31. package/dist/components/chapter/Footnote.svelte +11 -17
  32. package/dist/components/chapter/Footnote.svelte.d.ts +1 -1
  33. package/dist/components/chapter/Format.svelte +11 -11
  34. package/dist/components/chapter/Format.svelte.d.ts +1 -1
  35. package/dist/components/chapter/InlineCode.svelte.d.ts +1 -1
  36. package/dist/components/chapter/Label.svelte +1 -1
  37. package/dist/components/chapter/Label.svelte.d.ts +1 -1
  38. package/dist/components/chapter/LineBreak.svelte +1 -0
  39. package/dist/components/chapter/LineBreak.svelte.d.ts +1 -1
  40. package/dist/components/chapter/Link.svelte +14 -12
  41. package/dist/components/chapter/Link.svelte.d.ts +1 -1
  42. package/dist/components/chapter/List.svelte +1 -1
  43. package/dist/components/chapter/List.svelte.d.ts +1 -1
  44. package/dist/components/chapter/Marginal.svelte +36 -42
  45. package/dist/components/chapter/Paragraph.svelte +4 -4
  46. package/dist/components/chapter/Paragraph.svelte.d.ts +1 -1
  47. package/dist/components/chapter/Positioned.svelte +1 -0
  48. package/dist/components/chapter/Positioned.svelte.d.ts +1 -1
  49. package/dist/components/chapter/Python.svelte +42 -31
  50. package/dist/components/chapter/Python.svelte.d.ts +1 -1
  51. package/dist/components/chapter/Quote.svelte.d.ts +1 -1
  52. package/dist/components/chapter/Rule.svelte +1 -0
  53. package/dist/components/chapter/Rule.svelte.d.ts +1 -1
  54. package/dist/components/chapter/Table.svelte.d.ts +1 -1
  55. package/dist/components/chapter/Text.svelte +41 -50
  56. package/dist/components/chapter/Text.svelte.d.ts +1 -1
  57. package/dist/components/controls/DarkToggle.svelte +4 -4
  58. package/dist/components/editor/BookishEditor.svelte +605 -569
  59. package/dist/components/editor/BookishEditor.svelte.d.ts +1 -1
  60. package/dist/components/editor/CalloutEditor.svelte +1 -1
  61. package/dist/components/editor/CalloutEditor.svelte.d.ts +1 -1
  62. package/dist/components/editor/CaptionedCodeEditor.svelte +1 -1
  63. package/dist/components/editor/CaptionedCodeEditor.svelte.d.ts +1 -1
  64. package/dist/components/editor/CaretContext.d.ts +14 -14
  65. package/dist/components/editor/CaretState.d.ts +3 -3
  66. package/dist/components/editor/CaretView.svelte +8 -19
  67. package/dist/components/editor/CitationsEditor.svelte +10 -18
  68. package/dist/components/editor/CitationsEditor.svelte.d.ts +1 -1
  69. package/dist/components/editor/Clipboard.d.ts +1 -1
  70. package/dist/components/editor/Command.d.ts +1 -1
  71. package/dist/components/editor/Commands.js +19 -19
  72. package/dist/components/editor/ConfirmButton.svelte +1 -6
  73. package/dist/components/editor/DefinitionEditor.svelte +9 -7
  74. package/dist/components/editor/DefinitionEditor.svelte.d.ts +1 -1
  75. package/dist/components/editor/EmbedEditor.svelte +25 -34
  76. package/dist/components/editor/EmbedEditor.svelte.d.ts +1 -1
  77. package/dist/components/editor/ImageChooser.svelte +8 -7
  78. package/dist/components/editor/ImageChooser.svelte.d.ts +1 -1
  79. package/dist/components/editor/ImageThumbnail.svelte +21 -18
  80. package/dist/components/editor/InlineCodeEditor.svelte +1 -1
  81. package/dist/components/editor/InlineCodeEditor.svelte.d.ts +1 -1
  82. package/dist/components/editor/LabelEditor.svelte +2 -2
  83. package/dist/components/editor/LabelEditor.svelte.d.ts +1 -1
  84. package/dist/components/editor/LanguageEditor.svelte +8 -1
  85. package/dist/components/editor/LinkEditor.svelte +42 -44
  86. package/dist/components/editor/LinkEditor.svelte.d.ts +1 -1
  87. package/dist/components/editor/Permissions.svelte +23 -29
  88. package/dist/components/editor/PositionEditor.svelte +1 -1
  89. package/dist/components/editor/PositionEditor.svelte.d.ts +1 -1
  90. package/dist/components/editor/QuoteEditor.svelte +1 -1
  91. package/dist/components/editor/QuoteEditor.svelte.d.ts +1 -1
  92. package/dist/components/editor/Switch.svelte +5 -11
  93. package/dist/components/editor/TableEditor.svelte +1 -1
  94. package/dist/components/editor/TableEditor.svelte.d.ts +1 -1
  95. package/dist/components/editor/TextEditor.svelte +61 -58
  96. package/dist/components/editor/Toggle.svelte +16 -14
  97. package/dist/components/editor/Toolbar.svelte +81 -94
  98. package/dist/components/editor/UndoState.d.ts +2 -2
  99. package/dist/components/page/Acknowledgements.svelte +2 -8
  100. package/dist/components/page/Authors.svelte +12 -21
  101. package/dist/components/page/BookLoader.svelte +32 -34
  102. package/dist/components/page/BulkReferenceEditor.svelte +21 -41
  103. package/dist/components/page/Chapter.svelte +139 -114
  104. package/dist/components/page/Chapter.svelte.d.ts +1 -1
  105. package/dist/components/page/ChapterTitle.svelte +1 -1
  106. package/dist/components/page/Contexts.js +3 -1
  107. package/dist/components/page/DefinitionView.svelte +30 -42
  108. package/dist/components/page/DefinitionView.svelte.d.ts +1 -1
  109. package/dist/components/page/Description.svelte +2 -8
  110. package/dist/components/page/DownloadEPUB.svelte +83 -41
  111. package/dist/components/page/EditableHeader.svelte.d.ts +1 -1
  112. package/dist/components/page/Edition.svelte +44 -30
  113. package/dist/components/page/Edition.svelte.d.ts +1 -1
  114. package/dist/components/page/EditionLoader.svelte +101 -100
  115. package/dist/components/page/Editions.svelte +13 -13
  116. package/dist/components/page/Glossary.svelte +9 -10
  117. package/dist/components/page/Header.svelte +15 -28
  118. package/dist/components/page/Index.svelte +17 -18
  119. package/dist/components/page/License.svelte +2 -8
  120. package/dist/components/page/Media.svelte +7 -14
  121. package/dist/components/page/MediaPreview.svelte +14 -17
  122. package/dist/components/page/Outline.svelte +74 -66
  123. package/dist/components/page/Page.svelte +23 -17
  124. package/dist/components/page/PossibleChapter.svelte +2 -2
  125. package/dist/components/page/PossibleReference.svelte +1 -1
  126. package/dist/components/page/PossibleReference.svelte.d.ts +2 -2
  127. package/dist/components/page/Print.svelte +5 -8
  128. package/dist/components/page/Publish.svelte +33 -39
  129. package/dist/components/page/Reference.svelte +9 -11
  130. package/dist/components/page/Reference.svelte.d.ts +1 -1
  131. package/dist/components/page/References.svelte +1 -1
  132. package/dist/components/page/Search.svelte +39 -40
  133. package/dist/components/page/SubdomainEditor.svelte +11 -10
  134. package/dist/components/page/TableOfContents.svelte +52 -48
  135. package/dist/components/page/TableOfContentsImage.svelte +2 -2
  136. package/dist/components/page/TableOfContentsRow.svelte +9 -22
  137. package/dist/components/page/TableOfContentsRow.svelte.d.ts +2 -2
  138. package/dist/components/page/ThemeEditor.svelte +10 -17
  139. package/dist/components/page/ThemeEditorPreview.svelte +3 -6
  140. package/dist/components/page/ThemeEditorPreview.svelte.d.ts +1 -1
  141. package/dist/components/page/ThemeVariableEditor.svelte +6 -6
  142. package/dist/components/page/Unknown.svelte +1 -1
  143. package/dist/epub/build.d.ts +6 -0
  144. package/dist/epub/build.js +16 -3
  145. package/dist/epub/build.test.js +65 -0
  146. package/dist/epub/images.d.ts +7 -5
  147. package/dist/epub/images.js +15 -10
  148. package/dist/epub/images.test.js +8 -6
  149. package/dist/epub/package.js +25 -3
  150. package/dist/models/FirebaseAvailable.d.ts +9 -0
  151. package/dist/models/FirebaseAvailable.js +10 -0
  152. package/dist/models/book/BookMedia.d.ts +2 -1
  153. package/dist/models/book/BookMedia.js +33 -9
  154. package/package.json +18 -14
@@ -1,4 +1,4 @@
1
- import type RootNode from '../../models/chapter/RootNode';
1
+ import type RootNode from '../../models/chapter/RootNode.js';
2
2
  interface Props {
3
3
  text: string;
4
4
  parser: (text: string) => RootNode;
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">import PositionEditor from "./PositionEditor.svelte";
2
- import { getCaret } from "../page/Contexts";
2
+ import { getCaret } from "../page/Contexts.js";
3
3
  let { callout } = $props();
4
4
  let caret = getCaret();
5
5
  </script>
@@ -1,4 +1,4 @@
1
- import type CalloutNode from '../../models/chapter/CalloutNode';
1
+ import type CalloutNode from '../../models/chapter/CalloutNode.js';
2
2
  interface Props {
3
3
  callout: CalloutNode;
4
4
  }
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">import LanguageEditor from "./LanguageEditor.svelte";
2
2
  import PositionEditor from "./PositionEditor.svelte";
3
3
  import Switch from "./Switch.svelte";
4
- import { getCaret } from "../page/Contexts";
4
+ import { getCaret } from "../page/Contexts.js";
5
5
  let { code } = $props();
6
6
  let caret = getCaret();
7
7
  </script>
@@ -1,4 +1,4 @@
1
- import type CodeNode from '../../models/chapter/CodeNode';
1
+ import type CodeNode from '../../models/chapter/CodeNode.js';
2
2
  interface Props {
3
3
  code: CodeNode;
4
4
  }
@@ -1,19 +1,19 @@
1
- import type Caret from '../../models/chapter/Caret';
2
- import type { CaretRange } from '../../models/chapter/Caret';
3
- import type ParagraphNode from '../../models/chapter/ParagraphNode';
4
- import type AtomNode from '../../models/chapter/AtomNode';
5
- import type FormatNode from '../../models/chapter/FormatNode';
6
- import type BlocksNode from '../../models/chapter/BlocksNode';
7
- import type ListNode from '../../models/chapter/ListNode';
8
- import type TableNode from '../../models/chapter/TableNode';
9
- import type MetadataNode from '../../models/chapter/MetadataNode';
10
- import type RootNode from '../../models/chapter/RootNode';
11
- import type Edit from '../../models/chapter/Edit';
12
- import type CodeNode from '../../models/chapter/CodeNode';
13
- import type BlockNode from '../../models/chapter/BlockNode';
1
+ import type Caret from '../../models/chapter/Caret.js';
2
+ import type { CaretRange } from '../../models/chapter/Caret.js';
3
+ import type ParagraphNode from '../../models/chapter/ParagraphNode.js';
4
+ import type AtomNode from '../../models/chapter/AtomNode.js';
5
+ import type FormatNode from '../../models/chapter/FormatNode.js';
6
+ import type BlocksNode from '../../models/chapter/BlocksNode.js';
7
+ import type ListNode from '../../models/chapter/ListNode.js';
8
+ import type TableNode from '../../models/chapter/TableNode.js';
9
+ import type MetadataNode from '../../models/chapter/MetadataNode.js';
10
+ import type RootNode from '../../models/chapter/RootNode.js';
11
+ import type Edit from '../../models/chapter/Edit.js';
12
+ import type CodeNode from '../../models/chapter/CodeNode.js';
13
+ import type BlockNode from '../../models/chapter/BlockNode.js';
14
14
  import type Clipboard from './Clipboard';
15
15
  import type UndoState from './UndoState';
16
- import type Node from '../../models/chapter/Node';
16
+ import type Node from '../../models/chapter/Node.js';
17
17
  export type PasteContent = {
18
18
  plain: string | undefined;
19
19
  };
@@ -1,7 +1,7 @@
1
- import type { CaretRange } from '../../models/chapter/Caret';
2
- import type RootNode from '../../models/chapter/RootNode';
1
+ import type { CaretRange } from '../../models/chapter/Caret.js';
2
+ import type RootNode from '../../models/chapter/RootNode.js';
3
3
  import type CaretContext from './CaretContext';
4
- import type Node from '../../models/chapter/Node';
4
+ import type Node from '../../models/chapter/Node.js';
5
5
  import type Command from './Command';
6
6
  type CaretState = {
7
7
  root: RootNode;
@@ -1,26 +1,15 @@
1
1
  <script lang="ts">import { tick } from "svelte";
2
- let {
3
- left,
4
- top,
5
- height,
6
- linked,
7
- italic,
8
- bold,
9
- disabled,
10
- ignored,
11
- blink,
12
- locked,
13
- accent
14
- } = $props();
2
+ let { left, top, height, linked, italic, bold, disabled, ignored, blink, locked, accent } = $props();
15
3
  let element = $state();
16
4
  let headerHeight = $state(0);
5
+ // When the caret updates position, scroll the element into view after
6
+ // the render is complete, and re-measure the header height so we can
7
+ // snap to the caret position.
17
8
  $effect(() => {
18
- void left;
19
- void top;
20
- tick().then(
21
- () => element ? element.scrollIntoView({ block: "nearest" }) : void 0
22
- );
23
- headerHeight = document.querySelector(".bookish-app > .header")?.offsetHeight ?? 0;
9
+ void left;
10
+ void top;
11
+ tick().then(() => element ? element.scrollIntoView({ block: "nearest" }) : undefined);
12
+ headerHeight = document.querySelector(".bookish-app > .header")?.offsetHeight ?? 0;
24
13
  });
25
14
  </script>
26
15
 
@@ -1,35 +1,27 @@
1
1
  <script lang="ts">import Note from "./Note.svelte";
2
2
  import Options from "../app/Options.svelte";
3
3
  import Button from "../app/Button.svelte";
4
- import { getCaret, getEdition } from "../page/Contexts";
4
+ import { getCaret, getEdition } from "../page/Contexts.js";
5
5
  let { citations } = $props();
6
6
  let caret = getCaret();
7
7
  let edition = getEdition();
8
8
  let value = $state("");
9
9
  function handleSelection(selection) {
10
- if (selection.length > 0)
11
- update(/* @__PURE__ */ new Set([...citations.getMeta(), selection]));
10
+ if (selection.length > 0) update(new Set([...citations.getMeta(), selection]));
12
11
  }
13
12
  function removeSelection(citationID) {
14
- let ids = new Set(citations.getMeta());
15
- ids.delete(citationID);
16
- update(ids);
13
+ let ids = new Set(citations.getMeta());
14
+ ids.delete(citationID);
15
+ update(ids);
17
16
  }
18
17
  function update(set) {
19
- $caret?.edit(citations, citations.withMeta(Array.from(set)));
18
+ $caret?.edit(citations, citations.withMeta(Array.from(set)));
20
19
  }
21
- let uncited = $derived($edition === void 0 ? [] : Object.keys($edition.getReferences()).filter(
22
- (citationID) => !citations.getMeta().includes(citationID)
23
- ).sort());
20
+ let uncited = $derived($edition === undefined ? [] : Object.keys($edition.getReferences()).filter((citationID) => !citations.getMeta().includes(citationID)).sort());
24
21
  let options = $derived.by(() => {
25
- const list = [
26
- [
27
- uncited.length > 0 ? "Choose references" : "No uncited references",
28
- ""
29
- ]
30
- ];
31
- for (const citationID of uncited) list.push([citationID, citationID]);
32
- return list;
22
+ const list = [[uncited.length > 0 ? "Choose references" : "No uncited references", ""]];
23
+ for (const citationID of uncited) list.push([citationID, citationID]);
24
+ return list;
33
25
  });
34
26
  </script>
35
27
 
@@ -1,4 +1,4 @@
1
- import type CitationsNode from '../../models/chapter/CitationsNode';
1
+ import type CitationsNode from '../../models/chapter/CitationsNode.js';
2
2
  interface Props {
3
3
  citations: CitationsNode;
4
4
  }
@@ -1,3 +1,3 @@
1
- import type Node from '../../models/chapter/Node';
1
+ import type Node from '../../models/chapter/Node.js';
2
2
  type Clipboard = undefined | Node;
3
3
  export type { Clipboard as default };
@@ -1,4 +1,4 @@
1
- import type Edit from '../../models/chapter/Edit';
1
+ import type Edit from '../../models/chapter/Edit.js';
2
2
  import type CaretUtilities from './CaretUtilities';
3
3
  import type CaretContext from './CaretContext';
4
4
  export type CommandCategory = 'navigation' | 'selection' | 'text' | 'history' | 'clipboard' | 'annotation' | 'block' | 'level' | 'list' | 'table';
@@ -1,22 +1,22 @@
1
- import CalloutNode from '../../models/chapter/CalloutNode';
2
- import CitationsNode from '../../models/chapter/CitationsNode';
3
- import CodeNode from '../../models/chapter/CodeNode';
4
- import CommentNode from '../../models/chapter/CommentNode';
5
- import DefinitionNode from '../../models/chapter/DefinitionNode';
6
- import EmbedNode from '../../models/chapter/EmbedNode';
7
- import FootnoteNode from '../../models/chapter/FootnoteNode';
8
- import FormatNode from '../../models/chapter/FormatNode';
9
- import InlineCodeNode from '../../models/chapter/InlineCodeNode';
10
- import LabelNode from '../../models/chapter/LabelNode';
11
- import LinkNode from '../../models/chapter/LinkNode';
12
- import ListNode from '../../models/chapter/ListNode';
13
- import ParagraphNode from '../../models/chapter/ParagraphNode';
14
- import QuoteNode from '../../models/chapter/QuoteNode';
15
- import RuleNode from '../../models/chapter/RuleNode';
16
- import TableNode from '../../models/chapter/TableNode';
17
- import TextNode from '../../models/chapter/TextNode';
18
- import AtomNode from '../../models/chapter/AtomNode';
19
- import BlocksNode from '../../models/chapter/BlocksNode';
1
+ import CalloutNode from '../../models/chapter/CalloutNode.js';
2
+ import CitationsNode from '../../models/chapter/CitationsNode.js';
3
+ import CodeNode from '../../models/chapter/CodeNode.js';
4
+ import CommentNode from '../../models/chapter/CommentNode.js';
5
+ import DefinitionNode from '../../models/chapter/DefinitionNode.js';
6
+ import EmbedNode from '../../models/chapter/EmbedNode.js';
7
+ import FootnoteNode from '../../models/chapter/FootnoteNode.js';
8
+ import FormatNode from '../../models/chapter/FormatNode.js';
9
+ import InlineCodeNode from '../../models/chapter/InlineCodeNode.js';
10
+ import LabelNode from '../../models/chapter/LabelNode.js';
11
+ import LinkNode from '../../models/chapter/LinkNode.js';
12
+ import ListNode from '../../models/chapter/ListNode.js';
13
+ import ParagraphNode from '../../models/chapter/ParagraphNode.js';
14
+ import QuoteNode from '../../models/chapter/QuoteNode.js';
15
+ import RuleNode from '../../models/chapter/RuleNode.js';
16
+ import TableNode from '../../models/chapter/TableNode.js';
17
+ import TextNode from '../../models/chapter/TextNode.js';
18
+ import AtomNode from '../../models/chapter/AtomNode.js';
19
+ import BlocksNode from '../../models/chapter/BlocksNode.js';
20
20
  import BoldIcon from './icons/bold.svg?raw';
21
21
  import BulletsIcon from './icons/bullets.svg?raw';
22
22
  import CalloutIcon from './icons/callout.svg?raw';
@@ -1,10 +1,5 @@
1
1
  <script lang="ts">import Button from "../app/Button.svelte";
2
- let {
3
- tooltip,
4
- confirm,
5
- command,
6
- children
7
- } = $props();
2
+ let { tooltip, confirm, command, children } = $props();
8
3
  let confirming = $state(false);
9
4
  </script>
10
5
 
@@ -1,18 +1,20 @@
1
1
  <script lang="ts">import Options from "../app/Options.svelte";
2
2
  import Note from "./Note.svelte";
3
- import { getCaret, getEdition } from "../page/Contexts";
3
+ import { getCaret, getEdition } from "../page/Contexts.js";
4
4
  let { definition } = $props();
5
5
  let caret = getCaret();
6
6
  let edition = getEdition();
7
7
  let glossary = $derived($edition?.getGlossary());
8
8
  function handleChange(glossaryID) {
9
- $caret?.edit(definition, definition.withMeta(glossaryID));
9
+ $caret?.edit(definition, definition.withMeta(glossaryID));
10
10
  }
11
- let entries = $derived(glossary === void 0 ? void 0 : Object.entries(glossary).map(([key, value]) => {
12
- return { glossaryID: key, phrase: value.phrase };
13
- }).sort(
14
- (a, b) => a && b ? a.phrase.localeCompare(b.phrase) : 0
15
- ));
11
+ // Sort the glossary entries by phrase
12
+ let entries = $derived(glossary === undefined ? undefined : Object.entries(glossary).map(([key, value]) => {
13
+ return {
14
+ glossaryID: key,
15
+ phrase: value.phrase
16
+ };
17
+ }).sort((a, b) => a && b ? a.phrase.localeCompare(b.phrase) : 0));
16
18
  </script>
17
19
 
18
20
  {#if entries !== undefined && glossary !== undefined}
@@ -1,4 +1,4 @@
1
- import type DefinitionNode from '../../models/chapter/DefinitionNode';
1
+ import type DefinitionNode from '../../models/chapter/DefinitionNode.js';
2
2
  interface Props {
3
3
  definition: DefinitionNode;
4
4
  }
@@ -1,52 +1,43 @@
1
1
  <script lang="ts">import PositionEditor from "./PositionEditor.svelte";
2
- import EmbedNode from "../../models/chapter/EmbedNode";
2
+ import EmbedNode from "../../models/chapter/EmbedNode.js";
3
3
  import TextEditor from "./TextEditor.svelte";
4
- import { storage } from "../../models/Firebase";
4
+ import { storage } from "../../models/Firebase.js";
5
5
  import ToolbarSpacer from "./ToolbarSpacer.svelte";
6
6
  import ImageChooser from "./ImageChooser.svelte";
7
7
  import URLEditor from "./URLEditor.svelte";
8
8
  import Note from "./Note.svelte";
9
- import { getBook, getCaret } from "../page/Contexts";
9
+ import { getBook, getCaret } from "../page/Contexts.js";
10
10
  let { embed } = $props();
11
11
  let caret = getCaret();
12
- let upload = $state(void 0);
12
+ let upload = $state(undefined);
13
13
  let description = $derived(embed.getDescription());
14
14
  let book = getBook();
15
15
  function isValidURL(url) {
16
- try {
17
- let test = new URL(url);
18
- if (test.protocol === "http:" || test.protocol === "https:") return;
19
- } catch (_) {
20
- }
21
- return "URL doesn't seem valid";
16
+ // Is it a valid URL?
17
+ try {
18
+ let test = new URL(url);
19
+ if (test.protocol === "http:" || test.protocol === "https:") return;
20
+ } catch (_) {}
21
+ return "URL doesn't seem valid";
22
22
  }
23
23
  function handleImageChange(event) {
24
- if ($book === void 0) return;
25
- if ($caret === void 0) return;
26
- const target = event.target;
27
- const file = target.files === null ? void 0 : target.files[0];
28
- const media = $book.getMedia();
29
- if (file === void 0) return;
30
- if (storage === void 0) return;
31
- if (media === void 0) return;
32
- media.upload(
33
- file,
34
- (progress) => upload = `${progress}% done`,
35
- (error) => upload = error,
36
- (url, thumbnail) => {
37
- $caret?.edit(embed, embed.withURLs(url, thumbnail));
38
- upload = void 0;
39
- }
40
- );
24
+ if ($book === undefined) return;
25
+ if ($caret === undefined) return;
26
+ const target = event.target;
27
+ const file = target.files === null ? undefined : target.files[0];
28
+ const media = $book.getMedia();
29
+ if (file === undefined) return;
30
+ if (storage === undefined) return;
31
+ if (media === undefined) return;
32
+ media.upload(file, (progress) => upload = `${progress}% done`, (error) => upload = error, (url, thumbnail) => {
33
+ // Upload completed successfully, update the front end.
34
+ // Preserve the description, in case it's an image revision, to avoid data loss.
35
+ $caret?.edit(embed, embed.withURLs(url, thumbnail));
36
+ upload = undefined;
37
+ });
41
38
  }
42
39
  function handleImageSelection(image) {
43
- $caret?.edit(
44
- embed,
45
- embed.getURL() === image.url ? (
46
- // Toggle the embed if choosing the same image
47
- embed.withURL("").withDescription("")
48
- ) : embed.withURLs(image.url, image.thumb)
49
- );
40
+ $caret?.edit(embed, embed.getURL() === image.url ? embed.withURL("").withDescription("") : embed.withURLs(image.url, image.thumb));
50
41
  }
51
42
  </script>
52
43
 
@@ -1,4 +1,4 @@
1
- import EmbedNode from '../../models/chapter/EmbedNode';
1
+ import EmbedNode from '../../models/chapter/EmbedNode.js';
2
2
  interface Props {
3
3
  embed: EmbedNode;
4
4
  }
@@ -1,18 +1,19 @@
1
1
  <script lang="ts">import { onMount } from "svelte";
2
- import { getBook } from "../page/Contexts";
2
+ import { getBook } from "../page/Contexts.js";
3
3
  import ImageThumbnail from "./ImageThumbnail.svelte";
4
4
  let { select, selection } = $props();
5
5
  let book = getBook();
6
- let images = $state(void 0);
6
+ let images = $state(undefined);
7
7
  let expanded = $state(false);
8
8
  function updateImages(newImages) {
9
- images = newImages;
9
+ images = newImages;
10
10
  }
11
+ // Load the latest images in the book, and keep them updated as they change.
11
12
  onMount(() => {
12
- if ($book === void 0) return;
13
- const media = $book.getMedia();
14
- media.notify(updateImages);
15
- return () => media.stopNotifying(updateImages);
13
+ if ($book === undefined) return;
14
+ const media = $book.getMedia();
15
+ media.notify(updateImages);
16
+ return () => media.stopNotifying(updateImages);
16
17
  });
17
18
  </script>
18
19
 
@@ -1,4 +1,4 @@
1
- import type { Image } from '../../models/book/BookMedia';
1
+ import type { Image } from '../../models/book/BookMedia.js';
2
2
  interface Props {
3
3
  select: (image: Image) => void;
4
4
  selection: string;
@@ -3,27 +3,30 @@ let retries = 3;
3
3
  let error = $state(false);
4
4
  let loading = $state(true);
5
5
  function loadImage(url) {
6
- retries--;
7
- let img = new Image();
8
- img.onerror = () => {
9
- if (retries > 0) {
10
- setTimeout(() => loadImage(url), 1e3);
11
- } else {
12
- loading = false;
13
- error = true;
14
- }
15
- };
16
- img.onload = () => {
17
- loading = false;
18
- };
19
- img.src = url;
6
+ retries--;
7
+ let img = new Image();
8
+ img.onerror = () => {
9
+ if (retries > 0) {
10
+ setTimeout(() => loadImage(url), 1e3);
11
+ } else {
12
+ loading = false;
13
+ error = true;
14
+ }
15
+ };
16
+ img.onload = () => {
17
+ loading = false;
18
+ };
19
+ img.src = url;
20
20
  }
21
+ // Load now and whenever the image prop changes (thumbnails can be
22
+ // reused for a different image by an unkeyed list).
21
23
  $effect(() => {
22
- retries = 3;
23
- loading = true;
24
- error = false;
25
- loadImage(image.thumb);
24
+ retries = 3;
25
+ loading = true;
26
+ error = false;
27
+ loadImage(image.thumb);
26
28
  });
29
+ export {};
27
30
  </script>
28
31
 
29
32
  {#if loading}
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">import LanguageEditor from "./LanguageEditor.svelte";
2
- import { getCaret } from "../page/Contexts";
2
+ import { getCaret } from "../page/Contexts.js";
3
3
  let { code } = $props();
4
4
  let caret = getCaret();
5
5
  </script>
@@ -1,4 +1,4 @@
1
- import type InlineCodeNode from '../../models/chapter/InlineCodeNode';
1
+ import type InlineCodeNode from '../../models/chapter/InlineCodeNode.js';
2
2
  interface Props {
3
3
  code: InlineCodeNode;
4
4
  }
@@ -1,11 +1,11 @@
1
1
  <script lang="ts">import TextEditor from "./TextEditor.svelte";
2
2
  import { getChapter, getEdition } from "../page/Contexts";
3
- import { getCaret } from "../page/Contexts";
3
+ import { getCaret } from "../page/Contexts.js";
4
4
  let { label } = $props();
5
5
  let edition = getEdition();
6
6
  let chapter = getChapter();
7
7
  let caret = getCaret();
8
- let ast = $derived($edition && $chapter ? $chapter.chapter.getAST($edition) : void 0);
8
+ let ast = $derived($edition && $chapter ? $chapter.chapter.getAST($edition) : undefined);
9
9
  </script>
10
10
 
11
11
  <code>
@@ -1,4 +1,4 @@
1
- import type LabelNode from '../../models/chapter/LabelNode';
1
+ import type LabelNode from '../../models/chapter/LabelNode.js';
2
2
  interface Props {
3
3
  label: LabelNode;
4
4
  }
@@ -1,7 +1,14 @@
1
1
  <script lang="ts">import Options from "../app/Options.svelte";
2
2
  import Note from "./Note.svelte";
3
3
  let { language, edit } = $props();
4
- const languages = ["", "html", "css", "javascript", "python", "java"];
4
+ const languages = [
5
+ "",
6
+ "html",
7
+ "css",
8
+ "javascript",
9
+ "python",
10
+ "java"
11
+ ];
5
12
  </script>
6
13
 
7
14
  <Options
@@ -4,7 +4,7 @@ import Icon from "./Icon.svelte";
4
4
  import Button from "../app/Button.svelte";
5
5
  import UnlinkIcon from "./icons/unlink.svg?raw";
6
6
  import Options from "../app/Options.svelte";
7
- import { getCaret } from "../page/Contexts";
7
+ import { getCaret } from "../page/Contexts.js";
8
8
  let { link } = $props();
9
9
  let caret = getCaret();
10
10
  let edition = getEdition();
@@ -12,54 +12,52 @@ let chapter = getChapter();
12
12
  let root = getRoot();
13
13
  let url = $derived(link.getMeta());
14
14
  function saveEdit(value) {
15
- $caret?.edit(link, link.withMeta(value));
15
+ $caret?.edit(link, link.withMeta(value));
16
16
  }
17
- function isValidURL(url2) {
18
- try {
19
- let test = new URL(url2);
20
- if (test.protocol === "http:" || test.protocol === "https:")
21
- return true;
22
- } catch (_) {
23
- }
24
- return false;
17
+ function isValidURL(url) {
18
+ // Is it a valid URL?
19
+ try {
20
+ let test = new URL(url);
21
+ if (test.protocol === "http:" || test.protocol === "https:") return true;
22
+ } catch (_) {}
23
+ return false;
25
24
  }
26
25
  function validate(urlOrChapter) {
27
- if (urlOrChapter.length === 0) return "link URL can't be empty";
28
- if ($edition === void 0) return;
29
- if (isValidURL(urlOrChapter)) return;
30
- if ($edition.hasChapter(urlOrChapter)) return;
31
- const [chapterID, labelID] = urlOrChapter.split(":");
32
- if (chapterID === void 0 || labelID === void 0) return;
33
- const correspondingChapter = chapterID === "" ? $root : $edition?.getChapter(chapterID)?.getAST($edition);
34
- if (correspondingChapter === void 0)
35
- return "Not a valid URL or chapter.";
36
- if (!correspondingChapter.hasLabel(labelID))
37
- return "Not a valid chapter label.";
26
+ if (urlOrChapter.length === 0) return "link URL can't be empty";
27
+ if ($edition === undefined) return;
28
+ if (isValidURL(urlOrChapter)) return;
29
+ // If not, is it a valid chapterID?
30
+ if ($edition.hasChapter(urlOrChapter)) return;
31
+ // If not, is it a valid chapterID:label?
32
+ const [chapterID, labelID] = urlOrChapter.split(":");
33
+ if (chapterID === undefined || labelID === undefined) return;
34
+ // The chapter ID is optional; if it's missing, it refers to this chapter.
35
+ const correspondingChapter = chapterID === "" ? $root : $edition?.getChapter(chapterID)?.getAST($edition);
36
+ if (correspondingChapter === undefined) return "Not a valid URL or chapter.";
37
+ if (!correspondingChapter.hasLabel(labelID)) return "Not a valid chapter label.";
38
38
  }
39
39
  let options = $derived.by(() => {
40
- const list = [];
41
- list.push(["External link", url.startsWith("http") ? url : ""]);
42
- if ($edition) {
43
- for (const chap of $edition?.getChapters() ?? []) {
44
- list.push([`Chapter: ${chap.getTitle()}`, chap.getID()]);
45
- const root2 = chap.getAST($edition);
46
- if (root2) {
47
- const headers = root2.getHeaders();
48
- for (let number = 0; number < headers.length; number++) {
49
- list.push([
50
- chap.getTitle() + ": " + headers[number].toText(),
51
- `${chap.getID()}#header-${number}`
52
- ]);
53
- }
54
- for (const label of root2.getLabels())
55
- list.push([
56
- chap.getTitle() + ": " + label.getMeta(),
57
- `${chap.getID()}:${label.getMeta()}`
58
- ]);
59
- }
60
- }
61
- }
62
- return list;
40
+ const list = [];
41
+ // Add an empty option.
42
+ list.push(["External link", url.startsWith("http") ? url : ""]);
43
+ // Add an option for each chapter and it's labels.
44
+ if ($edition) {
45
+ for (const chap of $edition?.getChapters() ?? []) {
46
+ // Include the chapter itself
47
+ list.push([`Chapter: ${chap.getTitle()}`, chap.getID()]);
48
+ const root = chap.getAST($edition);
49
+ if (root) {
50
+ // Include the chapter's headers
51
+ const headers = root.getHeaders();
52
+ for (let number = 0; number < headers.length; number++) {
53
+ list.push([chap.getTitle() + ": " + headers[number].toText(), `${chap.getID()}#header-${number}`]);
54
+ }
55
+ // Include all of the labels in the chapter
56
+ for (const label of root.getLabels()) list.push([chap.getTitle() + ": " + label.getMeta(), `${chap.getID()}:${label.getMeta()}`]);
57
+ }
58
+ }
59
+ }
60
+ return list;
63
61
  });
64
62
  </script>
65
63
 
@@ -1,4 +1,4 @@
1
- import type LinkNode from '../../models/chapter/LinkNode';
1
+ import type LinkNode from '../../models/chapter/LinkNode.js';
2
2
  interface Props {
3
3
  link: LinkNode;
4
4
  }