@bendyline/docblocks-react 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (300) hide show
  1. package/README.md +6 -0
  2. package/dist/{ExportDialog-MEUISWZX.js → ExportDialog-7LDIXJZ3.js} +3 -2
  3. package/dist/{ExportToolbarControls-D2YDWOXW.js → ExportToolbarControls-GHAOJMH6.js} +147 -12
  4. package/dist/ExportToolbarControls-GHAOJMH6.js.map +1 -0
  5. package/dist/{GitToolbarControl-LMIR4R7I.js → GitToolbarControl-GNMRVKWQ.js} +62 -43
  6. package/dist/GitToolbarControl-GNMRVKWQ.js.map +1 -0
  7. package/dist/{GitUI-KGF5MSNV.js → GitUI-VHOBQY43.js} +225 -140
  8. package/dist/GitUI-VHOBQY43.js.map +1 -0
  9. package/dist/ShareDialog-63ENBEDZ.js +213 -0
  10. package/dist/ShareDialog-63ENBEDZ.js.map +1 -0
  11. package/dist/chunk-57ZJJOC5.js +89 -0
  12. package/dist/chunk-57ZJJOC5.js.map +1 -0
  13. package/dist/chunk-FEWQUQML.js +256 -0
  14. package/dist/chunk-FEWQUQML.js.map +1 -0
  15. package/dist/chunk-FMGTHSTX.js +110 -0
  16. package/dist/chunk-FMGTHSTX.js.map +1 -0
  17. package/dist/chunk-UNYZQXWR.js +324 -0
  18. package/dist/chunk-UNYZQXWR.js.map +1 -0
  19. package/dist/editor.d.ts +5 -4
  20. package/dist/editor.js +8 -69
  21. package/dist/editor.js.map +1 -1
  22. package/dist/export/index.d.ts +7 -1
  23. package/dist/export/index.js +2 -1
  24. package/dist/index.d.ts +346 -21
  25. package/dist/index.js +6169 -20
  26. package/dist/index.js.map +1 -1
  27. package/dist/settings/index.d.ts +9 -1
  28. package/dist/settings/index.js +6 -4
  29. package/package.json +18 -13
  30. package/src/styles/docblocks.css +537 -26
  31. package/dist/AppMenu/AppMenu.d.ts +0 -53
  32. package/dist/AppMenu/AppMenu.d.ts.map +0 -1
  33. package/dist/AppMenu/AppMenu.js +0 -67
  34. package/dist/AppMenu/AppMenu.js.map +0 -1
  35. package/dist/AppMenu/index.d.ts +0 -3
  36. package/dist/AppMenu/index.d.ts.map +0 -1
  37. package/dist/AppMenu/index.js +0 -2
  38. package/dist/AppMenu/index.js.map +0 -1
  39. package/dist/DocBlocksShell/DocBlocksShell.d.ts +0 -49
  40. package/dist/DocBlocksShell/DocBlocksShell.d.ts.map +0 -1
  41. package/dist/DocBlocksShell/DocBlocksShell.js +0 -2730
  42. package/dist/DocBlocksShell/DocBlocksShell.js.map +0 -1
  43. package/dist/DocBlocksShell/LazyEditorShell.d.ts +0 -3
  44. package/dist/DocBlocksShell/LazyEditorShell.d.ts.map +0 -1
  45. package/dist/DocBlocksShell/LazyEditorShell.js +0 -3
  46. package/dist/DocBlocksShell/LazyEditorShell.js.map +0 -1
  47. package/dist/DocBlocksShell/UpdateAvailableNotice.d.ts +0 -13
  48. package/dist/DocBlocksShell/UpdateAvailableNotice.d.ts.map +0 -1
  49. package/dist/DocBlocksShell/UpdateAvailableNotice.js +0 -16
  50. package/dist/DocBlocksShell/UpdateAvailableNotice.js.map +0 -1
  51. package/dist/DocBlocksShell/document-title.d.ts +0 -3
  52. package/dist/DocBlocksShell/document-title.d.ts.map +0 -1
  53. package/dist/DocBlocksShell/document-title.js +0 -17
  54. package/dist/DocBlocksShell/document-title.js.map +0 -1
  55. package/dist/DocBlocksShell/index.d.ts +0 -3
  56. package/dist/DocBlocksShell/index.d.ts.map +0 -1
  57. package/dist/DocBlocksShell/index.js +0 -2
  58. package/dist/DocBlocksShell/index.js.map +0 -1
  59. package/dist/DocBlocksShell/workspace-authority-barrier.d.ts +0 -14
  60. package/dist/DocBlocksShell/workspace-authority-barrier.d.ts.map +0 -1
  61. package/dist/DocBlocksShell/workspace-authority-barrier.js +0 -23
  62. package/dist/DocBlocksShell/workspace-authority-barrier.js.map +0 -1
  63. package/dist/Export/DeferredExportToolbarControls.d.ts +0 -5
  64. package/dist/Export/DeferredExportToolbarControls.d.ts.map +0 -1
  65. package/dist/Export/DeferredExportToolbarControls.js +0 -10
  66. package/dist/Export/DeferredExportToolbarControls.js.map +0 -1
  67. package/dist/Export/ExportDialog.d.ts +0 -25
  68. package/dist/Export/ExportDialog.d.ts.map +0 -1
  69. package/dist/Export/ExportDialog.js +0 -160
  70. package/dist/Export/ExportDialog.js.map +0 -1
  71. package/dist/Export/ExportToolbarControls.d.ts +0 -37
  72. package/dist/Export/ExportToolbarControls.d.ts.map +0 -1
  73. package/dist/Export/ExportToolbarControls.js +0 -285
  74. package/dist/Export/ExportToolbarControls.js.map +0 -1
  75. package/dist/Export/export-destination.d.ts +0 -3
  76. package/dist/Export/export-destination.d.ts.map +0 -1
  77. package/dist/Export/export-destination.js +0 -32
  78. package/dist/Export/export-destination.js.map +0 -1
  79. package/dist/Export/export-options.d.ts +0 -53
  80. package/dist/Export/export-options.d.ts.map +0 -1
  81. package/dist/Export/export-options.js +0 -49
  82. package/dist/Export/export-options.js.map +0 -1
  83. package/dist/Export/index.d.ts +0 -10
  84. package/dist/Export/index.d.ts.map +0 -1
  85. package/dist/Export/index.js +0 -6
  86. package/dist/Export/index.js.map +0 -1
  87. package/dist/Export/public-api.d.ts +0 -12
  88. package/dist/Export/public-api.d.ts.map +0 -1
  89. package/dist/Export/public-api.js +0 -9
  90. package/dist/Export/public-api.js.map +0 -1
  91. package/dist/Export/run-export.d.ts +0 -10
  92. package/dist/Export/run-export.d.ts.map +0 -1
  93. package/dist/Export/run-export.js +0 -313
  94. package/dist/Export/run-export.js.map +0 -1
  95. package/dist/Export/transform-summaries.d.ts +0 -7
  96. package/dist/Export/transform-summaries.d.ts.map +0 -1
  97. package/dist/Export/transform-summaries.js +0 -6
  98. package/dist/Export/transform-summaries.js.map +0 -1
  99. package/dist/ExportToolbarControls-D2YDWOXW.js.map +0 -1
  100. package/dist/FileExplorer/FileExplorer.d.ts +0 -43
  101. package/dist/FileExplorer/FileExplorer.d.ts.map +0 -1
  102. package/dist/FileExplorer/FileExplorer.js +0 -315
  103. package/dist/FileExplorer/FileExplorer.js.map +0 -1
  104. package/dist/FileExplorer/FileTreeNode.d.ts +0 -39
  105. package/dist/FileExplorer/FileTreeNode.d.ts.map +0 -1
  106. package/dist/FileExplorer/FileTreeNode.js +0 -131
  107. package/dist/FileExplorer/FileTreeNode.js.map +0 -1
  108. package/dist/FileExplorer/index.d.ts +0 -6
  109. package/dist/FileExplorer/index.d.ts.map +0 -1
  110. package/dist/FileExplorer/index.js +0 -4
  111. package/dist/FileExplorer/index.js.map +0 -1
  112. package/dist/FileExplorer/useFileTree.d.ts +0 -37
  113. package/dist/FileExplorer/useFileTree.d.ts.map +0 -1
  114. package/dist/FileExplorer/useFileTree.js +0 -284
  115. package/dist/FileExplorer/useFileTree.js.map +0 -1
  116. package/dist/Git/GitAuthGuidanceDialog.d.ts +0 -18
  117. package/dist/Git/GitAuthGuidanceDialog.d.ts.map +0 -1
  118. package/dist/Git/GitAuthGuidanceDialog.js +0 -27
  119. package/dist/Git/GitAuthGuidanceDialog.js.map +0 -1
  120. package/dist/Git/GitBranchesDialog.d.ts +0 -13
  121. package/dist/Git/GitBranchesDialog.d.ts.map +0 -1
  122. package/dist/Git/GitBranchesDialog.js +0 -59
  123. package/dist/Git/GitBranchesDialog.js.map +0 -1
  124. package/dist/Git/GitCloneDialog.d.ts +0 -14
  125. package/dist/Git/GitCloneDialog.d.ts.map +0 -1
  126. package/dist/Git/GitCloneDialog.js +0 -79
  127. package/dist/Git/GitCloneDialog.js.map +0 -1
  128. package/dist/Git/GitCommitDialog.d.ts +0 -12
  129. package/dist/Git/GitCommitDialog.d.ts.map +0 -1
  130. package/dist/Git/GitCommitDialog.js +0 -38
  131. package/dist/Git/GitCommitDialog.js.map +0 -1
  132. package/dist/Git/GitConflictsDialog.d.ts +0 -12
  133. package/dist/Git/GitConflictsDialog.d.ts.map +0 -1
  134. package/dist/Git/GitConflictsDialog.js +0 -17
  135. package/dist/Git/GitConflictsDialog.js.map +0 -1
  136. package/dist/Git/GitContext.d.ts +0 -89
  137. package/dist/Git/GitContext.d.ts.map +0 -1
  138. package/dist/Git/GitContext.js +0 -15
  139. package/dist/Git/GitContext.js.map +0 -1
  140. package/dist/Git/GitDiffDialog.d.ts +0 -20
  141. package/dist/Git/GitDiffDialog.d.ts.map +0 -1
  142. package/dist/Git/GitDiffDialog.js +0 -100
  143. package/dist/Git/GitDiffDialog.js.map +0 -1
  144. package/dist/Git/GitDiffView.d.ts +0 -23
  145. package/dist/Git/GitDiffView.d.ts.map +0 -1
  146. package/dist/Git/GitDiffView.js +0 -77
  147. package/dist/Git/GitDiffView.js.map +0 -1
  148. package/dist/Git/GitHistoryDialog.d.ts +0 -15
  149. package/dist/Git/GitHistoryDialog.d.ts.map +0 -1
  150. package/dist/Git/GitHistoryDialog.js +0 -107
  151. package/dist/Git/GitHistoryDialog.js.map +0 -1
  152. package/dist/Git/GitStatusBar.d.ts +0 -8
  153. package/dist/Git/GitStatusBar.d.ts.map +0 -1
  154. package/dist/Git/GitStatusBar.js +0 -49
  155. package/dist/Git/GitStatusBar.js.map +0 -1
  156. package/dist/Git/GitToolbarControl.d.ts +0 -15
  157. package/dist/Git/GitToolbarControl.d.ts.map +0 -1
  158. package/dist/Git/GitToolbarControl.js +0 -51
  159. package/dist/Git/GitToolbarControl.js.map +0 -1
  160. package/dist/Git/GitUI.d.ts +0 -14
  161. package/dist/Git/GitUI.d.ts.map +0 -1
  162. package/dist/Git/GitUI.js +0 -21
  163. package/dist/Git/GitUI.js.map +0 -1
  164. package/dist/Git/commit-selection.d.ts +0 -22
  165. package/dist/Git/commit-selection.d.ts.map +0 -1
  166. package/dist/Git/commit-selection.js +0 -47
  167. package/dist/Git/commit-selection.js.map +0 -1
  168. package/dist/Git/git-clone-utils.d.ts +0 -8
  169. package/dist/Git/git-clone-utils.d.ts.map +0 -1
  170. package/dist/Git/git-clone-utils.js +0 -26
  171. package/dist/Git/git-clone-utils.js.map +0 -1
  172. package/dist/Git/git-status.d.ts +0 -24
  173. package/dist/Git/git-status.d.ts.map +0 -1
  174. package/dist/Git/git-status.js +0 -105
  175. package/dist/Git/git-status.js.map +0 -1
  176. package/dist/Git/useGit.d.ts +0 -15
  177. package/dist/Git/useGit.d.ts.map +0 -1
  178. package/dist/Git/useGit.js +0 -206
  179. package/dist/Git/useGit.js.map +0 -1
  180. package/dist/Git/useGitStatus.d.ts +0 -17
  181. package/dist/Git/useGitStatus.d.ts.map +0 -1
  182. package/dist/Git/useGitStatus.js +0 -63
  183. package/dist/Git/useGitStatus.js.map +0 -1
  184. package/dist/GitToolbarControl-LMIR4R7I.js.map +0 -1
  185. package/dist/GitUI-KGF5MSNV.js.map +0 -1
  186. package/dist/Settings/Settings.d.ts +0 -23
  187. package/dist/Settings/Settings.d.ts.map +0 -1
  188. package/dist/Settings/Settings.js +0 -22
  189. package/dist/Settings/Settings.js.map +0 -1
  190. package/dist/Settings/public-api.d.ts +0 -3
  191. package/dist/Settings/public-api.d.ts.map +0 -1
  192. package/dist/Settings/public-api.js +0 -2
  193. package/dist/Settings/public-api.js.map +0 -1
  194. package/dist/WorkspacePicker/WorkspacePicker.d.ts +0 -22
  195. package/dist/WorkspacePicker/WorkspacePicker.d.ts.map +0 -1
  196. package/dist/WorkspacePicker/WorkspacePicker.js +0 -74
  197. package/dist/WorkspacePicker/WorkspacePicker.js.map +0 -1
  198. package/dist/WorkspacePicker/WorkspaceSettingsButton.d.ts +0 -11
  199. package/dist/WorkspacePicker/WorkspaceSettingsButton.d.ts.map +0 -1
  200. package/dist/WorkspacePicker/WorkspaceSettingsButton.js +0 -27
  201. package/dist/WorkspacePicker/WorkspaceSettingsButton.js.map +0 -1
  202. package/dist/WorkspacePicker/WorkspaceSettingsDialog.d.ts +0 -20
  203. package/dist/WorkspacePicker/WorkspaceSettingsDialog.d.ts.map +0 -1
  204. package/dist/WorkspacePicker/WorkspaceSettingsDialog.js +0 -36
  205. package/dist/WorkspacePicker/WorkspaceSettingsDialog.js.map +0 -1
  206. package/dist/WorkspacePicker/index.d.ts +0 -3
  207. package/dist/WorkspacePicker/index.d.ts.map +0 -1
  208. package/dist/WorkspacePicker/index.js +0 -2
  209. package/dist/WorkspacePicker/index.js.map +0 -1
  210. package/dist/chunk-3SAXDU2U.js +0 -157
  211. package/dist/chunk-3SAXDU2U.js.map +0 -1
  212. package/dist/chunk-AOVTHZU7.js +0 -321
  213. package/dist/chunk-AOVTHZU7.js.map +0 -1
  214. package/dist/chunk-GSNZSCIK.js +0 -55
  215. package/dist/chunk-GSNZSCIK.js.map +0 -1
  216. package/dist/components/Dialog.d.ts +0 -22
  217. package/dist/components/Dialog.d.ts.map +0 -1
  218. package/dist/components/Dialog.js +0 -33
  219. package/dist/components/Dialog.js.map +0 -1
  220. package/dist/editor.d.ts.map +0 -1
  221. package/dist/hooks/index.d.ts +0 -3
  222. package/dist/hooks/index.d.ts.map +0 -1
  223. package/dist/hooks/index.js +0 -2
  224. package/dist/hooks/index.js.map +0 -1
  225. package/dist/hooks/useDocumentSession.d.ts +0 -16
  226. package/dist/hooks/useDocumentSession.d.ts.map +0 -1
  227. package/dist/hooks/useDocumentSession.js +0 -18
  228. package/dist/hooks/useDocumentSession.js.map +0 -1
  229. package/dist/icons.d.ts +0 -12
  230. package/dist/icons.d.ts.map +0 -1
  231. package/dist/icons.js +0 -28
  232. package/dist/icons.js.map +0 -1
  233. package/dist/index.d.ts.map +0 -1
  234. package/dist/preferences/theme.d.ts +0 -18
  235. package/dist/preferences/theme.d.ts.map +0 -1
  236. package/dist/preferences/theme.js +0 -63
  237. package/dist/preferences/theme.js.map +0 -1
  238. package/dist/preferences/versioning.d.ts +0 -27
  239. package/dist/preferences/versioning.d.ts.map +0 -1
  240. package/dist/preferences/versioning.js +0 -62
  241. package/dist/preferences/versioning.js.map +0 -1
  242. package/dist/provider-lease.d.ts +0 -10
  243. package/dist/provider-lease.d.ts.map +0 -1
  244. package/dist/provider-lease.js +0 -42
  245. package/dist/provider-lease.js.map +0 -1
  246. package/src/AppMenu/AppMenu.tsx +0 -334
  247. package/src/AppMenu/index.ts +0 -2
  248. package/src/DocBlocksShell/DocBlocksShell.tsx +0 -3398
  249. package/src/DocBlocksShell/LazyEditorShell.ts +0 -2
  250. package/src/DocBlocksShell/UpdateAvailableNotice.tsx +0 -60
  251. package/src/DocBlocksShell/document-title.ts +0 -19
  252. package/src/DocBlocksShell/index.ts +0 -2
  253. package/src/DocBlocksShell/workspace-authority-barrier.ts +0 -26
  254. package/src/Export/DeferredExportToolbarControls.tsx +0 -23
  255. package/src/Export/ExportDialog.tsx +0 -437
  256. package/src/Export/ExportToolbarControls.tsx +0 -511
  257. package/src/Export/export-destination.ts +0 -30
  258. package/src/Export/export-options.ts +0 -99
  259. package/src/Export/index.ts +0 -19
  260. package/src/Export/public-api.ts +0 -17
  261. package/src/Export/run-export.ts +0 -374
  262. package/src/Export/transform-summaries.ts +0 -14
  263. package/src/FileExplorer/FileExplorer.tsx +0 -528
  264. package/src/FileExplorer/FileTreeNode.tsx +0 -306
  265. package/src/FileExplorer/index.ts +0 -5
  266. package/src/FileExplorer/useFileTree.ts +0 -352
  267. package/src/Git/GitAuthGuidanceDialog.tsx +0 -84
  268. package/src/Git/GitBranchesDialog.tsx +0 -144
  269. package/src/Git/GitCloneDialog.tsx +0 -200
  270. package/src/Git/GitCommitDialog.tsx +0 -119
  271. package/src/Git/GitConflictsDialog.tsx +0 -62
  272. package/src/Git/GitContext.tsx +0 -88
  273. package/src/Git/GitDiffDialog.tsx +0 -147
  274. package/src/Git/GitDiffView.tsx +0 -105
  275. package/src/Git/GitHistoryDialog.tsx +0 -195
  276. package/src/Git/GitStatusBar.tsx +0 -157
  277. package/src/Git/GitToolbarControl.tsx +0 -123
  278. package/src/Git/GitUI.tsx +0 -68
  279. package/src/Git/commit-selection.ts +0 -63
  280. package/src/Git/git-clone-utils.ts +0 -23
  281. package/src/Git/git-status.ts +0 -113
  282. package/src/Git/useGit.ts +0 -279
  283. package/src/Git/useGitStatus.ts +0 -78
  284. package/src/Settings/Settings.tsx +0 -118
  285. package/src/Settings/public-api.ts +0 -8
  286. package/src/WorkspacePicker/WorkspacePicker.tsx +0 -191
  287. package/src/WorkspacePicker/WorkspaceSettingsButton.tsx +0 -88
  288. package/src/WorkspacePicker/WorkspaceSettingsDialog.tsx +0 -121
  289. package/src/WorkspacePicker/index.ts +0 -2
  290. package/src/components/Dialog.tsx +0 -81
  291. package/src/editor.ts +0 -72
  292. package/src/hooks/index.ts +0 -2
  293. package/src/hooks/useDocumentSession.ts +0 -37
  294. package/src/icons.tsx +0 -48
  295. package/src/index.ts +0 -61
  296. package/src/preferences/theme.ts +0 -67
  297. package/src/preferences/versioning.ts +0 -69
  298. package/src/provider-lease.ts +0 -52
  299. package/src/types/pwa-dom.d.ts +0 -31
  300. /package/dist/{ExportDialog-MEUISWZX.js.map → ExportDialog-7LDIXJZ3.js.map} +0 -0
