@glw907/cairn-cms 0.60.0 → 0.62.1
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/CHANGELOG.md +82 -0
- package/dist/components/AdminLayout.svelte +152 -229
- package/dist/components/CairnAdmin.svelte +13 -42
- package/dist/components/CairnLogo.svelte +1 -6
- package/dist/components/CairnMediaLibrary.svelte +821 -1210
- package/dist/components/CairnTidySettings.svelte +194 -261
- package/dist/components/CairnTidySettings.svelte.d.ts +1 -1
- package/dist/components/ComponentForm.svelte +110 -185
- package/dist/components/ComponentInsertDialog.svelte +163 -283
- package/dist/components/ConceptList.svelte +111 -191
- package/dist/components/ConfirmPage.svelte +5 -12
- package/dist/components/CsrfField.svelte +5 -11
- package/dist/components/DeleteDialog.svelte +15 -42
- package/dist/components/EditPage.svelte +781 -1205
- package/dist/components/EditorToolbar.svelte +108 -170
- package/dist/components/HelpHome.svelte +824 -0
- package/dist/components/HelpHome.svelte.d.ts +22 -0
- package/dist/components/IconPicker.svelte +23 -53
- package/dist/components/LinkPicker.svelte +34 -58
- package/dist/components/LoginPage.svelte +14 -27
- package/dist/components/ManageEditors.svelte +3 -15
- package/dist/components/MarkdownEditor.svelte +689 -957
- package/dist/components/MarkdownHelpDialog.svelte +12 -27
- package/dist/components/MediaCaptureCard.svelte +18 -57
- package/dist/components/MediaFigureControl.svelte +32 -71
- package/dist/components/MediaHeroField.svelte +210 -329
- package/dist/components/MediaInsertPopover.svelte +156 -283
- package/dist/components/MediaPicker.svelte +67 -131
- package/dist/components/NavTree.svelte +46 -78
- package/dist/components/RenameDialog.svelte +16 -43
- package/dist/components/ShortcutsDialog.svelte +9 -13
- package/dist/components/ShortcutsGrid.svelte +1 -2
- package/dist/components/TidyReview.svelte +140 -248
- package/dist/components/WebLinkDialog.svelte +19 -40
- package/dist/components/cairn-admin.css +4 -0
- package/dist/components/client-ingest.d.ts +16 -8
- package/dist/components/client-ingest.js +12 -6
- package/dist/components/editor-media.js +16 -8
- package/dist/components/editor-placeholder.d.ts +4 -2
- package/dist/components/editor-tidy.d.ts +24 -12
- package/dist/components/editor-tidy.js +8 -4
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.js +1 -0
- package/dist/components/link-completion.d.ts +12 -6
- package/dist/components/link-completion.js +12 -6
- package/dist/components/markdown-directives.d.ts +9 -6
- package/dist/components/markdown-directives.js +9 -6
- package/dist/components/markdown-format.d.ts +7 -2
- package/dist/components/markdown-format.js +59 -28
- package/dist/components/markdown-reference.d.ts +8 -0
- package/dist/components/markdown-reference.js +22 -0
- package/dist/components/media-upload-outcome.d.ts +12 -6
- package/dist/components/objective-errors.d.ts +8 -4
- package/dist/components/objective-errors.js +8 -4
- package/dist/components/preview-doc.d.ts +4 -2
- package/dist/components/preview-doc.js +4 -2
- package/dist/components/spellcheck.d.ts +57 -29
- package/dist/components/spellcheck.js +50 -20
- package/dist/components/tidy-categorize.d.ts +20 -10
- package/dist/components/tidy-categorize.js +16 -8
- package/dist/components/tidy-validate.d.ts +12 -6
- package/dist/components/tidy-validate.js +20 -10
- package/dist/components/topbar-context.d.ts +4 -2
- package/dist/content/advisories.d.ts +51 -0
- package/dist/content/advisories.js +79 -0
- package/dist/content/compose.d.ts +4 -2
- package/dist/content/compose.js +1 -0
- package/dist/content/excerpt.js +4 -2
- package/dist/content/getting-started.d.ts +18 -0
- package/dist/content/getting-started.js +12 -0
- package/dist/content/links.d.ts +16 -8
- package/dist/content/links.js +12 -6
- package/dist/content/manifest.d.ts +36 -18
- package/dist/content/manifest.js +32 -16
- package/dist/content/media-refs.d.ts +4 -2
- package/dist/content/media-refs.js +4 -2
- package/dist/content/media-rewrite.d.ts +8 -4
- package/dist/content/media-rewrite.js +76 -38
- package/dist/content/schema.d.ts +20 -10
- package/dist/content/site-dictionary.d.ts +4 -2
- package/dist/content/site-dictionary.js +8 -4
- package/dist/content/types.d.ts +97 -42
- package/dist/delivery/CairnHead.svelte +8 -11
- package/dist/delivery/content-index.d.ts +16 -8
- package/dist/delivery/feeds.js +4 -2
- package/dist/delivery/json-ld.d.ts +3 -0
- package/dist/delivery/json-ld.js +3 -0
- package/dist/delivery/manifest.d.ts +4 -2
- package/dist/delivery/manifest.js +4 -2
- package/dist/delivery/public-routes.d.ts +12 -6
- package/dist/delivery/public-routes.js +4 -2
- package/dist/delivery/seo-fields.d.ts +12 -6
- package/dist/delivery/seo-fields.js +8 -4
- package/dist/delivery/site-indexes.d.ts +4 -2
- package/dist/delivery/site-resolver.d.ts +4 -2
- package/dist/delivery/site-resolver.js +4 -2
- package/dist/doctor/cloudflare-api.d.ts +6 -0
- package/dist/doctor/cloudflare-api.js +6 -0
- package/dist/doctor/index.d.ts +12 -6
- package/dist/doctor/report.d.ts +3 -0
- package/dist/doctor/report.js +3 -0
- package/dist/doctor/run.d.ts +3 -0
- package/dist/doctor/run.js +3 -0
- package/dist/doctor/types.d.ts +10 -2
- package/dist/doctor/types.js +6 -0
- package/dist/doctor/wrangler-config.d.ts +7 -2
- package/dist/doctor/wrangler-config.js +3 -0
- package/dist/email.d.ts +4 -2
- package/dist/env.d.ts +0 -3
- package/dist/env.js +0 -3
- package/dist/github/branches.d.ts +4 -2
- package/dist/github/branches.js +4 -2
- package/dist/github/signing.d.ts +1 -1
- package/dist/github/signing.js +2 -2
- package/dist/log/events.d.ts +1 -1
- package/dist/media/bulk-delete-plan.d.ts +8 -4
- package/dist/media/config.d.ts +12 -6
- package/dist/media/config.js +16 -8
- package/dist/media/delivery-bucket.d.ts +4 -2
- package/dist/media/library-entry.d.ts +4 -2
- package/dist/media/library-entry.js +4 -2
- package/dist/media/manifest.d.ts +29 -15
- package/dist/media/manifest.js +29 -16
- package/dist/media/naming.d.ts +12 -6
- package/dist/media/naming.js +24 -12
- package/dist/media/orphan-scan.d.ts +4 -2
- package/dist/media/reconcile.d.ts +21 -11
- package/dist/media/reconcile.js +12 -6
- package/dist/media/reference.d.ts +8 -4
- package/dist/media/reference.js +12 -6
- package/dist/media/rewrite-plan.d.ts +12 -6
- package/dist/media/sniff.d.ts +4 -2
- package/dist/media/sniff.js +28 -14
- package/dist/media/store.d.ts +16 -8
- package/dist/media/store.js +4 -2
- package/dist/media/transform-url.d.ts +12 -6
- package/dist/media/transform-url.js +8 -4
- package/dist/media/usage.d.ts +8 -4
- package/dist/nav/site-config.d.ts +16 -8
- package/dist/render/component-grammar.d.ts +23 -10
- package/dist/render/component-grammar.js +19 -8
- package/dist/render/component-insert.d.ts +8 -4
- package/dist/render/component-insert.js +4 -2
- package/dist/render/component-reference.d.ts +4 -2
- package/dist/render/component-reference.js +4 -2
- package/dist/render/component-validate.d.ts +3 -0
- package/dist/render/component-validate.js +3 -0
- package/dist/render/glyph.d.ts +4 -2
- package/dist/render/glyph.js +4 -2
- package/dist/render/pipeline.d.ts +20 -10
- package/dist/render/pipeline.js +4 -2
- package/dist/render/registry.d.ts +40 -20
- package/dist/render/registry.js +16 -8
- package/dist/render/rehype-dispatch.d.ts +22 -8
- package/dist/render/rehype-dispatch.js +22 -8
- package/dist/render/remark-directives.d.ts +3 -0
- package/dist/render/remark-directives.js +3 -0
- package/dist/render/remark-figure.d.ts +4 -2
- package/dist/render/remark-figure.js +4 -2
- package/dist/render/resolve-links.d.ts +4 -2
- package/dist/render/resolve-links.js +4 -2
- package/dist/render/resolve-media.d.ts +16 -8
- package/dist/render/resolve-media.js +12 -6
- package/dist/sveltekit/admin-dispatch.d.ts +2 -0
- package/dist/sveltekit/admin-dispatch.js +9 -3
- package/dist/sveltekit/auth-routes.d.ts +3 -0
- package/dist/sveltekit/auth-routes.js +3 -0
- package/dist/sveltekit/cairn-admin.d.ts +16 -5
- package/dist/sveltekit/cairn-admin.js +26 -10
- package/dist/sveltekit/content-routes.d.ts +191 -86
- package/dist/sveltekit/content-routes.js +295 -107
- package/dist/sveltekit/editors-routes.d.ts +3 -0
- package/dist/sveltekit/editors-routes.js +3 -0
- package/dist/sveltekit/guard.d.ts +4 -2
- package/dist/sveltekit/guard.js +4 -2
- package/dist/sveltekit/https-required-page.d.ts +1 -1
- package/dist/sveltekit/https-required-page.js +1 -1
- package/dist/sveltekit/index.d.ts +1 -1
- package/dist/sveltekit/media-route.d.ts +1 -2
- package/dist/sveltekit/media-route.js +13 -8
- package/dist/sveltekit/nav-routes.d.ts +7 -2
- package/dist/sveltekit/nav-routes.js +3 -0
- package/dist/sveltekit/types.d.ts +4 -2
- package/dist/vite/index.d.ts +32 -16
- package/dist/vite/index.js +52 -26
- package/dist/vite/resolve-root.d.ts +8 -4
- package/dist/vite/resolve-root.js +4 -2
- package/package.json +8 -2
- package/src/lib/components/AdminLayout.svelte +22 -0
- package/src/lib/components/CairnAdmin.svelte +3 -0
- package/src/lib/components/CairnTidySettings.svelte +2 -2
- package/src/lib/components/ComponentForm.svelte +0 -1
- package/src/lib/components/EditPage.svelte +133 -41
- package/src/lib/components/HelpHome.svelte +850 -0
- package/src/lib/components/MarkdownHelpDialog.svelte +4 -15
- package/src/lib/components/client-ingest.ts +20 -10
- package/src/lib/components/editor-media.ts +20 -10
- package/src/lib/components/editor-placeholder.ts +12 -6
- package/src/lib/components/editor-tidy.ts +28 -14
- package/src/lib/components/index.ts +1 -0
- package/src/lib/components/link-completion.ts +12 -6
- package/src/lib/components/markdown-directives.ts +13 -8
- package/src/lib/components/markdown-format.ts +63 -30
- package/src/lib/components/markdown-reference.ts +30 -0
- package/src/lib/components/media-upload-outcome.ts +12 -6
- package/src/lib/components/objective-errors.ts +16 -8
- package/src/lib/components/preview-doc.ts +4 -2
- package/src/lib/components/spellcheck.ts +92 -40
- package/src/lib/components/tidy-categorize.ts +28 -14
- package/src/lib/components/tidy-validate.ts +28 -14
- package/src/lib/components/topbar-context.ts +4 -2
- package/src/lib/content/advisories.ts +141 -0
- package/src/lib/content/compose.ts +5 -2
- package/src/lib/content/excerpt.ts +4 -2
- package/src/lib/content/getting-started.ts +31 -0
- package/src/lib/content/links.ts +16 -8
- package/src/lib/content/manifest.ts +36 -18
- package/src/lib/content/media-refs.ts +4 -2
- package/src/lib/content/media-rewrite.ts +100 -50
- package/src/lib/content/schema.ts +20 -10
- package/src/lib/content/site-dictionary.ts +8 -4
- package/src/lib/content/types.ts +97 -42
- package/src/lib/delivery/content-index.ts +16 -8
- package/src/lib/delivery/feeds.ts +4 -2
- package/src/lib/delivery/json-ld.ts +3 -0
- package/src/lib/delivery/manifest.ts +4 -2
- package/src/lib/delivery/public-routes.ts +16 -8
- package/src/lib/delivery/seo-fields.ts +12 -6
- package/src/lib/delivery/site-indexes.ts +4 -2
- package/src/lib/delivery/site-resolver.ts +4 -2
- package/src/lib/doctor/cloudflare-api.ts +6 -0
- package/src/lib/doctor/index.ts +12 -6
- package/src/lib/doctor/report.ts +3 -0
- package/src/lib/doctor/run.ts +3 -0
- package/src/lib/doctor/types.ts +10 -2
- package/src/lib/doctor/wrangler-config.ts +7 -2
- package/src/lib/email.ts +4 -2
- package/src/lib/env.ts +0 -3
- package/src/lib/github/branches.ts +4 -2
- package/src/lib/github/signing.ts +2 -2
- package/src/lib/log/events.ts +1 -0
- package/src/lib/media/bulk-delete-plan.ts +8 -4
- package/src/lib/media/config.ts +24 -12
- package/src/lib/media/delivery-bucket.ts +4 -2
- package/src/lib/media/library-entry.ts +4 -2
- package/src/lib/media/manifest.ts +33 -18
- package/src/lib/media/naming.ts +24 -12
- package/src/lib/media/orphan-scan.ts +4 -2
- package/src/lib/media/reconcile.ts +21 -11
- package/src/lib/media/reference.ts +12 -6
- package/src/lib/media/rewrite-plan.ts +12 -6
- package/src/lib/media/sniff.ts +28 -14
- package/src/lib/media/store.ts +16 -8
- package/src/lib/media/transform-url.ts +12 -6
- package/src/lib/media/usage.ts +8 -4
- package/src/lib/nav/site-config.ts +16 -8
- package/src/lib/render/component-grammar.ts +23 -10
- package/src/lib/render/component-insert.ts +8 -4
- package/src/lib/render/component-reference.ts +4 -2
- package/src/lib/render/component-validate.ts +3 -0
- package/src/lib/render/glyph.ts +4 -2
- package/src/lib/render/pipeline.ts +20 -10
- package/src/lib/render/registry.ts +44 -22
- package/src/lib/render/rehype-dispatch.ts +22 -8
- package/src/lib/render/remark-directives.ts +3 -0
- package/src/lib/render/remark-figure.ts +4 -2
- package/src/lib/render/resolve-links.ts +4 -2
- package/src/lib/render/resolve-media.ts +16 -8
- package/src/lib/sveltekit/admin-dispatch.ts +10 -4
- package/src/lib/sveltekit/auth-routes.ts +3 -0
- package/src/lib/sveltekit/cairn-admin.ts +37 -15
- package/src/lib/sveltekit/content-routes.ts +492 -197
- package/src/lib/sveltekit/editors-routes.ts +3 -0
- package/src/lib/sveltekit/guard.ts +4 -2
- package/src/lib/sveltekit/https-required-page.ts +1 -1
- package/src/lib/sveltekit/index.ts +3 -0
- package/src/lib/sveltekit/media-route.ts +13 -8
- package/src/lib/sveltekit/nav-routes.ts +7 -2
- package/src/lib/sveltekit/types.ts +4 -2
- package/src/lib/vite/index.ts +60 -30
- package/src/lib/vite/resolve-root.ts +8 -4
|
@@ -9,177 +9,115 @@ widths, reported to the host through `onDevice`. The writing-mode toggles live i
|
|
|
9
9
|
footer (the bottom strip carries the writing environment; this strip acts on the text). The glyphs
|
|
10
10
|
are stroke SVG icons in the admin's house style (24x24 viewBox, `currentColor`, round caps).
|
|
11
11
|
-->
|
|
12
|
-
<script lang="ts">
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
],
|
|
69
|
-
},
|
|
70
|
-
{ kind: 'ul', label: 'Bulleted list (Ctrl+Shift+8)', paths: ['M8 6h13', 'M8 12h13', 'M8 18h13', 'M3 6h.01', 'M3 12h.01', 'M3 18h.01'] },
|
|
71
|
-
{
|
|
72
|
-
kind: 'ol',
|
|
73
|
-
label: 'Numbered list (Ctrl+Shift+7)',
|
|
74
|
-
paths: ['M10 12h11', 'M10 18h11', 'M10 6h11', 'M4 10h2', 'M4 6h1v4', 'M6 18H4c0-1 2-2 2-3s-1-1.5-2-1'],
|
|
75
|
-
},
|
|
76
|
-
{
|
|
77
|
-
kind: 'quote',
|
|
78
|
-
label: 'Quote (Ctrl+Shift+9)',
|
|
79
|
-
paths: [
|
|
80
|
-
'M16 3a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2 1 1 0 0 1 1 1v1a2 2 0 0 1-2 2 1 1 0 0 0-1 1 1 1 0 0 0 1 1 4 4 0 0 0 4-4V5a2 2 0 0 0-2-2z',
|
|
81
|
-
'M5 3a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2 1 1 0 0 1 1 1v1a2 2 0 0 1-2 2 1 1 0 0 0-1 1 1 1 0 0 0 1 1 4 4 0 0 0 4-4V5a2 2 0 0 0-2-2z',
|
|
82
|
-
],
|
|
83
|
-
},
|
|
84
|
-
// The everyday formats promoted out of the More menu onto the strip (after Quote, before
|
|
85
|
-
// More), per mockup screen 1. They keep the strip's glyph grammar.
|
|
86
|
-
{ kind: 'code', label: 'Inline code (Ctrl+E)', paths: ['m9 8-4 4 4 4', 'm15 8 4 4-4 4'] },
|
|
87
|
-
{
|
|
88
|
-
kind: 'strike',
|
|
89
|
-
label: 'Strikethrough',
|
|
90
|
-
paths: ['M14 12a4 4 0 0 1 0 8H8', 'M16 4H9.5a3.5 3.5 0 0 0-1.4 6.7', 'M4 12h16'],
|
|
91
|
-
},
|
|
92
|
-
{
|
|
93
|
-
kind: 'table',
|
|
94
|
-
label: 'Table',
|
|
95
|
-
paths: ['M3 5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z', 'M3 10h18', 'M10 3v18'],
|
|
96
|
-
},
|
|
97
|
-
];
|
|
98
|
-
|
|
99
|
-
const ellipsisPaths = ['M5 12h.01', 'M12 12h.01', 'M19 12h.01'];
|
|
100
|
-
// The check glyph marking an active pick, shared by the More menu's toggles and the device list.
|
|
101
|
-
const checkPaths = ['M20 6 9 17l-5-5'];
|
|
102
|
-
|
|
103
|
-
// The trimmed overflow: the block formats that stay rare. A divider splits the code block from
|
|
104
|
-
// the rest (the spec keeps "code block and the rest" behind the ellipsis once inline code,
|
|
105
|
-
// strikethrough, and table promote into the strip).
|
|
106
|
-
const moreItems: { kind: FormatKind; label: string; divideBefore?: boolean }[] = [
|
|
107
|
-
{ kind: 'codeblock', label: 'Code block' },
|
|
108
|
-
{ kind: 'hr', label: 'Horizontal rule', divideBefore: true },
|
|
109
|
-
{ kind: 'task', label: 'Task list' },
|
|
110
|
-
];
|
|
111
|
-
|
|
112
|
-
// The More menu's popover element and its open state, mirrored from the toggle event into
|
|
113
|
-
// aria-expanded on the trigger.
|
|
114
|
-
let moreMenu = $state<HTMLUListElement | null>(null);
|
|
115
|
-
let moreOpen = $state(false);
|
|
116
|
-
|
|
117
|
-
// Picking dismisses the menu; hiding returns focus to the trigger, keeping the roving order.
|
|
118
|
-
function hideMenu(menu: HTMLUListElement | null) {
|
|
119
|
-
if (menu?.matches(':popover-open')) menu.hidePopover();
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
function pickMore(kind: FormatKind) {
|
|
123
|
-
format(kind);
|
|
124
|
-
hideMenu(moreMenu);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// The device menu's popover element and its open state, mirrored from the toggle event into
|
|
128
|
-
// aria-expanded on the trigger (the More menu's pattern).
|
|
129
|
-
let deviceMenu = $state<HTMLUListElement | null>(null);
|
|
130
|
-
let deviceOpen = $state(false);
|
|
131
|
-
const activeDevice = $derived(previewDevice(device));
|
|
132
|
-
// Whether the device trigger renders as the capsule's third segment.
|
|
133
|
-
const showDeviceTrigger = $derived(mode === 'preview' && !!onDevice);
|
|
134
|
-
|
|
135
|
-
function pickDevice(id: PreviewDeviceId) {
|
|
136
|
-
onDevice?.(id);
|
|
137
|
-
hideMenu(deviceMenu);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
let toolbarEl = $state<HTMLDivElement | null>(null);
|
|
141
|
-
// The roving tab stop's position among the strip's enabled top-level controls. The Write/Preview
|
|
142
|
-
// tabs join the toolbar's roving order instead of managing their own arrow keys: the ARIA toolbar
|
|
143
|
-
// pattern allows either, and one arrow model over the whole strip is the simpler of the two.
|
|
144
|
-
let roving = $state(0);
|
|
145
|
-
|
|
146
|
-
/** The strip's top-level controls in DOM order: every enabled button outside the More menu's
|
|
147
|
-
* popover and outside the insert controls' dialogs. The host's insertControls render their own
|
|
148
|
-
* buttons, so the set is queried, not declared. */
|
|
149
|
-
function rovingControls(): HTMLElement[] {
|
|
150
|
-
if (!toolbarEl) return [];
|
|
151
|
-
return Array.from(toolbarEl.querySelectorAll<HTMLElement>('button')).filter(
|
|
152
|
-
(el) => !el.hasAttribute('disabled') && !el.closest('[popover]') && !el.closest('dialog'),
|
|
153
|
-
);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// Keep exactly one tab stop. Runs on mount (the snippet's buttons render synchronously, so the
|
|
157
|
-
// first pass sees them) and again whenever the stop moves or a mode switch changes which
|
|
158
|
-
// controls are enabled.
|
|
159
|
-
$effect(() => {
|
|
160
|
-
void mode;
|
|
161
|
-
const items = rovingControls();
|
|
162
|
-
if (items.length === 0) return;
|
|
163
|
-
const stop = Math.min(roving, items.length - 1);
|
|
164
|
-
// Write the clamp back so the stored stop never drifts from the displayed one across a
|
|
165
|
-
// Preview round trip. The effect reads roving, so the guarded write re-runs it once and
|
|
166
|
-
// converges (the second pass computes the same stop and writes nothing).
|
|
167
|
-
if (stop !== roving) roving = stop;
|
|
168
|
-
for (const [i, el] of items.entries()) el.setAttribute('tabindex', i === stop ? '0' : '-1');
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
function onToolbarKeydown(e: KeyboardEvent) {
|
|
172
|
-
if (e.key !== 'ArrowLeft' && e.key !== 'ArrowRight') return;
|
|
173
|
-
// Leave the keys alone inside the open More menu; its items are not part of the roving order.
|
|
174
|
-
if ((e.target as HTMLElement | null)?.closest('[popover]')) return;
|
|
175
|
-
const items = rovingControls();
|
|
176
|
-
if (items.length === 0) return;
|
|
177
|
-
const current = items.indexOf(document.activeElement as HTMLElement);
|
|
178
|
-
const base = current >= 0 ? current : Math.min(roving, items.length - 1);
|
|
179
|
-
roving = (base + (e.key === 'ArrowRight' ? 1 : -1) + items.length) % items.length;
|
|
180
|
-
items[roving].focus();
|
|
181
|
-
e.preventDefault();
|
|
12
|
+
<script lang="ts">import { deviceLabel, previewDevice, previewDevices } from "./preview-doc.js";
|
|
13
|
+
let {
|
|
14
|
+
format,
|
|
15
|
+
mode,
|
|
16
|
+
onMode,
|
|
17
|
+
device = "desktop",
|
|
18
|
+
onDevice,
|
|
19
|
+
insertControls
|
|
20
|
+
} = $props();
|
|
21
|
+
const textButtons = [
|
|
22
|
+
{ kind: "bold", label: "Bold (Ctrl+B)", paths: ["M6 12h9a4 4 0 0 1 0 8H7a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h7a4 4 0 0 1 0 8"] },
|
|
23
|
+
{ kind: "italic", label: "Italic (Ctrl+I)", paths: ["M19 4h-9", "M14 20H5", "M15 4 9 20"] }
|
|
24
|
+
];
|
|
25
|
+
const structureButtons = [
|
|
26
|
+
{
|
|
27
|
+
kind: "h2",
|
|
28
|
+
label: "Heading (Ctrl+Alt+2)",
|
|
29
|
+
paths: ["M4 12h8", "M4 18V6", "M12 18V6", "M21 18h-4c0-4 4-3 4-6 0-1.5-2-2.5-4-1"]
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
kind: "h3",
|
|
33
|
+
label: "Smaller heading (Ctrl+Alt+3)",
|
|
34
|
+
paths: [
|
|
35
|
+
"M4 12h8",
|
|
36
|
+
"M4 18V6",
|
|
37
|
+
"M12 18V6",
|
|
38
|
+
"M17.5 10.5c1.7-1 3.5 0 3.5 1.5a2 2 0 0 1-2 2",
|
|
39
|
+
"M17 17.5c2 1.5 4 .3 4-1.5a2 2 0 0 0-2-2"
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
{ kind: "ul", label: "Bulleted list (Ctrl+Shift+8)", paths: ["M8 6h13", "M8 12h13", "M8 18h13", "M3 6h.01", "M3 12h.01", "M3 18h.01"] },
|
|
43
|
+
{
|
|
44
|
+
kind: "ol",
|
|
45
|
+
label: "Numbered list (Ctrl+Shift+7)",
|
|
46
|
+
paths: ["M10 12h11", "M10 18h11", "M10 6h11", "M4 10h2", "M4 6h1v4", "M6 18H4c0-1 2-2 2-3s-1-1.5-2-1"]
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
kind: "quote",
|
|
50
|
+
label: "Quote (Ctrl+Shift+9)",
|
|
51
|
+
paths: [
|
|
52
|
+
"M16 3a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2 1 1 0 0 1 1 1v1a2 2 0 0 1-2 2 1 1 0 0 0-1 1 1 1 0 0 0 1 1 4 4 0 0 0 4-4V5a2 2 0 0 0-2-2z",
|
|
53
|
+
"M5 3a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2 1 1 0 0 1 1 1v1a2 2 0 0 1-2 2 1 1 0 0 0-1 1 1 1 0 0 0 1 1 4 4 0 0 0 4-4V5a2 2 0 0 0-2-2z"
|
|
54
|
+
]
|
|
55
|
+
},
|
|
56
|
+
// The everyday formats promoted out of the More menu onto the strip (after Quote, before
|
|
57
|
+
// More), per mockup screen 1. They keep the strip's glyph grammar.
|
|
58
|
+
{ kind: "code", label: "Inline code (Ctrl+E)", paths: ["m9 8-4 4 4 4", "m15 8 4 4-4 4"] },
|
|
59
|
+
{
|
|
60
|
+
kind: "strike",
|
|
61
|
+
label: "Strikethrough",
|
|
62
|
+
paths: ["M14 12a4 4 0 0 1 0 8H8", "M16 4H9.5a3.5 3.5 0 0 0-1.4 6.7", "M4 12h16"]
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
kind: "table",
|
|
66
|
+
label: "Table",
|
|
67
|
+
paths: ["M3 5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z", "M3 10h18", "M10 3v18"]
|
|
182
68
|
}
|
|
69
|
+
];
|
|
70
|
+
const ellipsisPaths = ["M5 12h.01", "M12 12h.01", "M19 12h.01"];
|
|
71
|
+
const checkPaths = ["M20 6 9 17l-5-5"];
|
|
72
|
+
const moreItems = [
|
|
73
|
+
{ kind: "codeblock", label: "Code block" },
|
|
74
|
+
{ kind: "hr", label: "Horizontal rule", divideBefore: true },
|
|
75
|
+
{ kind: "task", label: "Task list" }
|
|
76
|
+
];
|
|
77
|
+
let moreMenu = $state(null);
|
|
78
|
+
let moreOpen = $state(false);
|
|
79
|
+
function hideMenu(menu) {
|
|
80
|
+
if (menu?.matches(":popover-open")) menu.hidePopover();
|
|
81
|
+
}
|
|
82
|
+
function pickMore(kind) {
|
|
83
|
+
format(kind);
|
|
84
|
+
hideMenu(moreMenu);
|
|
85
|
+
}
|
|
86
|
+
let deviceMenu = $state(null);
|
|
87
|
+
let deviceOpen = $state(false);
|
|
88
|
+
const activeDevice = $derived(previewDevice(device));
|
|
89
|
+
const showDeviceTrigger = $derived(mode === "preview" && !!onDevice);
|
|
90
|
+
function pickDevice(id) {
|
|
91
|
+
onDevice?.(id);
|
|
92
|
+
hideMenu(deviceMenu);
|
|
93
|
+
}
|
|
94
|
+
let toolbarEl = $state(null);
|
|
95
|
+
let roving = $state(0);
|
|
96
|
+
function rovingControls() {
|
|
97
|
+
if (!toolbarEl) return [];
|
|
98
|
+
return Array.from(toolbarEl.querySelectorAll("button")).filter(
|
|
99
|
+
(el) => !el.hasAttribute("disabled") && !el.closest("[popover]") && !el.closest("dialog")
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
$effect(() => {
|
|
103
|
+
void mode;
|
|
104
|
+
const items = rovingControls();
|
|
105
|
+
if (items.length === 0) return;
|
|
106
|
+
const stop = Math.min(roving, items.length - 1);
|
|
107
|
+
if (stop !== roving) roving = stop;
|
|
108
|
+
for (const [i, el] of items.entries()) el.setAttribute("tabindex", i === stop ? "0" : "-1");
|
|
109
|
+
});
|
|
110
|
+
function onToolbarKeydown(e) {
|
|
111
|
+
if (e.key !== "ArrowLeft" && e.key !== "ArrowRight") return;
|
|
112
|
+
if (e.target?.closest("[popover]")) return;
|
|
113
|
+
const items = rovingControls();
|
|
114
|
+
if (items.length === 0) return;
|
|
115
|
+
const current = items.indexOf(document.activeElement);
|
|
116
|
+
const base = current >= 0 ? current : Math.min(roving, items.length - 1);
|
|
117
|
+
roving = (base + (e.key === "ArrowRight" ? 1 : -1) + items.length) % items.length;
|
|
118
|
+
items[roving].focus();
|
|
119
|
+
e.preventDefault();
|
|
120
|
+
}
|
|
183
121
|
</script>
|
|
184
122
|
|
|
185
123
|
{#snippet strokeIcon(paths: string[])}
|