@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.
- package/README.md +6 -0
- package/dist/{ExportDialog-MEUISWZX.js → ExportDialog-7LDIXJZ3.js} +3 -2
- package/dist/{ExportToolbarControls-D2YDWOXW.js → ExportToolbarControls-GHAOJMH6.js} +147 -12
- package/dist/ExportToolbarControls-GHAOJMH6.js.map +1 -0
- package/dist/{GitToolbarControl-LMIR4R7I.js → GitToolbarControl-GNMRVKWQ.js} +62 -43
- package/dist/GitToolbarControl-GNMRVKWQ.js.map +1 -0
- package/dist/{GitUI-KGF5MSNV.js → GitUI-VHOBQY43.js} +225 -140
- package/dist/GitUI-VHOBQY43.js.map +1 -0
- package/dist/ShareDialog-63ENBEDZ.js +213 -0
- package/dist/ShareDialog-63ENBEDZ.js.map +1 -0
- package/dist/chunk-57ZJJOC5.js +89 -0
- package/dist/chunk-57ZJJOC5.js.map +1 -0
- package/dist/chunk-FEWQUQML.js +256 -0
- package/dist/chunk-FEWQUQML.js.map +1 -0
- package/dist/chunk-FMGTHSTX.js +110 -0
- package/dist/chunk-FMGTHSTX.js.map +1 -0
- package/dist/chunk-UNYZQXWR.js +324 -0
- package/dist/chunk-UNYZQXWR.js.map +1 -0
- package/dist/editor.d.ts +5 -4
- package/dist/editor.js +8 -69
- package/dist/editor.js.map +1 -1
- package/dist/export/index.d.ts +7 -1
- package/dist/export/index.js +2 -1
- package/dist/index.d.ts +346 -21
- package/dist/index.js +6169 -20
- package/dist/index.js.map +1 -1
- package/dist/settings/index.d.ts +9 -1
- package/dist/settings/index.js +6 -4
- package/package.json +18 -13
- package/src/styles/docblocks.css +537 -26
- package/dist/AppMenu/AppMenu.d.ts +0 -53
- package/dist/AppMenu/AppMenu.d.ts.map +0 -1
- package/dist/AppMenu/AppMenu.js +0 -67
- package/dist/AppMenu/AppMenu.js.map +0 -1
- package/dist/AppMenu/index.d.ts +0 -3
- package/dist/AppMenu/index.d.ts.map +0 -1
- package/dist/AppMenu/index.js +0 -2
- package/dist/AppMenu/index.js.map +0 -1
- package/dist/DocBlocksShell/DocBlocksShell.d.ts +0 -49
- package/dist/DocBlocksShell/DocBlocksShell.d.ts.map +0 -1
- package/dist/DocBlocksShell/DocBlocksShell.js +0 -2730
- package/dist/DocBlocksShell/DocBlocksShell.js.map +0 -1
- package/dist/DocBlocksShell/LazyEditorShell.d.ts +0 -3
- package/dist/DocBlocksShell/LazyEditorShell.d.ts.map +0 -1
- package/dist/DocBlocksShell/LazyEditorShell.js +0 -3
- package/dist/DocBlocksShell/LazyEditorShell.js.map +0 -1
- package/dist/DocBlocksShell/UpdateAvailableNotice.d.ts +0 -13
- package/dist/DocBlocksShell/UpdateAvailableNotice.d.ts.map +0 -1
- package/dist/DocBlocksShell/UpdateAvailableNotice.js +0 -16
- package/dist/DocBlocksShell/UpdateAvailableNotice.js.map +0 -1
- package/dist/DocBlocksShell/document-title.d.ts +0 -3
- package/dist/DocBlocksShell/document-title.d.ts.map +0 -1
- package/dist/DocBlocksShell/document-title.js +0 -17
- package/dist/DocBlocksShell/document-title.js.map +0 -1
- package/dist/DocBlocksShell/index.d.ts +0 -3
- package/dist/DocBlocksShell/index.d.ts.map +0 -1
- package/dist/DocBlocksShell/index.js +0 -2
- package/dist/DocBlocksShell/index.js.map +0 -1
- package/dist/DocBlocksShell/workspace-authority-barrier.d.ts +0 -14
- package/dist/DocBlocksShell/workspace-authority-barrier.d.ts.map +0 -1
- package/dist/DocBlocksShell/workspace-authority-barrier.js +0 -23
- package/dist/DocBlocksShell/workspace-authority-barrier.js.map +0 -1
- package/dist/Export/DeferredExportToolbarControls.d.ts +0 -5
- package/dist/Export/DeferredExportToolbarControls.d.ts.map +0 -1
- package/dist/Export/DeferredExportToolbarControls.js +0 -10
- package/dist/Export/DeferredExportToolbarControls.js.map +0 -1
- package/dist/Export/ExportDialog.d.ts +0 -25
- package/dist/Export/ExportDialog.d.ts.map +0 -1
- package/dist/Export/ExportDialog.js +0 -160
- package/dist/Export/ExportDialog.js.map +0 -1
- package/dist/Export/ExportToolbarControls.d.ts +0 -37
- package/dist/Export/ExportToolbarControls.d.ts.map +0 -1
- package/dist/Export/ExportToolbarControls.js +0 -285
- package/dist/Export/ExportToolbarControls.js.map +0 -1
- package/dist/Export/export-destination.d.ts +0 -3
- package/dist/Export/export-destination.d.ts.map +0 -1
- package/dist/Export/export-destination.js +0 -32
- package/dist/Export/export-destination.js.map +0 -1
- package/dist/Export/export-options.d.ts +0 -53
- package/dist/Export/export-options.d.ts.map +0 -1
- package/dist/Export/export-options.js +0 -49
- package/dist/Export/export-options.js.map +0 -1
- package/dist/Export/index.d.ts +0 -10
- package/dist/Export/index.d.ts.map +0 -1
- package/dist/Export/index.js +0 -6
- package/dist/Export/index.js.map +0 -1
- package/dist/Export/public-api.d.ts +0 -12
- package/dist/Export/public-api.d.ts.map +0 -1
- package/dist/Export/public-api.js +0 -9
- package/dist/Export/public-api.js.map +0 -1
- package/dist/Export/run-export.d.ts +0 -10
- package/dist/Export/run-export.d.ts.map +0 -1
- package/dist/Export/run-export.js +0 -313
- package/dist/Export/run-export.js.map +0 -1
- package/dist/Export/transform-summaries.d.ts +0 -7
- package/dist/Export/transform-summaries.d.ts.map +0 -1
- package/dist/Export/transform-summaries.js +0 -6
- package/dist/Export/transform-summaries.js.map +0 -1
- package/dist/ExportToolbarControls-D2YDWOXW.js.map +0 -1
- package/dist/FileExplorer/FileExplorer.d.ts +0 -43
- package/dist/FileExplorer/FileExplorer.d.ts.map +0 -1
- package/dist/FileExplorer/FileExplorer.js +0 -315
- package/dist/FileExplorer/FileExplorer.js.map +0 -1
- package/dist/FileExplorer/FileTreeNode.d.ts +0 -39
- package/dist/FileExplorer/FileTreeNode.d.ts.map +0 -1
- package/dist/FileExplorer/FileTreeNode.js +0 -131
- package/dist/FileExplorer/FileTreeNode.js.map +0 -1
- package/dist/FileExplorer/index.d.ts +0 -6
- package/dist/FileExplorer/index.d.ts.map +0 -1
- package/dist/FileExplorer/index.js +0 -4
- package/dist/FileExplorer/index.js.map +0 -1
- package/dist/FileExplorer/useFileTree.d.ts +0 -37
- package/dist/FileExplorer/useFileTree.d.ts.map +0 -1
- package/dist/FileExplorer/useFileTree.js +0 -284
- package/dist/FileExplorer/useFileTree.js.map +0 -1
- package/dist/Git/GitAuthGuidanceDialog.d.ts +0 -18
- package/dist/Git/GitAuthGuidanceDialog.d.ts.map +0 -1
- package/dist/Git/GitAuthGuidanceDialog.js +0 -27
- package/dist/Git/GitAuthGuidanceDialog.js.map +0 -1
- package/dist/Git/GitBranchesDialog.d.ts +0 -13
- package/dist/Git/GitBranchesDialog.d.ts.map +0 -1
- package/dist/Git/GitBranchesDialog.js +0 -59
- package/dist/Git/GitBranchesDialog.js.map +0 -1
- package/dist/Git/GitCloneDialog.d.ts +0 -14
- package/dist/Git/GitCloneDialog.d.ts.map +0 -1
- package/dist/Git/GitCloneDialog.js +0 -79
- package/dist/Git/GitCloneDialog.js.map +0 -1
- package/dist/Git/GitCommitDialog.d.ts +0 -12
- package/dist/Git/GitCommitDialog.d.ts.map +0 -1
- package/dist/Git/GitCommitDialog.js +0 -38
- package/dist/Git/GitCommitDialog.js.map +0 -1
- package/dist/Git/GitConflictsDialog.d.ts +0 -12
- package/dist/Git/GitConflictsDialog.d.ts.map +0 -1
- package/dist/Git/GitConflictsDialog.js +0 -17
- package/dist/Git/GitConflictsDialog.js.map +0 -1
- package/dist/Git/GitContext.d.ts +0 -89
- package/dist/Git/GitContext.d.ts.map +0 -1
- package/dist/Git/GitContext.js +0 -15
- package/dist/Git/GitContext.js.map +0 -1
- package/dist/Git/GitDiffDialog.d.ts +0 -20
- package/dist/Git/GitDiffDialog.d.ts.map +0 -1
- package/dist/Git/GitDiffDialog.js +0 -100
- package/dist/Git/GitDiffDialog.js.map +0 -1
- package/dist/Git/GitDiffView.d.ts +0 -23
- package/dist/Git/GitDiffView.d.ts.map +0 -1
- package/dist/Git/GitDiffView.js +0 -77
- package/dist/Git/GitDiffView.js.map +0 -1
- package/dist/Git/GitHistoryDialog.d.ts +0 -15
- package/dist/Git/GitHistoryDialog.d.ts.map +0 -1
- package/dist/Git/GitHistoryDialog.js +0 -107
- package/dist/Git/GitHistoryDialog.js.map +0 -1
- package/dist/Git/GitStatusBar.d.ts +0 -8
- package/dist/Git/GitStatusBar.d.ts.map +0 -1
- package/dist/Git/GitStatusBar.js +0 -49
- package/dist/Git/GitStatusBar.js.map +0 -1
- package/dist/Git/GitToolbarControl.d.ts +0 -15
- package/dist/Git/GitToolbarControl.d.ts.map +0 -1
- package/dist/Git/GitToolbarControl.js +0 -51
- package/dist/Git/GitToolbarControl.js.map +0 -1
- package/dist/Git/GitUI.d.ts +0 -14
- package/dist/Git/GitUI.d.ts.map +0 -1
- package/dist/Git/GitUI.js +0 -21
- package/dist/Git/GitUI.js.map +0 -1
- package/dist/Git/commit-selection.d.ts +0 -22
- package/dist/Git/commit-selection.d.ts.map +0 -1
- package/dist/Git/commit-selection.js +0 -47
- package/dist/Git/commit-selection.js.map +0 -1
- package/dist/Git/git-clone-utils.d.ts +0 -8
- package/dist/Git/git-clone-utils.d.ts.map +0 -1
- package/dist/Git/git-clone-utils.js +0 -26
- package/dist/Git/git-clone-utils.js.map +0 -1
- package/dist/Git/git-status.d.ts +0 -24
- package/dist/Git/git-status.d.ts.map +0 -1
- package/dist/Git/git-status.js +0 -105
- package/dist/Git/git-status.js.map +0 -1
- package/dist/Git/useGit.d.ts +0 -15
- package/dist/Git/useGit.d.ts.map +0 -1
- package/dist/Git/useGit.js +0 -206
- package/dist/Git/useGit.js.map +0 -1
- package/dist/Git/useGitStatus.d.ts +0 -17
- package/dist/Git/useGitStatus.d.ts.map +0 -1
- package/dist/Git/useGitStatus.js +0 -63
- package/dist/Git/useGitStatus.js.map +0 -1
- package/dist/GitToolbarControl-LMIR4R7I.js.map +0 -1
- package/dist/GitUI-KGF5MSNV.js.map +0 -1
- package/dist/Settings/Settings.d.ts +0 -23
- package/dist/Settings/Settings.d.ts.map +0 -1
- package/dist/Settings/Settings.js +0 -22
- package/dist/Settings/Settings.js.map +0 -1
- package/dist/Settings/public-api.d.ts +0 -3
- package/dist/Settings/public-api.d.ts.map +0 -1
- package/dist/Settings/public-api.js +0 -2
- package/dist/Settings/public-api.js.map +0 -1
- package/dist/WorkspacePicker/WorkspacePicker.d.ts +0 -22
- package/dist/WorkspacePicker/WorkspacePicker.d.ts.map +0 -1
- package/dist/WorkspacePicker/WorkspacePicker.js +0 -74
- package/dist/WorkspacePicker/WorkspacePicker.js.map +0 -1
- package/dist/WorkspacePicker/WorkspaceSettingsButton.d.ts +0 -11
- package/dist/WorkspacePicker/WorkspaceSettingsButton.d.ts.map +0 -1
- package/dist/WorkspacePicker/WorkspaceSettingsButton.js +0 -27
- package/dist/WorkspacePicker/WorkspaceSettingsButton.js.map +0 -1
- package/dist/WorkspacePicker/WorkspaceSettingsDialog.d.ts +0 -20
- package/dist/WorkspacePicker/WorkspaceSettingsDialog.d.ts.map +0 -1
- package/dist/WorkspacePicker/WorkspaceSettingsDialog.js +0 -36
- package/dist/WorkspacePicker/WorkspaceSettingsDialog.js.map +0 -1
- package/dist/WorkspacePicker/index.d.ts +0 -3
- package/dist/WorkspacePicker/index.d.ts.map +0 -1
- package/dist/WorkspacePicker/index.js +0 -2
- package/dist/WorkspacePicker/index.js.map +0 -1
- package/dist/chunk-3SAXDU2U.js +0 -157
- package/dist/chunk-3SAXDU2U.js.map +0 -1
- package/dist/chunk-AOVTHZU7.js +0 -321
- package/dist/chunk-AOVTHZU7.js.map +0 -1
- package/dist/chunk-GSNZSCIK.js +0 -55
- package/dist/chunk-GSNZSCIK.js.map +0 -1
- package/dist/components/Dialog.d.ts +0 -22
- package/dist/components/Dialog.d.ts.map +0 -1
- package/dist/components/Dialog.js +0 -33
- package/dist/components/Dialog.js.map +0 -1
- package/dist/editor.d.ts.map +0 -1
- package/dist/hooks/index.d.ts +0 -3
- package/dist/hooks/index.d.ts.map +0 -1
- package/dist/hooks/index.js +0 -2
- package/dist/hooks/index.js.map +0 -1
- package/dist/hooks/useDocumentSession.d.ts +0 -16
- package/dist/hooks/useDocumentSession.d.ts.map +0 -1
- package/dist/hooks/useDocumentSession.js +0 -18
- package/dist/hooks/useDocumentSession.js.map +0 -1
- package/dist/icons.d.ts +0 -12
- package/dist/icons.d.ts.map +0 -1
- package/dist/icons.js +0 -28
- package/dist/icons.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/preferences/theme.d.ts +0 -18
- package/dist/preferences/theme.d.ts.map +0 -1
- package/dist/preferences/theme.js +0 -63
- package/dist/preferences/theme.js.map +0 -1
- package/dist/preferences/versioning.d.ts +0 -27
- package/dist/preferences/versioning.d.ts.map +0 -1
- package/dist/preferences/versioning.js +0 -62
- package/dist/preferences/versioning.js.map +0 -1
- package/dist/provider-lease.d.ts +0 -10
- package/dist/provider-lease.d.ts.map +0 -1
- package/dist/provider-lease.js +0 -42
- package/dist/provider-lease.js.map +0 -1
- package/src/AppMenu/AppMenu.tsx +0 -334
- package/src/AppMenu/index.ts +0 -2
- package/src/DocBlocksShell/DocBlocksShell.tsx +0 -3398
- package/src/DocBlocksShell/LazyEditorShell.ts +0 -2
- package/src/DocBlocksShell/UpdateAvailableNotice.tsx +0 -60
- package/src/DocBlocksShell/document-title.ts +0 -19
- package/src/DocBlocksShell/index.ts +0 -2
- package/src/DocBlocksShell/workspace-authority-barrier.ts +0 -26
- package/src/Export/DeferredExportToolbarControls.tsx +0 -23
- package/src/Export/ExportDialog.tsx +0 -437
- package/src/Export/ExportToolbarControls.tsx +0 -511
- package/src/Export/export-destination.ts +0 -30
- package/src/Export/export-options.ts +0 -99
- package/src/Export/index.ts +0 -19
- package/src/Export/public-api.ts +0 -17
- package/src/Export/run-export.ts +0 -374
- package/src/Export/transform-summaries.ts +0 -14
- package/src/FileExplorer/FileExplorer.tsx +0 -528
- package/src/FileExplorer/FileTreeNode.tsx +0 -306
- package/src/FileExplorer/index.ts +0 -5
- package/src/FileExplorer/useFileTree.ts +0 -352
- package/src/Git/GitAuthGuidanceDialog.tsx +0 -84
- package/src/Git/GitBranchesDialog.tsx +0 -144
- package/src/Git/GitCloneDialog.tsx +0 -200
- package/src/Git/GitCommitDialog.tsx +0 -119
- package/src/Git/GitConflictsDialog.tsx +0 -62
- package/src/Git/GitContext.tsx +0 -88
- package/src/Git/GitDiffDialog.tsx +0 -147
- package/src/Git/GitDiffView.tsx +0 -105
- package/src/Git/GitHistoryDialog.tsx +0 -195
- package/src/Git/GitStatusBar.tsx +0 -157
- package/src/Git/GitToolbarControl.tsx +0 -123
- package/src/Git/GitUI.tsx +0 -68
- package/src/Git/commit-selection.ts +0 -63
- package/src/Git/git-clone-utils.ts +0 -23
- package/src/Git/git-status.ts +0 -113
- package/src/Git/useGit.ts +0 -279
- package/src/Git/useGitStatus.ts +0 -78
- package/src/Settings/Settings.tsx +0 -118
- package/src/Settings/public-api.ts +0 -8
- package/src/WorkspacePicker/WorkspacePicker.tsx +0 -191
- package/src/WorkspacePicker/WorkspaceSettingsButton.tsx +0 -88
- package/src/WorkspacePicker/WorkspaceSettingsDialog.tsx +0 -121
- package/src/WorkspacePicker/index.ts +0 -2
- package/src/components/Dialog.tsx +0 -81
- package/src/editor.ts +0 -72
- package/src/hooks/index.ts +0 -2
- package/src/hooks/useDocumentSession.ts +0 -37
- package/src/icons.tsx +0 -48
- package/src/index.ts +0 -61
- package/src/preferences/theme.ts +0 -67
- package/src/preferences/versioning.ts +0 -69
- package/src/provider-lease.ts +0 -52
- package/src/types/pwa-dom.d.ts +0 -31
- /package/dist/{ExportDialog-MEUISWZX.js.map → ExportDialog-7LDIXJZ3.js.map} +0 -0
package/src/Git/useGitStatus.ts
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* useGitStatus — subscribes to the host's owner-scoped repository stream.
|
|
3
|
-
*
|
|
4
|
-
* Dedupes identical payloads so a permanently-dirty working tree (normal
|
|
5
|
-
* under the manual-commit model) doesn't repaint the tree on every push
|
|
6
|
-
* from the main process.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
10
|
-
import type { DocBlocksHostGitAPI, GitStatus } from '@bendyline/docblocks/host';
|
|
11
|
-
|
|
12
|
-
const SCHEDULE_REFRESH_MS = 1500;
|
|
13
|
-
|
|
14
|
-
function statusKey(status: GitStatus): string {
|
|
15
|
-
return JSON.stringify(status);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export interface UseGitStatusResult {
|
|
19
|
-
status: GitStatus | null;
|
|
20
|
-
/** Fetch a fresh status immediately (after a renderer-initiated git op). */
|
|
21
|
-
refresh: () => void;
|
|
22
|
-
/** Trailing-debounced refresh (after autosave writes). */
|
|
23
|
-
scheduleRefresh: () => void;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function useGitStatus(
|
|
27
|
-
gitApi: DocBlocksHostGitAPI | null,
|
|
28
|
-
repositoryId: string | null,
|
|
29
|
-
enabled: boolean,
|
|
30
|
-
): UseGitStatusResult {
|
|
31
|
-
const [status, setStatus] = useState<GitStatus | null>(null);
|
|
32
|
-
const lastKeyRef = useRef<string | null>(null);
|
|
33
|
-
const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
34
|
-
|
|
35
|
-
const apply = useCallback((next: GitStatus) => {
|
|
36
|
-
const key = statusKey(next);
|
|
37
|
-
if (key === lastKeyRef.current) return;
|
|
38
|
-
lastKeyRef.current = key;
|
|
39
|
-
setStatus(next);
|
|
40
|
-
}, []);
|
|
41
|
-
|
|
42
|
-
useEffect(() => {
|
|
43
|
-
lastKeyRef.current = null;
|
|
44
|
-
setStatus(null);
|
|
45
|
-
if (!gitApi || !repositoryId || !enabled) return;
|
|
46
|
-
let cancelled = false;
|
|
47
|
-
const unsubscribe = gitApi.onStatusChanged(repositoryId, (next) => {
|
|
48
|
-
if (!cancelled) apply(next);
|
|
49
|
-
});
|
|
50
|
-
return () => {
|
|
51
|
-
cancelled = true;
|
|
52
|
-
unsubscribe();
|
|
53
|
-
};
|
|
54
|
-
}, [gitApi, repositoryId, enabled, apply]);
|
|
55
|
-
|
|
56
|
-
const refresh = useCallback(() => {
|
|
57
|
-
if (!gitApi || !repositoryId || !enabled) return;
|
|
58
|
-
void gitApi.status(repositoryId).then((result) => {
|
|
59
|
-
if (result.ok) apply(result.value);
|
|
60
|
-
});
|
|
61
|
-
}, [gitApi, repositoryId, enabled, apply]);
|
|
62
|
-
|
|
63
|
-
const scheduleRefresh = useCallback(() => {
|
|
64
|
-
if (timerRef.current) clearTimeout(timerRef.current);
|
|
65
|
-
timerRef.current = setTimeout(() => {
|
|
66
|
-
timerRef.current = null;
|
|
67
|
-
refresh();
|
|
68
|
-
}, SCHEDULE_REFRESH_MS);
|
|
69
|
-
}, [refresh]);
|
|
70
|
-
|
|
71
|
-
useEffect(() => {
|
|
72
|
-
return () => {
|
|
73
|
-
if (timerRef.current) clearTimeout(timerRef.current);
|
|
74
|
-
};
|
|
75
|
-
}, []);
|
|
76
|
-
|
|
77
|
-
return { status, refresh, scheduleRefresh };
|
|
78
|
-
}
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
/** Shared controls used by the app and host-specific DocBlocks settings dialogs. */
|
|
2
|
-
|
|
3
|
-
import type { ReactNode } from 'react';
|
|
4
|
-
import { Dialog } from '../components/Dialog.js';
|
|
5
|
-
import { ACCENT_COLORS, type AccentColor, type ThemePreference } from '../preferences/theme.js';
|
|
6
|
-
|
|
7
|
-
export type { AccentColor, ThemePreference } from '../preferences/theme.js';
|
|
8
|
-
|
|
9
|
-
const ACCENT_LABELS: Record<AccentColor, string> = {
|
|
10
|
-
brown: 'Brown',
|
|
11
|
-
green: 'Green',
|
|
12
|
-
blue: 'Blue',
|
|
13
|
-
purple: 'Purple',
|
|
14
|
-
maroon: 'Maroon',
|
|
15
|
-
orange: 'Orange',
|
|
16
|
-
gray: 'Gray',
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export interface SettingsDialogProps {
|
|
20
|
-
title?: string;
|
|
21
|
-
onClose: () => void;
|
|
22
|
-
children: ReactNode;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export function SettingsDialog({ title = 'Settings', onClose, children }: SettingsDialogProps) {
|
|
26
|
-
return (
|
|
27
|
-
<Dialog title={title} onClose={onClose}>
|
|
28
|
-
{children}
|
|
29
|
-
</Dialog>
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export interface ThemeSettingsProps {
|
|
34
|
-
value: ThemePreference;
|
|
35
|
-
onChange: (theme: ThemePreference) => void;
|
|
36
|
-
name?: string;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export function ThemeSettings({ value, onChange, name = 'theme' }: ThemeSettingsProps) {
|
|
40
|
-
return (
|
|
41
|
-
<fieldset className="db-settings-fieldset">
|
|
42
|
-
<legend className="db-settings-legend">Theme</legend>
|
|
43
|
-
<label className="db-settings-radio">
|
|
44
|
-
<input
|
|
45
|
-
type="radio"
|
|
46
|
-
name={name}
|
|
47
|
-
value="auto"
|
|
48
|
-
checked={value === 'auto'}
|
|
49
|
-
onChange={() => onChange('auto')}
|
|
50
|
-
/>
|
|
51
|
-
System default
|
|
52
|
-
</label>
|
|
53
|
-
<label className="db-settings-radio">
|
|
54
|
-
<input
|
|
55
|
-
type="radio"
|
|
56
|
-
name={name}
|
|
57
|
-
value="light"
|
|
58
|
-
checked={value === 'light'}
|
|
59
|
-
onChange={() => onChange('light')}
|
|
60
|
-
/>
|
|
61
|
-
Light
|
|
62
|
-
</label>
|
|
63
|
-
<label className="db-settings-radio">
|
|
64
|
-
<input
|
|
65
|
-
type="radio"
|
|
66
|
-
name={name}
|
|
67
|
-
value="dark"
|
|
68
|
-
checked={value === 'dark'}
|
|
69
|
-
onChange={() => onChange('dark')}
|
|
70
|
-
/>
|
|
71
|
-
Dark
|
|
72
|
-
</label>
|
|
73
|
-
</fieldset>
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export interface AccentColorSettingsProps {
|
|
78
|
-
value: AccentColor;
|
|
79
|
-
onChange: (color: AccentColor) => void;
|
|
80
|
-
name?: string;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
export function AccentColorSettings({
|
|
84
|
-
value,
|
|
85
|
-
onChange,
|
|
86
|
-
name = 'accent-color',
|
|
87
|
-
}: AccentColorSettingsProps) {
|
|
88
|
-
return (
|
|
89
|
-
<fieldset className="db-settings-fieldset">
|
|
90
|
-
<legend className="db-settings-legend">Accent color</legend>
|
|
91
|
-
<p className="db-settings-hint">Used in both light and dark appearances.</p>
|
|
92
|
-
<div className="db-settings-accent-grid">
|
|
93
|
-
{ACCENT_COLORS.map((color) => (
|
|
94
|
-
<label
|
|
95
|
-
className={`db-settings-accent${
|
|
96
|
-
value === color ? ' db-settings-accent--selected' : ''
|
|
97
|
-
}`}
|
|
98
|
-
key={color}
|
|
99
|
-
>
|
|
100
|
-
<input
|
|
101
|
-
className="db-settings-accent-input"
|
|
102
|
-
type="radio"
|
|
103
|
-
name={name}
|
|
104
|
-
value={color}
|
|
105
|
-
checked={value === color}
|
|
106
|
-
onChange={() => onChange(color)}
|
|
107
|
-
/>
|
|
108
|
-
<span
|
|
109
|
-
className={`db-settings-accent-swatch db-settings-accent-swatch--${color}`}
|
|
110
|
-
aria-hidden="true"
|
|
111
|
-
/>
|
|
112
|
-
<span>{ACCENT_LABELS[color]}</span>
|
|
113
|
-
</label>
|
|
114
|
-
))}
|
|
115
|
-
</div>
|
|
116
|
-
</fieldset>
|
|
117
|
-
);
|
|
118
|
-
}
|
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* WorkspacePicker — dropdown for switching between workspaces
|
|
3
|
-
* (IndexedDB-based or native folder via File System Access API).
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { Fragment, useState, useEffect, useCallback, useRef } from 'react';
|
|
7
|
-
import type { WorkspaceDescriptor } from '@bendyline/docblocks/workspace';
|
|
8
|
-
import { listWorkspaces, saveWorkspace, touchWorkspace } from '@bendyline/docblocks/workspace';
|
|
9
|
-
import { isElectronHost } from '@bendyline/docblocks/host';
|
|
10
|
-
import { FolderIcon, NewFolderIcon } from '../icons.js';
|
|
11
|
-
|
|
12
|
-
function isNativeFileSystemSupported(): boolean {
|
|
13
|
-
return (
|
|
14
|
-
typeof globalThis !== 'undefined' &&
|
|
15
|
-
typeof (globalThis as { showDirectoryPicker?: unknown }).showDirectoryPicker === 'function'
|
|
16
|
-
);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export interface WorkspacePickerProps {
|
|
20
|
-
/** Currently active workspace id. */
|
|
21
|
-
activeWorkspaceId: string | null;
|
|
22
|
-
/** Called when the user picks a different workspace. */
|
|
23
|
-
onSelect: (descriptor: WorkspaceDescriptor) => void;
|
|
24
|
-
/** Called when the user chooses "Open Folder" (native FS). */
|
|
25
|
-
onOpenFolder: () => void;
|
|
26
|
-
/**
|
|
27
|
-
* Called when the user chooses "Clone Git repository". Only provided on
|
|
28
|
-
* the desktop when git is available — omitted, the item is hidden.
|
|
29
|
-
*/
|
|
30
|
-
onCloneRepository?: () => void;
|
|
31
|
-
/** Optional className. */
|
|
32
|
-
className?: string;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function WorkspacePath({ path }: { path: string }) {
|
|
36
|
-
return path.split(/([\\/])/).map((segment, index) => (
|
|
37
|
-
<Fragment key={index}>
|
|
38
|
-
{segment}
|
|
39
|
-
{(segment === '\\' || segment === '/') && <wbr />}
|
|
40
|
-
</Fragment>
|
|
41
|
-
));
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export function WorkspacePicker({
|
|
45
|
-
activeWorkspaceId,
|
|
46
|
-
onSelect,
|
|
47
|
-
onOpenFolder,
|
|
48
|
-
onCloneRepository,
|
|
49
|
-
className,
|
|
50
|
-
}: WorkspacePickerProps) {
|
|
51
|
-
const [workspaces, setWorkspaces] = useState<WorkspaceDescriptor[]>([]);
|
|
52
|
-
const [isOpen, setIsOpen] = useState(false);
|
|
53
|
-
const pickerRef = useRef<HTMLDivElement>(null);
|
|
54
|
-
|
|
55
|
-
// Close dropdown on outside click
|
|
56
|
-
useEffect(() => {
|
|
57
|
-
if (!isOpen) return;
|
|
58
|
-
function handleOutsideClick(e: MouseEvent) {
|
|
59
|
-
if (pickerRef.current && !pickerRef.current.contains(e.target as Node)) {
|
|
60
|
-
setIsOpen(false);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
document.addEventListener('mousedown', handleOutsideClick);
|
|
64
|
-
return () => document.removeEventListener('mousedown', handleOutsideClick);
|
|
65
|
-
}, [isOpen]);
|
|
66
|
-
|
|
67
|
-
const electron = isElectronHost();
|
|
68
|
-
|
|
69
|
-
const refresh = useCallback(async () => {
|
|
70
|
-
const list = await listWorkspaces();
|
|
71
|
-
// On desktop, hide web-only workspaces (indexeddb/native).
|
|
72
|
-
const filtered = electron
|
|
73
|
-
? list.filter((w) => w.type === 'electron-native')
|
|
74
|
-
: list.filter((w) => w.type !== 'electron-native');
|
|
75
|
-
setWorkspaces(filtered);
|
|
76
|
-
}, [electron]);
|
|
77
|
-
|
|
78
|
-
useEffect(() => {
|
|
79
|
-
refresh();
|
|
80
|
-
}, [refresh, activeWorkspaceId]);
|
|
81
|
-
|
|
82
|
-
const handleSelect = useCallback(
|
|
83
|
-
async (ws: WorkspaceDescriptor) => {
|
|
84
|
-
await touchWorkspace(ws.id);
|
|
85
|
-
onSelect(ws);
|
|
86
|
-
setIsOpen(false);
|
|
87
|
-
},
|
|
88
|
-
[onSelect],
|
|
89
|
-
);
|
|
90
|
-
|
|
91
|
-
const handleCreateNew = useCallback(async () => {
|
|
92
|
-
const name = `Workspace ${workspaces.length + 1}`;
|
|
93
|
-
const id = `ws-${Date.now()}`;
|
|
94
|
-
const descriptor: WorkspaceDescriptor = {
|
|
95
|
-
id,
|
|
96
|
-
name,
|
|
97
|
-
type: 'indexeddb',
|
|
98
|
-
lastOpened: new Date().toISOString(),
|
|
99
|
-
};
|
|
100
|
-
await saveWorkspace(descriptor);
|
|
101
|
-
await refresh();
|
|
102
|
-
onSelect(descriptor);
|
|
103
|
-
setIsOpen(false);
|
|
104
|
-
}, [workspaces.length, onSelect, refresh]);
|
|
105
|
-
|
|
106
|
-
const activeWs = workspaces.find((w) => w.id === activeWorkspaceId);
|
|
107
|
-
const activeWorkspaceName = activeWs?.name ?? 'No workspace';
|
|
108
|
-
|
|
109
|
-
return (
|
|
110
|
-
<div ref={pickerRef} className={`db-workspace-picker ${className ?? ''}`}>
|
|
111
|
-
<button
|
|
112
|
-
className="db-workspace-picker-btn"
|
|
113
|
-
onClick={() => setIsOpen(!isOpen)}
|
|
114
|
-
title="Switch workspace"
|
|
115
|
-
aria-label={`Switch workspace, current: ${activeWorkspaceName}`}
|
|
116
|
-
>
|
|
117
|
-
<span className="db-workspace-picker-label">{activeWorkspaceName}</span>
|
|
118
|
-
<span className="db-workspace-picker-compact-icon">
|
|
119
|
-
<FolderIcon />
|
|
120
|
-
</span>
|
|
121
|
-
<span
|
|
122
|
-
className={`db-workspace-picker-caret${isOpen ? ' db-workspace-picker-caret--open' : ''}`}
|
|
123
|
-
aria-hidden="true"
|
|
124
|
-
/>
|
|
125
|
-
</button>
|
|
126
|
-
|
|
127
|
-
{isOpen && (
|
|
128
|
-
<div className="db-workspace-dropdown">
|
|
129
|
-
{workspaces.map((ws) => (
|
|
130
|
-
<button
|
|
131
|
-
key={ws.id}
|
|
132
|
-
className={`db-workspace-dropdown-item ${
|
|
133
|
-
ws.id === activeWorkspaceId ? 'db-workspace-dropdown-item--active' : ''
|
|
134
|
-
}`}
|
|
135
|
-
onClick={() => handleSelect(ws)}
|
|
136
|
-
>
|
|
137
|
-
<span className="db-workspace-details">
|
|
138
|
-
<span className="db-workspace-heading">
|
|
139
|
-
<span>{ws.name}</span>
|
|
140
|
-
{(ws.type === 'native' || ws.type === 'electron-native') && (
|
|
141
|
-
<span className="db-workspace-type">(folder)</span>
|
|
142
|
-
)}
|
|
143
|
-
</span>
|
|
144
|
-
{ws.rootPath && (
|
|
145
|
-
<span className="db-workspace-path" title={ws.rootPath}>
|
|
146
|
-
<WorkspacePath path={ws.rootPath} />
|
|
147
|
-
</span>
|
|
148
|
-
)}
|
|
149
|
-
</span>
|
|
150
|
-
</button>
|
|
151
|
-
))}
|
|
152
|
-
|
|
153
|
-
<div className="db-workspace-dropdown-divider" />
|
|
154
|
-
|
|
155
|
-
{!electron && (
|
|
156
|
-
<button className="db-workspace-dropdown-item" onClick={handleCreateNew}>
|
|
157
|
-
<span className="db-workspace-dropdown-action-label">
|
|
158
|
-
<NewFolderIcon />
|
|
159
|
-
<span>New Workspace</span>
|
|
160
|
-
</span>
|
|
161
|
-
</button>
|
|
162
|
-
)}
|
|
163
|
-
|
|
164
|
-
{(electron || isNativeFileSystemSupported()) && (
|
|
165
|
-
<button
|
|
166
|
-
className="db-workspace-dropdown-item"
|
|
167
|
-
onClick={() => {
|
|
168
|
-
setIsOpen(false);
|
|
169
|
-
onOpenFolder();
|
|
170
|
-
}}
|
|
171
|
-
>
|
|
172
|
-
Open Folder...
|
|
173
|
-
</button>
|
|
174
|
-
)}
|
|
175
|
-
|
|
176
|
-
{onCloneRepository && (
|
|
177
|
-
<button
|
|
178
|
-
className="db-workspace-dropdown-item"
|
|
179
|
-
onClick={() => {
|
|
180
|
-
setIsOpen(false);
|
|
181
|
-
onCloneRepository();
|
|
182
|
-
}}
|
|
183
|
-
>
|
|
184
|
-
Clone Git Repository...
|
|
185
|
-
</button>
|
|
186
|
-
)}
|
|
187
|
-
</div>
|
|
188
|
-
)}
|
|
189
|
-
</div>
|
|
190
|
-
);
|
|
191
|
-
}
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* WorkspaceSettingsButton — gear icon dropdown for workspace actions.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { useState, useCallback, useRef, useEffect } from 'react';
|
|
6
|
-
import { WorkspaceIcon } from '../icons.js';
|
|
7
|
-
|
|
8
|
-
export interface WorkspaceSettingsButtonProps {
|
|
9
|
-
onSettings: () => void;
|
|
10
|
-
onRename: () => void;
|
|
11
|
-
onDownload: () => void;
|
|
12
|
-
onRemove: () => void;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export function WorkspaceSettingsButton({
|
|
16
|
-
onSettings,
|
|
17
|
-
onRename,
|
|
18
|
-
onDownload,
|
|
19
|
-
onRemove,
|
|
20
|
-
}: WorkspaceSettingsButtonProps) {
|
|
21
|
-
const [isOpen, setIsOpen] = useState(false);
|
|
22
|
-
const ref = useRef<HTMLDivElement>(null);
|
|
23
|
-
|
|
24
|
-
useEffect(() => {
|
|
25
|
-
if (!isOpen) return;
|
|
26
|
-
function handleOutsideClick(e: MouseEvent) {
|
|
27
|
-
if (ref.current && !ref.current.contains(e.target as Node)) {
|
|
28
|
-
setIsOpen(false);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
document.addEventListener('mousedown', handleOutsideClick);
|
|
32
|
-
return () => document.removeEventListener('mousedown', handleOutsideClick);
|
|
33
|
-
}, [isOpen]);
|
|
34
|
-
|
|
35
|
-
const handleAction = useCallback((action: () => void) => {
|
|
36
|
-
setIsOpen(false);
|
|
37
|
-
action();
|
|
38
|
-
}, []);
|
|
39
|
-
|
|
40
|
-
return (
|
|
41
|
-
<div ref={ref} className="db-ws-settings">
|
|
42
|
-
<button
|
|
43
|
-
className="db-ws-settings-btn"
|
|
44
|
-
onClick={() => setIsOpen(!isOpen)}
|
|
45
|
-
aria-expanded={isOpen}
|
|
46
|
-
aria-haspopup="true"
|
|
47
|
-
aria-label="Workspace settings"
|
|
48
|
-
title="Workspace settings"
|
|
49
|
-
>
|
|
50
|
-
<WorkspaceIcon />
|
|
51
|
-
</button>
|
|
52
|
-
|
|
53
|
-
{isOpen && (
|
|
54
|
-
<div className="db-ws-settings-dropdown" role="menu">
|
|
55
|
-
<button
|
|
56
|
-
className="db-ws-settings-item"
|
|
57
|
-
role="menuitem"
|
|
58
|
-
onClick={() => handleAction(onSettings)}
|
|
59
|
-
>
|
|
60
|
-
Workspace settings…
|
|
61
|
-
</button>
|
|
62
|
-
<button
|
|
63
|
-
className="db-ws-settings-item"
|
|
64
|
-
role="menuitem"
|
|
65
|
-
onClick={() => handleAction(onRename)}
|
|
66
|
-
>
|
|
67
|
-
Rename workspace
|
|
68
|
-
</button>
|
|
69
|
-
<button
|
|
70
|
-
className="db-ws-settings-item"
|
|
71
|
-
role="menuitem"
|
|
72
|
-
onClick={() => handleAction(onDownload)}
|
|
73
|
-
>
|
|
74
|
-
Download workspace
|
|
75
|
-
</button>
|
|
76
|
-
<div className="db-ws-settings-divider" />
|
|
77
|
-
<button
|
|
78
|
-
className="db-ws-settings-item db-ws-settings-item--danger"
|
|
79
|
-
role="menuitem"
|
|
80
|
-
onClick={() => handleAction(onRemove)}
|
|
81
|
-
>
|
|
82
|
-
Remove workspace
|
|
83
|
-
</button>
|
|
84
|
-
</div>
|
|
85
|
-
)}
|
|
86
|
-
</div>
|
|
87
|
-
);
|
|
88
|
-
}
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* WorkspaceSettingsDialog — per-workspace settings modal.
|
|
3
|
-
*
|
|
4
|
-
* Lets the user override the global versioning preference for a single
|
|
5
|
-
* workspace (or fall back to inheriting it). The override is stored on
|
|
6
|
-
* the WorkspaceDescriptor and persisted via `saveWorkspace`.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { useCallback, useEffect } from 'react';
|
|
10
|
-
import type { WorkspaceDescriptor } from '@bendyline/docblocks/workspace';
|
|
11
|
-
import {
|
|
12
|
-
isLocalWorkspaceType,
|
|
13
|
-
resolveVersioningEnabled,
|
|
14
|
-
type VersioningPreference,
|
|
15
|
-
} from '../preferences/versioning.js';
|
|
16
|
-
|
|
17
|
-
export type WorkspaceVersioningOverride = NonNullable<WorkspaceDescriptor['versioningOverride']>;
|
|
18
|
-
|
|
19
|
-
export interface WorkspaceSettingsDialogProps {
|
|
20
|
-
workspace: WorkspaceDescriptor;
|
|
21
|
-
/** Current global versioning preference — used to label "Inherit". */
|
|
22
|
-
globalVersioningPreference: VersioningPreference;
|
|
23
|
-
/** Apply a new override and close the dialog. */
|
|
24
|
-
onChange: (override: WorkspaceVersioningOverride) => void;
|
|
25
|
-
onClose: () => void;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const VERSIONING_LABELS: Record<VersioningPreference, string> = {
|
|
29
|
-
on: 'on',
|
|
30
|
-
'browser-only': 'on for browser workspaces, off for local folders',
|
|
31
|
-
off: 'off',
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
export function WorkspaceSettingsDialog({
|
|
35
|
-
workspace,
|
|
36
|
-
globalVersioningPreference,
|
|
37
|
-
onChange,
|
|
38
|
-
onClose,
|
|
39
|
-
}: WorkspaceSettingsDialogProps) {
|
|
40
|
-
// Treat absent/undefined as 'inherit' for the radio state.
|
|
41
|
-
const current: WorkspaceVersioningOverride = workspace.versioningOverride ?? 'inherit';
|
|
42
|
-
|
|
43
|
-
useEffect(() => {
|
|
44
|
-
const onKey = (e: KeyboardEvent) => {
|
|
45
|
-
if (e.key === 'Escape') onClose();
|
|
46
|
-
};
|
|
47
|
-
window.addEventListener('keydown', onKey);
|
|
48
|
-
return () => window.removeEventListener('keydown', onKey);
|
|
49
|
-
}, [onClose]);
|
|
50
|
-
|
|
51
|
-
const handleBackdropClick = useCallback(
|
|
52
|
-
(e: React.MouseEvent) => {
|
|
53
|
-
if (e.target === e.currentTarget) onClose();
|
|
54
|
-
},
|
|
55
|
-
[onClose],
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
const isLocal = isLocalWorkspaceType(workspace.type);
|
|
59
|
-
const inheritedEnabled = resolveVersioningEnabled(
|
|
60
|
-
{ ...workspace, versioningOverride: 'inherit' },
|
|
61
|
-
globalVersioningPreference,
|
|
62
|
-
);
|
|
63
|
-
const inheritLabel = `Inherit default — currently ${VERSIONING_LABELS[globalVersioningPreference]} (${inheritedEnabled ? 'on' : 'off'} for this workspace)`;
|
|
64
|
-
|
|
65
|
-
return (
|
|
66
|
-
<div className="db-dialog-overlay" onClick={handleBackdropClick}>
|
|
67
|
-
<div className="db-dialog" role="dialog" aria-label="Workspace settings">
|
|
68
|
-
<div className="db-dialog-header">
|
|
69
|
-
<h2 className="db-dialog-title">Workspace settings</h2>
|
|
70
|
-
<button type="button" className="db-dialog-close" onClick={onClose} aria-label="Close">
|
|
71
|
-
×
|
|
72
|
-
</button>
|
|
73
|
-
</div>
|
|
74
|
-
<div className="db-dialog-body">
|
|
75
|
-
<p className="db-settings-hint">
|
|
76
|
-
<strong>{workspace.name}</strong> ·{' '}
|
|
77
|
-
{isLocal ? 'Local folder workspace' : 'Browser workspace'}
|
|
78
|
-
</p>
|
|
79
|
-
|
|
80
|
-
<fieldset className="db-settings-fieldset">
|
|
81
|
-
<legend className="db-settings-legend">Version history</legend>
|
|
82
|
-
<p className="db-settings-hint">
|
|
83
|
-
Controls whether DocBlocks keeps prior revisions in{' '}
|
|
84
|
-
<code><name>_files/.versions/</code> for documents in this workspace.
|
|
85
|
-
</p>
|
|
86
|
-
<label className="db-settings-radio">
|
|
87
|
-
<input
|
|
88
|
-
type="radio"
|
|
89
|
-
name="ws-versioning"
|
|
90
|
-
value="inherit"
|
|
91
|
-
checked={current === 'inherit'}
|
|
92
|
-
onChange={() => onChange('inherit')}
|
|
93
|
-
/>
|
|
94
|
-
{inheritLabel}
|
|
95
|
-
</label>
|
|
96
|
-
<label className="db-settings-radio">
|
|
97
|
-
<input
|
|
98
|
-
type="radio"
|
|
99
|
-
name="ws-versioning"
|
|
100
|
-
value="on"
|
|
101
|
-
checked={current === 'on'}
|
|
102
|
-
onChange={() => onChange('on')}
|
|
103
|
-
/>
|
|
104
|
-
On for this workspace
|
|
105
|
-
</label>
|
|
106
|
-
<label className="db-settings-radio">
|
|
107
|
-
<input
|
|
108
|
-
type="radio"
|
|
109
|
-
name="ws-versioning"
|
|
110
|
-
value="off"
|
|
111
|
-
checked={current === 'off'}
|
|
112
|
-
onChange={() => onChange('off')}
|
|
113
|
-
/>
|
|
114
|
-
Off for this workspace
|
|
115
|
-
</label>
|
|
116
|
-
</fieldset>
|
|
117
|
-
</div>
|
|
118
|
-
</div>
|
|
119
|
-
</div>
|
|
120
|
-
);
|
|
121
|
-
}
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Dialog — shared modal primitive.
|
|
3
|
-
*
|
|
4
|
-
* Promotes the `db-dialog-overlay` / `db-dialog` pattern used by the
|
|
5
|
-
* settings dialogs into a reusable component, adding aria-modal and
|
|
6
|
-
* initial focus. Escape and (by default) backdrop clicks close it.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { useCallback, useEffect, useRef } from 'react';
|
|
10
|
-
|
|
11
|
-
export interface DialogProps {
|
|
12
|
-
title: string;
|
|
13
|
-
onClose: () => void;
|
|
14
|
-
/** default 380px / wide 560px / full min(1100px, 94vw) column. */
|
|
15
|
-
size?: 'default' | 'wide' | 'full';
|
|
16
|
-
children: React.ReactNode;
|
|
17
|
-
/** Right-aligned action row below the body. */
|
|
18
|
-
footer?: React.ReactNode;
|
|
19
|
-
/** Element to focus on open; defaults to the close button. */
|
|
20
|
-
initialFocusRef?: React.RefObject<HTMLElement | null>;
|
|
21
|
-
/** Set false when a stray backdrop click would lose user input. */
|
|
22
|
-
closeOnBackdrop?: boolean;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export function Dialog({
|
|
26
|
-
title,
|
|
27
|
-
onClose,
|
|
28
|
-
size = 'default',
|
|
29
|
-
children,
|
|
30
|
-
footer,
|
|
31
|
-
initialFocusRef,
|
|
32
|
-
closeOnBackdrop = true,
|
|
33
|
-
}: DialogProps) {
|
|
34
|
-
const closeButtonRef = useRef<HTMLButtonElement>(null);
|
|
35
|
-
|
|
36
|
-
useEffect(() => {
|
|
37
|
-
const onKey = (e: KeyboardEvent) => {
|
|
38
|
-
if (e.key === 'Escape') onClose();
|
|
39
|
-
};
|
|
40
|
-
window.addEventListener('keydown', onKey);
|
|
41
|
-
return () => window.removeEventListener('keydown', onKey);
|
|
42
|
-
}, [onClose]);
|
|
43
|
-
|
|
44
|
-
useEffect(() => {
|
|
45
|
-
const target = initialFocusRef?.current ?? closeButtonRef.current;
|
|
46
|
-
target?.focus();
|
|
47
|
-
// Focus only on mount — refocusing on every re-render would fight the user.
|
|
48
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
49
|
-
}, []);
|
|
50
|
-
|
|
51
|
-
const handleBackdropClick = useCallback(
|
|
52
|
-
(e: React.MouseEvent) => {
|
|
53
|
-
if (closeOnBackdrop && e.target === e.currentTarget) onClose();
|
|
54
|
-
},
|
|
55
|
-
[closeOnBackdrop, onClose],
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
const sizeClass =
|
|
59
|
-
size === 'wide' ? ' db-dialog--wide' : size === 'full' ? ' db-dialog--full' : '';
|
|
60
|
-
|
|
61
|
-
return (
|
|
62
|
-
<div className="db-dialog-overlay" onClick={handleBackdropClick}>
|
|
63
|
-
<div className={`db-dialog${sizeClass}`} role="dialog" aria-modal="true" aria-label={title}>
|
|
64
|
-
<div className="db-dialog-header">
|
|
65
|
-
<h2 className="db-dialog-title">{title}</h2>
|
|
66
|
-
<button
|
|
67
|
-
ref={closeButtonRef}
|
|
68
|
-
type="button"
|
|
69
|
-
className="db-dialog-close"
|
|
70
|
-
onClick={onClose}
|
|
71
|
-
aria-label="Close"
|
|
72
|
-
>
|
|
73
|
-
×
|
|
74
|
-
</button>
|
|
75
|
-
</div>
|
|
76
|
-
<div className="db-dialog-body">{children}</div>
|
|
77
|
-
{footer && <div className="db-dialog-footer">{footer}</div>}
|
|
78
|
-
</div>
|
|
79
|
-
</div>
|
|
80
|
-
);
|
|
81
|
-
}
|