@@ -0,0 +1,256 @@
1
+ import {
2
+ Dialog
3
+ } from "./chunk-FMGTHSTX.js";
4
+
5
+ // src/preferences/theme.ts
6
+ var ACCENT_COLORS = [
7
+ "brown",
8
+ "green",
9
+ "blue",
10
+ "purple",
11
+ "maroon",
12
+ "orange",
13
+ "gray"
14
+ ];
15
+ var DB_CHROME_COLORS = {
16
+ light: "#f3eede",
17
+ dark: "#262219"
18
+ };
19
+ var THEME_STORAGE_KEY = "docblocks:themePreference";
20
+ var ACCENT_STORAGE_KEY = "docblocks:accentColor";
21
+ function loadThemePreference() {
22
+ try {
23
+ const raw = localStorage.getItem(THEME_STORAGE_KEY);
24
+ if (raw === "light" || raw === "dark" || raw === "auto") return raw;
25
+ } catch {
26
+ }
27
+ return "auto";
28
+ }
29
+ function saveThemePreference(value) {
30
+ try {
31
+ localStorage.setItem(THEME_STORAGE_KEY, value);
32
+ } catch {
33
+ }
34
+ }
35
+ function loadAccentColor() {
36
+ try {
37
+ const raw = localStorage.getItem(ACCENT_STORAGE_KEY);
38
+ if (ACCENT_COLORS.some((color) => color === raw)) return raw;
39
+ } catch {
40
+ }
41
+ return "brown";
42
+ }
43
+ function saveAccentColor(value) {
44
+ try {
45
+ localStorage.setItem(ACCENT_STORAGE_KEY, value);
46
+ } catch {
47
+ }
48
+ }
49
+
50
+ // src/preferences/write-canvas.ts
51
+ var WRITE_CANVAS_TEXT_SIZE_MIN = 12;
52
+ var WRITE_CANVAS_TEXT_SIZE_MAX = 32;
53
+ var WRITE_CANVAS_LINE_SPACING_MIN = 1.2;
54
+ var WRITE_CANVAS_LINE_SPACING_MAX = 2.4;
55
+ var DEFAULT_WRITE_CANVAS_PREFERENCES = {
56
+ textSize: 16,
57
+ lineSpacing: 1.7
58
+ };
59
+ var WRITE_CANVAS_STORAGE_KEY = "docblocks:writeCanvasSettings";
60
+ function loadWriteCanvasPreferences() {
61
+ try {
62
+ const raw = localStorage.getItem(WRITE_CANVAS_STORAGE_KEY);
63
+ if (!raw) return { ...DEFAULT_WRITE_CANVAS_PREFERENCES };
64
+ const stored = JSON.parse(raw);
65
+ if (!isRecord(stored)) return { ...DEFAULT_WRITE_CANVAS_PREFERENCES };
66
+ return {
67
+ textSize: numberInRange(
68
+ stored.textSize,
69
+ WRITE_CANVAS_TEXT_SIZE_MIN,
70
+ WRITE_CANVAS_TEXT_SIZE_MAX
71
+ ) ? stored.textSize : DEFAULT_WRITE_CANVAS_PREFERENCES.textSize,
72
+ lineSpacing: numberInRange(
73
+ stored.lineSpacing,
74
+ WRITE_CANVAS_LINE_SPACING_MIN,
75
+ WRITE_CANVAS_LINE_SPACING_MAX
76
+ ) ? stored.lineSpacing : DEFAULT_WRITE_CANVAS_PREFERENCES.lineSpacing
77
+ };
78
+ } catch {
79
+ return { ...DEFAULT_WRITE_CANVAS_PREFERENCES };
80
+ }
81
+ }
82
+ function saveWriteCanvasPreferences(value) {
83
+ try {
84
+ localStorage.setItem(WRITE_CANVAS_STORAGE_KEY, JSON.stringify(value));
85
+ } catch {
86
+ }
87
+ }
88
+ function numberInRange(value, min, max) {
89
+ return typeof value === "number" && Number.isFinite(value) && value >= min && value <= max;
90
+ }
91
+ function isRecord(value) {
92
+ return typeof value === "object" && value !== null && !Array.isArray(value);
93
+ }
94
+
95
+ // src/Settings/Settings.tsx
96
+ import { jsx, jsxs } from "react/jsx-runtime";
97
+ var ACCENT_LABELS = {
98
+ brown: "Brown",
99
+ green: "Green",
100
+ blue: "Blue",
101
+ purple: "Purple",
102
+ maroon: "Maroon",
103
+ orange: "Orange",
104
+ gray: "Gray"
105
+ };
106
+ function SettingsDialog({ title = "Settings", onClose, children }) {
107
+ return /* @__PURE__ */ jsx(Dialog, { title, onClose, size: "wide", children });
108
+ }
109
+ function ThemeSettings({ value, onChange, name = "theme" }) {
110
+ return /* @__PURE__ */ jsxs("fieldset", { className: "db-settings-fieldset", children: [
111
+ /* @__PURE__ */ jsx("legend", { className: "db-settings-legend", children: "Theme" }),
112
+ /* @__PURE__ */ jsxs("label", { className: "db-settings-radio", children: [
113
+ /* @__PURE__ */ jsx(
114
+ "input",
115
+ {
116
+ type: "radio",
117
+ name,
118
+ value: "auto",
119
+ checked: value === "auto",
120
+ onChange: () => onChange("auto")
121
+ }
122
+ ),
123
+ "System default"
124
+ ] }),
125
+ /* @__PURE__ */ jsxs("label", { className: "db-settings-radio", children: [
126
+ /* @__PURE__ */ jsx(
127
+ "input",
128
+ {
129
+ type: "radio",
130
+ name,
131
+ value: "light",
132
+ checked: value === "light",
133
+ onChange: () => onChange("light")
134
+ }
135
+ ),
136
+ "Light"
137
+ ] }),
138
+ /* @__PURE__ */ jsxs("label", { className: "db-settings-radio", children: [
139
+ /* @__PURE__ */ jsx(
140
+ "input",
141
+ {
142
+ type: "radio",
143
+ name,
144
+ value: "dark",
145
+ checked: value === "dark",
146
+ onChange: () => onChange("dark")
147
+ }
148
+ ),
149
+ "Dark"
150
+ ] })
151
+ ] });
152
+ }
153
+ function AccentColorSettings({
154
+ value,
155
+ onChange,
156
+ name = "accent-color"
157
+ }) {
158
+ return /* @__PURE__ */ jsxs("fieldset", { className: "db-settings-fieldset", children: [
159
+ /* @__PURE__ */ jsx("legend", { className: "db-settings-legend", children: "Accent color" }),
160
+ /* @__PURE__ */ jsx("p", { className: "db-settings-hint", children: "Used in both light and dark appearances." }),
161
+ /* @__PURE__ */ jsx("div", { className: "db-settings-accent-grid", children: ACCENT_COLORS.map((color) => /* @__PURE__ */ jsxs(
162
+ "label",
163
+ {
164
+ className: `db-settings-accent${value === color ? " db-settings-accent--selected" : ""}`,
165
+ children: [
166
+ /* @__PURE__ */ jsx(
167
+ "input",
168
+ {
169
+ className: "db-settings-accent-input",
170
+ type: "radio",
171
+ name,
172
+ value: color,
173
+ checked: value === color,
174
+ onChange: () => onChange(color)
175
+ }
176
+ ),
177
+ /* @__PURE__ */ jsx(
178
+ "span",
179
+ {
180
+ className: `db-settings-accent-swatch db-settings-accent-swatch--${color}`,
181
+ "aria-hidden": "true"
182
+ }
183
+ ),
184
+ /* @__PURE__ */ jsx("span", { children: ACCENT_LABELS[color] })
185
+ ]
186
+ },
187
+ color
188
+ )) })
189
+ ] });
190
+ }
191
+ function WriteCanvasSettingsControls({ value, onChange }) {
192
+ return /* @__PURE__ */ jsxs("fieldset", { className: "db-settings-fieldset", children: [
193
+ /* @__PURE__ */ jsx("legend", { className: "db-settings-legend", children: "Write canvas" }),
194
+ /* @__PURE__ */ jsx("p", { className: "db-settings-hint", children: "Adjust the writing view without changing the document or its exported text." }),
195
+ /* @__PURE__ */ jsxs("label", { className: "db-settings-slider", children: [
196
+ /* @__PURE__ */ jsxs("span", { className: "db-settings-slider-header", children: [
197
+ /* @__PURE__ */ jsx("span", { children: "Text size" }),
198
+ /* @__PURE__ */ jsxs("output", { className: "db-settings-slider-value", "aria-hidden": "true", children: [
199
+ value.textSize,
200
+ "px"
201
+ ] })
202
+ ] }),
203
+ /* @__PURE__ */ jsx(
204
+ "input",
205
+ {
206
+ type: "range",
207
+ min: WRITE_CANVAS_TEXT_SIZE_MIN,
208
+ max: WRITE_CANVAS_TEXT_SIZE_MAX,
209
+ step: 1,
210
+ value: value.textSize,
211
+ "aria-label": "Text size",
212
+ "aria-valuetext": `${value.textSize} pixels`,
213
+ onChange: (event) => onChange({ ...value, textSize: Number(event.currentTarget.value) })
214
+ }
215
+ )
216
+ ] }),
217
+ /* @__PURE__ */ jsxs("label", { className: "db-settings-slider", children: [
218
+ /* @__PURE__ */ jsxs("span", { className: "db-settings-slider-header", children: [
219
+ /* @__PURE__ */ jsx("span", { children: "Line spacing" }),
220
+ /* @__PURE__ */ jsx("output", { className: "db-settings-slider-value", "aria-hidden": "true", children: formatLineSpacing(value.lineSpacing) })
221
+ ] }),
222
+ /* @__PURE__ */ jsx(
223
+ "input",
224
+ {
225
+ type: "range",
226
+ min: WRITE_CANVAS_LINE_SPACING_MIN,
227
+ max: WRITE_CANVAS_LINE_SPACING_MAX,
228
+ step: 0.1,
229
+ value: value.lineSpacing,
230
+ "aria-label": "Line spacing",
231
+ "aria-valuetext": `${value.lineSpacing} times`,
232
+ onChange: (event) => onChange({ ...value, lineSpacing: Number(event.currentTarget.value) })
233
+ }
234
+ )
235
+ ] })
236
+ ] });
237
+ }
238
+ function formatLineSpacing(value) {
239
+ return `${value.toFixed(1).replace(/\.0$/, "")}\xD7`;
240
+ }
241
+
242
+ export {
243
+ DEFAULT_WRITE_CANVAS_PREFERENCES,
244
+ loadWriteCanvasPreferences,
245
+ saveWriteCanvasPreferences,
246
+ DB_CHROME_COLORS,
247
+ loadThemePreference,
248
+ saveThemePreference,
249
+ loadAccentColor,
250
+ saveAccentColor,
251
+ SettingsDialog,
252
+ ThemeSettings,
253
+ AccentColorSettings,
254
+ WriteCanvasSettingsControls
255
+ };
256
+ //# sourceMappingURL=chunk-FEWQUQML.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/preferences/theme.ts","../src/preferences/write-canvas.ts","../src/Settings/Settings.tsx"],"sourcesContent":["/** Appearance preferences shared by the shell and settings UI. */\n\nexport type ThemePreference = 'auto' | 'light' | 'dark';\n\nexport const ACCENT_COLORS = [\n 'brown',\n 'green',\n 'blue',\n 'purple',\n 'maroon',\n 'orange',\n 'gray',\n] as const;\n\nexport type AccentColor = (typeof ACCENT_COLORS)[number];\n\n/**\n * Chrome (titlebar) background per resolved theme. Keep in sync with\n * `--db-bg-subtle` for the default accent in styles/docblocks.css and with\n * the static `<meta name=\"theme-color\">` values in the site's index.html.\n * The shell writes these into the theme-color metas so the installed web\n * app's titlebar (Window Controls Overlay caption area, Android status bar)\n * follows the resolved theme.\n */\nexport const DB_CHROME_COLORS: Record<'light' | 'dark', string> = {\n light: '#f3eede',\n dark: '#262219',\n};\n\nconst THEME_STORAGE_KEY = 'docblocks:themePreference';\nconst ACCENT_STORAGE_KEY = 'docblocks:accentColor';\n\nexport function loadThemePreference(): ThemePreference {\n try {\n const raw = localStorage.getItem(THEME_STORAGE_KEY);\n if (raw === 'light' || raw === 'dark' || raw === 'auto') return raw;\n } catch {\n // ignore unavailable storage\n }\n return 'auto';\n}\n\nexport function saveThemePreference(value: ThemePreference): void {\n try {\n localStorage.setItem(THEME_STORAGE_KEY, value);\n } catch {\n // ignore quota errors\n }\n}\n\nexport function loadAccentColor(): AccentColor {\n try {\n const raw = localStorage.getItem(ACCENT_STORAGE_KEY);\n if (ACCENT_COLORS.some((color) => color === raw)) return raw as AccentColor;\n } catch {\n // ignore unavailable storage\n }\n return 'brown';\n}\n\nexport function saveAccentColor(value: AccentColor): void {\n try {\n localStorage.setItem(ACCENT_STORAGE_KEY, value);\n } catch {\n // ignore quota errors\n }\n}\n","import type { WriteCanvasSettings } from '@bendyline/squisq-editor-react';\n\nexport type WriteCanvasPreferences = Required<WriteCanvasSettings>;\n\nexport const WRITE_CANVAS_TEXT_SIZE_MIN = 12;\nexport const WRITE_CANVAS_TEXT_SIZE_MAX = 32;\nexport const WRITE_CANVAS_LINE_SPACING_MIN = 1.2;\nexport const WRITE_CANVAS_LINE_SPACING_MAX = 2.4;\n\nexport const DEFAULT_WRITE_CANVAS_PREFERENCES: Readonly<WriteCanvasPreferences> = {\n textSize: 16,\n lineSpacing: 1.7,\n};\n\nconst WRITE_CANVAS_STORAGE_KEY = 'docblocks:writeCanvasSettings';\n\nexport function loadWriteCanvasPreferences(): WriteCanvasPreferences {\n try {\n const raw = localStorage.getItem(WRITE_CANVAS_STORAGE_KEY);\n if (!raw) return { ...DEFAULT_WRITE_CANVAS_PREFERENCES };\n\n const stored: unknown = JSON.parse(raw);\n if (!isRecord(stored)) return { ...DEFAULT_WRITE_CANVAS_PREFERENCES };\n\n return {\n textSize: numberInRange(\n stored.textSize,\n WRITE_CANVAS_TEXT_SIZE_MIN,\n WRITE_CANVAS_TEXT_SIZE_MAX,\n )\n ? stored.textSize\n : DEFAULT_WRITE_CANVAS_PREFERENCES.textSize,\n lineSpacing: numberInRange(\n stored.lineSpacing,\n WRITE_CANVAS_LINE_SPACING_MIN,\n WRITE_CANVAS_LINE_SPACING_MAX,\n )\n ? stored.lineSpacing\n : DEFAULT_WRITE_CANVAS_PREFERENCES.lineSpacing,\n };\n } catch {\n return { ...DEFAULT_WRITE_CANVAS_PREFERENCES };\n }\n}\n\nexport function saveWriteCanvasPreferences(value: WriteCanvasPreferences): void {\n try {\n localStorage.setItem(WRITE_CANVAS_STORAGE_KEY, JSON.stringify(value));\n } catch {\n // Ignore unavailable storage and quota errors; the in-memory choice still works.\n }\n}\n\nfunction numberInRange(value: unknown, min: number, max: number): value is number {\n return typeof value === 'number' && Number.isFinite(value) && value >= min && value <= max;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n","/** Shared controls used by the app and host-specific DocBlocks settings dialogs. */\n\nimport type { ReactNode } from 'react';\nimport { Dialog } from '../components/Dialog.js';\nimport { ACCENT_COLORS, type AccentColor, type ThemePreference } from '../preferences/theme.js';\nimport {\n WRITE_CANVAS_LINE_SPACING_MAX,\n WRITE_CANVAS_LINE_SPACING_MIN,\n WRITE_CANVAS_TEXT_SIZE_MAX,\n WRITE_CANVAS_TEXT_SIZE_MIN,\n type WriteCanvasPreferences,\n} from '../preferences/write-canvas.js';\n\nexport type { AccentColor, ThemePreference } from '../preferences/theme.js';\n\nconst ACCENT_LABELS: Record<AccentColor, string> = {\n brown: 'Brown',\n green: 'Green',\n blue: 'Blue',\n purple: 'Purple',\n maroon: 'Maroon',\n orange: 'Orange',\n gray: 'Gray',\n};\n\nexport interface SettingsDialogProps {\n title?: string;\n onClose: () => void;\n children: ReactNode;\n}\n\nexport function SettingsDialog({ title = 'Settings', onClose, children }: SettingsDialogProps) {\n return (\n <Dialog title={title} onClose={onClose} size=\"wide\">\n {children}\n </Dialog>\n );\n}\n\nexport interface ThemeSettingsProps {\n value: ThemePreference;\n onChange: (theme: ThemePreference) => void;\n name?: string;\n}\n\nexport function ThemeSettings({ value, onChange, name = 'theme' }: ThemeSettingsProps) {\n return (\n <fieldset className=\"db-settings-fieldset\">\n <legend className=\"db-settings-legend\">Theme</legend>\n <label className=\"db-settings-radio\">\n <input\n type=\"radio\"\n name={name}\n value=\"auto\"\n checked={value === 'auto'}\n onChange={() => onChange('auto')}\n />\n System default\n </label>\n <label className=\"db-settings-radio\">\n <input\n type=\"radio\"\n name={name}\n value=\"light\"\n checked={value === 'light'}\n onChange={() => onChange('light')}\n />\n Light\n </label>\n <label className=\"db-settings-radio\">\n <input\n type=\"radio\"\n name={name}\n value=\"dark\"\n checked={value === 'dark'}\n onChange={() => onChange('dark')}\n />\n Dark\n </label>\n </fieldset>\n );\n}\n\nexport interface AccentColorSettingsProps {\n value: AccentColor;\n onChange: (color: AccentColor) => void;\n name?: string;\n}\n\nexport function AccentColorSettings({\n value,\n onChange,\n name = 'accent-color',\n}: AccentColorSettingsProps) {\n return (\n <fieldset className=\"db-settings-fieldset\">\n <legend className=\"db-settings-legend\">Accent color</legend>\n <p className=\"db-settings-hint\">Used in both light and dark appearances.</p>\n <div className=\"db-settings-accent-grid\">\n {ACCENT_COLORS.map((color) => (\n <label\n className={`db-settings-accent${\n value === color ? ' db-settings-accent--selected' : ''\n }`}\n key={color}\n >\n <input\n className=\"db-settings-accent-input\"\n type=\"radio\"\n name={name}\n value={color}\n checked={value === color}\n onChange={() => onChange(color)}\n />\n <span\n className={`db-settings-accent-swatch db-settings-accent-swatch--${color}`}\n aria-hidden=\"true\"\n />\n <span>{ACCENT_LABELS[color]}</span>\n </label>\n ))}\n </div>\n </fieldset>\n );\n}\n\nexport interface WriteCanvasSettingsControlsProps {\n value: WriteCanvasPreferences;\n onChange: (settings: WriteCanvasPreferences) => void;\n}\n\nexport function WriteCanvasSettingsControls({ value, onChange }: WriteCanvasSettingsControlsProps) {\n return (\n <fieldset className=\"db-settings-fieldset\">\n <legend className=\"db-settings-legend\">Write canvas</legend>\n <p className=\"db-settings-hint\">\n Adjust the writing view without changing the document or its exported text.\n </p>\n <label className=\"db-settings-slider\">\n <span className=\"db-settings-slider-header\">\n <span>Text size</span>\n <output className=\"db-settings-slider-value\" aria-hidden=\"true\">\n {value.textSize}px\n </output>\n </span>\n <input\n type=\"range\"\n min={WRITE_CANVAS_TEXT_SIZE_MIN}\n max={WRITE_CANVAS_TEXT_SIZE_MAX}\n step={1}\n value={value.textSize}\n aria-label=\"Text size\"\n aria-valuetext={`${value.textSize} pixels`}\n onChange={(event) => onChange({ ...value, textSize: Number(event.currentTarget.value) })}\n />\n </label>\n <label className=\"db-settings-slider\">\n <span className=\"db-settings-slider-header\">\n <span>Line spacing</span>\n <output className=\"db-settings-slider-value\" aria-hidden=\"true\">\n {formatLineSpacing(value.lineSpacing)}\n </output>\n </span>\n <input\n type=\"range\"\n min={WRITE_CANVAS_LINE_SPACING_MIN}\n max={WRITE_CANVAS_LINE_SPACING_MAX}\n step={0.1}\n value={value.lineSpacing}\n aria-label=\"Line spacing\"\n aria-valuetext={`${value.lineSpacing} times`}\n onChange={(event) =>\n onChange({ ...value, lineSpacing: Number(event.currentTarget.value) })\n }\n />\n </label>\n </fieldset>\n );\n}\n\nfunction formatLineSpacing(value: number): string {\n return `${value.toFixed(1).replace(/\\.0$/, '')}\\u00d7`;\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,110 @@
1
+ // src/components/Dialog.tsx
2
+ import { useCallback, useEffect, useId, useRef } from "react";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ function Dialog({
5
+ title,
6
+ onClose,
7
+ size = "default",
8
+ children,
9
+ footer,
10
+ initialFocusRef,
11
+ closeOnBackdrop = true,
12
+ className,
13
+ bodyClassName,
14
+ footerClassName
15
+ }) {
16
+ const closeButtonRef = useRef(null);
17
+ const dialogRef = useRef(null);
18
+ const titleId = useId();
19
+ useEffect(() => {
20
+ const onKey = (e) => {
21
+ if (e.key === "Escape") {
22
+ e.preventDefault();
23
+ onClose();
24
+ return;
25
+ }
26
+ if (e.key !== "Tab") return;
27
+ const dialog = dialogRef.current;
28
+ if (!dialog) return;
29
+ const focusable = [...dialog.querySelectorAll(FOCUSABLE_SELECTOR)].filter(
30
+ (element) => !element.hasAttribute("disabled") && element.getAttribute("aria-hidden") !== "true"
31
+ );
32
+ if (focusable.length === 0) {
33
+ e.preventDefault();
34
+ dialog.focus();
35
+ return;
36
+ }
37
+ const first = focusable[0];
38
+ const last = focusable[focusable.length - 1];
39
+ if (e.shiftKey && document.activeElement === first) {
40
+ e.preventDefault();
41
+ last.focus();
42
+ } else if (!e.shiftKey && document.activeElement === last) {
43
+ e.preventDefault();
44
+ first.focus();
45
+ }
46
+ };
47
+ window.addEventListener("keydown", onKey);
48
+ return () => window.removeEventListener("keydown", onKey);
49
+ }, [onClose]);
50
+ useEffect(() => {
51
+ const previousFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;
52
+ const target = initialFocusRef?.current ?? closeButtonRef.current;
53
+ target?.focus();
54
+ return () => {
55
+ if (previousFocus?.isConnected) previousFocus.focus();
56
+ };
57
+ }, []);
58
+ const handleBackdropClick = useCallback(
59
+ (e) => {
60
+ if (closeOnBackdrop && e.target === e.currentTarget) onClose();
61
+ },
62
+ [closeOnBackdrop, onClose]
63
+ );
64
+ const sizeClass = size === "wide" ? "db-dialog--wide" : size === "full" ? "db-dialog--full" : "";
65
+ const panelClassName = ["db-dialog", sizeClass, className].filter(Boolean).join(" ");
66
+ const bodyClasses = ["db-dialog-body", bodyClassName].filter(Boolean).join(" ");
67
+ const footerClasses = ["db-dialog-footer", footerClassName].filter(Boolean).join(" ");
68
+ return /* @__PURE__ */ jsx("div", { className: "db-dialog-overlay", onClick: handleBackdropClick, children: /* @__PURE__ */ jsxs(
69
+ "div",
70
+ {
71
+ ref: dialogRef,
72
+ className: panelClassName,
73
+ role: "dialog",
74
+ "aria-modal": "true",
75
+ "aria-labelledby": titleId,
76
+ tabIndex: -1,
77
+ children: [
78
+ /* @__PURE__ */ jsxs("div", { className: "db-dialog-header", children: [
79
+ /* @__PURE__ */ jsx("h2", { id: titleId, className: "db-dialog-title", children: title }),
80
+ /* @__PURE__ */ jsx(
81
+ "button",
82
+ {
83
+ ref: closeButtonRef,
84
+ type: "button",
85
+ className: "db-dialog-close",
86
+ onClick: onClose,
87
+ "aria-label": "Close",
88
+ children: "\xD7"
89
+ }
90
+ )
91
+ ] }),
92
+ /* @__PURE__ */ jsx("div", { className: bodyClasses, children }),
93
+ footer && /* @__PURE__ */ jsx("div", { className: footerClasses, children: footer })
94
+ ]
95
+ }
96
+ ) });
97
+ }
98
+ var FOCUSABLE_SELECTOR = [
99
+ "a[href]",
100
+ "button",
101
+ "input",
102
+ "select",
103
+ "textarea",
104
+ '[tabindex]:not([tabindex="-1"])'
105
+ ].join(",");
106
+
107
+ export {
108
+ Dialog
109
+ };
110
+ //# sourceMappingURL=chunk-FMGTHSTX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/Dialog.tsx"],"sourcesContent":["/**\n * Dialog — shared modal primitive.\n *\n * Promotes the `db-dialog-overlay` / `db-dialog` pattern used by the\n * settings dialogs into a reusable component, adding aria-modal and\n * initial focus. Escape and (by default) backdrop clicks close it.\n */\n\nimport React, { useCallback, useEffect, useId, useRef } from 'react';\n\nexport interface DialogProps {\n title: string;\n onClose: () => void;\n /** default 380px / wide 560px / full min(1100px, 94vw) column. */\n size?: 'default' | 'wide' | 'full';\n children: React.ReactNode;\n /** Right-aligned action row below the body. */\n footer?: React.ReactNode;\n /** Element to focus on open; defaults to the close button. */\n initialFocusRef?: React.RefObject<HTMLElement | null>;\n /** Set false when a stray backdrop click would lose user input. */\n closeOnBackdrop?: boolean;\n /** Additional class on the dialog panel. */\n className?: string;\n /** Additional class on the dialog body. */\n bodyClassName?: string;\n /** Additional class on the footer wrapper. */\n footerClassName?: string;\n}\n\nexport function Dialog({\n title,\n onClose,\n size = 'default',\n children,\n footer,\n initialFocusRef,\n closeOnBackdrop = true,\n className,\n bodyClassName,\n footerClassName,\n}: DialogProps) {\n const closeButtonRef = useRef<HTMLButtonElement>(null);\n const dialogRef = useRef<HTMLDivElement>(null);\n const titleId = useId();\n\n useEffect(() => {\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n onClose();\n return;\n }\n if (e.key !== 'Tab') return;\n\n const dialog = dialogRef.current;\n if (!dialog) return;\n const focusable = [...dialog.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR)].filter(\n (element) =>\n !element.hasAttribute('disabled') && element.getAttribute('aria-hidden') !== 'true',\n );\n if (focusable.length === 0) {\n e.preventDefault();\n dialog.focus();\n return;\n }\n\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n if (e.shiftKey && document.activeElement === first) {\n e.preventDefault();\n last.focus();\n } else if (!e.shiftKey && document.activeElement === last) {\n e.preventDefault();\n first.focus();\n }\n };\n window.addEventListener('keydown', onKey);\n return () => window.removeEventListener('keydown', onKey);\n }, [onClose]);\n\n useEffect(() => {\n const previousFocus =\n document.activeElement instanceof HTMLElement ? document.activeElement : null;\n const target = initialFocusRef?.current ?? closeButtonRef.current;\n target?.focus();\n return () => {\n if (previousFocus?.isConnected) previousFocus.focus();\n };\n // Focus only on mount — refocusing on every re-render would fight the user.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const handleBackdropClick = useCallback(\n (e: React.MouseEvent) => {\n if (closeOnBackdrop && e.target === e.currentTarget) onClose();\n },\n [closeOnBackdrop, onClose],\n );\n\n const sizeClass = size === 'wide' ? 'db-dialog--wide' : size === 'full' ? 'db-dialog--full' : '';\n const panelClassName = ['db-dialog', sizeClass, className].filter(Boolean).join(' ');\n const bodyClasses = ['db-dialog-body', bodyClassName].filter(Boolean).join(' ');\n const footerClasses = ['db-dialog-footer', footerClassName].filter(Boolean).join(' ');\n\n return (\n <div className=\"db-dialog-overlay\" onClick={handleBackdropClick}>\n <div\n ref={dialogRef}\n className={panelClassName}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n tabIndex={-1}\n >\n <div className=\"db-dialog-header\">\n <h2 id={titleId} className=\"db-dialog-title\">\n {title}\n </h2>\n <button\n ref={closeButtonRef}\n type=\"button\"\n className=\"db-dialog-close\"\n onClick={onClose}\n aria-label=\"Close\"\n >\n &times;\n </button>\n </div>\n <div className={bodyClasses}>{children}</div>\n {footer && <div className={footerClasses}>{footer}</div>}\n </div>\n </div>\n );\n}\n\nconst FOCUSABLE_SELECTOR = [\n 'a[href]',\n 'button',\n 'input',\n 'select',\n 'textarea',\n '[tabindex]:not([tabindex=\"-1\"])',\n].join(',');\n"],"mappings":"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","names":[]}