@bendyline/docblocks-react 2.7.6 → 2.7.8

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 (43) hide show
  1. package/THIRD_PARTY_NOTICES.txt +205 -35
  2. package/dist/{AiDiagrams-VOCEZS6U.js → AiDiagrams-2IKKSBAU.js} +6 -4
  3. package/dist/{AiEditorAssistant-2MW6UYNI.js → AiEditorAssistant-ANYGVG7P.js} +128 -12
  4. package/dist/AiImagePanel-OXWEFOBC.js +314 -0
  5. package/dist/{AiStudyDialog-DQZVTBI7.js → AiStudyDialog-T3FY74HY.js} +3 -3
  6. package/dist/{AudioExportDialog-EICCBSSE.js → AudioExportDialog-CBMSLQBS.js} +1 -1
  7. package/dist/DocumentConflictDialog-4R4QMKBT.js +217 -0
  8. package/dist/{ExportDialog-LGWBXIWN.js → ExportDialog-FNFD53SY.js} +2 -2
  9. package/dist/{ExportToolbarControls-4LYTXGT3.js → ExportToolbarControls-ZOYH4I36.js} +146 -68
  10. package/dist/{GitUI-F3CNBURE.js → GitUI-3FANM7I3.js} +88 -155
  11. package/dist/{KeyboardShortcutsDialog-HVKDFP5Z.js → KeyboardShortcutsDialog-7XJTDIX2.js} +1 -1
  12. package/dist/{PresentationMaker-T526TBRJ.js → PresentationMaker-COLTVMTS.js} +3 -3
  13. package/dist/{QuickOpenDialog-3QEX7RZG.js → QuickOpenDialog-U2FWCEPA.js} +1 -1
  14. package/dist/{Settings-CfhY489G.d.ts → Settings-ButIB78y.d.ts} +20 -4
  15. package/dist/{ShareDialog-PF7D7ORP.js → ShareDialog-WOWHI6YI.js} +1 -1
  16. package/dist/{SpeechToolbarControl-E6OSJGHL.js → SpeechToolbarControl-BZW6IVZM.js} +1 -1
  17. package/dist/{TextFromNarration-ME6FAYWO.js → TextFromNarration-6BYTUKVZ.js} +2 -2
  18. package/dist/chunk-27E2OON2.js +90 -0
  19. package/dist/{chunk-5O5YTOXG.js → chunk-5YMULR6A.js} +13 -1
  20. package/dist/{chunk-NOYDVL6M.js → chunk-6QHZNL6C.js} +45 -17
  21. package/dist/{chunk-45YTIVYS.js → chunk-A7BK6QFL.js} +363 -26
  22. package/dist/{chunk-PRUEYW3G.js → chunk-BGA5UVKL.js} +58 -17
  23. package/dist/{chunk-T42BH6YX.js → chunk-CXLXGFG2.js} +37 -15
  24. package/dist/{chunk-7CSBRAMT.js → chunk-F7TR5EKX.js} +8 -6
  25. package/dist/chunk-HIKMOKBQ.js +37 -0
  26. package/dist/chunk-OW6JWRAA.js +66 -0
  27. package/dist/{chunk-BNKIPCXO.js → chunk-QXBV3G6T.js} +5 -3
  28. package/dist/{chunk-7HBKKXRV.js → chunk-TN7BY5N3.js} +722 -281
  29. package/dist/{chunk-VJPGZCFS.js → chunk-UYJCL6OW.js} +4 -2
  30. package/dist/{chunk-GFK4TCKN.js → chunk-WDNE5TI3.js} +21 -7
  31. package/dist/{chunk-KBUHWZCF.js → chunk-YX275NPE.js} +1 -1
  32. package/dist/editor.js +3 -3
  33. package/dist/export/index.d.ts +16 -162
  34. package/dist/export/index.js +6 -4
  35. package/dist/image-save-D18dJrUr.d.ts +182 -0
  36. package/dist/index.d.ts +15 -11
  37. package/dist/index.js +1365 -1078
  38. package/dist/{run-export-SPNNH32M.js → run-export-C3PLLWLS.js} +2 -2
  39. package/dist/settings/index.d.ts +1 -1
  40. package/dist/settings/index.js +3 -2
  41. package/package.json +8 -8
  42. package/src/styles/docblocks.css +349 -11
  43. package/dist/DocumentConflictDialog-DZ2BV2IH.js +0 -111
@@ -1,17 +1,221 @@
1
+ import {
2
+ imageAccessSentence,
3
+ useImageAccess
4
+ } from "./chunk-OW6JWRAA.js";
1
5
  import {
2
6
  HighlightedText
3
7
  } from "./chunk-TBLZBNQF.js";
4
8
  import {
5
9
  Dialog
6
- } from "./chunk-VJPGZCFS.js";
10
+ } from "./chunk-UYJCL6OW.js";
7
11
 
8
12
  // src/Settings/AiSettings.tsx
9
- import { useCallback, useEffect as useEffect2, useId as useId2, useRef as useRef2, useState as useState2 } from "react";
13
+ import { useCallback as useCallback2, useEffect as useEffect3, useId as useId2, useRef as useRef3, useState as useState3 } from "react";
14
+
15
+ // src/Settings/AiImageSettings.tsx
16
+ import { useCallback, useEffect, useRef, useState } from "react";
17
+
18
+ // src/Speech/format.ts
19
+ function formatModelSize(bytes) {
20
+ const gigabytes = bytes / 1024 ** 3;
21
+ if (gigabytes >= 0.95) return `${gigabytes.toFixed(1)} GB`;
22
+ return `${Math.max(1, Math.round(bytes / 1024 ** 2))} MB`;
23
+ }
24
+
25
+ // src/Settings/image-model-facts.ts
26
+ function imageModelFacts(model) {
27
+ const facts = [];
28
+ if (model.downloadBytes !== null) facts.push(formatModelSize(model.downloadBytes));
29
+ if (model.license) facts.push(model.license);
30
+ if (model.commercialUse === false) facts.push("Not for commercial use");
31
+ if (model.rendersText) facts.push("Draws legible text");
32
+ if (model.hardwareTier === "workstation") {
33
+ facts.push(
34
+ model.minRamGb !== null ? `Workstation \xB7 ${String(model.minRamGb)} GB+ memory` : "Workstation"
35
+ );
36
+ }
37
+ if (model.shared) facts.push("Shared with Gezel, no download needed");
38
+ if (model.fit && model.fit.verdict !== "fits" && model.fit.reason) facts.push(model.fit.reason);
39
+ return facts;
40
+ }
41
+
42
+ // src/Settings/AiImageSettings.tsx
43
+ import { jsx, jsxs } from "react/jsx-runtime";
44
+ function AiImageSettings({ images }) {
45
+ const access = useImageAccess(images);
46
+ const [models, setModels] = useState(null);
47
+ const [preferences, setPreferences] = useState(null);
48
+ const [failure, setFailure] = useState(null);
49
+ const [installing, setInstalling] = useState(
50
+ null
51
+ );
52
+ const [allowing, setAllowing] = useState(false);
53
+ const installHandle = useRef(null);
54
+ const mounted = useRef(true);
55
+ const ready = access?.kind === "ready";
56
+ const refresh = useCallback(async () => {
57
+ const result = await images.models();
58
+ if (!mounted.current) return;
59
+ if (result.ok) setModels(result.value);
60
+ else setFailure(result.error.message);
61
+ }, [images]);
62
+ useEffect(() => {
63
+ mounted.current = true;
64
+ void images.getPreferences().then(
65
+ (initial) => {
66
+ if (mounted.current) setPreferences(initial);
67
+ },
68
+ () => void 0
69
+ );
70
+ return () => {
71
+ mounted.current = false;
72
+ installHandle.current?.cancel();
73
+ };
74
+ }, [images]);
75
+ useEffect(() => {
76
+ if (ready) void refresh();
77
+ }, [ready, refresh]);
78
+ const install = async (model) => {
79
+ setFailure(null);
80
+ setInstalling({ id: model.id, progress: null });
81
+ const handle = images.installModel(model.id, (progress) => {
82
+ if (mounted.current) setInstalling({ id: model.id, progress });
83
+ });
84
+ installHandle.current = handle;
85
+ try {
86
+ const result = await handle.done;
87
+ if (!mounted.current) return;
88
+ if (!result.ok && result.error.code !== "cancelled") setFailure(result.error.message);
89
+ await refresh();
90
+ } finally {
91
+ if (installHandle.current === handle) installHandle.current = null;
92
+ if (mounted.current) setInstalling(null);
93
+ }
94
+ };
95
+ const remove = async (model) => {
96
+ setFailure(null);
97
+ const result = await images.removeModel(model.id);
98
+ if (!mounted.current) return;
99
+ if (!result.ok) setFailure(result.error.message);
100
+ else setPreferences(await images.getPreferences());
101
+ await refresh();
102
+ };
103
+ const choose = async (patch) => {
104
+ setPreferences(await images.setPreferences(patch));
105
+ };
106
+ const allow = async () => {
107
+ setAllowing(true);
108
+ setFailure(null);
109
+ const result = await images.requestAccess();
110
+ if (!mounted.current) return;
111
+ setAllowing(false);
112
+ if (!result.ok) setFailure(result.error.message);
113
+ };
114
+ const installed = (models ?? []).filter((model) => model.state === "installed");
115
+ const designModels = installed.filter((model) => model.rendersText);
116
+ const blocked = imageAccessSentence(access);
117
+ const modelRow = (model) => {
118
+ const busy = installing?.id === model.id;
119
+ const percent = busy && installing.progress ? installing.progress.percent : null;
120
+ const wontRun = model.fit?.verdict === "wont-run";
121
+ return /* @__PURE__ */ jsxs("li", { className: "db-settings-speech-model", children: [
122
+ /* @__PURE__ */ jsxs("div", { className: "db-settings-speech-model-text", children: [
123
+ /* @__PURE__ */ jsx("span", { className: "db-settings-speech-model-name", children: model.label }),
124
+ /* @__PURE__ */ jsx("span", { className: "db-settings-hint", children: imageModelFacts(model).join(" \xB7 ") })
125
+ ] }),
126
+ busy ? /* @__PURE__ */ jsxs("div", { className: "db-settings-ai-download-progress", role: "status", children: [
127
+ /* @__PURE__ */ jsx(
128
+ "progress",
129
+ {
130
+ max: 100,
131
+ value: percent ?? void 0,
132
+ "aria-label": `${model.label} download progress`
133
+ }
134
+ ),
135
+ /* @__PURE__ */ jsx("span", { children: installing.progress?.phase === "verifying" ? "Verifying\u2026" : percent === null ? "Starting\u2026" : `${String(Math.round(percent))}%` }),
136
+ /* @__PURE__ */ jsx(
137
+ "button",
138
+ {
139
+ type: "button",
140
+ className: "db-settings-action db-settings-action--secondary",
141
+ onClick: () => installHandle.current?.cancel(),
142
+ children: "Cancel"
143
+ }
144
+ )
145
+ ] }) : model.state === "installed" ? model.shared ? null : /* @__PURE__ */ jsx(
146
+ "button",
147
+ {
148
+ type: "button",
149
+ className: "db-settings-action db-settings-action--secondary",
150
+ disabled: installing !== null,
151
+ onClick: () => void remove(model),
152
+ children: "Remove"
153
+ }
154
+ ) : /* @__PURE__ */ jsx(
155
+ "button",
156
+ {
157
+ type: "button",
158
+ className: "db-settings-action",
159
+ disabled: installing !== null || wontRun,
160
+ title: wontRun ? model.fit?.reason ?? void 0 : void 0,
161
+ onClick: () => void install(model),
162
+ children: model.state === "downloading" ? "Show download" : "Download"
163
+ }
164
+ )
165
+ ] }, model.id);
166
+ };
167
+ return /* @__PURE__ */ jsxs("section", { className: "db-settings-ai-knowledge", "aria-label": "Image generation", children: [
168
+ /* @__PURE__ */ jsx("h3", { className: "db-settings-select-header", children: "Image generation" }),
169
+ blocked ? /* @__PURE__ */ jsx("p", { className: "db-settings-hint", role: "status", "aria-live": "polite", children: access?.kind === "awaiting-approval" && access.verificationCode ? `In Gezel, approve DocBlocks and enter the code ${access.verificationCode}.` : blocked }) : /* @__PURE__ */ jsx("p", { className: "db-settings-hint", children: "Images are generated on this computer. Models download only when you choose, and some are large." }),
170
+ access?.kind === "needs-approval" && /* @__PURE__ */ jsx(
171
+ "button",
172
+ {
173
+ type: "button",
174
+ className: "db-settings-action",
175
+ disabled: allowing,
176
+ onClick: () => void allow(),
177
+ children: "Allow image generation\u2026"
178
+ }
179
+ ),
180
+ failure && /* @__PURE__ */ jsx("p", { className: "db-settings-hint db-settings-ai-error", role: "alert", children: failure }),
181
+ ready && preferences && installed.length > 0 && /* @__PURE__ */ jsxs("label", { className: "db-settings-select", children: [
182
+ /* @__PURE__ */ jsx("span", { className: "db-settings-select-header", children: "Model for Generate image" }),
183
+ /* @__PURE__ */ jsxs(
184
+ "select",
185
+ {
186
+ className: "db-settings-select-input",
187
+ value: preferences.model ?? "",
188
+ onChange: (event) => void choose({ model: event.currentTarget.value || null }),
189
+ children: [
190
+ /* @__PURE__ */ jsx("option", { value: "", children: "First installed" }),
191
+ installed.map((model) => /* @__PURE__ */ jsx("option", { value: model.id, children: model.label }, model.id))
192
+ ]
193
+ }
194
+ )
195
+ ] }),
196
+ ready && preferences && designModels.length > 0 && /* @__PURE__ */ jsxs("label", { className: "db-settings-select", children: [
197
+ /* @__PURE__ */ jsx("span", { className: "db-settings-select-header", children: "Model for design graphics" }),
198
+ /* @__PURE__ */ jsxs(
199
+ "select",
200
+ {
201
+ className: "db-settings-select-input",
202
+ value: preferences.designModel ?? "",
203
+ onChange: (event) => void choose({ designModel: event.currentTarget.value || null }),
204
+ children: [
205
+ /* @__PURE__ */ jsx("option", { value: "", children: "None" }),
206
+ designModels.map((model) => /* @__PURE__ */ jsx("option", { value: model.id, children: model.label }, model.id))
207
+ ]
208
+ }
209
+ )
210
+ ] }),
211
+ ready && models && /* @__PURE__ */ jsx("ul", { className: "db-settings-speech-models", children: models.map(modelRow) })
212
+ ] });
213
+ }
10
214
 
