@inkbar/svelte 0.3.0 → 0.5.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 +17 -12
- package/dist/components/InkAnnotation.svelte +0 -12
- package/dist/components/InkAnnotation.svelte.d.ts.map +1 -1
- package/dist/components/InkColorMenu.svelte +247 -0
- package/dist/components/InkColorMenu.svelte.d.ts +35 -0
- package/dist/components/InkColorMenu.svelte.d.ts.map +1 -0
- package/dist/components/InkHighlightMenu.svelte +175 -0
- package/dist/components/InkHighlightMenu.svelte.d.ts +16 -0
- package/dist/components/InkHighlightMenu.svelte.d.ts.map +1 -0
- package/dist/components/InkLineStyleMenu.svelte +141 -0
- package/dist/components/InkLineStyleMenu.svelte.d.ts +15 -0
- package/dist/components/InkLineStyleMenu.svelte.d.ts.map +1 -0
- package/dist/components/InkRoot.svelte +90 -3
- package/dist/components/InkRoot.svelte.d.ts +27 -2
- package/dist/components/InkRoot.svelte.d.ts.map +1 -1
- package/dist/components/InkShapeMenu.svelte +161 -0
- package/dist/components/InkShapeMenu.svelte.d.ts +15 -0
- package/dist/components/InkShapeMenu.svelte.d.ts.map +1 -0
- package/dist/components/InkSignatureDialog.svelte +70 -0
- package/dist/components/InkSignatureDialog.svelte.d.ts +22 -0
- package/dist/components/InkSignatureDialog.svelte.d.ts.map +1 -0
- package/dist/components/InkSignatureMenu.svelte +267 -0
- package/dist/components/InkSignatureMenu.svelte.d.ts +18 -0
- package/dist/components/InkSignatureMenu.svelte.d.ts.map +1 -0
- package/dist/components/InkTextStyleMenu.svelte +225 -0
- package/dist/components/InkTextStyleMenu.svelte.d.ts +15 -0
- package/dist/components/InkTextStyleMenu.svelte.d.ts.map +1 -0
- package/dist/components/{InkNotePopover.svelte → InkThreadPopover.svelte} +44 -32
- package/dist/components/InkThreadPopover.svelte.d.ts +9 -0
- package/dist/components/InkThreadPopover.svelte.d.ts.map +1 -0
- package/dist/components/InkToolButton.svelte +23 -7
- package/dist/components/InkToolButton.svelte.d.ts.map +1 -1
- package/dist/components/InkViewport.svelte +26 -2
- package/dist/components/InkViewport.svelte.d.ts.map +1 -1
- package/dist/components/SignatureForm.svelte +219 -0
- package/dist/components/SignatureForm.svelte.d.ts +10 -0
- package/dist/components/SignatureForm.svelte.d.ts.map +1 -0
- package/dist/components/ThreadForm.svelte +4 -2
- package/dist/components/ThreadForm.svelte.d.ts +1 -0
- package/dist/components/ThreadForm.svelte.d.ts.map +1 -1
- package/dist/components/child-snippet.d.ts +8 -0
- package/dist/components/child-snippet.d.ts.map +1 -1
- package/dist/components/child-snippet.js +15 -0
- package/dist/components/popover-focus.d.ts +16 -2
- package/dist/components/popover-focus.d.ts.map +1 -1
- package/dist/components/popover-focus.js +24 -3
- package/dist/context.d.ts +21 -2
- package/dist/context.d.ts.map +1 -1
- package/dist/hooks/useAnnotations.svelte.d.ts +1333 -578
- package/dist/hooks/useAnnotations.svelte.d.ts.map +1 -1
- package/dist/hooks/useAnnotations.svelte.js +1 -7
- package/dist/hooks/useToolOptions.svelte.d.ts +11 -0
- package/dist/hooks/useToolOptions.svelte.d.ts.map +1 -0
- package/dist/hooks/useToolOptions.svelte.js +19 -0
- package/dist/hooks/useToolStyle.svelte.d.ts +33 -0
- package/dist/hooks/useToolStyle.svelte.d.ts.map +1 -0
- package/dist/hooks/useToolStyle.svelte.js +33 -0
- package/dist/index.d.ts +21 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -2
- package/package.json +5 -5
- package/dist/components/InkNotePopover.svelte.d.ts +0 -9
- package/dist/components/InkNotePopover.svelte.d.ts.map +0 -1
- package/dist/components/InkSuggestionCard.svelte +0 -121
- package/dist/components/InkSuggestionCard.svelte.d.ts +0 -9
- package/dist/components/InkSuggestionCard.svelte.d.ts.map +0 -1
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte'
|
|
3
|
+
import type { HTMLButtonAttributes } from 'svelte/elements'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Line weight, solid or dashed, and arrowheads, for the selection or the active tool. Each
|
|
7
|
+
* section disables when nothing selected (or no active tool) supports its props. The
|
|
8
|
+
* trigger carries `data-mixed` when the selection disagrees on any of them; a section with
|
|
9
|
+
* no single value shows no checkmark.
|
|
10
|
+
*/
|
|
11
|
+
export interface InkLineStyleMenuProps extends Omit<HTMLButtonAttributes, 'children'> {
|
|
12
|
+
children?: Snippet | undefined
|
|
13
|
+
}
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<script lang="ts">
|
|
17
|
+
import {
|
|
18
|
+
focusInitialMenuItem,
|
|
19
|
+
handleMenuKeys,
|
|
20
|
+
lineStyleMenuModel,
|
|
21
|
+
menuItems,
|
|
22
|
+
} from '@inkbar/core/dom'
|
|
23
|
+
import { Check, Minus } from '@inkbar/icons'
|
|
24
|
+
import { Popover, Toolbar } from 'bits-ui'
|
|
25
|
+
|
|
26
|
+
import { useToolStyle } from '../hooks/useToolStyle.svelte.js'
|
|
27
|
+
|
|
28
|
+
import { asBitsProps, composeHandlers } from './child-snippet.js'
|
|
29
|
+
import InkIcon from './InkIcon.svelte'
|
|
30
|
+
|
|
31
|
+
let {
|
|
32
|
+
class: className,
|
|
33
|
+
children,
|
|
34
|
+
disabled,
|
|
35
|
+
onclick,
|
|
36
|
+
onkeydown,
|
|
37
|
+
...rest
|
|
38
|
+
}: InkLineStyleMenuProps = $props()
|
|
39
|
+
|
|
40
|
+
const style = useToolStyle()
|
|
41
|
+
let open = $state(false)
|
|
42
|
+
|
|
43
|
+
const model = $derived(lineStyleMenuModel(style.current, style.supported))
|
|
44
|
+
|
|
45
|
+
let menu = $state<HTMLElement | null>(null)
|
|
46
|
+
|
|
47
|
+
// The menu closes when the control disables (the selection cleared while it was open).
|
|
48
|
+
$effect(() => {
|
|
49
|
+
if (!model.enabled) open = false
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
/** ArrowDown opens on the first item; a click opens on the checked one. */
|
|
53
|
+
let focusFirst = false
|
|
54
|
+
// Bits runs the open-focus callback more than once, so the flag outlives it; reset on close.
|
|
55
|
+
$effect(() => {
|
|
56
|
+
if (!open) focusFirst = false
|
|
57
|
+
})
|
|
58
|
+
function onTriggerKeydown(e: KeyboardEvent): void {
|
|
59
|
+
if (e.key !== 'ArrowDown' || e.defaultPrevented || open || !model.enabled) return
|
|
60
|
+
e.preventDefault()
|
|
61
|
+
focusFirst = true
|
|
62
|
+
open = true
|
|
63
|
+
}
|
|
64
|
+
</script>
|
|
65
|
+
|
|
66
|
+
<Popover.Root bind:open>
|
|
67
|
+
<Popover.Trigger>
|
|
68
|
+
{#snippet child({ props })}
|
|
69
|
+
<Toolbar.Button
|
|
70
|
+
{...props}
|
|
71
|
+
{...asBitsProps(rest)}
|
|
72
|
+
class={['ink-menu-trigger ink-line-style-menu', className]}
|
|
73
|
+
data-ink-line-style-menu=""
|
|
74
|
+
data-state={open ? 'open' : 'closed'}
|
|
75
|
+
data-mixed={model.mixed ? '' : undefined}
|
|
76
|
+
aria-label="Line style"
|
|
77
|
+
title="Line style"
|
|
78
|
+
aria-haspopup="menu"
|
|
79
|
+
onclick={composeHandlers(onclick, props.onclick)}
|
|
80
|
+
onkeydown={composeHandlers(onkeydown, props.onkeydown, onTriggerKeydown)}
|
|
81
|
+
disabled={!!disabled || !model.enabled}
|
|
82
|
+
>
|
|
83
|
+
{#if children}{@render children()}{:else}<InkIcon icon={Minus} />{/if}
|
|
84
|
+
</Toolbar.Button>
|
|
85
|
+
{/snippet}
|
|
86
|
+
</Popover.Trigger>
|
|
87
|
+
<Popover.Portal>
|
|
88
|
+
<Popover.Content
|
|
89
|
+
bind:ref={menu}
|
|
90
|
+
role="menu"
|
|
91
|
+
aria-label="Line style"
|
|
92
|
+
class="ink-select-content ink-menu-content"
|
|
93
|
+
data-ink-select-content=""
|
|
94
|
+
data-ink-menu="line-style"
|
|
95
|
+
side="bottom"
|
|
96
|
+
align="start"
|
|
97
|
+
sideOffset={4}
|
|
98
|
+
collisionPadding={8}
|
|
99
|
+
onOpenAutoFocus={(e) => {
|
|
100
|
+
e.preventDefault()
|
|
101
|
+
if (menu) {
|
|
102
|
+
if (focusFirst) menuItems(menu)[0]?.focus({ preventScroll: true })
|
|
103
|
+
else focusInitialMenuItem(menu)
|
|
104
|
+
}
|
|
105
|
+
}}
|
|
106
|
+
onkeydown={(e) => menu && handleMenuKeys(e, menu)}
|
|
107
|
+
>
|
|
108
|
+
{#each model.sections as section (section.label)}
|
|
109
|
+
<div
|
|
110
|
+
role="group"
|
|
111
|
+
class="ink-menu-group"
|
|
112
|
+
aria-label={section.label}
|
|
113
|
+
aria-disabled={section.disabled || undefined}
|
|
114
|
+
data-disabled={section.disabled ? '' : undefined}
|
|
115
|
+
>
|
|
116
|
+
<div class="ink-menu-label" aria-hidden="true">{section.label}</div>
|
|
117
|
+
{#each section.items as item (item.key)}
|
|
118
|
+
<button
|
|
119
|
+
type="button"
|
|
120
|
+
role="menuitemradio"
|
|
121
|
+
class="ink-select-item ink-menu-item"
|
|
122
|
+
data-ink-select-item=""
|
|
123
|
+
tabindex={-1}
|
|
124
|
+
aria-checked={item.checked}
|
|
125
|
+
disabled={section.disabled}
|
|
126
|
+
data-state={item.checked ? 'checked' : 'unchecked'}
|
|
127
|
+
onclick={() => style.set(item.patch)}
|
|
128
|
+
>
|
|
129
|
+
{item.label}
|
|
130
|
+
{#if item.checked}
|
|
131
|
+
<span class="ink-select-indicator"
|
|
132
|
+
><InkIcon icon={Check} size={16} /></span
|
|
133
|
+
>
|
|
134
|
+
{/if}
|
|
135
|
+
</button>
|
|
136
|
+
{/each}
|
|
137
|
+
</div>
|
|
138
|
+
{/each}
|
|
139
|
+
</Popover.Content>
|
|
140
|
+
</Popover.Portal>
|
|
141
|
+
</Popover.Root>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { HTMLButtonAttributes } from 'svelte/elements';
|
|
3
|
+
/**
|
|
4
|
+
* Line weight, solid or dashed, and arrowheads, for the selection or the active tool. Each
|
|
5
|
+
* section disables when nothing selected (or no active tool) supports its props. The
|
|
6
|
+
* trigger carries `data-mixed` when the selection disagrees on any of them; a section with
|
|
7
|
+
* no single value shows no checkmark.
|
|
8
|
+
*/
|
|
9
|
+
export interface InkLineStyleMenuProps extends Omit<HTMLButtonAttributes, 'children'> {
|
|
10
|
+
children?: Snippet | undefined;
|
|
11
|
+
}
|
|
12
|
+
declare const InkLineStyleMenu: import("svelte").Component<InkLineStyleMenuProps, {}, "">;
|
|
13
|
+
type InkLineStyleMenu = ReturnType<typeof InkLineStyleMenu>;
|
|
14
|
+
export default InkLineStyleMenu;
|
|
15
|
+
//# sourceMappingURL=InkLineStyleMenu.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InkLineStyleMenu.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/InkLineStyleMenu.svelte.ts"],"names":[],"mappings":"AAGE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAA;AACrC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAA;AAE3D;;;;;GAKG;AACH,MAAM,WAAW,qBAAsB,SAAQ,IAAI,CAAC,oBAAoB,EAAE,UAAU,CAAC;IACnF,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;CAC/B;AAmGH,QAAA,MAAM,gBAAgB,2DAAwC,CAAC;AAC/D,KAAK,gBAAgB,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC5D,eAAe,gBAAgB,CAAC"}
|
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
InkError,
|
|
10
10
|
InkStatus,
|
|
11
11
|
PdfAssets,
|
|
12
|
+
SignatureStore,
|
|
12
13
|
} from '@inkbar/core'
|
|
13
|
-
import type { ToolId, ZoomValue } from '@inkbar/core/dom'
|
|
14
|
+
import type { DecorateAnnotation, Tool, ToolId, ZoomValue } from '@inkbar/core/dom'
|
|
14
15
|
import type { Snippet } from 'svelte'
|
|
15
16
|
import type { HTMLAttributes } from 'svelte/elements'
|
|
16
17
|
|
|
@@ -33,6 +34,31 @@
|
|
|
33
34
|
onChange?: ((change: AnnotationChange) => void) | undefined
|
|
34
35
|
tool?: ToolId | undefined
|
|
35
36
|
onToolChange?: ((tool: ToolId) => void) | undefined
|
|
37
|
+
/**
|
|
38
|
+
* Host tools, added to the built-ins; one with a built-in's id replaces it. Read when a
|
|
39
|
+
* document opens.
|
|
40
|
+
*/
|
|
41
|
+
tools?: Tool[] | undefined
|
|
42
|
+
/**
|
|
43
|
+
* Adds `data-*` attributes, classes and a screen-reader description to each annotation's
|
|
44
|
+
* element (see `DecorateAnnotation`). Decorations re-apply whenever the annotations change
|
|
45
|
+
* and when this prop changes, without rebuilding the viewer. Pass a new function when its
|
|
46
|
+
* output would change for any other reason.
|
|
47
|
+
*/
|
|
48
|
+
decorateAnnotation?: DecorateAnnotation | undefined
|
|
49
|
+
/**
|
|
50
|
+
* The font families text boxes offer, replacing the PDF standard families
|
|
51
|
+
* (`FONT_FAMILIES`). Fonts beyond those are the PDF writer's to embed.
|
|
52
|
+
*/
|
|
53
|
+
fonts?: string[] | undefined
|
|
54
|
+
/**
|
|
55
|
+
* Where saved signatures live. Default: memory, gone on reload.
|
|
56
|
+
* `createLocalSignatureStore` keeps them in the browser; a host can keep them anywhere.
|
|
57
|
+
* A new store takes effect at once, for the menus and the `signature` tool alike.
|
|
58
|
+
*/
|
|
59
|
+
signatures?: SignatureStore | undefined
|
|
60
|
+
/** The handwriting fonts a typed signature offers; the host loads them. */
|
|
61
|
+
signatureFonts?: string[] | undefined
|
|
36
62
|
page?: number | undefined
|
|
37
63
|
onPageChange?: ((page: number) => void) | undefined
|
|
38
64
|
zoom?: ZoomValue | undefined
|
|
@@ -55,11 +81,19 @@
|
|
|
55
81
|
|
|
56
82
|
<script lang="ts">
|
|
57
83
|
import {
|
|
84
|
+
createMemorySignatureStore,
|
|
85
|
+
createSignatureLibrary,
|
|
58
86
|
createSnapshotHistory,
|
|
59
87
|
InkError as InkErrorClass,
|
|
60
88
|
openDocument,
|
|
61
89
|
} from '@inkbar/core'
|
|
62
|
-
import {
|
|
90
|
+
import {
|
|
91
|
+
createToolOptions,
|
|
92
|
+
cssVariableDefaults,
|
|
93
|
+
FONT_FAMILIES,
|
|
94
|
+
SIGNATURE_FONTS,
|
|
95
|
+
trackToolStyle,
|
|
96
|
+
} from '@inkbar/core/dom'
|
|
63
97
|
import { DEV } from 'esm-env'
|
|
64
98
|
import { untrack } from 'svelte'
|
|
65
99
|
import { createAttachmentKey } from 'svelte/attachments'
|
|
@@ -79,6 +113,11 @@
|
|
|
79
113
|
onChange,
|
|
80
114
|
tool = $bindable(),
|
|
81
115
|
onToolChange,
|
|
116
|
+
tools: hostTools,
|
|
117
|
+
decorateAnnotation,
|
|
118
|
+
fonts,
|
|
119
|
+
signatures: signatureStore,
|
|
120
|
+
signatureFonts,
|
|
82
121
|
page = $bindable(),
|
|
83
122
|
onPageChange,
|
|
84
123
|
zoom = $bindable(),
|
|
@@ -95,6 +134,15 @@
|
|
|
95
134
|
|
|
96
135
|
type TestHookElement = HTMLElement & { __inkDocument?: InkDocument | undefined }
|
|
97
136
|
|
|
137
|
+
const signatures = $derived(
|
|
138
|
+
createSignatureLibrary(signatureStore ?? createMemorySignatureStore())
|
|
139
|
+
)
|
|
140
|
+
$effect(() => {
|
|
141
|
+
void signatures.refresh()
|
|
142
|
+
})
|
|
143
|
+
/** Tool options last as long as the root; the tool style is per document. */
|
|
144
|
+
const toolOptions = createToolOptions()
|
|
145
|
+
|
|
98
146
|
const IDLE: InkStatus = { state: 'idle' }
|
|
99
147
|
const NO_ANNOTATIONS: readonly Annotation[] = []
|
|
100
148
|
const NO_IDS: readonly string[] = []
|
|
@@ -130,7 +178,7 @@
|
|
|
130
178
|
() => document?.annotations.selection,
|
|
131
179
|
NO_IDS
|
|
132
180
|
)
|
|
133
|
-
const currentTool = $derived<ToolId>(tool ?? '
|
|
181
|
+
const currentTool = $derived<ToolId>(tool ?? 'select-text')
|
|
134
182
|
|
|
135
183
|
// What the next open will do follows the prop; the open document's mode is fixed.
|
|
136
184
|
const controlledProp = $derived(annotations !== undefined)
|
|
@@ -239,6 +287,8 @@
|
|
|
239
287
|
})
|
|
240
288
|
|
|
241
289
|
function setTool(id: ToolId): void {
|
|
290
|
+
// Picking the active tool again starts it afresh, as after a one-shot tool's use.
|
|
291
|
+
if (currentTool === id && tools?.active.get() === id) tools.set(id)
|
|
242
292
|
tool = id
|
|
243
293
|
onToolChange?.(id)
|
|
244
294
|
}
|
|
@@ -277,6 +327,24 @@
|
|
|
277
327
|
},
|
|
278
328
|
}
|
|
279
329
|
|
|
330
|
+
/** The document's tool style; it batches through `inkHistory`, whichever mode is on. */
|
|
331
|
+
const styleTracker = $derived.by(() => {
|
|
332
|
+
const doc = document
|
|
333
|
+
if (!doc) return null
|
|
334
|
+
return untrack(() =>
|
|
335
|
+
trackToolStyle({
|
|
336
|
+
store: doc.annotations,
|
|
337
|
+
history: { batch: (fn) => inkHistory.batch(fn) },
|
|
338
|
+
tools: hostTools,
|
|
339
|
+
tool: currentTool,
|
|
340
|
+
})
|
|
341
|
+
)
|
|
342
|
+
})
|
|
343
|
+
$effect(() => {
|
|
344
|
+
const id = currentTool
|
|
345
|
+
styleTracker?.setTool(id)
|
|
346
|
+
})
|
|
347
|
+
|
|
280
348
|
const context: InkContext = {
|
|
281
349
|
get assets() {
|
|
282
350
|
return assets
|
|
@@ -303,6 +371,25 @@
|
|
|
303
371
|
return currentTool
|
|
304
372
|
},
|
|
305
373
|
setTool,
|
|
374
|
+
get hostTools() {
|
|
375
|
+
return hostTools
|
|
376
|
+
},
|
|
377
|
+
get decorateAnnotation() {
|
|
378
|
+
return decorateAnnotation
|
|
379
|
+
},
|
|
380
|
+
get fonts() {
|
|
381
|
+
return fonts ?? FONT_FAMILIES
|
|
382
|
+
},
|
|
383
|
+
toolOptions,
|
|
384
|
+
get signatures() {
|
|
385
|
+
return signatures
|
|
386
|
+
},
|
|
387
|
+
get signatureFonts() {
|
|
388
|
+
return signatureFonts ?? SIGNATURE_FONTS
|
|
389
|
+
},
|
|
390
|
+
get toolStyle() {
|
|
391
|
+
return styleTracker?.toolStyle ?? null
|
|
392
|
+
},
|
|
306
393
|
get zoomModel() {
|
|
307
394
|
return zoom
|
|
308
395
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ChildSnippet } from './child-snippet.js';
|
|
2
|
-
import type { Annotation, AnnotationChange, AnnotationDefaults, DocumentSource, InkDocument, InkError, InkStatus, PdfAssets } from '@inkbar/core';
|
|
3
|
-
import type { ToolId, ZoomValue } from '@inkbar/core/dom';
|
|
2
|
+
import type { Annotation, AnnotationChange, AnnotationDefaults, DocumentSource, InkDocument, InkError, InkStatus, PdfAssets, SignatureStore } from '@inkbar/core';
|
|
3
|
+
import type { DecorateAnnotation, Tool, ToolId, ZoomValue } from '@inkbar/core/dom';
|
|
4
4
|
import type { Snippet } from 'svelte';
|
|
5
5
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
6
6
|
export interface InkRootProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children' | 'onchange' | 'onerror'> {
|
|
@@ -19,6 +19,31 @@ export interface InkRootProps extends Omit<HTMLAttributes<HTMLDivElement>, 'chil
|
|
|
19
19
|
onChange?: ((change: AnnotationChange) => void) | undefined;
|
|
20
20
|
tool?: ToolId | undefined;
|
|
21
21
|
onToolChange?: ((tool: ToolId) => void) | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* Host tools, added to the built-ins; one with a built-in's id replaces it. Read when a
|
|
24
|
+
* document opens.
|
|
25
|
+
*/
|
|
26
|
+
tools?: Tool[] | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* Adds `data-*` attributes, classes and a screen-reader description to each annotation's
|
|
29
|
+
* element (see `DecorateAnnotation`). Decorations re-apply whenever the annotations change
|
|
30
|
+
* and when this prop changes, without rebuilding the viewer. Pass a new function when its
|
|
31
|
+
* output would change for any other reason.
|
|
32
|
+
*/
|
|
33
|
+
decorateAnnotation?: DecorateAnnotation | undefined;
|
|
34
|
+
/**
|
|
35
|
+
* The font families text boxes offer, replacing the PDF standard families
|
|
36
|
+
* (`FONT_FAMILIES`). Fonts beyond those are the PDF writer's to embed.
|
|
37
|
+
*/
|
|
38
|
+
fonts?: string[] | undefined;
|
|
39
|
+
/**
|
|
40
|
+
* Where saved signatures live. Default: memory, gone on reload.
|
|
41
|
+
* `createLocalSignatureStore` keeps them in the browser; a host can keep them anywhere.
|
|
42
|
+
* A new store takes effect at once, for the menus and the `signature` tool alike.
|
|
43
|
+
*/
|
|
44
|
+
signatures?: SignatureStore | undefined;
|
|
45
|
+
/** The handwriting fonts a typed signature offers; the host loads them. */
|
|
46
|
+
signatureFonts?: string[] | undefined;
|
|
22
47
|
page?: number | undefined;
|
|
23
48
|
onPageChange?: ((page: number) => void) | undefined;
|
|
24
49
|
zoom?: ZoomValue | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InkRoot.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/InkRoot.svelte.ts"],"names":[],"mappings":"AAGE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACtD,OAAO,KAAK,EACV,UAAU,EACV,gBAAgB,EAChB,kBAAkB,EAClB,cAAc,EACd,WAAW,EACX,QAAQ,EACR,SAAS,EACT,SAAS,
|
|
1
|
+
{"version":3,"file":"InkRoot.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/InkRoot.svelte.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte'
|
|
3
|
+
import type { HTMLAttributes } from 'svelte/elements'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A split button for the shape tool. The main part activates the tool with the current
|
|
7
|
+
* kind and draws that kind's icon; the chevron opens a two-column grid of kinds. Choosing
|
|
8
|
+
* a kind switches to the tool with it.
|
|
9
|
+
*/
|
|
10
|
+
export interface InkShapeMenuProps extends Omit<
|
|
11
|
+
HTMLAttributes<HTMLDivElement>,
|
|
12
|
+
'children'
|
|
13
|
+
> {
|
|
14
|
+
/** Replaces the main button's icon. */
|
|
15
|
+
children?: Snippet | undefined
|
|
16
|
+
}
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<script lang="ts">
|
|
20
|
+
import {
|
|
21
|
+
focusInitialMenuItem,
|
|
22
|
+
handleMenuKeys,
|
|
23
|
+
menuItems,
|
|
24
|
+
SHAPE_COLUMNS,
|
|
25
|
+
SHAPE_ICONS,
|
|
26
|
+
SHAPE_KINDS,
|
|
27
|
+
shapeMenuModel,
|
|
28
|
+
type ShapeKind,
|
|
29
|
+
type ShapeOptions,
|
|
30
|
+
} from '@inkbar/core/dom'
|
|
31
|
+
import { ChevronDown } from '@inkbar/icons'
|
|
32
|
+
import { Popover, Toolbar } from 'bits-ui'
|
|
33
|
+
|
|
34
|
+
import { useTool } from '../hooks/useTool.svelte.js'
|
|
35
|
+
import { useToolOptions } from '../hooks/useToolOptions.svelte.js'
|
|
36
|
+
|
|
37
|
+
import InkIcon from './InkIcon.svelte'
|
|
38
|
+
|
|
39
|
+
let { class: className, children, ...rest }: InkShapeMenuProps = $props()
|
|
40
|
+
|
|
41
|
+
const current = useTool()
|
|
42
|
+
const shape = useToolOptions<ShapeOptions>('shape')
|
|
43
|
+
let open = $state(false)
|
|
44
|
+
/** The split button: the panel lines up under it rather than the chevron. */
|
|
45
|
+
let group = $state<HTMLElement | null>(null)
|
|
46
|
+
|
|
47
|
+
const model = $derived(shapeMenuModel(shape.options, SHAPE_KINDS))
|
|
48
|
+
const active = $derived(current.tool === 'shape')
|
|
49
|
+
|
|
50
|
+
let menu = $state<HTMLElement | null>(null)
|
|
51
|
+
|
|
52
|
+
/** ArrowDown opens on the first item; a click opens on the checked one. */
|
|
53
|
+
let focusFirst = false
|
|
54
|
+
// Bits runs the open-focus callback more than once, so the flag outlives it; reset on close.
|
|
55
|
+
$effect(() => {
|
|
56
|
+
if (!open) focusFirst = false
|
|
57
|
+
})
|
|
58
|
+
function onTriggerKeydown(e: KeyboardEvent): void {
|
|
59
|
+
if (e.key !== 'ArrowDown' || e.defaultPrevented || open) return
|
|
60
|
+
e.preventDefault()
|
|
61
|
+
focusFirst = true
|
|
62
|
+
open = true
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function choose(kind: ShapeKind): void {
|
|
66
|
+
shape.setOptions({ kind })
|
|
67
|
+
current.setTool('shape')
|
|
68
|
+
open = false
|
|
69
|
+
}
|
|
70
|
+
</script>
|
|
71
|
+
|
|
72
|
+
<div
|
|
73
|
+
bind:this={group}
|
|
74
|
+
role="group"
|
|
75
|
+
aria-label="Shape"
|
|
76
|
+
class={['ink-split-button ink-shape-menu', className]}
|
|
77
|
+
data-ink-shape-menu=""
|
|
78
|
+
{...rest}
|
|
79
|
+
>
|
|
80
|
+
<Toolbar.Button
|
|
81
|
+
class="ink-tool-button ink-shape-button"
|
|
82
|
+
data-ink-tool-button=""
|
|
83
|
+
data-ink-shape-button=""
|
|
84
|
+
data-tool="shape"
|
|
85
|
+
data-kind={model.kind}
|
|
86
|
+
data-state={active ? 'on' : 'off'}
|
|
87
|
+
aria-pressed={active}
|
|
88
|
+
aria-label={model.label}
|
|
89
|
+
title={model.label}
|
|
90
|
+
onclick={() => current.setTool('shape')}
|
|
91
|
+
>
|
|
92
|
+
{#if children}{@render children()}{:else}<InkIcon
|
|
93
|
+
icon={SHAPE_ICONS[model.kind]}
|
|
94
|
+
/>{/if}
|
|
95
|
+
</Toolbar.Button>
|
|
96
|
+
<Popover.Root bind:open>
|
|
97
|
+
<Popover.Trigger>
|
|
98
|
+
{#snippet child({ props })}
|
|
99
|
+
<Toolbar.Button
|
|
100
|
+
{...props}
|
|
101
|
+
class="ink-menu-trigger ink-shape-menu-trigger"
|
|
102
|
+
data-ink-shape-menu-trigger=""
|
|
103
|
+
data-state={open ? 'open' : 'closed'}
|
|
104
|
+
aria-label="Choose shape"
|
|
105
|
+
title="Choose shape"
|
|
106
|
+
aria-haspopup="menu"
|
|
107
|
+
onkeydown={onTriggerKeydown}
|
|
108
|
+
>
|
|
109
|
+
<InkIcon icon={ChevronDown} />
|
|
110
|
+
</Toolbar.Button>
|
|
111
|
+
{/snippet}
|
|
112
|
+
</Popover.Trigger>
|
|
113
|
+
<Popover.Portal>
|
|
114
|
+
<Popover.Content
|
|
115
|
+
bind:ref={menu}
|
|
116
|
+
role="menu"
|
|
117
|
+
aria-label="Shapes"
|
|
118
|
+
class="ink-select-content ink-menu-content"
|
|
119
|
+
data-ink-select-content=""
|
|
120
|
+
data-ink-menu="shape"
|
|
121
|
+
customAnchor={group}
|
|
122
|
+
side="bottom"
|
|
123
|
+
align="start"
|
|
124
|
+
sideOffset={4}
|
|
125
|
+
collisionPadding={8}
|
|
126
|
+
onOpenAutoFocus={(e) => {
|
|
127
|
+
e.preventDefault()
|
|
128
|
+
if (menu) {
|
|
129
|
+
if (focusFirst) menuItems(menu)[0]?.focus({ preventScroll: true })
|
|
130
|
+
else focusInitialMenuItem(menu)
|
|
131
|
+
}
|
|
132
|
+
}}
|
|
133
|
+
onkeydown={(e) => menu && handleMenuKeys(e, menu)}
|
|
134
|
+
>
|
|
135
|
+
<div
|
|
136
|
+
role="group"
|
|
137
|
+
aria-label="Shapes"
|
|
138
|
+
class="ink-shape-grid"
|
|
139
|
+
data-ink-menu-columns={SHAPE_COLUMNS}
|
|
140
|
+
>
|
|
141
|
+
{#each model.items as item (item.kind)}
|
|
142
|
+
<button
|
|
143
|
+
type="button"
|
|
144
|
+
role="menuitemradio"
|
|
145
|
+
class="ink-select-item ink-menu-item ink-shape-item"
|
|
146
|
+
data-ink-select-item=""
|
|
147
|
+
tabindex={-1}
|
|
148
|
+
data-key={item.kind}
|
|
149
|
+
aria-checked={item.checked}
|
|
150
|
+
data-state={item.checked ? 'checked' : 'unchecked'}
|
|
151
|
+
onclick={() => choose(item.kind)}
|
|
152
|
+
>
|
|
153
|
+
<InkIcon icon={SHAPE_ICONS[item.kind]} size={16} />
|
|
154
|
+
{item.label}
|
|
155
|
+
</button>
|
|
156
|
+
{/each}
|
|
157
|
+
</div>
|
|
158
|
+
</Popover.Content>
|
|
159
|
+
</Popover.Portal>
|
|
160
|
+
</Popover.Root>
|
|
161
|
+
</div>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
+
/**
|
|
4
|
+
* A split button for the shape tool. The main part activates the tool with the current
|
|
5
|
+
* kind and draws that kind's icon; the chevron opens a two-column grid of kinds. Choosing
|
|
6
|
+
* a kind switches to the tool with it.
|
|
7
|
+
*/
|
|
8
|
+
export interface InkShapeMenuProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {
|
|
9
|
+
/** Replaces the main button's icon. */
|
|
10
|
+
children?: Snippet | undefined;
|
|
11
|
+
}
|
|
12
|
+
declare const InkShapeMenu: import("svelte").Component<InkShapeMenuProps, {}, "">;
|
|
13
|
+
type InkShapeMenu = ReturnType<typeof InkShapeMenu>;
|
|
14
|
+
export default InkShapeMenu;
|
|
15
|
+
//# sourceMappingURL=InkShapeMenu.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InkShapeMenu.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/InkShapeMenu.svelte.ts"],"names":[],"mappings":"AAGE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAA;AACrC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAErD;;;;GAIG;AACH,MAAM,WAAW,iBAAkB,SAAQ,IAAI,CAC7C,cAAc,CAAC,cAAc,CAAC,EAC9B,UAAU,CACX;IACC,uCAAuC;IACvC,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;CAC/B;AAsGH,QAAA,MAAM,YAAY,uDAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
import type { SignatureTemplate } from '@inkbar/core'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* "Create signature": a modal with Draw, Type and Image tabs. Draw is a pad with the draw
|
|
6
|
+
* tool's renderer; Type sets a name in one of the host's handwriting fonts; Image takes a PNG
|
|
7
|
+
* or JPEG scan. Save stores the template through InkRoot's signature store and selects it
|
|
8
|
+
* for the `signature` tool. Escape, Cancel or a press outside closes it.
|
|
9
|
+
*/
|
|
10
|
+
export interface InkSignatureDialogProps {
|
|
11
|
+
open?: boolean
|
|
12
|
+
onOpenChange?: ((open: boolean) => void) | undefined
|
|
13
|
+
/** The fonts the Type tab offers. Default: InkRoot's `signatureFonts`. */
|
|
14
|
+
fonts?: readonly string[] | undefined
|
|
15
|
+
/** Called with the new template once it is saved and selected. */
|
|
16
|
+
onSave?: ((template: SignatureTemplate) => void) | undefined
|
|
17
|
+
/** Where focus goes on close; by default, back to what had it before. */
|
|
18
|
+
onCloseAutoFocus?: ((event: Event) => void) | undefined
|
|
19
|
+
class?: string | undefined
|
|
20
|
+
}
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<script lang="ts">
|
|
24
|
+
import { SIGNATURE_LABELS } from '@inkbar/core/dom'
|
|
25
|
+
import { Dialog } from 'bits-ui'
|
|
26
|
+
|
|
27
|
+
import SignatureForm from './SignatureForm.svelte'
|
|
28
|
+
|
|
29
|
+
let {
|
|
30
|
+
open = $bindable(false),
|
|
31
|
+
onOpenChange,
|
|
32
|
+
fonts,
|
|
33
|
+
onSave,
|
|
34
|
+
onCloseAutoFocus,
|
|
35
|
+
class: className,
|
|
36
|
+
}: InkSignatureDialogProps = $props()
|
|
37
|
+
|
|
38
|
+
let content = $state<HTMLElement | null>(null)
|
|
39
|
+
|
|
40
|
+
function setOpen(next: boolean): void {
|
|
41
|
+
open = next
|
|
42
|
+
onOpenChange?.(next)
|
|
43
|
+
}
|
|
44
|
+
</script>
|
|
45
|
+
|
|
46
|
+
<Dialog.Root bind:open={() => open, setOpen}>
|
|
47
|
+
<Dialog.Portal>
|
|
48
|
+
<Dialog.Overlay class="ink-dialog-overlay" data-ink-dialog-overlay="" />
|
|
49
|
+
<Dialog.Content
|
|
50
|
+
bind:ref={content}
|
|
51
|
+
class={['ink-dialog ink-signature-dialog', className]}
|
|
52
|
+
data-ink-signature-dialog=""
|
|
53
|
+
aria-modal="true"
|
|
54
|
+
onOpenAutoFocus={(e) => {
|
|
55
|
+
e.preventDefault()
|
|
56
|
+
content
|
|
57
|
+
?.querySelector<HTMLElement>('[role="tab"][aria-selected="true"]')
|
|
58
|
+
?.focus({ preventScroll: true })
|
|
59
|
+
}}
|
|
60
|
+
onCloseAutoFocus={(e) => onCloseAutoFocus?.(e)}
|
|
61
|
+
>
|
|
62
|
+
<Dialog.Title class="ink-dialog-title">{SIGNATURE_LABELS.dialog}</Dialog.Title>
|
|
63
|
+
<SignatureForm
|
|
64
|
+
{fonts}
|
|
65
|
+
onSaved={(t) => onSave?.(t)}
|
|
66
|
+
onClose={() => setOpen(false)}
|
|
67
|
+
/>
|
|
68
|
+
</Dialog.Content>
|
|
69
|
+
</Dialog.Portal>
|
|
70
|
+
</Dialog.Root>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { SignatureTemplate } from '@inkbar/core';
|
|
2
|
+
/**
|
|
3
|
+
* "Create signature": a modal with Draw, Type and Image tabs. Draw is a pad with the draw
|
|
4
|
+
* tool's renderer; Type sets a name in one of the host's handwriting fonts; Image takes a PNG
|
|
5
|
+
* or JPEG scan. Save stores the template through InkRoot's signature store and selects it
|
|
6
|
+
* for the `signature` tool. Escape, Cancel or a press outside closes it.
|
|
7
|
+
*/
|
|
8
|
+
export interface InkSignatureDialogProps {
|
|
9
|
+
open?: boolean;
|
|
10
|
+
onOpenChange?: ((open: boolean) => void) | undefined;
|
|
11
|
+
/** The fonts the Type tab offers. Default: InkRoot's `signatureFonts`. */
|
|
12
|
+
fonts?: readonly string[] | undefined;
|
|
13
|
+
/** Called with the new template once it is saved and selected. */
|
|
14
|
+
onSave?: ((template: SignatureTemplate) => void) | undefined;
|
|
15
|
+
/** Where focus goes on close; by default, back to what had it before. */
|
|
16
|
+
onCloseAutoFocus?: ((event: Event) => void) | undefined;
|
|
17
|
+
class?: string | undefined;
|
|
18
|
+
}
|
|
19
|
+
declare const InkSignatureDialog: import("svelte").Component<InkSignatureDialogProps, {}, "open">;
|
|
20
|
+
type InkSignatureDialog = ReturnType<typeof InkSignatureDialog>;
|
|
21
|
+
export default InkSignatureDialog;
|
|
22
|
+
//# sourceMappingURL=InkSignatureDialog.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InkSignatureDialog.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/InkSignatureDialog.svelte.ts"],"names":[],"mappings":"AAGE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAErD;;;;;GAKG;AACH,MAAM,WAAW,uBAAuB;IACtC,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,YAAY,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC,GAAG,SAAS,CAAA;IACpD,0EAA0E;IAC1E,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAA;IACrC,kEAAkE;IAClE,MAAM,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,iBAAiB,KAAK,IAAI,CAAC,GAAG,SAAS,CAAA;IAC5D,yEAAyE;IACzE,gBAAgB,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC,GAAG,SAAS,CAAA;IACvD,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAC3B;AAkDH,QAAA,MAAM,kBAAkB,iEAAwC,CAAC;AACjE,KAAK,kBAAkB,GAAG,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAChE,eAAe,kBAAkB,CAAC"}
|