@embedpdf/svelte 0.0.0-stage → 3.0.0-next.15
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/LICENSE +192 -0
- package/README.md +312 -2
- package/dist/actions/readers.svelte.d.ts +29 -0
- package/dist/actions/readers.svelte.js +55 -0
- package/dist/actions.d.ts +13 -0
- package/dist/actions.js +13 -0
- package/dist/anchored/Anchored.svelte +24 -0
- package/dist/anchored/Anchored.svelte.d.ts +4 -0
- package/dist/anchored/PlacedAnchored.svelte +97 -0
- package/dist/anchored/PlacedAnchored.svelte.d.ts +4 -0
- package/dist/anchored/context.d.ts +31 -0
- package/dist/anchored/context.js +36 -0
- package/dist/anchored/props.d.ts +29 -0
- package/dist/anchored/props.js +1 -0
- package/dist/anchored.d.ts +12 -0
- package/dist/anchored.js +2 -0
- package/dist/annotation/AnnotationChrome.svelte +173 -0
- package/dist/annotation/AnnotationChrome.svelte.d.ts +11 -0
- package/dist/annotation/AnnotationDraftMenu.svelte +27 -0
- package/dist/annotation/AnnotationDraftMenu.svelte.d.ts +4 -0
- package/dist/annotation/AnnotationFrame.svelte +46 -0
- package/dist/annotation/AnnotationFrame.svelte.d.ts +15 -0
- package/dist/annotation/AnnotationLayer.svelte +241 -0
- package/dist/annotation/AnnotationLayer.svelte.d.ts +4 -0
- package/dist/annotation/AnnotationLook.svelte +67 -0
- package/dist/annotation/AnnotationLook.svelte.d.ts +21 -0
- package/dist/annotation/AnnotationMenu.svelte +47 -0
- package/dist/annotation/AnnotationMenu.svelte.d.ts +4 -0
- package/dist/annotation/AnnotationRotationBadge.svelte +52 -0
- package/dist/annotation/AnnotationRotationBadge.svelte.d.ts +4 -0
- package/dist/annotation/AnnotationScene.svelte +27 -0
- package/dist/annotation/AnnotationScene.svelte.d.ts +7 -0
- package/dist/annotation/FreeTextBox.svelte +55 -0
- package/dist/annotation/FreeTextBox.svelte.d.ts +9 -0
- package/dist/annotation/NativeDrawing.svelte +61 -0
- package/dist/annotation/NativeDrawing.svelte.d.ts +10 -0
- package/dist/annotation/StampGhost.svelte +79 -0
- package/dist/annotation/StampGhost.svelte.d.ts +7 -0
- package/dist/annotation/chrome-paint.svelte.d.ts +30 -0
- package/dist/annotation/chrome-paint.svelte.js +27 -0
- package/dist/annotation/props.d.ts +181 -0
- package/dist/annotation/props.js +1 -0
- package/dist/annotation/readers.svelte.d.ts +59 -0
- package/dist/annotation/readers.svelte.js +136 -0
- package/dist/annotation/state.d.ts +18 -0
- package/dist/annotation/state.js +20 -0
- package/dist/annotation/text-box.svelte.d.ts +27 -0
- package/dist/annotation/text-box.svelte.js +94 -0
- package/dist/annotation.d.ts +32 -0
- package/dist/annotation.js +31 -0
- package/dist/commands/readers.svelte.d.ts +50 -0
- package/dist/commands/readers.svelte.js +83 -0
- package/dist/commands.d.ts +9 -0
- package/dist/commands.js +9 -0
- package/dist/form/ButtonControl.svelte +38 -0
- package/dist/form/ButtonControl.svelte.d.ts +11 -0
- package/dist/form/ComboControl.svelte +52 -0
- package/dist/form/ComboControl.svelte.d.ts +11 -0
- package/dist/form/FieldPictures.svelte +145 -0
- package/dist/form/FieldPictures.svelte.d.ts +3 -0
- package/dist/form/FormFocusRing.svelte +25 -0
- package/dist/form/FormFocusRing.svelte.d.ts +8 -0
- package/dist/form/FormLayer.svelte +98 -0
- package/dist/form/FormLayer.svelte.d.ts +3 -0
- package/dist/form/ListControl.svelte +49 -0
- package/dist/form/ListControl.svelte.d.ts +11 -0
- package/dist/form/NativeListBox.svelte +57 -0
- package/dist/form/NativeListBox.svelte.d.ts +4 -0
- package/dist/form/SignatureControl.svelte +53 -0
- package/dist/form/SignatureControl.svelte.d.ts +11 -0
- package/dist/form/TextControl.svelte +107 -0
- package/dist/form/TextControl.svelte.d.ts +11 -0
- package/dist/form/ToggleControl.svelte +50 -0
- package/dist/form/ToggleControl.svelte.d.ts +11 -0
- package/dist/form/WidgetBox.svelte +82 -0
- package/dist/form/WidgetBox.svelte.d.ts +15 -0
- package/dist/form/props.d.ts +21 -0
- package/dist/form/props.js +1 -0
- package/dist/form/readers.svelte.d.ts +46 -0
- package/dist/form/readers.svelte.js +52 -0
- package/dist/form/widget.d.ts +16 -0
- package/dist/form/widget.js +20 -0
- package/dist/form.d.ts +11 -0
- package/dist/form.js +12 -0
- package/dist/history/readers.d.ts +22 -0
- package/dist/history/readers.js +21 -0
- package/dist/history.d.ts +10 -0
- package/dist/history.js +11 -0
- package/dist/i18n/readers.svelte.d.ts +32 -0
- package/dist/i18n/readers.svelte.js +30 -0
- package/dist/i18n.d.ts +8 -0
- package/dist/i18n.js +9 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.js +28 -0
- package/dist/interaction/PagePointerSource.svelte +37 -0
- package/dist/interaction/PagePointerSource.svelte.d.ts +3 -0
- package/dist/interaction/readers.svelte.d.ts +26 -0
- package/dist/interaction/readers.svelte.js +47 -0
- package/dist/interaction.d.ts +11 -0
- package/dist/interaction.js +13 -0
- package/dist/link/LinkLayer.svelte +164 -0
- package/dist/link/LinkLayer.svelte.d.ts +4 -0
- package/dist/link/props.d.ts +17 -0
- package/dist/link/props.js +1 -0
- package/dist/link/readers.svelte.d.ts +18 -0
- package/dist/link/readers.svelte.js +38 -0
- package/dist/link.d.ts +11 -0
- package/dist/link.js +11 -0
- package/dist/measurement/readers.d.ts +44 -0
- package/dist/measurement/readers.js +46 -0
- package/dist/measurement.d.ts +12 -0
- package/dist/measurement.js +13 -0
- package/dist/metadata/readers.d.ts +22 -0
- package/dist/metadata/readers.js +22 -0
- package/dist/metadata.d.ts +12 -0
- package/dist/metadata.js +13 -0
- package/dist/page-edit/readers.d.ts +7 -0
- package/dist/page-edit/readers.js +11 -0
- package/dist/page-edit.d.ts +12 -0
- package/dist/page-edit.js +13 -0
- package/dist/page-view/PageView.svelte +192 -0
- package/dist/page-view/PageView.svelte.d.ts +4 -0
- package/dist/page-view/props.d.ts +32 -0
- package/dist/page-view/props.js +1 -0
- package/dist/page-view.d.ts +8 -0
- package/dist/page-view.js +7 -0
- package/dist/redaction/readers.d.ts +37 -0
- package/dist/redaction/readers.js +38 -0
- package/dist/redaction.d.ts +12 -0
- package/dist/redaction.js +13 -0
- package/dist/render/RenderLayer.svelte +116 -0
- package/dist/render/RenderLayer.svelte.d.ts +4 -0
- package/dist/render/TileImage.svelte +65 -0
- package/dist/render/TileImage.svelte.d.ts +11 -0
- package/dist/render/TilePlane.svelte +88 -0
- package/dist/render/TilePlane.svelte.d.ts +7 -0
- package/dist/render/props.d.ts +16 -0
- package/dist/render/props.js +1 -0
- package/dist/render/readers.svelte.d.ts +9 -0
- package/dist/render/readers.svelte.js +13 -0
- package/dist/render.d.ts +10 -0
- package/dist/render.js +10 -0
- package/dist/runtime/DocumentGate.svelte +26 -0
- package/dist/runtime/DocumentGate.svelte.d.ts +4 -0
- package/dist/runtime/DocumentScope.svelte +14 -0
- package/dist/runtime/DocumentScope.svelte.d.ts +4 -0
- package/dist/runtime/KernelProvider.svelte +33 -0
- package/dist/runtime/KernelProvider.svelte.d.ts +4 -0
- package/dist/runtime/SvgShapes.svelte +30 -0
- package/dist/runtime/SvgShapes.svelte.d.ts +8 -0
- package/dist/runtime/Viewer.svelte +124 -0
- package/dist/runtime/Viewer.svelte.d.ts +4 -0
- package/dist/runtime/binding.svelte.d.ts +33 -0
- package/dist/runtime/binding.svelte.js +71 -0
- package/dist/runtime/capability-handle.d.ts +6 -0
- package/dist/runtime/capability-handle.js +71 -0
- package/dist/runtime/dev.d.ts +10 -0
- package/dist/runtime/dev.js +23 -0
- package/dist/runtime/documents.svelte.d.ts +34 -0
- package/dist/runtime/documents.svelte.js +49 -0
- package/dist/runtime/page-layers.svelte.d.ts +20 -0
- package/dist/runtime/page-layers.svelte.js +40 -0
- package/dist/runtime/page.d.ts +10 -0
- package/dist/runtime/page.js +23 -0
- package/dist/runtime/props.d.ts +63 -0
- package/dist/runtime/props.js +1 -0
- package/dist/runtime/readers.svelte.d.ts +47 -0
- package/dist/runtime/readers.svelte.js +122 -0
- package/dist/runtime/state.svelte.d.ts +35 -0
- package/dist/runtime/state.svelte.js +90 -0
- package/dist/runtime/theme.d.ts +12 -0
- package/dist/runtime/theme.js +15 -0
- package/dist/runtime/values.svelte.d.ts +28 -0
- package/dist/runtime/values.svelte.js +51 -0
- package/dist/runtime.d.ts +26 -0
- package/dist/runtime.js +25 -0
- package/dist/search/SearchLayer.svelte +94 -0
- package/dist/search/SearchLayer.svelte.d.ts +4 -0
- package/dist/search/props.d.ts +11 -0
- package/dist/search/props.js +1 -0
- package/dist/search/readers.svelte.d.ts +41 -0
- package/dist/search/readers.svelte.js +40 -0
- package/dist/search.d.ts +11 -0
- package/dist/search.js +11 -0
- package/dist/selection/SelectionClipboard.svelte +35 -0
- package/dist/selection/SelectionClipboard.svelte.d.ts +4 -0
- package/dist/selection/SelectionHandles.svelte +192 -0
- package/dist/selection/SelectionHandles.svelte.d.ts +4 -0
- package/dist/selection/SelectionLayer.svelte +67 -0
- package/dist/selection/SelectionLayer.svelte.d.ts +3 -0
- package/dist/selection/SelectionMenu.svelte +36 -0
- package/dist/selection/SelectionMenu.svelte.d.ts +4 -0
- package/dist/selection/props.d.ts +26 -0
- package/dist/selection/props.js +1 -0
- package/dist/selection/readers.svelte.d.ts +31 -0
- package/dist/selection/readers.svelte.js +26 -0
- package/dist/selection.d.ts +16 -0
- package/dist/selection.js +18 -0
- package/dist/shell/readers.svelte.d.ts +40 -0
- package/dist/shell/readers.svelte.js +40 -0
- package/dist/shell/surface-focus.svelte.d.ts +16 -0
- package/dist/shell/surface-focus.svelte.js +33 -0
- package/dist/shell.d.ts +12 -0
- package/dist/shell.js +11 -0
- package/dist/signature/readers.svelte.d.ts +43 -0
- package/dist/signature/readers.svelte.js +46 -0
- package/dist/signature.d.ts +15 -0
- package/dist/signature.js +16 -0
- package/dist/stage/PageSurface.svelte +126 -0
- package/dist/stage/PageSurface.svelte.d.ts +18 -0
- package/dist/stage/Scrollbar.svelte +148 -0
- package/dist/stage/Scrollbar.svelte.d.ts +4 -0
- package/dist/stage/Stage.svelte +181 -0
- package/dist/stage/Stage.svelte.d.ts +4 -0
- package/dist/stage/StageScope.svelte +14 -0
- package/dist/stage/StageScope.svelte.d.ts +9 -0
- package/dist/stage/props.d.ts +71 -0
- package/dist/stage/props.js +1 -0
- package/dist/stage/readers.svelte.d.ts +39 -0
- package/dist/stage/readers.svelte.js +84 -0
- package/dist/stage/stage-scope.d.ts +18 -0
- package/dist/stage/stage-scope.js +35 -0
- package/dist/stage/two-way.svelte.d.ts +13 -0
- package/dist/stage/two-way.svelte.js +26 -0
- package/dist/stage.d.ts +17 -0
- package/dist/stage.js +15 -0
- package/dist/stamp/readers.svelte.d.ts +50 -0
- package/dist/stamp/readers.svelte.js +76 -0
- package/dist/stamp.d.ts +16 -0
- package/dist/stamp.js +18 -0
- package/dist/toolbar/DefaultCollapsed.svelte +39 -0
- package/dist/toolbar/DefaultCollapsed.svelte.d.ts +9 -0
- package/dist/toolbar/DefaultCommand.svelte +33 -0
- package/dist/toolbar/DefaultCommand.svelte.d.ts +8 -0
- package/dist/toolbar/DefaultGroupTrigger.svelte +39 -0
- package/dist/toolbar/DefaultGroupTrigger.svelte.d.ts +9 -0
- package/dist/toolbar/DefaultOverflowMenu.svelte +106 -0
- package/dist/toolbar/DefaultOverflowMenu.svelte.d.ts +9 -0
- package/dist/toolbar/DefaultOverflowTrigger.svelte +25 -0
- package/dist/toolbar/DefaultOverflowTrigger.svelte.d.ts +7 -0
- package/dist/toolbar/Measured.svelte +46 -0
- package/dist/toolbar/Measured.svelte.d.ts +11 -0
- package/dist/toolbar/NativeSlotSocket.svelte +43 -0
- package/dist/toolbar/NativeSlotSocket.svelte.d.ts +11 -0
- package/dist/toolbar/Toolbar.svelte +314 -0
- package/dist/toolbar/Toolbar.svelte.d.ts +4 -0
- package/dist/toolbar/paint.d.ts +3 -0
- package/dist/toolbar/paint.js +9 -0
- package/dist/toolbar/props.d.ts +48 -0
- package/dist/toolbar/props.js +1 -0
- package/dist/toolbar/strip.svelte.d.ts +14 -0
- package/dist/toolbar/strip.svelte.js +35 -0
- package/dist/toolbar/views.d.ts +14 -0
- package/dist/toolbar/views.js +1 -0
- package/dist/toolbar.d.ts +16 -0
- package/dist/toolbar.js +12 -0
- package/dist/view-manager/readers.d.ts +19 -0
- package/dist/view-manager/readers.js +17 -0
- package/dist/view-manager.d.ts +11 -0
- package/dist/view-manager.js +12 -0
- package/package.json +195 -3
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
The default "More" menu: a minimal popover under its button in a horizontal toolbar and beside
|
|
3
|
+
it in a vertical one, one section after another. A press anywhere outside it closes it, and
|
|
4
|
+
while it's open it takes the menu keys (`attachMenuKeys`): focus on its first row, the arrows,
|
|
5
|
+
typeahead, Enter, and Escape back to its button. A row that opens a submenu keeps the menu
|
|
6
|
+
open; every other row closes it after running.
|
|
7
|
+
-->
|
|
8
|
+
<script lang="ts">
|
|
9
|
+
import { untrack } from 'svelte';
|
|
10
|
+
import type { OverflowRow } from '@embedpdf/core-ui';
|
|
11
|
+
import {
|
|
12
|
+
attachMenuKeys,
|
|
13
|
+
focusablesIn,
|
|
14
|
+
observeOutsidePress,
|
|
15
|
+
type Orientation,
|
|
16
|
+
} from '@embedpdf/web';
|
|
17
|
+
import type { OverflowMenuView } from './views.js';
|
|
18
|
+
import { BORDER, SURFACE } from './paint.js';
|
|
19
|
+
|
|
20
|
+
let { view, orientation }: { view: OverflowMenuView; orientation: Orientation } = $props();
|
|
21
|
+
let menu = $state<HTMLElement | null>(null);
|
|
22
|
+
|
|
23
|
+
// Whether it's open, apart from the view: the toolbar hands a new view on every change, and
|
|
24
|
+
// attaching again would put focus back on the first row.
|
|
25
|
+
const isOpen = $derived(view.isOpen);
|
|
26
|
+
|
|
27
|
+
$effect(() => {
|
|
28
|
+
const element = menu;
|
|
29
|
+
if (!isOpen || !element) return;
|
|
30
|
+
return untrack(() => {
|
|
31
|
+
// The menu's parent holds its button too: a press on it is the button's own toggle.
|
|
32
|
+
const container = element.parentElement ?? element;
|
|
33
|
+
const trigger =
|
|
34
|
+
focusablesIn(container).find((candidate) => !element.contains(candidate)) ?? null;
|
|
35
|
+
const close = () => view.close();
|
|
36
|
+
const stopOutside = observeOutsidePress(container, close);
|
|
37
|
+
const detachKeys = attachMenuKeys(element, { trigger, close });
|
|
38
|
+
return () => {
|
|
39
|
+
stopOutside();
|
|
40
|
+
detachKeys();
|
|
41
|
+
};
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
/** Under a horizontal toolbar's button, beside a vertical one's. */
|
|
46
|
+
const placement = $derived(
|
|
47
|
+
orientation === 'vertical'
|
|
48
|
+
? 'top: 0; inset-inline-start: 100%;'
|
|
49
|
+
: 'top: 100%; inset-inline-end: 0;',
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
function choose(row: OverflowRow) {
|
|
53
|
+
view.execute(row.command);
|
|
54
|
+
if (row.type !== 'submenu') view.close();
|
|
55
|
+
}
|
|
56
|
+
</script>
|
|
57
|
+
|
|
58
|
+
{#if isOpen}
|
|
59
|
+
<div
|
|
60
|
+
bind:this={menu}
|
|
61
|
+
role="menu"
|
|
62
|
+
style="position: absolute; {placement}"
|
|
63
|
+
style:z-index="41"
|
|
64
|
+
style:min-width="200px"
|
|
65
|
+
style:padding="4px"
|
|
66
|
+
style:background={SURFACE}
|
|
67
|
+
style:border="1px solid {BORDER}"
|
|
68
|
+
style:border-radius="6px"
|
|
69
|
+
style:box-shadow="0 4px 16px rgba(0,0,0,0.15)"
|
|
70
|
+
>
|
|
71
|
+
{#each view.sections as section, index (index)}
|
|
72
|
+
{#if index > 0}
|
|
73
|
+
<div style:height="1px" style:background={BORDER} style:margin="4px 0"></div>
|
|
74
|
+
{/if}
|
|
75
|
+
{#each section.rows as row (row.command)}
|
|
76
|
+
{@const command = view.resolve(row.command)}
|
|
77
|
+
{#if command}
|
|
78
|
+
<button
|
|
79
|
+
type="button"
|
|
80
|
+
role={section.role === 'radio' ? 'menuitemradio' : 'menuitem'}
|
|
81
|
+
aria-checked={section.role === 'radio' ? command.active : undefined}
|
|
82
|
+
disabled={!command.enabled}
|
|
83
|
+
tabindex="-1"
|
|
84
|
+
onclick={() => choose(row)}
|
|
85
|
+
style:display="flex"
|
|
86
|
+
style:width="100%"
|
|
87
|
+
style:align-items="center"
|
|
88
|
+
style:justify-content="space-between"
|
|
89
|
+
style:gap="16px"
|
|
90
|
+
style:padding="6px 8px"
|
|
91
|
+
style:border="none"
|
|
92
|
+
style:color="inherit"
|
|
93
|
+
style:font="inherit"
|
|
94
|
+
style:background="transparent"
|
|
95
|
+
style:cursor={command.enabled ? 'pointer' : 'default'}
|
|
96
|
+
style:opacity={command.enabled ? 1 : 0.4}
|
|
97
|
+
style:white-space="nowrap"
|
|
98
|
+
>
|
|
99
|
+
<span>{command.active && section.role === 'radio' ? '• ' : ''}{command.label}</span>
|
|
100
|
+
{#if row.type === 'submenu'}<span>▸</span>{/if}
|
|
101
|
+
</button>
|
|
102
|
+
{/if}
|
|
103
|
+
{/each}
|
|
104
|
+
{/each}
|
|
105
|
+
</div>
|
|
106
|
+
{/if}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type Orientation } from '@embedpdf/web';
|
|
2
|
+
import type { OverflowMenuView } from './views.js';
|
|
3
|
+
type $$ComponentProps = {
|
|
4
|
+
view: OverflowMenuView;
|
|
5
|
+
orientation: Orientation;
|
|
6
|
+
};
|
|
7
|
+
declare const DefaultOverflowMenu: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
8
|
+
type DefaultOverflowMenu = ReturnType<typeof DefaultOverflowMenu>;
|
|
9
|
+
export default DefaultOverflowMenu;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<!-- The default "More" button: a plain ⋯ that shows whether its menu is open. -->
|
|
2
|
+
<script lang="ts">
|
|
3
|
+
import { ACTIVE, BORDER } from './paint.js';
|
|
4
|
+
|
|
5
|
+
let { isOpen, toggle }: { isOpen: boolean; toggle: () => void } = $props();
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<button
|
|
9
|
+
type="button"
|
|
10
|
+
onclick={toggle}
|
|
11
|
+
aria-haspopup="menu"
|
|
12
|
+
aria-expanded={isOpen}
|
|
13
|
+
title="More"
|
|
14
|
+
style:display="inline-flex"
|
|
15
|
+
style:align-items="center"
|
|
16
|
+
style:padding="4px 8px"
|
|
17
|
+
style:color="inherit"
|
|
18
|
+
style:font="inherit"
|
|
19
|
+
style:border="1px solid {BORDER}"
|
|
20
|
+
style:border-radius="4px"
|
|
21
|
+
style:background={isOpen ? ACTIVE : 'transparent'}
|
|
22
|
+
style:cursor="pointer"
|
|
23
|
+
>
|
|
24
|
+
⋯
|
|
25
|
+
</button>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
type $$ComponentProps = {
|
|
2
|
+
isOpen: boolean;
|
|
3
|
+
toggle: () => void;
|
|
4
|
+
};
|
|
5
|
+
declare const DefaultOverflowTrigger: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
6
|
+
type DefaultOverflowTrigger = ReturnType<typeof DefaultOverflowTrigger>;
|
|
7
|
+
export default DefaultOverflowTrigger;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
One element of the toolbar's measurement layer: reports its length along the toolbar (its width,
|
|
3
|
+
or its height in a vertical one) now and whenever it resizes (a new language, a font loading,
|
|
4
|
+
your CSS). With `onlyWhenDrawn` it reports only while it holds something: a custom item that
|
|
5
|
+
draws nothing here is measured where it renders, by the `ctx.measure` it reports to.
|
|
6
|
+
-->
|
|
7
|
+
<script lang="ts">
|
|
8
|
+
import { untrack, type Snippet } from 'svelte';
|
|
9
|
+
import { observeLength, type Orientation } from '@embedpdf/web';
|
|
10
|
+
|
|
11
|
+
let {
|
|
12
|
+
orientation,
|
|
13
|
+
onLength,
|
|
14
|
+
onlyWhenDrawn = false,
|
|
15
|
+
children,
|
|
16
|
+
}: {
|
|
17
|
+
orientation: Orientation;
|
|
18
|
+
onLength: (length: number) => void;
|
|
19
|
+
onlyWhenDrawn?: boolean;
|
|
20
|
+
children?: Snippet;
|
|
21
|
+
} = $props();
|
|
22
|
+
|
|
23
|
+
let element: HTMLSpanElement | undefined = $state();
|
|
24
|
+
|
|
25
|
+
/** Whether `element` holds an element or text: a snippet that drew nothing leaves only anchors. */
|
|
26
|
+
const drewSomething = (measured: Element): boolean =>
|
|
27
|
+
[...measured.childNodes].some(
|
|
28
|
+
(node) =>
|
|
29
|
+
node.nodeType === Node.ELEMENT_NODE ||
|
|
30
|
+
(node.nodeType === Node.TEXT_NODE && (node.textContent ?? '').trim() !== ''),
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
$effect(() => {
|
|
34
|
+
const measured = element;
|
|
35
|
+
const along = orientation;
|
|
36
|
+
if (!measured) return;
|
|
37
|
+
// The report writes the toolbar's lengths, which this effect must not depend on.
|
|
38
|
+
return untrack(() =>
|
|
39
|
+
observeLength(measured, along, (length) => {
|
|
40
|
+
if (!onlyWhenDrawn || drewSomething(measured)) onLength(length);
|
|
41
|
+
}),
|
|
42
|
+
);
|
|
43
|
+
});
|
|
44
|
+
</script>
|
|
45
|
+
|
|
46
|
+
<span bind:this={element} style="display: inline-flex; flex-shrink: 0">{@render children?.()}</span>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type Snippet } from 'svelte';
|
|
2
|
+
import { type Orientation } from '@embedpdf/web';
|
|
3
|
+
type $$ComponentProps = {
|
|
4
|
+
orientation: Orientation;
|
|
5
|
+
onLength: (length: number) => void;
|
|
6
|
+
onlyWhenDrawn?: boolean;
|
|
7
|
+
children?: Snippet;
|
|
8
|
+
};
|
|
9
|
+
declare const Measured: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
10
|
+
type Measured = ReturnType<typeof Measured>;
|
|
11
|
+
export default Measured;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
The socket for a custom item when no `custom` snippet draws it: a real, native <slot> element.
|
|
3
|
+
Inside a shadow root (a custom element that renders the toolbar) the browser projects the
|
|
4
|
+
host's same-named children into it; anywhere else it shows its own content, the item's
|
|
5
|
+
command. It is measured where it renders, never in the measurement layer: only the first
|
|
6
|
+
<slot> of a name gets the projected children.
|
|
7
|
+
-->
|
|
8
|
+
<script lang="ts">
|
|
9
|
+
import { untrack, type Snippet } from 'svelte';
|
|
10
|
+
import { observeLength, type Orientation } from '@embedpdf/web';
|
|
11
|
+
|
|
12
|
+
let {
|
|
13
|
+
name,
|
|
14
|
+
orientation,
|
|
15
|
+
onLength,
|
|
16
|
+
children,
|
|
17
|
+
}: {
|
|
18
|
+
name: string;
|
|
19
|
+
orientation: Orientation;
|
|
20
|
+
onLength: (length: number) => void;
|
|
21
|
+
children?: Snippet;
|
|
22
|
+
} = $props();
|
|
23
|
+
|
|
24
|
+
let socket: HTMLElement | undefined = $state();
|
|
25
|
+
|
|
26
|
+
// A child slotted in or out resizes the socket's box, so one observer covers both.
|
|
27
|
+
$effect(() => {
|
|
28
|
+
const element = socket;
|
|
29
|
+
const along = orientation;
|
|
30
|
+
if (!element) return;
|
|
31
|
+
return untrack(() => observeLength(element, along, (length) => onLength(length)));
|
|
32
|
+
});
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
<!-- `svelte:element` makes the element itself: Svelte reads a <slot> tag as its own syntax. -->
|
|
36
|
+
<svelte:element
|
|
37
|
+
this={'slot'}
|
|
38
|
+
bind:this={socket}
|
|
39
|
+
{name}
|
|
40
|
+
style="display: inline-flex; align-items: center; flex-shrink: 0"
|
|
41
|
+
>
|
|
42
|
+
{@render children?.()}
|
|
43
|
+
</svelte:element>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type Snippet } from 'svelte';
|
|
2
|
+
import { type Orientation } from '@embedpdf/web';
|
|
3
|
+
type $$ComponentProps = {
|
|
4
|
+
name: string;
|
|
5
|
+
orientation: Orientation;
|
|
6
|
+
onLength: (length: number) => void;
|
|
7
|
+
children?: Snippet;
|
|
8
|
+
};
|
|
9
|
+
declare const NativeSlotSocket: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
10
|
+
type NativeSlotSocket = ReturnType<typeof NativeSlotSocket>;
|
|
11
|
+
export default NativeSlotSocket;
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
<Toolbar>: measures what fits and makes room, and you draw every part.
|
|
3
|
+
|
|
4
|
+
1. A hidden measurement layer renders every unit in every variant (and the folded groups and
|
|
5
|
+
the "More" button), each watched with `observeLength` from @embedpdf/web along the toolbar
|
|
6
|
+
(widths, or heights when it is vertical), so a new language, a font loading, browser zoom
|
|
7
|
+
and your CSS all re-measure on their own (`createToolbarLengths`).
|
|
8
|
+
2. core-ui's `solve()` gives each unit a variant, a folded group or the "More" menu
|
|
9
|
+
(`layoutToolbar` turns that into parts).
|
|
10
|
+
3. The live row draws the parts; the "More" menu is derived from what didn't fit
|
|
11
|
+
(`projectOverflow`), never written by hand.
|
|
12
|
+
|
|
13
|
+
The toolbar is one tab stop with arrow keys along it (`attachToolbarFocus`), and its default
|
|
14
|
+
menus take the menu keys (`attachMenuKeys`). Every part is a snippet with a plain default:
|
|
15
|
+
`command`, `custom`, `collapsed`, `groupTrigger`, `separator`, `overflowTrigger` and
|
|
16
|
+
`overflowMenu`. The defaults' colors come from the `--epdf-toolbar-*` CSS variables only.
|
|
17
|
+
-->
|
|
18
|
+
<script lang="ts">
|
|
19
|
+
import { untrack } from 'svelte';
|
|
20
|
+
import { layoutToolbar, normalizeBar, type LiveSection } from '@embedpdf/core-ui';
|
|
21
|
+
// The "More" menu asks which menu a command opens, a host fact, so the host lens is bound here.
|
|
22
|
+
import { CommandsToken } from '@embedpdf/plugin-commands/contract/host';
|
|
23
|
+
import { unregisteredCommand } from '@embedpdf/plugin-commands/contract';
|
|
24
|
+
import type { ResolvedCommand } from '@embedpdf/plugin-commands/contract';
|
|
25
|
+
import {
|
|
26
|
+
TOOLBAR_ITEM_ATTRIBUTE,
|
|
27
|
+
attachToolbarFocus,
|
|
28
|
+
createToolbarLengths,
|
|
29
|
+
observeContentLength,
|
|
30
|
+
toolbarMeasureKey,
|
|
31
|
+
type RovingFocus,
|
|
32
|
+
} from '@embedpdf/web';
|
|
33
|
+
import { useKernelBinding } from '../runtime/binding.svelte.js';
|
|
34
|
+
import { useCapability, useDocumentId } from '../runtime/readers.svelte.js';
|
|
35
|
+
import DefaultCollapsed from './DefaultCollapsed.svelte';
|
|
36
|
+
import DefaultCommand from './DefaultCommand.svelte';
|
|
37
|
+
import DefaultGroupTrigger from './DefaultGroupTrigger.svelte';
|
|
38
|
+
import DefaultOverflowMenu from './DefaultOverflowMenu.svelte';
|
|
39
|
+
import DefaultOverflowTrigger from './DefaultOverflowTrigger.svelte';
|
|
40
|
+
import Measured from './Measured.svelte';
|
|
41
|
+
import NativeSlotSocket from './NativeSlotSocket.svelte';
|
|
42
|
+
import type { ToolbarProps } from './props.js';
|
|
43
|
+
import type { OverflowMenuView, ToolbarPart } from './views.js';
|
|
44
|
+
|
|
45
|
+
let {
|
|
46
|
+
bar,
|
|
47
|
+
orientation = 'horizontal',
|
|
48
|
+
gap = 8,
|
|
49
|
+
separatorWidth = 1,
|
|
50
|
+
'aria-label': ariaLabel,
|
|
51
|
+
class: className,
|
|
52
|
+
style,
|
|
53
|
+
command,
|
|
54
|
+
custom,
|
|
55
|
+
collapsed,
|
|
56
|
+
groupTrigger,
|
|
57
|
+
separator,
|
|
58
|
+
overflowTrigger,
|
|
59
|
+
overflowMenu,
|
|
60
|
+
}: ToolbarProps = $props();
|
|
61
|
+
|
|
62
|
+
const binding = useKernelBinding();
|
|
63
|
+
const commands = useCapability(CommandsToken);
|
|
64
|
+
const documentId = useDocumentId();
|
|
65
|
+
const vertical = $derived(orientation === 'vertical');
|
|
66
|
+
|
|
67
|
+
// ── measuring ──────────────────────────────────────────────────────────────
|
|
68
|
+
|
|
69
|
+
let container: HTMLDivElement | undefined = $state();
|
|
70
|
+
let containerLength = $state(0);
|
|
71
|
+
$effect(() => {
|
|
72
|
+
const element = container;
|
|
73
|
+
const along = orientation;
|
|
74
|
+
if (!element) return;
|
|
75
|
+
return untrack(() =>
|
|
76
|
+
observeContentLength(element, along, (length) => (containerLength = length)),
|
|
77
|
+
);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// A length that changed by more than half a pixel fits (and draws) again. Untracked: a report
|
|
81
|
+
// can come from an effect, which must not run again because the count moved.
|
|
82
|
+
const lengths = createToolbarLengths();
|
|
83
|
+
let measured = $state(0);
|
|
84
|
+
function report(key: string, length: number) {
|
|
85
|
+
untrack(() => {
|
|
86
|
+
if (lengths.report(orientation, key, length)) measured += 1;
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// ── the fit ────────────────────────────────────────────────────────────────
|
|
91
|
+
|
|
92
|
+
const normalized = $derived(normalizeBar(bar));
|
|
93
|
+
|
|
94
|
+
const resolve = (id: string): ResolvedCommand | null =>
|
|
95
|
+
commands.resolveCommand(id, documentId.current ?? undefined);
|
|
96
|
+
const execute = (id: string): void =>
|
|
97
|
+
void commands.execute(id, { documentId: documentId.current ?? undefined });
|
|
98
|
+
|
|
99
|
+
// Command state is derived on read, so this runs again on every kernel change: labels, `active`
|
|
100
|
+
// and `visible` (and with them the measurement layer) stay live. A toolbar is a few dozen
|
|
101
|
+
// items, so drawing it again on each change is the simple, correct baseline.
|
|
102
|
+
const layout = $derived.by(() => {
|
|
103
|
+
binding.track();
|
|
104
|
+
void measured;
|
|
105
|
+
return layoutToolbar({
|
|
106
|
+
bar: normalized,
|
|
107
|
+
resolve,
|
|
108
|
+
unregistered: unregisteredCommand,
|
|
109
|
+
execute,
|
|
110
|
+
menuTarget: (id) => commands.getMenuTarget(id),
|
|
111
|
+
metrics: lengths.metrics(orientation, gap, separatorWidth),
|
|
112
|
+
measureKey: toolbarMeasureKey,
|
|
113
|
+
containerLength,
|
|
114
|
+
orientation,
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// ── the "More" menu ────────────────────────────────────────────────────────
|
|
119
|
+
|
|
120
|
+
let overflowOpen = $state(false);
|
|
121
|
+
const hasOverflow = $derived(layout.hasOverflow);
|
|
122
|
+
$effect(() => {
|
|
123
|
+
if (!hasOverflow) overflowOpen = false;
|
|
124
|
+
});
|
|
125
|
+
const toggleOverflow = () => (overflowOpen = !overflowOpen);
|
|
126
|
+
const noop = () => {};
|
|
127
|
+
|
|
128
|
+
const overflowView: OverflowMenuView = $derived({
|
|
129
|
+
sections: layout.overflow,
|
|
130
|
+
isOpen: overflowOpen,
|
|
131
|
+
close: () => (overflowOpen = false),
|
|
132
|
+
resolve,
|
|
133
|
+
execute,
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// ── the keyboard ───────────────────────────────────────────────────────────
|
|
137
|
+
|
|
138
|
+
// One tab stop, and arrow keys along the toolbar. The handle is no state: nothing draws from it.
|
|
139
|
+
const keyboard: { focus: RovingFocus | null } = { focus: null };
|
|
140
|
+
$effect(() => {
|
|
141
|
+
const element = container;
|
|
142
|
+
const along = orientation;
|
|
143
|
+
if (!element) return;
|
|
144
|
+
return untrack(() => {
|
|
145
|
+
const focus = attachToolbarFocus(element, along);
|
|
146
|
+
keyboard.focus = focus;
|
|
147
|
+
return () => {
|
|
148
|
+
focus.detach();
|
|
149
|
+
keyboard.focus = null;
|
|
150
|
+
};
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
// Any draw can add, remove or disable an item, so the tab stop is checked after each one: a new
|
|
154
|
+
// fit, the "More" menu, or snippets of yours that draw the parts. An effect runs after the DOM
|
|
155
|
+
// it follows is updated.
|
|
156
|
+
$effect(() => {
|
|
157
|
+
void [layout, overflowOpen, command, custom, collapsed, groupTrigger, overflowTrigger];
|
|
158
|
+
untrack(() => keyboard.focus?.refresh());
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
// ── layout ─────────────────────────────────────────────────────────────────
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* The sections run along the toolbar. The center one carries auto margins: it centers in the
|
|
165
|
+
* space the other two leave, and gives way before anything overlaps. The toolbar itself has no
|
|
166
|
+
* gap, so what the fit says fits, fits. Sections never grow or shrink: fitting is the solver's
|
|
167
|
+
* job, not flexbox's.
|
|
168
|
+
*/
|
|
169
|
+
const sectionStyle = (name: LiveSection['name']) =>
|
|
170
|
+
`display: flex; flex-direction: ${vertical ? 'column' : 'row'}; align-items: center; ` +
|
|
171
|
+
`gap: ${gap}px; flex: 0 0 auto;` +
|
|
172
|
+
(name !== 'center'
|
|
173
|
+
? ''
|
|
174
|
+
: vertical
|
|
175
|
+
? ' margin-top: auto; margin-bottom: auto;'
|
|
176
|
+
: ' margin-left: auto; margin-right: auto;');
|
|
177
|
+
|
|
178
|
+
/** The default separator: a 1px line across the toolbar, flat in a vertical one. */
|
|
179
|
+
const separatorStyle = $derived(
|
|
180
|
+
`${vertical ? 'height' : 'width'}: 1px; align-self: stretch; background: currentColor; ` +
|
|
181
|
+
'opacity: 0.2',
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
/** The toolbar runs along its orientation; a `style` of yours comes after. */
|
|
185
|
+
const rootStyle = $derived(
|
|
186
|
+
`position: relative; display: flex; flex-direction: ${vertical ? 'column' : 'row'}; ` +
|
|
187
|
+
`align-items: center; ${style ?? ''}`,
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
/** Marks the element around each item of the live row: its first focusable element is a stop. */
|
|
191
|
+
const TOOLBAR_ITEM = { [TOOLBAR_ITEM_ATTRIBUTE]: '' };
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* The hidden measurement layer: a row for a horizontal toolbar, a column for a vertical one, and
|
|
195
|
+
* no height either way, so it never adds to the page. A column keeps each item at its own
|
|
196
|
+
* width, so no text wraps and changes the heights it reports.
|
|
197
|
+
*/
|
|
198
|
+
const measureLayerStyle = $derived(
|
|
199
|
+
'position: absolute; left: 0; top: 0; height: 0; overflow: hidden; visibility: hidden; ' +
|
|
200
|
+
'pointer-events: none; display: flex; white-space: nowrap;' +
|
|
201
|
+
(vertical ? ' flex-direction: column; align-items: flex-start;' : ''),
|
|
202
|
+
);
|
|
203
|
+
</script>
|
|
204
|
+
|
|
205
|
+
{#snippet commandButton(item: ResolvedCommand, variant: string, run: () => void)}
|
|
206
|
+
{#if command}
|
|
207
|
+
{@render command(item, variant, run)}
|
|
208
|
+
{:else}
|
|
209
|
+
<DefaultCommand command={item} {run} />
|
|
210
|
+
{/if}
|
|
211
|
+
{/snippet}
|
|
212
|
+
|
|
213
|
+
{#snippet part(item: ToolbarPart, layer: 'live' | 'measure')}
|
|
214
|
+
{#if item.kind === 'command'}
|
|
215
|
+
{@render commandButton(item.command, item.variant, item.run)}
|
|
216
|
+
{:else if item.kind === 'custom'}
|
|
217
|
+
{#if custom}
|
|
218
|
+
{@render custom(item.name, item.variant, {
|
|
219
|
+
layer,
|
|
220
|
+
measure: (length) => report(item.measureKey, length),
|
|
221
|
+
})}
|
|
222
|
+
{:else}
|
|
223
|
+
<NativeSlotSocket
|
|
224
|
+
name={item.name}
|
|
225
|
+
{orientation}
|
|
226
|
+
onLength={(length) => report(item.measureKey, length)}
|
|
227
|
+
>
|
|
228
|
+
{#if item.terminal}
|
|
229
|
+
{@render commandButton(item.terminal, 'icon', item.runTerminal)}
|
|
230
|
+
{/if}
|
|
231
|
+
</NativeSlotSocket>
|
|
232
|
+
{/if}
|
|
233
|
+
{:else if item.kind === 'collapsed'}
|
|
234
|
+
{#if collapsed}
|
|
235
|
+
{@render collapsed(item.view)}
|
|
236
|
+
{:else}
|
|
237
|
+
<DefaultCollapsed view={item.view} {orientation} />
|
|
238
|
+
{/if}
|
|
239
|
+
{:else if groupTrigger}
|
|
240
|
+
{@render groupTrigger(item.view)}
|
|
241
|
+
{:else}
|
|
242
|
+
<DefaultGroupTrigger view={item.view} {orientation} />
|
|
243
|
+
{/if}
|
|
244
|
+
{/snippet}
|
|
245
|
+
|
|
246
|
+
{#snippet moreButton(isOpen: boolean, toggle: () => void)}
|
|
247
|
+
{#if overflowTrigger}
|
|
248
|
+
{@render overflowTrigger(isOpen, toggle)}
|
|
249
|
+
{:else}
|
|
250
|
+
<DefaultOverflowTrigger {isOpen} {toggle} />
|
|
251
|
+
{/if}
|
|
252
|
+
{/snippet}
|
|
253
|
+
|
|
254
|
+
<div
|
|
255
|
+
bind:this={container}
|
|
256
|
+
role="toolbar"
|
|
257
|
+
aria-orientation={orientation}
|
|
258
|
+
aria-label={ariaLabel}
|
|
259
|
+
class={className}
|
|
260
|
+
style={rootStyle}
|
|
261
|
+
>
|
|
262
|
+
{#each layout.sections as section (section.name)}
|
|
263
|
+
<div style={sectionStyle(section.name)}>
|
|
264
|
+
{#each section.groups as group, index (group.id)}
|
|
265
|
+
{#if index > 0}
|
|
266
|
+
{#if separator}
|
|
267
|
+
{@render separator()}
|
|
268
|
+
{:else}
|
|
269
|
+
<span style={separatorStyle}></span>
|
|
270
|
+
{/if}
|
|
271
|
+
{/if}
|
|
272
|
+
{#each group.parts as item (item.key)}
|
|
273
|
+
<!-- The element around an item adds no box: the item lays out as the section's child. -->
|
|
274
|
+
<span {...TOOLBAR_ITEM} style="display: contents">{@render part(item, 'live')}</span>
|
|
275
|
+
{/each}
|
|
276
|
+
{/each}
|
|
277
|
+
{#if section.name === 'end' && layout.hasOverflow}
|
|
278
|
+
<span {...TOOLBAR_ITEM} style="position: relative; display: inline-flex">
|
|
279
|
+
{@render moreButton(overflowOpen, toggleOverflow)}
|
|
280
|
+
{#if overflowMenu}
|
|
281
|
+
{@render overflowMenu(overflowView)}
|
|
282
|
+
{:else}
|
|
283
|
+
<DefaultOverflowMenu view={overflowView} {orientation} />
|
|
284
|
+
{/if}
|
|
285
|
+
</span>
|
|
286
|
+
{/if}
|
|
287
|
+
</div>
|
|
288
|
+
{/each}
|
|
289
|
+
|
|
290
|
+
<!-- The measurement layer: hidden, inert and observed. Text reflow (a language, a font,
|
|
291
|
+
browser zoom) fires the observers; no code handles it. -->
|
|
292
|
+
<div aria-hidden="true" inert style={measureLayerStyle}>
|
|
293
|
+
{#each layout.measured as measuredPart (measuredPart.measureKey)}
|
|
294
|
+
<!-- A custom item without a `custom` snippet is a socket, measured where it renders: a
|
|
295
|
+
second <slot> of its name here would take the projected children from the row. One
|
|
296
|
+
whose snippet draws nothing here is measured where it renders too, by `ctx.measure`. -->
|
|
297
|
+
{#if measuredPart.kind !== 'custom' || custom}
|
|
298
|
+
<Measured
|
|
299
|
+
{orientation}
|
|
300
|
+
onlyWhenDrawn={measuredPart.kind === 'custom'}
|
|
301
|
+
onLength={(length) => report(measuredPart.measureKey, length)}
|
|
302
|
+
>
|
|
303
|
+
{@render part(measuredPart, 'measure')}
|
|
304
|
+
</Measured>
|
|
305
|
+
{/if}
|
|
306
|
+
{/each}
|
|
307
|
+
<Measured
|
|
308
|
+
{orientation}
|
|
309
|
+
onLength={(length) => report(toolbarMeasureKey.overflowTrigger, length)}
|
|
310
|
+
>
|
|
311
|
+
{@render moreButton(false, noop)}
|
|
312
|
+
</Measured>
|
|
313
|
+
</div>
|
|
314
|
+
</div>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The default parts' colors: CSS variables only, because the defaults are meant to be replaced.
|
|
3
|
+
* `--epdf-toolbar-surface` (the "More" menu and folded groups), `--epdf-toolbar-border` and
|
|
4
|
+
* `--epdf-toolbar-active` (a pressed or open button).
|
|
5
|
+
*/
|
|
6
|
+
import { paintDefault } from '@embedpdf/web';
|
|
7
|
+
export const SURFACE = paintDefault('toolbar-surface');
|
|
8
|
+
export const BORDER = paintDefault('toolbar-border');
|
|
9
|
+
export const ACTIVE = paintDefault('toolbar-active');
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/** The props of `<Toolbar>`: the bar and how it runs, and a snippet for every part you draw. */
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import type { BarSchema, CustomSlotCtx } from '@embedpdf/core-ui';
|
|
4
|
+
import type { ResolvedCommand } from '@embedpdf/plugin-commands/contract';
|
|
5
|
+
import type { CollapsedGroupView, GroupDisclosureView, OverflowMenuView } from './views.js';
|
|
6
|
+
export interface ToolbarProps {
|
|
7
|
+
/** What goes in the toolbar: its sections, groups and items. */
|
|
8
|
+
bar: BarSchema;
|
|
9
|
+
/**
|
|
10
|
+
* Which way the toolbar runs. A vertical toolbar fits the height it's given, so give it one; it
|
|
11
|
+
* stacks its sections top, middle and bottom, and draws every command at `'icon'`, with the
|
|
12
|
+
* label for a tooltip. Default `'horizontal'`.
|
|
13
|
+
*/
|
|
14
|
+
orientation?: 'horizontal' | 'vertical';
|
|
15
|
+
/** Px between adjacent items (the CSS flex gap; the fit budgets the same number). Default 8. */
|
|
16
|
+
gap?: number;
|
|
17
|
+
/**
|
|
18
|
+
* The thickness of the separator your `separator` snippet draws: its width across a horizontal
|
|
19
|
+
* toolbar, its height in a vertical one. Default 1.
|
|
20
|
+
*/
|
|
21
|
+
separatorWidth?: number;
|
|
22
|
+
/** The toolbar's name for screen readers, for a page with more than one toolbar. */
|
|
23
|
+
'aria-label'?: string;
|
|
24
|
+
class?: string;
|
|
25
|
+
style?: string;
|
|
26
|
+
/** A command's button at a variant. Default: a plain `<button>` with the command's label. */
|
|
27
|
+
command?: Snippet<[command: ResolvedCommand, variant: string, run: () => void]>;
|
|
28
|
+
/**
|
|
29
|
+
* Your own items, by `name` (from `custom(name, command)`): it draws every custom item in the
|
|
30
|
+
* bar, in the live row and in the hidden measurement layer (`ctx.layer`). Without it, each item
|
|
31
|
+
* is a native `<slot name>` element with its command's button inside, for a custom element's
|
|
32
|
+
* children to fill. An item the snippet draws nothing for in the measurement layer
|
|
33
|
+
* (`ctx.layer === 'measure'`) is measured where it renders instead: report its length with
|
|
34
|
+
* `ctx.measure`. The first element of an item that takes focus is the item's stop in the
|
|
35
|
+
* toolbar's arrow-key order.
|
|
36
|
+
*/
|
|
37
|
+
custom?: Snippet<[name: string, variant: string, ctx: CustomSlotCtx]>;
|
|
38
|
+
/** A folded group: its button and its menu. Default: a `<select>` for `'select'`, a menu button for `'menu'`. */
|
|
39
|
+
collapsed?: Snippet<[view: CollapsedGroupView]>;
|
|
40
|
+
/** The button of a group that shed items, and its menu. Default: a chevron opening a menu. */
|
|
41
|
+
groupTrigger?: Snippet<[view: GroupDisclosureView]>;
|
|
42
|
+
/** The line between groups. Default: a 1px line across the toolbar. */
|
|
43
|
+
separator?: Snippet;
|
|
44
|
+
/** The "More" button. Default: a plain ⋯ button. */
|
|
45
|
+
overflowTrigger?: Snippet<[isOpen: boolean, toggle: () => void]>;
|
|
46
|
+
/** The "More" menu, with its sections, rows and the call that runs each one. Default: a minimal popover. */
|
|
47
|
+
overflowMenu?: Snippet<[view: OverflowMenuView]>;
|
|
48
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { BarSchema, StripView as StripViewOf, StripViewGroup as StripViewGroupOf } from '@embedpdf/core-ui';
|
|
2
|
+
import type { ResolvedCommand } from '@embedpdf/plugin-commands/contract';
|
|
3
|
+
import { type CurrentValue, type MaybeGetter } from '../runtime/values.svelte.js';
|
|
4
|
+
/** A group of a strip: its visible commands, in bar order. Groups are separator boundaries. */
|
|
5
|
+
export type StripViewGroup = StripViewGroupOf<ResolvedCommand>;
|
|
6
|
+
/** A strip, resolved: only visible commands, only groups with one; `execute` runs one for this component's document. */
|
|
7
|
+
export type StripView = StripViewOf<ResolvedCommand>;
|
|
8
|
+
/**
|
|
9
|
+
* The strip a bar shows now, as `{ current }`: the schema says what could appear, each command's
|
|
10
|
+
* `visible` decides what does. `null` while nothing applies, so `{#if strip.current}` is all the
|
|
11
|
+
* show-and-hide logic a strip needs. `current` changes only when a command in it changes. Pass a
|
|
12
|
+
* function for a bar that changes.
|
|
13
|
+
*/
|
|
14
|
+
export declare function useStripView(bar: MaybeGetter<BarSchema | undefined>): CurrentValue<StripView | null>;
|