11
215
  // src/Settings/AiKnowledgeSettings.tsx
12
- import { useEffect, useId, useRef, useState } from "react";
216
+ import { useEffect as useEffect2, useId, useRef as useRef2, useState as useState2 } from "react";
13
217
  import { createPortal } from "react-dom";
14
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
218
+ import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
15
219
  function sizedArticle(bytes) {
16
220
  const megabytes = String(Math.max(1, Math.round(bytes / 1024 ** 2)));
17
221
  const an = megabytes.startsWith("8") || megabytes.length % 3 === 2 && (megabytes.startsWith("11") || megabytes.startsWith("18"));
@@ -40,24 +244,24 @@ function matchRanges(text, query) {
40
244
  return ranges;
41
245
  }
42
246
  function AiKnowledgeSettings({ knowledge }) {
43
- const [state, setState] = useState(null);
44
- const [error, setError] = useState(null);
45
- const [loadError, setLoadError] = useState(null);
46
- const [unsupported, setUnsupported] = useState(null);
47
- const [busy, setBusy] = useState(false);
48
- const [revision, setRevision] = useState(0);
49
- const [adding, setAdding] = useState(false);
50
- const [expanded, setExpanded] = useState(() => /* @__PURE__ */ new Set());
51
- const [removing, setRemoving] = useState(null);
247
+ const [state, setState] = useState2(null);
248
+ const [error, setError] = useState2(null);
249
+ const [loadError, setLoadError] = useState2(null);
250
+ const [unsupported, setUnsupported] = useState2(null);
251
+ const [busy, setBusy] = useState2(false);
252
+ const [revision, setRevision] = useState2(0);
253
+ const [adding, setAdding] = useState2(false);
254
+ const [expanded, setExpanded] = useState2(() => /* @__PURE__ */ new Set());
255
+ const [removing, setRemoving] = useState2(null);
52
256
  const binHeadingId = useId();
53
- const generation = useRef(0);
54
- useEffect(
257
+ const generation = useRef2(0);
258
+ useEffect2(
55
259
  () => () => {
56
260
  generation.current++;
57
261
  },
58
262
  [knowledge]
59
263
  );
60
- useEffect(() => {
264
+ useEffect2(() => {
61
265
  let live = true;
62
266
  let timer;
63
267
  const refresh2 = async () => {
@@ -119,16 +323,16 @@ function AiKnowledgeSettings({ knowledge }) {
119
323
  ) ?? [];
120
324
  const problem = error ?? loadError;
121
325
  if (unsupported)
122
- return /* @__PURE__ */ jsxs("section", { className: "db-settings-ai-knowledge", "aria-label": "Knowledge catalogs", children: [
123
- /* @__PURE__ */ jsx("h3", { className: "db-settings-select-header", children: "Knowledge catalogs" }),
124
- /* @__PURE__ */ jsx("p", { className: "db-settings-hint", children: unsupported })
326
+ return /* @__PURE__ */ jsxs2("section", { className: "db-settings-ai-knowledge", "aria-label": "Knowledge catalogs", children: [
327
+ /* @__PURE__ */ jsx2("h3", { className: "db-settings-select-header", children: "Knowledge catalogs" }),
328
+ /* @__PURE__ */ jsx2("p", { className: "db-settings-hint", children: unsupported })
125
329
  ] });
126
- return /* @__PURE__ */ jsxs("section", { className: "db-settings-ai-knowledge", "aria-label": "Knowledge catalogs", children: [
127
- /* @__PURE__ */ jsx("h3", { className: "db-settings-select-header", children: "Knowledge catalogs" }),
128
- /* @__PURE__ */ jsx("p", { className: "db-settings-hint", children: "Add reference material for AI writing, review, and chat. Relevant passages from enabled catalogs are included in each request." }),
129
- problem && !adding && /* @__PURE__ */ jsx("p", { className: "db-settings-hint db-settings-ai-error", role: "alert", children: problem }),
130
- !state && !loadError && /* @__PURE__ */ jsx("p", { className: "db-settings-hint", role: "status", children: "Loading knowledge catalogs\u2026" }),
131
- !state && loadError && /* @__PURE__ */ jsx(
330
+ return /* @__PURE__ */ jsxs2("section", { className: "db-settings-ai-knowledge", "aria-label": "Knowledge catalogs", children: [
331
+ /* @__PURE__ */ jsx2("h3", { className: "db-settings-select-header", children: "Knowledge catalogs" }),
332
+ /* @__PURE__ */ jsx2("p", { className: "db-settings-hint", children: "Add reference material for AI writing, review, and chat. Relevant passages from enabled catalogs are included in each request." }),
333
+ problem && !adding && /* @__PURE__ */ jsx2("p", { className: "db-settings-hint db-settings-ai-error", role: "alert", children: problem }),
334
+ !state && !loadError && /* @__PURE__ */ jsx2("p", { className: "db-settings-hint", role: "status", children: "Loading knowledge catalogs\u2026" }),
335
+ !state && loadError && /* @__PURE__ */ jsx2(
132
336
  "button",
133
337
  {
134
338
  type: "button",
@@ -137,7 +341,7 @@ function AiKnowledgeSettings({ knowledge }) {
137
341
  children: "Try again"
138
342
  }
139
343
  ),
140
- state?.improvement && !state.improvement.downloading && /* @__PURE__ */ jsx("p", { className: "db-settings-hint", children: /* @__PURE__ */ jsxs(
344
+ state?.improvement && !state.improvement.downloading && /* @__PURE__ */ jsx2("p", { className: "db-settings-hint", children: /* @__PURE__ */ jsxs2(
141
345
  "button",
142
346
  {
143
347
  type: "button",
@@ -151,11 +355,11 @@ function AiKnowledgeSettings({ knowledge }) {
151
355
  ]
152
356
  }
153
357
  ) }),
154
- state && /* @__PURE__ */ jsxs("div", { className: "db-knowledge-bin", children: [
155
- /* @__PURE__ */ jsxs("div", { className: "db-knowledge-bin-header", children: [
156
- /* @__PURE__ */ jsx("h4", { id: binHeadingId, className: "db-knowledge-bin-title", children: "Downloaded catalogs" }),
157
- /* @__PURE__ */ jsx("span", { className: "db-knowledge-bin-count", "aria-hidden": "true", children: downloaded.length }),
158
- /* @__PURE__ */ jsx(
358
+ state && /* @__PURE__ */ jsxs2("div", { className: "db-knowledge-bin", children: [
359
+ /* @__PURE__ */ jsxs2("div", { className: "db-knowledge-bin-header", children: [
360
+ /* @__PURE__ */ jsx2("h4", { id: binHeadingId, className: "db-knowledge-bin-title", children: "Downloaded catalogs" }),
361
+ /* @__PURE__ */ jsx2("span", { className: "db-knowledge-bin-count", "aria-hidden": "true", children: downloaded.length }),
362
+ /* @__PURE__ */ jsx2(
159
363
  "button",
160
364
  {
161
365
  type: "button",
@@ -165,7 +369,7 @@ function AiKnowledgeSettings({ knowledge }) {
165
369
  }
166
370
  )
167
371
  ] }),
168
- downloaded.length === 0 ? /* @__PURE__ */ jsx("p", { className: "db-settings-hint db-knowledge-bin-empty", children: "No catalogs downloaded yet. Add a catalog to give AI writing, review, and chat reference material." }) : /* @__PURE__ */ jsx("ul", { className: "db-knowledge-bin-list", "aria-labelledby": binHeadingId, children: downloaded.map((catalog) => /* @__PURE__ */ jsx(
372
+ downloaded.length === 0 ? /* @__PURE__ */ jsx2("p", { className: "db-settings-hint db-knowledge-bin-empty", children: "No catalogs downloaded yet. Add a catalog to give AI writing, review, and chat reference material." }) : /* @__PURE__ */ jsx2("ul", { className: "db-knowledge-bin-list", "aria-labelledby": binHeadingId, children: downloaded.map((catalog) => /* @__PURE__ */ jsx2(
169
373
  DownloadedCatalog,
170
374
  {
171
375
  catalog,
@@ -179,7 +383,7 @@ function AiKnowledgeSettings({ knowledge }) {
179
383
  catalog.id
180
384
  )) })
181
385
  ] }),
182
- adding && state && /* @__PURE__ */ jsx(
386
+ adding && state && /* @__PURE__ */ jsx2(
183
387
  AddCatalogDialog,
184
388
  {
185
389
  catalogs: state.catalogs,
@@ -202,8 +406,8 @@ function DownloadedCatalog({
202
406
  onAction
203
407
  }) {
204
408
  const bodyId = useId();
205
- return /* @__PURE__ */ jsxs("li", { className: "db-knowledge-item", children: [
206
- /* @__PURE__ */ jsxs(
409
+ return /* @__PURE__ */ jsxs2("li", { className: "db-knowledge-item", children: [
410
+ /* @__PURE__ */ jsxs2(
207
411
  "button",
208
412
  {
209
413
  type: "button",
@@ -212,15 +416,15 @@ function DownloadedCatalog({
212
416
  "aria-controls": expanded ? bodyId : void 0,
213
417
  onClick: onToggle,
214
418
  children: [
215
- /* @__PURE__ */ jsx(
419
+ /* @__PURE__ */ jsx2(
216
420
  "span",
217
421
  {
218
422
  className: `db-knowledge-item-caret${expanded ? " db-knowledge-item-caret--open" : ""}`,
219
423
  "aria-hidden": "true"
220
424
  }
221
425
  ),
222
- /* @__PURE__ */ jsx("span", { className: "db-knowledge-item-name", children: catalog.name }),
223
- /* @__PURE__ */ jsx(
426
+ /* @__PURE__ */ jsx2("span", { className: "db-knowledge-item-name", children: catalog.name }),
427
+ /* @__PURE__ */ jsx2(
224
428
  "span",
225
429
  {
226
430
  className: `db-knowledge-item-summary${catalog.state === "error" ? " db-knowledge-item-summary--error" : ""}`,
@@ -230,12 +434,12 @@ function DownloadedCatalog({
230
434
  ]
231
435
  }
232
436
  ),
233
- expanded && /* @__PURE__ */ jsxs("div", { id: bodyId, className: "db-knowledge-item-body", children: [
234
- /* @__PURE__ */ jsx("p", { className: "db-settings-hint", children: catalog.description }),
235
- /* @__PURE__ */ jsx("p", { className: "db-settings-hint", children: catalogFacts(catalog, catalog.installedVersion ?? catalog.version) }),
236
- catalog.message && /* @__PURE__ */ jsx("p", { className: "db-settings-hint", role: catalog.state === "error" ? "alert" : "status", children: catalog.message }),
237
- catalog.state === "downloading" ? /* @__PURE__ */ jsxs("div", { className: "db-settings-ai-knowledge-actions", children: [
238
- /* @__PURE__ */ jsx(
437
+ expanded && /* @__PURE__ */ jsxs2("div", { id: bodyId, className: "db-knowledge-item-body", children: [
438
+ /* @__PURE__ */ jsx2("p", { className: "db-settings-hint", children: catalog.description }),
439
+ /* @__PURE__ */ jsx2("p", { className: "db-settings-hint", children: catalogFacts(catalog, catalog.installedVersion ?? catalog.version) }),
440
+ catalog.message && /* @__PURE__ */ jsx2("p", { className: "db-settings-hint", role: catalog.state === "error" ? "alert" : "status", children: catalog.message }),
441
+ catalog.state === "downloading" ? /* @__PURE__ */ jsxs2("div", { className: "db-settings-ai-knowledge-actions", children: [
442
+ /* @__PURE__ */ jsx2(
239
443
  "progress",
240
444
  {
241
445
  max: 100,
@@ -243,7 +447,7 @@ function DownloadedCatalog({
243
447
  "aria-label": `${catalog.name} download progress`
244
448
  }
245
449
  ),
246
- /* @__PURE__ */ jsx(
450
+ /* @__PURE__ */ jsx2(
247
451
  "button",
248
452
  {
249
453
  type: "button",
@@ -253,9 +457,9 @@ function DownloadedCatalog({
253
457
  children: "Cancel download"
254
458
  }
255
459
  )
256
- ] }) : /* @__PURE__ */ jsxs("div", { className: "db-settings-ai-knowledge-actions", children: [
257
- /* @__PURE__ */ jsxs("label", { className: "db-settings-checkbox", children: [
258
- /* @__PURE__ */ jsx(
460
+ ] }) : /* @__PURE__ */ jsxs2("div", { className: "db-settings-ai-knowledge-actions", children: [
461
+ /* @__PURE__ */ jsxs2("label", { className: "db-settings-checkbox", children: [
462
+ /* @__PURE__ */ jsx2(
259
463
  "input",
260
464
  {
261
465
  type: "checkbox",
@@ -270,7 +474,7 @@ function DownloadedCatalog({
270
474
  "Use ",
271
475
  catalog.name
272
476
  ] }),
273
- catalog.updateAvailable && /* @__PURE__ */ jsxs(
477
+ catalog.updateAvailable && /* @__PURE__ */ jsxs2(
274
478
  "button",
275
479
  {
276
480
  type: "button",
@@ -283,7 +487,7 @@ function DownloadedCatalog({
283
487
  ]
284
488
  }
285
489
  ),
286
- /* @__PURE__ */ jsxs(
490
+ /* @__PURE__ */ jsxs2(
287
491
  "button",
288
492
  {
289
493
  type: "button",
@@ -298,14 +502,14 @@ function DownloadedCatalog({
298
502
  }
299
503
  )
300
504
  ] }),
301
- removing && /* @__PURE__ */ jsxs("div", { role: "group", "aria-label": `Confirm removal of ${catalog.name}`, children: [
302
- /* @__PURE__ */ jsxs("p", { className: "db-settings-hint", children: [
505
+ removing && /* @__PURE__ */ jsxs2("div", { role: "group", "aria-label": `Confirm removal of ${catalog.name}`, children: [
506
+ /* @__PURE__ */ jsxs2("p", { className: "db-settings-hint", children: [
303
507
  "Remove ",
304
508
  catalog.name,
305
509
  " from the connected AI service? Other apps using that service will also lose access to this catalog."
306
510
  ] }),
307
- /* @__PURE__ */ jsxs("div", { className: "db-settings-ai-knowledge-actions", children: [
308
- /* @__PURE__ */ jsx(
511
+ /* @__PURE__ */ jsxs2("div", { className: "db-settings-ai-knowledge-actions", children: [
512
+ /* @__PURE__ */ jsx2(
309
513
  "button",
310
514
  {
311
515
  type: "button",
@@ -315,7 +519,7 @@ function DownloadedCatalog({
315
519
  children: "Confirm removal"
316
520
  }
317
521
  ),
318
- /* @__PURE__ */ jsx(
522
+ /* @__PURE__ */ jsx2(
319
523
  "button",
320
524
  {
321
525
  type: "button",
@@ -337,9 +541,9 @@ function AddCatalogDialog({
337
541
  onRefresh,
338
542
  onClose
339
543
  }) {
340
- const [query, setQuery] = useState("");
341
- const searchRef = useRef(null);
342
- const [order] = useState(
544
+ const [query, setQuery] = useState2("");
545
+ const searchRef = useRef2(null);
546
+ const [order] = useState2(
343
547
  () => [...catalogs].sort((a, b) => Number(a.installedVersion !== null) - Number(b.installedVersion !== null)).map((catalog) => catalog.id)
344
548
  );
345
549
  const rank = (catalog) => {
@@ -348,7 +552,7 @@ function AddCatalogDialog({
348
552
  };
349
553
  const needle = query.trim().toLowerCase();
350
554
  const matches = catalogs.filter((catalog) => `${catalog.name} ${catalog.description}`.toLowerCase().includes(needle)).sort((a, b) => rank(a) - rank(b));
351
- const dialog = /* @__PURE__ */ jsxs(
555
+ const dialog = /* @__PURE__ */ jsxs2(
352
556
  Dialog,
353
557
  {
354
558
  title: "Add knowledge catalog",
@@ -357,8 +561,8 @@ function AddCatalogDialog({
357
561
  initialFocusRef: searchRef,
358
562
  className: "db-knowledge-add-dialog",
359
563
  bodyClassName: "db-knowledge-add-body",
360
- footer: /* @__PURE__ */ jsxs(Fragment, { children: [
361
- /* @__PURE__ */ jsx(
564
+ footer: /* @__PURE__ */ jsxs2(Fragment, { children: [
565
+ /* @__PURE__ */ jsx2(
362
566
  "button",
363
567
  {
364
568
  type: "button",
@@ -368,14 +572,14 @@ function AddCatalogDialog({
368
572
  children: "Refresh catalogs"
369
573
  }
370
574
  ),
371
- /* @__PURE__ */ jsx("button", { type: "button", className: "db-settings-action", onClick: onClose, children: "Done" })
575
+ /* @__PURE__ */ jsx2("button", { type: "button", className: "db-settings-action", onClick: onClose, children: "Done" })
372
576
  ] }),
373
577
  children: [
374
- /* @__PURE__ */ jsx("p", { className: "db-settings-hint", children: "Catalogs come from the connected AI service. Once one is downloaded, relevant passages from it are included in AI writing, review, and chat." }),
375
- problem && /* @__PURE__ */ jsx("p", { className: "db-settings-hint db-settings-ai-error", role: "alert", children: problem }),
376
- /* @__PURE__ */ jsxs("label", { className: "db-settings-text db-knowledge-search", children: [
578
+ /* @__PURE__ */ jsx2("p", { className: "db-settings-hint", children: "Catalogs come from the connected AI service. Once one is downloaded, relevant passages from it are included in AI writing, review, and chat." }),
579
+ problem && /* @__PURE__ */ jsx2("p", { className: "db-settings-hint db-settings-ai-error", role: "alert", children: problem }),
580
+ /* @__PURE__ */ jsxs2("label", { className: "db-settings-text db-knowledge-search", children: [
377
581
  "Search catalogs",
378
- /* @__PURE__ */ jsx(
582
+ /* @__PURE__ */ jsx2(
379
583
  "input",
380
584
  {
381
585
  ref: searchRef,
@@ -386,19 +590,19 @@ function AddCatalogDialog({
386
590
  }
387
591
  )
388
592
  ] }),
389
- /* @__PURE__ */ jsx("p", { className: "db-settings-hint", role: "status", children: matches.length > 0 ? "" : catalogs.length === 0 ? "The connected AI service doesn\u2019t offer any catalogs right now." : `No catalogs match \u201C${query.trim()}\u201D.` }),
390
- matches.length > 0 && /* @__PURE__ */ jsx("ul", { className: "db-knowledge-catalog-list", "aria-label": "Catalogs", children: matches.map((catalog) => /* @__PURE__ */ jsxs("li", { className: "db-knowledge-catalog", children: [
391
- /* @__PURE__ */ jsxs("div", { className: "db-knowledge-catalog-text", children: [
392
- /* @__PURE__ */ jsx("strong", { className: "db-knowledge-catalog-name", children: /* @__PURE__ */ jsx(HighlightedText, { text: catalog.name, ranges: matchRanges(catalog.name, needle) }) }),
393
- /* @__PURE__ */ jsx("p", { className: "db-settings-hint", children: /* @__PURE__ */ jsx(
593
+ /* @__PURE__ */ jsx2("p", { className: "db-settings-hint", role: "status", children: matches.length > 0 ? "" : catalogs.length === 0 ? "The connected AI service doesn\u2019t offer any catalogs right now." : `No catalogs match \u201C${query.trim()}\u201D.` }),
594
+ matches.length > 0 && /* @__PURE__ */ jsx2("ul", { className: "db-knowledge-catalog-list", "aria-label": "Catalogs", children: matches.map((catalog) => /* @__PURE__ */ jsxs2("li", { className: "db-knowledge-catalog", children: [
595
+ /* @__PURE__ */ jsxs2("div", { className: "db-knowledge-catalog-text", children: [
596
+ /* @__PURE__ */ jsx2("strong", { className: "db-knowledge-catalog-name", children: /* @__PURE__ */ jsx2(HighlightedText, { text: catalog.name, ranges: matchRanges(catalog.name, needle) }) }),
597
+ /* @__PURE__ */ jsx2("p", { className: "db-settings-hint", children: /* @__PURE__ */ jsx2(
394
598
  HighlightedText,
395
599
  {
396
600
  text: catalog.description,
397
601
  ranges: matchRanges(catalog.description, needle)
398
602
  }
399
603
  ) }),
400
- /* @__PURE__ */ jsx("p", { className: "db-settings-hint", children: catalogFacts(catalog, catalog.version) }),
401
- catalog.message && /* @__PURE__ */ jsx(
604
+ /* @__PURE__ */ jsx2("p", { className: "db-settings-hint", children: catalogFacts(catalog, catalog.version) }),
605
+ catalog.message && /* @__PURE__ */ jsx2(
402
606
  "p",
403
607
  {
404
608
  className: "db-settings-hint",
@@ -407,8 +611,8 @@ function AddCatalogDialog({
407
611
  }
408
612
  )
409
613
  ] }),
410
- /* @__PURE__ */ jsx("div", { className: "db-knowledge-catalog-action", children: catalog.state === "downloading" ? /* @__PURE__ */ jsxs(Fragment, { children: [
411
- /* @__PURE__ */ jsx(
614
+ /* @__PURE__ */ jsx2("div", { className: "db-knowledge-catalog-action", children: catalog.state === "downloading" ? /* @__PURE__ */ jsxs2(Fragment, { children: [
615
+ /* @__PURE__ */ jsx2(
412
616
  "progress",
413
617
  {
414
618
  max: 100,
@@ -416,7 +620,7 @@ function AddCatalogDialog({
416
620
  "aria-label": `${catalog.name} download progress`
417
621
  }
418
622
  ),
419
- /* @__PURE__ */ jsx(
623
+ /* @__PURE__ */ jsx2(
420
624
  "button",
421
625
  {
422
626
  type: "button",
@@ -427,10 +631,10 @@ function AddCatalogDialog({
427
631
  children: "Cancel"
428
632
  }
429
633
  )
430
- ] }) : catalog.installedVersion !== null ? /* @__PURE__ */ jsxs("span", { className: "db-knowledge-catalog-added", children: [
431
- /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\u2713 " }),
634
+ ] }) : catalog.installedVersion !== null ? /* @__PURE__ */ jsxs2("span", { className: "db-knowledge-catalog-added", children: [
635
+ /* @__PURE__ */ jsx2("span", { "aria-hidden": "true", children: "\u2713 " }),
432
636
  "Downloaded"
433
- ] }) : /* @__PURE__ */ jsx(
637
+ ] }) : /* @__PURE__ */ jsx2(
434
638
  "button",
435
639
  {
436
640
  type: "button",
@@ -449,7 +653,7 @@ function AddCatalogDialog({
449
653
  }
450
654
 
451
655
  // src/Settings/AiSettings.tsx
452
- import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
656
+ import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
453
657
  function statusSentence(status) {
454
658
  switch (status.kind) {
455
659
  case "unavailable":
@@ -523,23 +727,23 @@ function downloadOptionLabel(model) {
523
727
  return `${model.label}${size ? ` \u2014 ${size}` : ""}${rating}${slow}`;
524
728
  }
525
729
  function AiSettingsControls({ ai }) {
526
- const [status, setStatus] = useState2(null);
527
- const [preferences, setPreferences] = useState2(null);
528
- const [providerInstalled, setProviderInstalled] = useState2(false);
529
- const [models, setModels] = useState2([]);
530
- const [availableModels, setAvailableModels] = useState2([]);
531
- const [showModelDownloads, setShowModelDownloads] = useState2(false);
532
- const [downloadModelId, setDownloadModelId] = useState2("");
533
- const [downloadProgress, setDownloadProgress] = useState2(null);
534
- const [loadingAvailableModels, setLoadingAvailableModels] = useState2(false);
535
- const [installingModel, setInstallingModel] = useState2(false);
536
- const [busy, setBusy] = useState2(false);
537
- const [saving, setSaving] = useState2(false);
538
- const [failure, setFailure] = useState2(null);
539
- const mounted = useRef2(true);
540
- const installHandle = useRef2(null);
730
+ const [status, setStatus] = useState3(null);
731
+ const [preferences, setPreferences] = useState3(null);
732
+ const [providerInstalled, setProviderInstalled] = useState3(false);
733
+ const [models, setModels] = useState3([]);
734
+ const [availableModels, setAvailableModels] = useState3([]);
735
+ const [showModelDownloads, setShowModelDownloads] = useState3(false);
736
+ const [downloadModelId, setDownloadModelId] = useState3("");
737
+ const [downloadProgress, setDownloadProgress] = useState3(null);
738
+ const [loadingAvailableModels, setLoadingAvailableModels] = useState3(false);
739
+ const [installingModel, setInstallingModel] = useState3(false);
740
+ const [busy, setBusy] = useState3(false);
741
+ const [saving, setSaving] = useState3(false);
742
+ const [failure, setFailure] = useState3(null);
743
+ const mounted = useRef3(true);
744
+ const installHandle = useRef3(null);
541
745
  const modelSelectId = useId2();
542
- useEffect2(() => {
746
+ useEffect3(() => {
543
747
  mounted.current = true;
544
748
  setProviderInstalled(false);
545
749
  const unsubscribe = ai.onStatus((next) => {
@@ -565,12 +769,12 @@ function AiSettingsControls({ ai }) {
565
769
  };
566
770
  }, [ai]);
567
771
  const ready = status?.kind === "ready";
568
- const refreshModels = useCallback(async () => {
772
+ const refreshModels = useCallback2(async () => {
569
773
  const result = await ai.models();
570
774
  if (mounted.current && result.ok) setModels(result.value);
571
775
  return result;
572
776
  }, [ai]);
573
- const refreshAvailableModels = useCallback(async () => {
777
+ const refreshAvailableModels = useCallback2(async () => {
574
778
  if (!ai.availableModels) return;
575
779
  setLoadingAvailableModels(true);
576
780
  try {
@@ -588,7 +792,7 @@ function AiSettingsControls({ ai }) {
588
792
  if (mounted.current) setLoadingAvailableModels(false);
589
793
  }
590
794
  }, [ai]);
591
- useEffect2(() => {
795
+ useEffect3(() => {
592
796
  if (!ready) {
593
797
  setModels([]);
594
798
  setAvailableModels([]);
@@ -597,7 +801,7 @@ function AiSettingsControls({ ai }) {
597
801
  }
598
802
  void refreshModels();
599
803
  }, [ready, refreshModels]);
600
- const connect = useCallback(async () => {
804
+ const connect = useCallback2(async () => {
601
805
  setBusy(true);
602
806
  setFailure(null);
603
807
  try {
@@ -609,7 +813,7 @@ function AiSettingsControls({ ai }) {
609
813
  if (mounted.current) setBusy(false);
610
814
  }
611
815
  }, [ai]);
612
- const switchToBuiltIn = useCallback(async () => {
816
+ const switchToBuiltIn = useCallback2(async () => {
613
817
  setBusy(true);
614
818
  setFailure(null);
615
819
  try {
@@ -618,7 +822,7 @@ function AiSettingsControls({ ai }) {
618
822
  if (mounted.current) setBusy(false);
619
823
  }
620
824
  }, [ai]);
621
- const setEnabled = useCallback(
825
+ const setEnabled = useCallback2(
622
826
  async (enabled2) => {
623
827
  const previous = preferences;
624
828
  setFailure(null);
@@ -638,7 +842,7 @@ function AiSettingsControls({ ai }) {
638
842
  },
639
843
  [ai, preferences]
640
844
  );
641
- const retryBuiltIn = useCallback(async () => {
845
+ const retryBuiltIn = useCallback2(async () => {
642
846
  setBusy(true);
643
847
  setFailure(null);
644
848
  try {
@@ -647,14 +851,14 @@ function AiSettingsControls({ ai }) {
647
851
  if (mounted.current) setBusy(false);
648
852
  }
649
853
  }, [ai]);
650
- const setModel = useCallback(
854
+ const setModel = useCallback2(
651
855
  async (model) => {
652
856
  const next = await ai.setPreferences({ model });
653
857
  if (mounted.current) setPreferences(next);
654
858
  },
655
859
  [ai]
656
860
  );
657
- const addModel = useCallback(async () => {
861
+ const addModel = useCallback2(async () => {
658
862
  if (!downloadModelId || !ai.installModel) return;
659
863
  setFailure(null);
660
864
  setDownloadProgress({ phase: "starting", message: "Starting download\u2026", percent: null });
@@ -692,10 +896,10 @@ function AiSettingsControls({ ai }) {
692
896
  const modelManagement = Boolean(ai.availableModels && ai.installModel);
693
897
  const selectedDownload = availableModels.find((model) => model.id === downloadModelId) ?? null;
694
898
  const failureMessage = failure && !(status.kind === "error" && status.error.message === failure.message) && !(status.kind === "unavailable" && failure.code === "provider-unavailable") ? failure.message : null;
695
- return /* @__PURE__ */ jsxs2("fieldset", { className: "db-settings-fieldset", children: [
696
- /* @__PURE__ */ jsx2("legend", { className: "db-settings-legend", children: "AI assistance" }),
697
- /* @__PURE__ */ jsxs2("label", { className: "db-settings-checkbox", children: [
698
- /* @__PURE__ */ jsx2(
899
+ return /* @__PURE__ */ jsxs3("fieldset", { className: "db-settings-fieldset", children: [
900
+ /* @__PURE__ */ jsx3("legend", { className: "db-settings-legend", children: "AI assistance" }),
901
+ /* @__PURE__ */ jsxs3("label", { className: "db-settings-checkbox", children: [
902
+ /* @__PURE__ */ jsx3(
699
903
  "input",
700
904
  {
701
905
  type: "checkbox",
@@ -706,19 +910,19 @@ function AiSettingsControls({ ai }) {
706
910
  ),
707
911
  "Use AI features"
708
912
  ] }),
709
- /* @__PURE__ */ jsx2("p", { className: "db-settings-hint", children: "DocBlocks can offer AI features that run entirely on this device \u2014 no account needed. Model downloads start only when you choose to add one." }),
710
- enabled && /* @__PURE__ */ jsxs2(Fragment2, { children: [
711
- /* @__PURE__ */ jsx2("p", { className: "db-settings-hint", role: "status", "aria-live": "polite", children: statusSentence(status) }),
712
- code && /* @__PURE__ */ jsxs2("p", { className: "db-settings-hint", children: [
913
+ /* @__PURE__ */ jsx3("p", { className: "db-settings-hint", children: "DocBlocks can offer AI features that run entirely on this device \u2014 no account needed. Model downloads start only when you choose to add one." }),
914
+ enabled && /* @__PURE__ */ jsxs3(Fragment2, { children: [
915
+ /* @__PURE__ */ jsx3("p", { className: "db-settings-hint", role: "status", "aria-live": "polite", children: statusSentence(status) }),
916
+ code && /* @__PURE__ */ jsxs3("p", { className: "db-settings-hint", children: [
713
917
  "Type this code in Gezel to approve DocBlocks:",
714
918
  " ",
715
- /* @__PURE__ */ jsx2("strong", { className: "db-settings-ai-code", children: code })
919
+ /* @__PURE__ */ jsx3("strong", { className: "db-settings-ai-code", children: code })
716
920
  ] }),
717
- failureMessage && /* @__PURE__ */ jsx2("p", { className: "db-settings-hint db-settings-ai-error", role: "alert", children: failureMessage }),
718
- ready && /* @__PURE__ */ jsxs2(Fragment2, { children: [
719
- /* @__PURE__ */ jsxs2("label", { className: "db-settings-select", htmlFor: modelSelectId, children: [
720
- /* @__PURE__ */ jsx2("span", { className: "db-settings-select-header", children: "Model" }),
721
- /* @__PURE__ */ jsxs2(
921
+ failureMessage && /* @__PURE__ */ jsx3("p", { className: "db-settings-hint db-settings-ai-error", role: "alert", children: failureMessage }),
922
+ ready && /* @__PURE__ */ jsxs3(Fragment2, { children: [
923
+ /* @__PURE__ */ jsxs3("label", { className: "db-settings-select", htmlFor: modelSelectId, children: [
924
+ /* @__PURE__ */ jsx3("span", { className: "db-settings-select-header", children: "Model" }),
925
+ /* @__PURE__ */ jsxs3(
722
926
  "select",
723
927
  {
724
928
  id: modelSelectId,
@@ -727,21 +931,21 @@ function AiSettingsControls({ ai }) {
727
931
  disabled: !hasReadyModels || installingModel,
728
932
  onChange: (event) => void setModel(event.currentTarget.value || null),
729
933
  children: [
730
- !hasReadyModels ? /* @__PURE__ */ jsx2("option", { value: "", children: models.length ? "No models ready" : "No models installed" }) : /* @__PURE__ */ jsx2("option", { value: "", children: defaultModel ? `Default: ${modelLabel(defaultModel)}` : "Default" }),
731
- preferences.model && !models.some((model) => model.id === preferences.model) && /* @__PURE__ */ jsx2("option", { value: preferences.model, disabled: true, children: "Previously selected model (not available)" }),
732
- models.map((model) => /* @__PURE__ */ jsx2("option", { value: model.id, disabled: !modelReady(model), children: modelReady(model) ? modelLabel(model) : `${model.label} (${readinessLabel(model)})` }, model.id))
934
+ !hasReadyModels ? /* @__PURE__ */ jsx3("option", { value: "", children: models.length ? "No models ready" : "No models installed" }) : /* @__PURE__ */ jsx3("option", { value: "", children: defaultModel ? `Default: ${modelLabel(defaultModel)}` : "Default" }),
935
+ preferences.model && !models.some((model) => model.id === preferences.model) && /* @__PURE__ */ jsx3("option", { value: preferences.model, disabled: true, children: "Previously selected model (not available)" }),
936
+ models.map((model) => /* @__PURE__ */ jsx3("option", { value: model.id, disabled: !modelReady(model), children: modelReady(model) ? modelLabel(model) : `${model.label} (${readinessLabel(model)})` }, model.id))
733
937
  ]
734
938
  }
735
939
  )
736
940
  ] }),
737
- unavailableModels.map((model) => /* @__PURE__ */ jsxs2("p", { className: "db-settings-hint", children: [
941
+ unavailableModels.map((model) => /* @__PURE__ */ jsxs3("p", { className: "db-settings-hint", children: [
738
942
  model.label,
739
943
  ":",
740
944
  " ",
741
945
  model.unavailableReason ?? "This model is not available right now."
742
946
  ] }, model.id)),
743
- modelManagement && /* @__PURE__ */ jsxs2("div", { className: "db-settings-ai-models", children: [
744
- /* @__PURE__ */ jsx2(
947
+ modelManagement && /* @__PURE__ */ jsxs3("div", { className: "db-settings-ai-models", children: [
948
+ /* @__PURE__ */ jsx3(
745
949
  "button",
746
950
  {
747
951
  type: "button",
@@ -755,27 +959,27 @@ function AiSettingsControls({ ai }) {
755
959
  children: showModelDownloads ? "Hide model downloads" : "Add model\u2026"
756
960
  }
757
961
  ),
758
- showModelDownloads && /* @__PURE__ */ jsxs2("div", { className: "db-settings-ai-model-downloads", children: [
759
- loadingAvailableModels ? /* @__PURE__ */ jsx2("p", { className: "db-settings-hint", role: "status", children: "Looking for models\u2026" }) : availableModels.length === 0 ? /* @__PURE__ */ jsx2("p", { className: "db-settings-hint", children: "No downloadable models are available for this device." }) : /* @__PURE__ */ jsxs2(Fragment2, { children: [
760
- /* @__PURE__ */ jsxs2("label", { className: "db-settings-select", children: [
761
- /* @__PURE__ */ jsx2("span", { className: "db-settings-select-header", children: "Model to download" }),
762
- /* @__PURE__ */ jsx2(
962
+ showModelDownloads && /* @__PURE__ */ jsxs3("div", { className: "db-settings-ai-model-downloads", children: [
963
+ loadingAvailableModels ? /* @__PURE__ */ jsx3("p", { className: "db-settings-hint", role: "status", children: "Looking for models\u2026" }) : availableModels.length === 0 ? /* @__PURE__ */ jsx3("p", { className: "db-settings-hint", children: "No downloadable models are available for this device." }) : /* @__PURE__ */ jsxs3(Fragment2, { children: [
964
+ /* @__PURE__ */ jsxs3("label", { className: "db-settings-select", children: [
965
+ /* @__PURE__ */ jsx3("span", { className: "db-settings-select-header", children: "Model to download" }),
966
+ /* @__PURE__ */ jsx3(
763
967
  "select",
764
968
  {
765
969
  className: "db-settings-select-input",
766
970
  value: downloadModelId,
767
971
  disabled: installingModel,
768
972
  onChange: (event) => setDownloadModelId(event.currentTarget.value),
769
- children: availableModels.map((model) => /* @__PURE__ */ jsx2("option", { value: model.id, children: downloadOptionLabel(model) }, model.id))
973
+ children: availableModels.map((model) => /* @__PURE__ */ jsx3("option", { value: model.id, children: downloadOptionLabel(model) }, model.id))
770
974
  }
771
975
  )
772
976
  ] }),
773
- selectedDownload && /* @__PURE__ */ jsxs2("p", { className: "db-settings-hint", title: selectedDownload.fit?.detail, children: [
977
+ selectedDownload && /* @__PURE__ */ jsxs3("p", { className: "db-settings-hint", title: selectedDownload.fit?.detail, children: [
774
978
  selectedDownload.recommended ? "Recommended for this device" : "Downloads and runs on this device",
775
979
  formatDownloadSize(selectedDownload.downloadBytes) ? ` \xB7 ${formatDownloadSize(selectedDownload.downloadBytes)}` : "",
776
980
  selectedDownload.fit ? ` \xB7 ${selectedDownload.fit.label}` : ""
777
981
  ] }),
778
- /* @__PURE__ */ jsx2(
982
+ /* @__PURE__ */ jsx3(
779
983
  "button",
780
984
  {
781
985
  type: "button",
@@ -786,8 +990,8 @@ function AiSettingsControls({ ai }) {
786
990
  }
787
991
  )
788
992
  ] }),
789
- installingModel && downloadProgress && /* @__PURE__ */ jsxs2("div", { className: "db-settings-ai-download-progress", role: "status", children: [
790
- /* @__PURE__ */ jsx2(
993
+ installingModel && downloadProgress && /* @__PURE__ */ jsxs3("div", { className: "db-settings-ai-download-progress", role: "status", children: [
994
+ /* @__PURE__ */ jsx3(
791
995
  "progress",
792
996
  {
793
997
  max: 100,
@@ -795,7 +999,7 @@ function AiSettingsControls({ ai }) {
795
999
  "aria-label": "Model download progress"
796
1000
  }
797
1001
  ),
798
- /* @__PURE__ */ jsx2(
1002
+ /* @__PURE__ */ jsx3(
799
1003
  "button",
800
1004
  {
801
1005
  type: "button",
@@ -804,7 +1008,7 @@ function AiSettingsControls({ ai }) {
804
1008
  children: "Cancel download"
805
1009
  }
806
1010
  ),
807
- /* @__PURE__ */ jsxs2("span", { children: [
1011
+ /* @__PURE__ */ jsxs3("span", { children: [
808
1012
  downloadProgress.message,
809
1013
  downloadProgress.percent === null ? "" : ` (${Math.round(downloadProgress.percent)}%)`
810
1014
  ] })
@@ -812,8 +1016,9 @@ function AiSettingsControls({ ai }) {
812
1016
  ] })
813
1017
  ] })
814
1018
  ] }),
815
- ready && ai.knowledge && /* @__PURE__ */ jsx2(AiKnowledgeSettings, { knowledge: ai.knowledge }, status.provider.mode),
816
- ready && status.provider.mode === "installed" ? /* @__PURE__ */ jsx2(
1019
+ ready && ai.knowledge && /* @__PURE__ */ jsx3(AiKnowledgeSettings, { knowledge: ai.knowledge }, status.provider.mode),
1020
+ ready && ai.images && /* @__PURE__ */ jsx3(AiImageSettings, { images: ai.images }, status.provider.mode),
1021
+ ready && status.provider.mode === "installed" ? /* @__PURE__ */ jsx3(
817
1022
  "button",
818
1023
  {
819
1024
  type: "button",
@@ -822,7 +1027,7 @@ function AiSettingsControls({ ai }) {
822
1027
  onClick: () => void switchToBuiltIn(),
823
1028
  children: "Use built-in AI"
824
1029
  }
825
- ) : ready && status.provider.mode === "hosted" && providerInstalled ? /* @__PURE__ */ jsx2(
1030
+ ) : ready && status.provider.mode === "hosted" && providerInstalled ? /* @__PURE__ */ jsx3(
826
1031
  "button",
827
1032
  {
828
1033
  type: "button",
@@ -831,7 +1036,7 @@ function AiSettingsControls({ ai }) {
831
1036
  onClick: () => void connect(),
832
1037
  children: "Connect Gezel app\u2026"
833
1038
  }
834
- ) : status.kind === "error" && status.retryable ? /* @__PURE__ */ jsx2(
1039
+ ) : status.kind === "error" && status.retryable ? /* @__PURE__ */ jsx3(
835
1040
  "button",
836
1041
  {
837
1042
  type: "button",
@@ -846,13 +1051,13 @@ function AiSettingsControls({ ai }) {
846
1051
  }
847
1052
 
848
1053
  // src/Settings/WorkspaceSettingsControls.tsx
849
- import { useEffect as useEffect3, useId as useId3, useState as useState3 } from "react";
1054
+ import { useEffect as useEffect4, useId as useId3, useState as useState4 } from "react";
850
1055
  import {
851
1056
  DEFAULT_CATALOG_HTML_PATH,
852
1057
  DEFAULT_CATALOG_JSON_PATH,
853
1058
  DEFAULT_CATALOG_TITLE
854
1059
  } from "@bendyline/docblocks/workspace-settings";
855
- import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
1060
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
856
1061
  function compactObject(value) {
857
1062
  const entries = Object.entries(value).filter(([, field]) => field !== void 0);
858
1063
  return entries.length > 0 ? Object.fromEntries(entries) : void 0;
@@ -904,14 +1109,14 @@ function WorkspaceSettingsControls({
904
1109
  const jsonEnabled = value.catalog?.json?.enabled === true;
905
1110
  const catalogEnabled = htmlEnabled || jsonEnabled;
906
1111
  const excludeText = (value.catalog?.exclude ?? []).join("\n");
907
- const [excludeDraft, setExcludeDraft] = useState3(excludeText);
908
- useEffect3(() => {
1112
+ const [excludeDraft, setExcludeDraft] = useState4(excludeText);
1113
+ useEffect4(() => {
909
1114
  setExcludeDraft(
910
1115
  (current) => current.split("\n").map((line) => line.trim()).filter(Boolean).join("\n") === excludeText ? current : excludeText
911
1116
  );
912
1117
  }, [excludeText]);
913
1118
  const versioning = value.versionHistory?.enabled === void 0 ? "inherit" : value.versionHistory.enabled ? "on" : "off";
914
- const themeSelect = (selectId, selected, emptyLabel, onSelect) => /* @__PURE__ */ jsxs3(
1119
+ const themeSelect = (selectId, selected, emptyLabel, onSelect) => /* @__PURE__ */ jsxs4(
915
1120
  "select",
916
1121
  {
917
1122
  id: selectId,
@@ -920,20 +1125,20 @@ function WorkspaceSettingsControls({
920
1125
  disabled,
921
1126
  onChange: (event) => onSelect(event.currentTarget.value || void 0),
922
1127
  children: [
923
- /* @__PURE__ */ jsx3("option", { value: "", children: emptyLabel }),
924
- themes.map((theme) => /* @__PURE__ */ jsx3("option", { value: theme.id, children: theme.name }, theme.id)),
925
- selected && !themes.some((theme) => theme.id === selected) && /* @__PURE__ */ jsxs3("option", { value: selected, children: [
1128
+ /* @__PURE__ */ jsx4("option", { value: "", children: emptyLabel }),
1129
+ themes.map((theme) => /* @__PURE__ */ jsx4("option", { value: theme.id, children: theme.name }, theme.id)),
1130
+ selected && !themes.some((theme) => theme.id === selected) && /* @__PURE__ */ jsxs4("option", { value: selected, children: [
926
1131
  selected,
927
1132
  " (not installed)"
928
1133
  ] })
929
1134
  ]
930
1135
  }
931
1136
  );
932
- return /* @__PURE__ */ jsxs3("div", { className: "db-workspace-settings", children: [
933
- /* @__PURE__ */ jsxs3("fieldset", { className: "db-settings-fieldset", disabled, children: [
934
- /* @__PURE__ */ jsx3("legend", { className: "db-settings-legend", children: "Documents" }),
935
- /* @__PURE__ */ jsxs3("div", { className: "db-settings-select", children: [
936
- /* @__PURE__ */ jsx3("label", { className: "db-settings-select-header", htmlFor: `${id}-theme`, children: "Default theme" }),
1137
+ return /* @__PURE__ */ jsxs4("div", { className: "db-workspace-settings", children: [
1138
+ /* @__PURE__ */ jsxs4("fieldset", { className: "db-settings-fieldset", disabled, children: [
1139
+ /* @__PURE__ */ jsx4("legend", { className: "db-settings-legend", children: "Documents" }),
1140
+ /* @__PURE__ */ jsxs4("div", { className: "db-settings-select", children: [
1141
+ /* @__PURE__ */ jsx4("label", { className: "db-settings-select-header", htmlFor: `${id}-theme`, children: "Default theme" }),
937
1142
  themeSelect(
938
1143
  `${id}-theme`,
939
1144
  value.documents?.defaultTheme,
@@ -947,13 +1152,13 @@ function WorkspaceSettingsControls({
947
1152
  )
948
1153
  )
949
1154
  ] }),
950
- /* @__PURE__ */ jsx3("p", { className: "db-settings-hint", children: "Used by documents in this folder that don\u2019t choose a theme of their own. Web pages pick up a change the next time they\u2019re saved." })
1155
+ /* @__PURE__ */ jsx4("p", { className: "db-settings-hint", children: "Used by documents in this folder that don\u2019t choose a theme of their own. Web pages pick up a change the next time they\u2019re saved." })
951
1156
  ] }),
952
- /* @__PURE__ */ jsxs3("fieldset", { className: "db-settings-fieldset", disabled, children: [
953
- /* @__PURE__ */ jsx3("legend", { className: "db-settings-legend", children: "Catalog" }),
954
- /* @__PURE__ */ jsx3("p", { className: "db-settings-hint", children: "Keep a list of every document in this folder up to date as you save. DocBlocks only ever replaces files it created." }),
955
- /* @__PURE__ */ jsxs3("label", { className: "db-settings-checkbox", children: [
956
- /* @__PURE__ */ jsx3(
1157
+ /* @__PURE__ */ jsxs4("fieldset", { className: "db-settings-fieldset", disabled, children: [
1158
+ /* @__PURE__ */ jsx4("legend", { className: "db-settings-legend", children: "Catalog" }),
1159
+ /* @__PURE__ */ jsx4("p", { className: "db-settings-hint", children: "Keep a list of every document in this folder up to date as you save. DocBlocks only ever replaces files it created." }),
1160
+ /* @__PURE__ */ jsxs4("label", { className: "db-settings-checkbox", children: [
1161
+ /* @__PURE__ */ jsx4(
957
1162
  "input",
958
1163
  {
959
1164
  type: "checkbox",
@@ -965,10 +1170,10 @@ function WorkspaceSettingsControls({
965
1170
  ),
966
1171
  "Catalog page"
967
1172
  ] }),
968
- htmlEnabled && /* @__PURE__ */ jsxs3("div", { className: "db-settings-subfields", children: [
969
- /* @__PURE__ */ jsxs3("div", { className: "db-settings-text", children: [
970
- /* @__PURE__ */ jsx3("label", { htmlFor: `${id}-html-path`, children: "Page file" }),
971
- /* @__PURE__ */ jsx3(
1173
+ htmlEnabled && /* @__PURE__ */ jsxs4("div", { className: "db-settings-subfields", children: [
1174
+ /* @__PURE__ */ jsxs4("div", { className: "db-settings-text", children: [
1175
+ /* @__PURE__ */ jsx4("label", { htmlFor: `${id}-html-path`, children: "Page file" }),
1176
+ /* @__PURE__ */ jsx4(
972
1177
  "input",
973
1178
  {
974
1179
  id: `${id}-html-path`,
@@ -983,8 +1188,8 @@ function WorkspaceSettingsControls({
983
1188
  }
984
1189
  )
985
1190
  ] }),
986
- /* @__PURE__ */ jsxs3("div", { className: "db-settings-text", children: [
987
- /* @__PURE__ */ jsx3("label", { htmlFor: `${id}-html-theme`, children: "Page theme" }),
1191
+ /* @__PURE__ */ jsxs4("div", { className: "db-settings-text", children: [
1192
+ /* @__PURE__ */ jsx4("label", { htmlFor: `${id}-html-theme`, children: "Page theme" }),
988
1193
  themeSelect(
989
1194
  `${id}-html-theme`,
990
1195
  value.catalog?.html?.theme,
@@ -993,8 +1198,8 @@ function WorkspaceSettingsControls({
993
1198
  )
994
1199
  ] })
995
1200
  ] }),
996
- /* @__PURE__ */ jsxs3("label", { className: "db-settings-checkbox", children: [
997
- /* @__PURE__ */ jsx3(
1201
+ /* @__PURE__ */ jsxs4("label", { className: "db-settings-checkbox", children: [
1202
+ /* @__PURE__ */ jsx4(
998
1203
  "input",
999
1204
  {
1000
1205
  type: "checkbox",
@@ -1006,10 +1211,10 @@ function WorkspaceSettingsControls({
1006
1211
  ),
1007
1212
  "Catalog data (JSON)"
1008
1213
  ] }),
1009
- jsonEnabled && /* @__PURE__ */ jsxs3("div", { className: "db-settings-subfields", children: [
1010
- /* @__PURE__ */ jsxs3("div", { className: "db-settings-text", children: [
1011
- /* @__PURE__ */ jsx3("label", { htmlFor: `${id}-json-path`, children: "Data file" }),
1012
- /* @__PURE__ */ jsx3(
1214
+ jsonEnabled && /* @__PURE__ */ jsxs4("div", { className: "db-settings-subfields", children: [
1215
+ /* @__PURE__ */ jsxs4("div", { className: "db-settings-text", children: [
1216
+ /* @__PURE__ */ jsx4("label", { htmlFor: `${id}-json-path`, children: "Data file" }),
1217
+ /* @__PURE__ */ jsx4(
1013
1218
  "input",
1014
1219
  {
1015
1220
  id: `${id}-json-path`,
@@ -1024,7 +1229,7 @@ function WorkspaceSettingsControls({
1024
1229
  }
1025
1230
  )
1026
1231
  ] }),
1027
- /* @__PURE__ */ jsx3(
1232
+ /* @__PURE__ */ jsx4(
1028
1233
  "div",
1029
1234
  {
1030
1235
  className: "db-settings-radio-row",
@@ -1033,8 +1238,8 @@ function WorkspaceSettingsControls({
1033
1238
  children: [
1034
1239
  ["metadata", "Titles, descriptions and outlines"],
1035
1240
  ["markdown", "Also include each document\u2019s Markdown"]
1036
- ].map(([content, label]) => /* @__PURE__ */ jsxs3("label", { className: "db-settings-radio db-settings-radio--inline", children: [
1037
- /* @__PURE__ */ jsx3(
1241
+ ].map(([content, label]) => /* @__PURE__ */ jsxs4("label", { className: "db-settings-radio db-settings-radio--inline", children: [
1242
+ /* @__PURE__ */ jsx4(
1038
1243
  "input",
1039
1244
  {
1040
1245
  type: "radio",
@@ -1052,10 +1257,10 @@ function WorkspaceSettingsControls({
1052
1257
  }
1053
1258
  )
1054
1259
  ] }),
1055
- catalogEnabled && /* @__PURE__ */ jsxs3("div", { className: "db-settings-subfields", children: [
1056
- /* @__PURE__ */ jsxs3("div", { className: "db-settings-text", children: [
1057
- /* @__PURE__ */ jsx3("label", { htmlFor: `${id}-title`, children: "Title" }),
1058
- /* @__PURE__ */ jsx3(
1260
+ catalogEnabled && /* @__PURE__ */ jsxs4("div", { className: "db-settings-subfields", children: [
1261
+ /* @__PURE__ */ jsxs4("div", { className: "db-settings-text", children: [
1262
+ /* @__PURE__ */ jsx4("label", { htmlFor: `${id}-title`, children: "Title" }),
1263
+ /* @__PURE__ */ jsx4(
1059
1264
  "input",
1060
1265
  {
1061
1266
  id: `${id}-title`,
@@ -1067,9 +1272,9 @@ function WorkspaceSettingsControls({
1067
1272
  }
1068
1273
  )
1069
1274
  ] }),
1070
- /* @__PURE__ */ jsxs3("div", { className: "db-settings-text", children: [
1071
- /* @__PURE__ */ jsx3("label", { htmlFor: `${id}-sort`, children: "Order" }),
1072
- /* @__PURE__ */ jsxs3(
1275
+ /* @__PURE__ */ jsxs4("div", { className: "db-settings-text", children: [
1276
+ /* @__PURE__ */ jsx4("label", { htmlFor: `${id}-sort`, children: "Order" }),
1277
+ /* @__PURE__ */ jsxs4(
1073
1278
  "select",
1074
1279
  {
1075
1280
  id: `${id}-sort`,
@@ -1080,16 +1285,16 @@ function WorkspaceSettingsControls({
1080
1285
  onChange(withCatalog(value, { sort: sort === "title" ? void 0 : sort }));
1081
1286
  },
1082
1287
  children: [
1083
- /* @__PURE__ */ jsx3("option", { value: "title", children: "By title" }),
1084
- /* @__PURE__ */ jsx3("option", { value: "date", children: "Newest first (frontmatter date)" }),
1085
- /* @__PURE__ */ jsx3("option", { value: "path", children: "By file path" })
1288
+ /* @__PURE__ */ jsx4("option", { value: "title", children: "By title" }),
1289
+ /* @__PURE__ */ jsx4("option", { value: "date", children: "Newest first (frontmatter date)" }),
1290
+ /* @__PURE__ */ jsx4("option", { value: "path", children: "By file path" })
1086
1291
  ]
1087
1292
  }
1088
1293
  )
1089
1294
  ] }),
1090
- /* @__PURE__ */ jsxs3("div", { className: "db-settings-text", children: [
1091
- /* @__PURE__ */ jsx3("label", { htmlFor: `${id}-exclude`, children: "Leave out" }),
1092
- /* @__PURE__ */ jsx3(
1295
+ /* @__PURE__ */ jsxs4("div", { className: "db-settings-text", children: [
1296
+ /* @__PURE__ */ jsx4("label", { htmlFor: `${id}-exclude`, children: "Leave out" }),
1297
+ /* @__PURE__ */ jsx4(
1093
1298
  "textarea",
1094
1299
  {
1095
1300
  id: `${id}-exclude`,
@@ -1109,9 +1314,9 @@ function WorkspaceSettingsControls({
1109
1314
  }
1110
1315
  )
1111
1316
  ] }),
1112
- /* @__PURE__ */ jsx3("p", { className: "db-settings-hint", children: "One folder or file per line." }),
1113
- (catalogStatus || onRegenerate) && /* @__PURE__ */ jsxs3("div", { className: "db-settings-status-row", children: [
1114
- catalogStatus && /* @__PURE__ */ jsx3(
1317
+ /* @__PURE__ */ jsx4("p", { className: "db-settings-hint", children: "One folder or file per line." }),
1318
+ (catalogStatus || onRegenerate) && /* @__PURE__ */ jsxs4("div", { className: "db-settings-status-row", children: [
1319
+ catalogStatus && /* @__PURE__ */ jsx4(
1115
1320
  "p",
1116
1321
  {
1117
1322
  className: `db-settings-status db-settings-status--${catalogStatus.tone}`,
@@ -1119,7 +1324,7 @@ function WorkspaceSettingsControls({
1119
1324
  children: catalogStatus.message
1120
1325
  }
1121
1326
  ),
1122
- onRegenerate && /* @__PURE__ */ jsx3(
1327
+ onRegenerate && /* @__PURE__ */ jsx4(
1123
1328
  "button",
1124
1329
  {
1125
1330
  type: "button",
@@ -1132,19 +1337,19 @@ function WorkspaceSettingsControls({
1132
1337
  ] })
1133
1338
  ] })
1134
1339
  ] }),
1135
- versionHistory && /* @__PURE__ */ jsxs3("fieldset", { className: "db-settings-fieldset", disabled, children: [
1136
- /* @__PURE__ */ jsx3("legend", { className: "db-settings-legend", children: "Version history" }),
1137
- /* @__PURE__ */ jsxs3("p", { className: "db-settings-hint", children: [
1340
+ versionHistory && /* @__PURE__ */ jsxs4("fieldset", { className: "db-settings-fieldset", disabled, children: [
1341
+ /* @__PURE__ */ jsx4("legend", { className: "db-settings-legend", children: "Version history" }),
1342
+ /* @__PURE__ */ jsxs4("p", { className: "db-settings-hint", children: [
1138
1343
  "Keeps prior revisions in ",
1139
- /* @__PURE__ */ jsx3("code", { children: "<name>_files/.versions/" }),
1344
+ /* @__PURE__ */ jsx4("code", { children: "<name>_files/.versions/" }),
1140
1345
  " for documents in this folder."
1141
1346
  ] }),
1142
1347
  [
1143
1348
  ["inherit", versionHistory.inheritLabel],
1144
1349
  ["on", "On for this folder"],
1145
1350
  ["off", "Off for this folder"]
1146
- ].map(([option, label]) => /* @__PURE__ */ jsxs3("label", { className: "db-settings-radio", children: [
1147
- /* @__PURE__ */ jsx3(
1351
+ ].map(([option, label]) => /* @__PURE__ */ jsxs4("label", { className: "db-settings-radio", children: [
1352
+ /* @__PURE__ */ jsx4(
1148
1353
  "input",
1149
1354
  {
1150
1355
  type: "radio",
@@ -1165,9 +1370,9 @@ function WorkspaceSettingsControls({
1165
1370
  ),
1166
1371
  label
1167
1372
  ] }, option)),
1168
- /* @__PURE__ */ jsxs3("div", { className: "db-settings-text", children: [
1169
- /* @__PURE__ */ jsx3("label", { htmlFor: `${id}-keep`, children: "Revisions to keep per document" }),
1170
- /* @__PURE__ */ jsx3(
1373
+ /* @__PURE__ */ jsxs4("div", { className: "db-settings-text", children: [
1374
+ /* @__PURE__ */ jsx4("label", { htmlFor: `${id}-keep`, children: "Revisions to keep per document" }),
1375
+ /* @__PURE__ */ jsx4(
1171
1376
  "input",
1172
1377
  {
1173
1378
  id: `${id}-keep`,
@@ -1199,14 +1404,115 @@ function WorkspaceSettingsControls({
1199
1404
 
1200
1405
  // src/Settings/Settings.tsx
1201
1406
  import {
1202
- useCallback as useCallback2,
1203
- useEffect as useEffect4,
1407
+ useCallback as useCallback3,
1408
+ useEffect as useEffect6,
1204
1409
  useId as useId4,
1205
1410
  useLayoutEffect,
1206
- useRef as useRef3,
1207
- useState as useState4
1411
+ useRef as useRef4,
1412
+ useState as useState6
1208
1413
  } from "react";
1209
1414
 
1415
+ // src/layout/form-factor.ts
1416
+ var DB_BREAKPOINTS = Object.freeze({
1417
+ /** Inclusive upper bound for phones and narrow slivers. */
1418
+ compactMax: 720,
1419
+ /** Inclusive upper bound for tablet-portrait and half-screen laptops. */
1420
+ mediumMax: 1023,
1421
+ /** Inclusive upper bound for tablet-landscape and laptops. */
1422
+ expandedMax: 1439,
1423
+ /**
1424
+ * Largest short edge still considered a phone. Orientation-independent on
1425
+ * purpose: a phone turned sideways is 844x390, which is `medium` by width but
1426
+ * is obviously not a tablet. The widest phone short edge in circulation is
1427
+ * around 430px; the narrowest tablet short edge is the iPad mini's 744px, so
1428
+ * 520 sits in open space between them.
1429
+ */
1430
+ phoneMaxShortEdge: 520
1431
+ });
1432
+ var SIDEBAR_WIDTH_DEFAULT = 320;
1433
+ var SIDEBAR_WIDTH_MIN = 320;
1434
+ var SIDEBAR_WIDTH_MAX = 600;
1435
+ var SIDEBAR_COLLAPSE_THRESHOLD = SIDEBAR_WIDTH_MIN;
1436
+ var DB_LAYOUT_MINIMA = Object.freeze({
1437
+ /**
1438
+ * Narrower than this, an editor pane beside the sidebar is not worth the
1439
+ * split. Paired with `SIDEBAR_WIDTH_MIN` to derive `splitPaneAllowed`.
1440
+ */
1441
+ editorMinWidth: 480
1442
+ });
1443
+ var SPLIT_PANE_MIN_WIDTH = SIDEBAR_WIDTH_MIN + DB_LAYOUT_MINIMA.editorMinWidth;
1444
+ function classifyWidth(width) {
1445
+ if (width <= DB_BREAKPOINTS.compactMax) return "compact";
1446
+ if (width <= DB_BREAKPOINTS.mediumMax) return "medium";
1447
+ if (width <= DB_BREAKPOINTS.expandedMax) return "expanded";
1448
+ return "wide";
1449
+ }
1450
+ function classifyFormFactor(input) {
1451
+ const widthClass = classifyWidth(input.width);
1452
+ const orientation = input.height >= input.width ? "portrait" : "landscape";
1453
+ let formFactor;
1454
+ if (input.pointer === "fine") {
1455
+ formFactor = "desktop";
1456
+ } else if (Math.min(input.width, input.height) <= DB_BREAKPOINTS.phoneMaxShortEdge) {
1457
+ formFactor = "phone";
1458
+ } else {
1459
+ formFactor = orientation === "portrait" ? "tablet-portrait" : "tablet-landscape";
1460
+ }
1461
+ return {
1462
+ ...input,
1463
+ widthClass,
1464
+ orientation,
1465
+ formFactor,
1466
+ splitPaneAllowed: input.width >= SPLIT_PANE_MIN_WIDTH
1467
+ };
1468
+ }
1469
+ function resolveLayoutMode(formFactor, preference) {
1470
+ if (!formFactor.splitPaneAllowed) return "single-pane";
1471
+ if (preference === "collapsed") return "single-pane";
1472
+ if (preference === "pinned") return "split-pane";
1473
+ if (formFactor.widthClass === "expanded" || formFactor.widthClass === "wide") {
1474
+ return "split-pane";
1475
+ }
1476
+ if (formFactor.pointer === "fine") return "split-pane";
1477
+ return "single-pane";
1478
+ }
1479
+ function formFactorDataAttributes(formFactor, layoutMode) {
1480
+ return Object.freeze({
1481
+ "data-db-width": formFactor.widthClass,
1482
+ "data-db-form-factor": formFactor.formFactor,
1483
+ "data-db-pointer": formFactor.pointer,
1484
+ "data-db-hover": formFactor.hover,
1485
+ "data-db-orientation": formFactor.orientation,
1486
+ "data-db-layout": layoutMode
1487
+ });
1488
+ }
1489
+
1490
+ // src/layout/useMediaQuery.ts
1491
+ import { useEffect as useEffect5, useState as useState5 } from "react";
1492
+ var INSTALLED_DISPLAY_QUERIES = [
1493
+ "(display-mode: window-controls-overlay)",
1494
+ "(display-mode: standalone)"
1495
+ ];
1496
+ function matchesMediaQuery(query) {
1497
+ if (typeof globalThis.matchMedia !== "function") return false;
1498
+ return globalThis.matchMedia(query).matches;
1499
+ }
1500
+ function isInstalledDisplayMode() {
1501
+ return INSTALLED_DISPLAY_QUERIES.some(matchesMediaQuery);
1502
+ }
1503
+ function useMediaQuery(query) {
1504
+ const [matches, setMatches] = useState5(() => matchesMediaQuery(query));
1505
+ useEffect5(() => {
1506
+ if (typeof globalThis.matchMedia !== "function") return;
1507
+ const list = globalThis.matchMedia(query);
1508
+ const update = () => setMatches(list.matches);
1509
+ update();
1510
+ list.addEventListener("change", update);
1511
+ return () => list.removeEventListener("change", update);
1512
+ }, [query]);
1513
+ return matches;
1514
+ }
1515
+
1210
1516
  // src/preferences/theme.ts
1211
1517
  var ACCENT_COLORS = [
1212
1518
  "rust",
@@ -1408,7 +1714,7 @@ function isRecord(value) {
1408
1714
  }
1409
1715
 
1410
1716
  // src/Settings/Settings.tsx
1411
- import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
1717
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
1412
1718
  var ACCENT_LABELS = {
1413
1719
  rust: "Rust",
1414
1720
  green: "Green",
@@ -1418,15 +1724,140 @@ var ACCENT_LABELS = {
1418
1724
  orange: "Orange",
1419
1725
  gray: "Gray"
1420
1726
  };
1421
- function SettingsDialog({ title = "Settings", onClose, children }) {
1422
- return /* @__PURE__ */ jsx4(Dialog, { title, onClose, size: "wide", children });
1727
+ function SettingsDialog({
1728
+ title = "Settings",
1729
+ onClose,
1730
+ children,
1731
+ sections,
1732
+ section,
1733
+ onSectionChange
1734
+ }) {
1735
+ const sectioned = sections !== void 0 && sections.length > 1;
1736
+ return /* @__PURE__ */ jsx5(
1737
+ Dialog,
1738
+ {
1739
+ title,
1740
+ onClose,
1741
+ size: "wide",
1742
+ className: sectioned ? "db-settings-dialog--sectioned" : void 0,
1743
+ bodyClassName: sectioned ? "db-settings-dialog-body--sectioned" : void 0,
1744
+ children: sectioned ? /* @__PURE__ */ jsx5(SettingsSections, { sections, section, onSectionChange }) : sections?.[0]?.content ?? children
1745
+ }
1746
+ );
1747
+ }
1748
+ var SECTION_DROPDOWN_QUERY = [
1749
+ `(max-width: ${DB_BREAKPOINTS.compactMax}px)`,
1750
+ "(pointer: coarse) and (orientation: portrait)",
1751
+ `(pointer: coarse) and (max-height: ${DB_BREAKPOINTS.phoneMaxShortEdge}px)`
1752
+ ].join(", ");
1753
+ function SettingsSections({
1754
+ sections,
1755
+ section,
1756
+ onSectionChange
1757
+ }) {
1758
+ const [ownSection, setOwnSection] = useState6(sections[0].id);
1759
+ const active = sections.find((entry) => entry.id === (section ?? ownSection)) ?? sections[0];
1760
+ const dropdown = useMediaQuery(SECTION_DROPDOWN_QUERY);
1761
+ const baseId = useId4();
1762
+ const tabRefs = useRef4(/* @__PURE__ */ new Map());
1763
+ const tabId = (id) => `${baseId}-${id}-tab`;
1764
+ const panelId = (id) => `${baseId}-${id}-panel`;
1765
+ const select = (id) => {
1766
+ setOwnSection(id);
1767
+ onSectionChange?.(id);
1768
+ };
1769
+ const handleTabKeyDown = (event) => {
1770
+ const index = sections.indexOf(active);
1771
+ let next;
1772
+ switch (event.key) {
1773
+ case "ArrowDown":
1774
+ next = (index + 1) % sections.length;
1775
+ break;
1776
+ case "ArrowUp":
1777
+ next = (index - 1 + sections.length) % sections.length;
1778
+ break;
1779
+ case "Home":
1780
+ next = 0;
1781
+ break;
1782
+ case "End":
1783
+ next = sections.length - 1;
1784
+ break;
1785
+ default:
1786
+ return;
1787
+ }
1788
+ event.preventDefault();
1789
+ const target = sections[next];
1790
+ select(target.id);
1791
+ tabRefs.current.get(target.id)?.focus();
1792
+ };
1793
+ return /* @__PURE__ */ jsxs5("div", { className: `db-settings-sections db-settings-sections--${dropdown ? "dropdown" : "tabs"}`, children: [
1794
+ dropdown ? /* @__PURE__ */ jsx5("div", { className: "db-settings-section-picker", children: /* @__PURE__ */ jsx5(
1795
+ "select",
1796
+ {
1797
+ className: "db-settings-select-input db-settings-section-select",
1798
+ "aria-label": "Settings section",
1799
+ value: active.id,
1800
+ onChange: (event) => {
1801
+ const value = event.currentTarget.value;
1802
+ const next = sections.find((entry) => entry.id === value);
1803
+ if (next) select(next.id);
1804
+ },
1805
+ children: sections.map((entry) => /* @__PURE__ */ jsx5("option", { value: entry.id, children: entry.label }, entry.id))
1806
+ }
1807
+ ) }) : /* @__PURE__ */ jsx5(
1808
+ "div",
1809
+ {
1810
+ className: "db-settings-tabs",
1811
+ role: "tablist",
1812
+ "aria-orientation": "vertical",
1813
+ "aria-label": "Settings sections",
1814
+ children: sections.map((entry) => {
1815
+ const selected = entry === active;
1816
+ return /* @__PURE__ */ jsx5(
1817
+ "button",
1818
+ {
1819
+ ref: (element) => {
1820
+ if (element) tabRefs.current.set(entry.id, element);
1821
+ else tabRefs.current.delete(entry.id);
1822
+ },
1823
+ type: "button",
1824
+ role: "tab",
1825
+ id: tabId(entry.id),
1826
+ className: `db-settings-tab${selected ? " db-settings-tab--selected" : ""}`,
1827
+ "aria-selected": selected,
1828
+ "aria-controls": panelId(entry.id),
1829
+ tabIndex: selected ? 0 : -1,
1830
+ onClick: () => select(entry.id),
1831
+ onKeyDown: handleTabKeyDown,
1832
+ children: entry.label
1833
+ },
1834
+ entry.id
1835
+ );
1836
+ })
1837
+ }
1838
+ ),
1839
+ sections.map((entry) => /* @__PURE__ */ jsx5(
1840
+ "div",
1841
+ {
1842
+ id: panelId(entry.id),
1843
+ className: "db-settings-panel",
1844
+ role: dropdown ? "region" : "tabpanel",
1845
+ "aria-labelledby": dropdown ? void 0 : tabId(entry.id),
1846
+ "aria-label": dropdown ? entry.label : void 0,
1847
+ tabIndex: dropdown ? void 0 : 0,
1848
+ hidden: entry !== active,
1849
+ children: entry.content
1850
+ },
1851
+ entry.id
1852
+ ))
1853
+ ] });
1423
1854
  }
1424
1855
  function ThemeSettings({ value, onChange, name = "theme" }) {
1425
- return /* @__PURE__ */ jsxs4("fieldset", { className: "db-settings-fieldset", children: [
1426
- /* @__PURE__ */ jsx4("legend", { className: "db-settings-legend", children: "Theme" }),
1427
- /* @__PURE__ */ jsxs4("div", { className: "db-settings-radio-row", children: [
1428
- /* @__PURE__ */ jsxs4("label", { className: "db-settings-radio db-settings-radio--inline", children: [
1429
- /* @__PURE__ */ jsx4(
1856
+ return /* @__PURE__ */ jsxs5("fieldset", { className: "db-settings-fieldset", children: [
1857
+ /* @__PURE__ */ jsx5("legend", { className: "db-settings-legend", children: "Theme" }),
1858
+ /* @__PURE__ */ jsxs5("div", { className: "db-settings-radio-row", children: [
1859
+ /* @__PURE__ */ jsxs5("label", { className: "db-settings-radio db-settings-radio--inline", children: [
1860
+ /* @__PURE__ */ jsx5(
1430
1861
  "input",
1431
1862
  {
1432
1863
  type: "radio",
@@ -1438,8 +1869,8 @@ function ThemeSettings({ value, onChange, name = "theme" }) {
1438
1869
  ),
1439
1870
  "System default"
1440
1871
  ] }),
1441
- /* @__PURE__ */ jsxs4("label", { className: "db-settings-radio db-settings-radio--inline", children: [
1442
- /* @__PURE__ */ jsx4(
1872
+ /* @__PURE__ */ jsxs5("label", { className: "db-settings-radio db-settings-radio--inline", children: [
1873
+ /* @__PURE__ */ jsx5(
1443
1874
  "input",
1444
1875
  {
1445
1876
  type: "radio",
@@ -1451,8 +1882,8 @@ function ThemeSettings({ value, onChange, name = "theme" }) {
1451
1882
  ),
1452
1883
  "Light"
1453
1884
  ] }),
1454
- /* @__PURE__ */ jsxs4("label", { className: "db-settings-radio db-settings-radio--inline", children: [
1455
- /* @__PURE__ */ jsx4(
1885
+ /* @__PURE__ */ jsxs5("label", { className: "db-settings-radio db-settings-radio--inline", children: [
1886
+ /* @__PURE__ */ jsx5(
1456
1887
  "input",
1457
1888
  {
1458
1889
  type: "radio",
@@ -1472,12 +1903,12 @@ function InterfaceFontSettings({
1472
1903
  onChange,
1473
1904
  name = "interface-font"
1474
1905
  }) {
1475
- return /* @__PURE__ */ jsxs4("fieldset", { className: "db-settings-fieldset", children: [
1476
- /* @__PURE__ */ jsx4("legend", { className: "db-settings-legend", children: "Interface font" }),
1477
- /* @__PURE__ */ jsx4("p", { className: "db-settings-hint", children: "Applies to menus and panels, never to your documents." }),
1478
- /* @__PURE__ */ jsxs4("div", { className: "db-settings-radio-row", children: [
1479
- /* @__PURE__ */ jsxs4("label", { className: "db-settings-radio db-settings-radio--inline", children: [
1480
- /* @__PURE__ */ jsx4(
1906
+ return /* @__PURE__ */ jsxs5("fieldset", { className: "db-settings-fieldset", children: [
1907
+ /* @__PURE__ */ jsx5("legend", { className: "db-settings-legend", children: "Interface font" }),
1908
+ /* @__PURE__ */ jsx5("p", { className: "db-settings-hint", children: "Applies to menus and panels, never to your documents." }),
1909
+ /* @__PURE__ */ jsxs5("div", { className: "db-settings-radio-row", children: [
1910
+ /* @__PURE__ */ jsxs5("label", { className: "db-settings-radio db-settings-radio--inline", children: [
1911
+ /* @__PURE__ */ jsx5(
1481
1912
  "input",
1482
1913
  {
1483
1914
  type: "radio",
@@ -1489,8 +1920,8 @@ function InterfaceFontSettings({
1489
1920
  ),
1490
1921
  "DocBlocks"
1491
1922
  ] }),
1492
- /* @__PURE__ */ jsxs4("label", { className: "db-settings-radio db-settings-radio--inline", children: [
1493
- /* @__PURE__ */ jsx4(
1923
+ /* @__PURE__ */ jsxs5("label", { className: "db-settings-radio db-settings-radio--inline", children: [
1924
+ /* @__PURE__ */ jsx5(
1494
1925
  "input",
1495
1926
  {
1496
1927
  type: "radio",
@@ -1510,15 +1941,15 @@ function AccentColorSettings({
1510
1941
  onChange,
1511
1942
  name = "accent-color"
1512
1943
  }) {
1513
- return /* @__PURE__ */ jsxs4("fieldset", { className: "db-settings-fieldset", children: [
1514
- /* @__PURE__ */ jsx4("legend", { className: "db-settings-legend", children: "Accent color" }),
1515
- /* @__PURE__ */ jsx4("p", { className: "db-settings-hint", children: "Used in both light and dark appearances." }),
1516
- /* @__PURE__ */ jsx4("div", { className: "db-settings-accent-grid", children: ACCENT_COLORS.map((color) => /* @__PURE__ */ jsxs4(
1944
+ return /* @__PURE__ */ jsxs5("fieldset", { className: "db-settings-fieldset", children: [
1945
+ /* @__PURE__ */ jsx5("legend", { className: "db-settings-legend", children: "Accent color" }),
1946
+ /* @__PURE__ */ jsx5("p", { className: "db-settings-hint", children: "Used in both light and dark appearances." }),
1947
+ /* @__PURE__ */ jsx5("div", { className: "db-settings-accent-grid", children: ACCENT_COLORS.map((color) => /* @__PURE__ */ jsxs5(
1517
1948
  "label",
1518
1949
  {
1519
1950
  className: `db-settings-accent${value === color ? " db-settings-accent--selected" : ""}`,
1520
1951
  children: [
1521
- /* @__PURE__ */ jsx4(
1952
+ /* @__PURE__ */ jsx5(
1522
1953
  "input",
1523
1954
  {
1524
1955
  className: "db-settings-accent-input",
@@ -1529,14 +1960,14 @@ function AccentColorSettings({
1529
1960
  onChange: () => onChange(color)
1530
1961
  }
1531
1962
  ),
1532
- /* @__PURE__ */ jsx4(
1963
+ /* @__PURE__ */ jsx5(
1533
1964
  "span",
1534
1965
  {
1535
1966
  className: `db-settings-accent-swatch db-settings-accent-swatch--${color}`,
1536
1967
  "aria-hidden": "true"
1537
1968
  }
1538
1969
  ),
1539
- /* @__PURE__ */ jsx4("span", { children: ACCENT_LABELS[color] })
1970
+ /* @__PURE__ */ jsx5("span", { children: ACCENT_LABELS[color] })
1540
1971
  ]
1541
1972
  },
1542
1973
  color
@@ -1544,11 +1975,11 @@ function AccentColorSettings({
1544
1975
  ] });
1545
1976
  }
1546
1977
  function ProofingSettingsControls({ value, onChange }) {
1547
- return /* @__PURE__ */ jsxs4("fieldset", { className: "db-settings-fieldset", children: [
1548
- /* @__PURE__ */ jsx4("legend", { className: "db-settings-legend", children: "Spelling and grammar" }),
1549
- /* @__PURE__ */ jsx4("p", { className: "db-settings-hint", children: "Checking runs on this device \u2014 nothing you write is sent anywhere." }),
1550
- /* @__PURE__ */ jsxs4("label", { className: "db-settings-checkbox", children: [
1551
- /* @__PURE__ */ jsx4(
1978
+ return /* @__PURE__ */ jsxs5("fieldset", { className: "db-settings-fieldset", children: [
1979
+ /* @__PURE__ */ jsx5("legend", { className: "db-settings-legend", children: "Spelling and grammar" }),
1980
+ /* @__PURE__ */ jsx5("p", { className: "db-settings-hint", children: "Checking runs on this device \u2014 nothing you write is sent anywhere." }),
1981
+ /* @__PURE__ */ jsxs5("label", { className: "db-settings-checkbox", children: [
1982
+ /* @__PURE__ */ jsx5(
1552
1983
  "input",
1553
1984
  {
1554
1985
  type: "checkbox",
@@ -1558,8 +1989,8 @@ function ProofingSettingsControls({ value, onChange }) {
1558
1989
  ),
1559
1990
  "Show inline spell checking"
1560
1991
  ] }),
1561
- /* @__PURE__ */ jsxs4("label", { className: "db-settings-checkbox", children: [
1562
- /* @__PURE__ */ jsx4(
1992
+ /* @__PURE__ */ jsxs5("label", { className: "db-settings-checkbox", children: [
1993
+ /* @__PURE__ */ jsx5(
1563
1994
  "input",
1564
1995
  {
1565
1996
  type: "checkbox",
@@ -1569,22 +2000,22 @@ function ProofingSettingsControls({ value, onChange }) {
1569
2000
  ),
1570
2001
  "Show inline grammar checking"
1571
2002
  ] }),
1572
- /* @__PURE__ */ jsx4("p", { className: "db-settings-hint", children: "(Grammar checking is currently only available for English)" })
2003
+ /* @__PURE__ */ jsx5("p", { className: "db-settings-hint", children: "(Grammar checking is currently only available for English)" })
1573
2004
  ] });
1574
2005
  }
1575
2006
  function WriteCanvasSettingsControls({ value, onChange }) {
1576
- return /* @__PURE__ */ jsxs4("fieldset", { className: "db-settings-fieldset", children: [
1577
- /* @__PURE__ */ jsx4("legend", { className: "db-settings-legend", children: "Write canvas" }),
1578
- /* @__PURE__ */ jsx4("p", { className: "db-settings-hint", children: "Adjust the writing view without changing the document or its exported text." }),
1579
- /* @__PURE__ */ jsxs4("label", { className: "db-settings-slider", children: [
1580
- /* @__PURE__ */ jsxs4("span", { className: "db-settings-slider-header", children: [
1581
- /* @__PURE__ */ jsx4("span", { children: "Text size" }),
1582
- /* @__PURE__ */ jsxs4("output", { className: "db-settings-slider-value", "aria-hidden": "true", children: [
2007
+ return /* @__PURE__ */ jsxs5("fieldset", { className: "db-settings-fieldset", children: [
2008
+ /* @__PURE__ */ jsx5("legend", { className: "db-settings-legend", children: "Write canvas" }),
2009
+ /* @__PURE__ */ jsx5("p", { className: "db-settings-hint", children: "Adjust the writing view without changing the document or its exported text." }),
2010
+ /* @__PURE__ */ jsxs5("label", { className: "db-settings-slider", children: [
2011
+ /* @__PURE__ */ jsxs5("span", { className: "db-settings-slider-header", children: [
2012
+ /* @__PURE__ */ jsx5("span", { children: "Text size" }),
2013
+ /* @__PURE__ */ jsxs5("output", { className: "db-settings-slider-value", "aria-hidden": "true", children: [
1583
2014
  value.textSize,
1584
2015
  "px"
1585
2016
  ] })
1586
2017
  ] }),
1587
- /* @__PURE__ */ jsx4(
2018
+ /* @__PURE__ */ jsx5(
1588
2019
  "input",
1589
2020
  {
1590
2021
  type: "range",
@@ -1598,12 +2029,12 @@ function WriteCanvasSettingsControls({ value, onChange }) {
1598
2029
  }
1599
2030
  )
1600
2031
  ] }),
1601
- /* @__PURE__ */ jsxs4("label", { className: "db-settings-slider", children: [
1602
- /* @__PURE__ */ jsxs4("span", { className: "db-settings-slider-header", children: [
1603
- /* @__PURE__ */ jsx4("span", { children: "Line spacing" }),
1604
- /* @__PURE__ */ jsx4("output", { className: "db-settings-slider-value", "aria-hidden": "true", children: formatLineSpacing(value.lineSpacing) })
2032
+ /* @__PURE__ */ jsxs5("label", { className: "db-settings-slider", children: [
2033
+ /* @__PURE__ */ jsxs5("span", { className: "db-settings-slider-header", children: [
2034
+ /* @__PURE__ */ jsx5("span", { children: "Line spacing" }),
2035
+ /* @__PURE__ */ jsx5("output", { className: "db-settings-slider-value", "aria-hidden": "true", children: formatLineSpacing(value.lineSpacing) })
1605
2036
  ] }),
1606
- /* @__PURE__ */ jsx4(
2037
+ /* @__PURE__ */ jsx5(
1607
2038
  "input",
1608
2039
  {
1609
2040
  type: "range",
@@ -1617,7 +2048,7 @@ function WriteCanvasSettingsControls({ value, onChange }) {
1617
2048
  }
1618
2049
  )
1619
2050
  ] }),
1620
- /* @__PURE__ */ jsx4(
2051
+ /* @__PURE__ */ jsx5(
1621
2052
  FontSchemePicker,
1622
2053
  {
1623
2054
  value: value.fontScheme,
@@ -1632,21 +2063,21 @@ function FontSchemePicker({ value, onChange }) {
1632
2063
  WRITE_CANVAS_FONT_SCHEMES.findIndex((scheme) => scheme.id === value)
1633
2064
  );
1634
2065
  const selectedScheme = WRITE_CANVAS_FONT_SCHEMES[selectedIndex];
1635
- const [isOpen, setIsOpen] = useState4(false);
1636
- const [activeIndex, setActiveIndex] = useState4(selectedIndex);
1637
- const [menuPosition, setMenuPosition] = useState4(null);
1638
- const rootRef = useRef3(null);
1639
- const triggerRef = useRef3(null);
1640
- const listboxRef = useRef3(null);
1641
- const optionRefs = useRef3([]);
2066
+ const [isOpen, setIsOpen] = useState6(false);
2067
+ const [activeIndex, setActiveIndex] = useState6(selectedIndex);
2068
+ const [menuPosition, setMenuPosition] = useState6(null);
2069
+ const rootRef = useRef4(null);
2070
+ const triggerRef = useRef4(null);
2071
+ const listboxRef = useRef4(null);
2072
+ const optionRefs = useRef4([]);
1642
2073
  const labelId = useId4();
1643
2074
  const listboxId = useId4();
1644
- const close = useCallback2((returnFocus) => {
2075
+ const close = useCallback3((returnFocus) => {
1645
2076
  setIsOpen(false);
1646
2077
  setMenuPosition(null);
1647
2078
  if (returnFocus) triggerRef.current?.focus({ preventScroll: true });
1648
2079
  }, []);
1649
- const updateMenuPosition = useCallback2(() => {
2080
+ const updateMenuPosition = useCallback3(() => {
1650
2081
  const trigger = triggerRef.current;
1651
2082
  if (!trigger) return;
1652
2083
  const rect = trigger.getBoundingClientRect();
@@ -1675,7 +2106,7 @@ function FontSchemePicker({ value, onChange }) {
1675
2106
  }
1676
2107
  );
1677
2108
  }, []);
1678
- const open = useCallback2(
2109
+ const open = useCallback3(
1679
2110
  (index) => {
1680
2111
  setActiveIndex(index);
1681
2112
  updateMenuPosition();
@@ -1683,7 +2114,7 @@ function FontSchemePicker({ value, onChange }) {
1683
2114
  },
1684
2115
  [updateMenuPosition]
1685
2116
  );
1686
- useEffect4(() => {
2117
+ useEffect6(() => {
1687
2118
  if (!isOpen) setActiveIndex(selectedIndex);
1688
2119
  }, [isOpen, selectedIndex]);
1689
2120
  useLayoutEffect(() => {
@@ -1692,7 +2123,7 @@ function FontSchemePicker({ value, onChange }) {
1692
2123
  listboxRef.current?.focus({ preventScroll: true });
1693
2124
  optionRefs.current[activeIndex]?.scrollIntoView?.({ block: "nearest" });
1694
2125
  }, [activeIndex, isOpen, updateMenuPosition]);
1695
- useEffect4(() => {
2126
+ useEffect6(() => {
1696
2127
  if (!isOpen) return;
1697
2128
  const handleOutsidePointer = (event) => {
1698
2129
  if (!rootRef.current?.contains(event.target)) close(false);
@@ -1707,7 +2138,7 @@ function FontSchemePicker({ value, onChange }) {
1707
2138
  window.removeEventListener("scroll", handleViewportChange, true);
1708
2139
  };
1709
2140
  }, [close, isOpen, updateMenuPosition]);
1710
- const select = useCallback2(
2141
+ const select = useCallback3(
1711
2142
  (index) => {
1712
2143
  const scheme = WRITE_CANVAS_FONT_SCHEMES[index];
1713
2144
  if (!scheme) return;
@@ -1764,9 +2195,9 @@ function FontSchemePicker({ value, onChange }) {
1764
2195
  width: `${menuPosition.width}px`,
1765
2196
  maxHeight: `${menuPosition.maxHeight}px`
1766
2197
  } : void 0;
1767
- return /* @__PURE__ */ jsxs4("div", { ref: rootRef, className: "db-settings-select db-font-picker", children: [
1768
- /* @__PURE__ */ jsx4("span", { className: "db-settings-select-header", children: /* @__PURE__ */ jsx4("span", { id: labelId, children: "Font" }) }),
1769
- /* @__PURE__ */ jsxs4(
2198
+ return /* @__PURE__ */ jsxs5("div", { ref: rootRef, className: "db-settings-select db-font-picker", children: [
2199
+ /* @__PURE__ */ jsx5("span", { className: "db-settings-select-header", children: /* @__PURE__ */ jsx5("span", { id: labelId, children: "Font" }) }),
2200
+ /* @__PURE__ */ jsxs5(
1770
2201
  "button",
1771
2202
  {
1772
2203
  ref: triggerRef,
@@ -1779,8 +2210,8 @@ function FontSchemePicker({ value, onChange }) {
1779
2210
  onClick: () => isOpen ? close(false) : open(selectedIndex),
1780
2211
  onKeyDown: handleTriggerKeyDown,
1781
2212
  children: [
1782
- /* @__PURE__ */ jsx4(FontSchemePreview, { scheme: selectedScheme, compact: true }),
1783
- /* @__PURE__ */ jsx4(
2213
+ /* @__PURE__ */ jsx5(FontSchemePreview, { scheme: selectedScheme, compact: true }),
2214
+ /* @__PURE__ */ jsx5(
1784
2215
  "span",
1785
2216
  {
1786
2217
  className: `db-font-picker-caret${isOpen ? " db-font-picker-caret--open" : ""}`,
@@ -1790,7 +2221,7 @@ function FontSchemePicker({ value, onChange }) {
1790
2221
  ]
1791
2222
  }
1792
2223
  ),
1793
- isOpen && /* @__PURE__ */ jsxs4(
2224
+ isOpen && /* @__PURE__ */ jsxs5(
1794
2225
  "div",
1795
2226
  {
1796
2227
  ref: listboxRef,
@@ -1806,8 +2237,8 @@ function FontSchemePicker({ value, onChange }) {
1806
2237
  WRITE_CANVAS_FONT_SCHEMES.filter((scheme) => scheme.group === "theme").map(
1807
2238
  (scheme) => renderFontSchemeOption(scheme)
1808
2239
  ),
1809
- FONT_SCHEME_GROUPS.map(({ group, label }) => /* @__PURE__ */ jsxs4("div", { role: "group", "aria-label": label, children: [
1810
- /* @__PURE__ */ jsx4("div", { className: "db-font-picker-group", "aria-hidden": "true", children: label }),
2240
+ FONT_SCHEME_GROUPS.map(({ group, label }) => /* @__PURE__ */ jsxs5("div", { role: "group", "aria-label": label, children: [
2241
+ /* @__PURE__ */ jsx5("div", { className: "db-font-picker-group", "aria-hidden": "true", children: label }),
1811
2242
  WRITE_CANVAS_FONT_SCHEMES.filter((scheme) => scheme.group === group).map(
1812
2243
  (scheme) => renderFontSchemeOption(scheme)
1813
2244
  )
@@ -1820,7 +2251,7 @@ function FontSchemePicker({ value, onChange }) {
1820
2251
  const index = WRITE_CANVAS_FONT_SCHEMES.indexOf(scheme);
1821
2252
  const selected = scheme.id === value;
1822
2253
  const active = index === activeIndex;
1823
- return /* @__PURE__ */ jsxs4(
2254
+ return /* @__PURE__ */ jsxs5(
1824
2255
  "div",
1825
2256
  {
1826
2257
  ref: (element) => {
@@ -1834,8 +2265,8 @@ function FontSchemePicker({ value, onChange }) {
1834
2265
  onMouseMove: () => setActiveIndex(index),
1835
2266
  onClick: () => select(index),
1836
2267
  children: [
1837
- /* @__PURE__ */ jsx4(FontSchemePreview, { scheme }),
1838
- /* @__PURE__ */ jsx4("span", { className: "db-font-picker-check", "aria-hidden": "true", children: selected ? "\u2713" : "" })
2268
+ /* @__PURE__ */ jsx5(FontSchemePreview, { scheme }),
2269
+ /* @__PURE__ */ jsx5("span", { className: "db-font-picker-check", "aria-hidden": "true", children: selected ? "\u2713" : "" })
1839
2270
  ]
1840
2271
  },
1841
2272
  scheme.id
@@ -1849,8 +2280,8 @@ function FontSchemePreview({
1849
2280
  const labels = scheme.label.split(/\s*\u00b7\s*/u);
1850
2281
  const headingLabel = labels[0] ?? scheme.label;
1851
2282
  const bodyLabel = labels[1] ?? (scheme.id === "theme" ? "Use the active theme" : "Headings & body");
1852
- return /* @__PURE__ */ jsxs4("span", { className: `db-font-picker-preview${compact ? " db-font-picker-preview--compact" : ""}`, children: [
1853
- /* @__PURE__ */ jsx4(
2283
+ return /* @__PURE__ */ jsxs5("span", { className: `db-font-picker-preview${compact ? " db-font-picker-preview--compact" : ""}`, children: [
2284
+ /* @__PURE__ */ jsx5(
1854
2285
  "span",
1855
2286
  {
1856
2287
  className: "db-font-picker-heading",
@@ -1858,7 +2289,7 @@ function FontSchemePreview({
1858
2289
  children: headingLabel
1859
2290
  }
1860
2291
  ),
1861
- /* @__PURE__ */ jsx4(
2292
+ /* @__PURE__ */ jsx5(
1862
2293
  "span",
1863
2294
  {
1864
2295
  className: "db-font-picker-body",
@@ -1916,6 +2347,15 @@ export {
1916
2347
  DEFAULT_PROOFING_PREFERENCES,
1917
2348
  loadProofingPreferences,
1918
2349
  saveProofingPreferences,
2350
+ SIDEBAR_WIDTH_DEFAULT,
2351
+ SIDEBAR_WIDTH_MIN,
2352
+ SIDEBAR_WIDTH_MAX,
2353
+ SIDEBAR_COLLAPSE_THRESHOLD,
2354
+ classifyFormFactor,
2355
+ resolveLayoutMode,
2356
+ formFactorDataAttributes,
2357
+ isInstalledDisplayMode,
2358
+ useMediaQuery,
1919
2359
  DB_CHROME_COLORS,
1920
2360
  DEFAULT_INTERFACE_FONT,
1921
2361
  loadThemePreference,
@@ -1930,6 +2370,7 @@ export {
1930
2370
  AccentColorSettings,
1931
2371
  ProofingSettingsControls,
1932
2372
  WriteCanvasSettingsControls,
2373
+ formatModelSize,
1933
2374
  AiSettingsControls,
1934
2375
  WorkspaceSettingsControls
1935
2376
  };