@inkbar/svelte 0.4.0 → 0.6.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 +23 -7
- package/dist/components/InkAnnotation.svelte +0 -12
- package/dist/components/InkAnnotation.svelte.d.ts.map +1 -1
- package/dist/components/InkColorMenu.svelte +13 -19
- package/dist/components/InkColorMenu.svelte.d.ts +2 -0
- package/dist/components/InkColorMenu.svelte.d.ts.map +1 -1
- package/dist/components/InkCommand.svelte +63 -0
- package/dist/components/InkCommand.svelte.d.ts +17 -0
- package/dist/components/InkCommand.svelte.d.ts.map +1 -0
- package/dist/components/InkHighlightMenu.svelte +15 -13
- package/dist/components/InkLineStyleMenu.svelte +7 -17
- package/dist/components/InkLineStyleMenu.svelte.d.ts.map +1 -1
- package/dist/components/InkRoot.svelte +111 -3
- package/dist/components/InkRoot.svelte.d.ts +14 -1
- package/dist/components/InkRoot.svelte.d.ts.map +1 -1
- package/dist/components/InkShapeMenu.svelte +10 -13
- package/dist/components/InkShapeMenu.svelte.d.ts.map +1 -1
- package/dist/components/InkSignatureMenu.svelte +10 -13
- package/dist/components/InkSignatureMenu.svelte.d.ts.map +1 -1
- package/dist/components/InkThreadPopover.svelte +7 -0
- package/dist/components/InkThreadPopover.svelte.d.ts.map +1 -1
- package/dist/components/InkToolButton.svelte +11 -3
- package/dist/components/InkToolButton.svelte.d.ts.map +1 -1
- package/dist/components/InkViewport.svelte +32 -2
- package/dist/components/InkViewport.svelte.d.ts.map +1 -1
- package/dist/components/menu-open-focus.d.ts +12 -0
- package/dist/components/menu-open-focus.d.ts.map +1 -0
- package/dist/components/menu-open-focus.js +35 -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 +22 -4
- package/dist/context.d.ts.map +1 -1
- package/dist/hooks/useAnnotations.svelte.d.ts +795 -1258
- package/dist/hooks/useAnnotations.svelte.d.ts.map +1 -1
- package/dist/hooks/useAnnotations.svelte.js +1 -7
- package/dist/hooks/useCommand.svelte.d.ts +23 -0
- package/dist/hooks/useCommand.svelte.d.ts.map +1 -0
- package/dist/hooks/useCommand.svelte.js +44 -0
- package/dist/index.d.ts +6 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/package.json +5 -5
- 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
|
@@ -11,7 +11,13 @@
|
|
|
11
11
|
PdfAssets,
|
|
12
12
|
SignatureStore,
|
|
13
13
|
} from '@inkbar/core'
|
|
14
|
-
import type {
|
|
14
|
+
import type {
|
|
15
|
+
DecorateAnnotation,
|
|
16
|
+
InkPlugin,
|
|
17
|
+
Tool,
|
|
18
|
+
ToolId,
|
|
19
|
+
ZoomValue,
|
|
20
|
+
} from '@inkbar/core/dom'
|
|
15
21
|
import type { Snippet } from 'svelte'
|
|
16
22
|
import type { HTMLAttributes } from 'svelte/elements'
|
|
17
23
|
|
|
@@ -39,6 +45,19 @@
|
|
|
39
45
|
* document opens.
|
|
40
46
|
*/
|
|
41
47
|
tools?: Tool[] | undefined
|
|
48
|
+
/**
|
|
49
|
+
* Plugins, set up once when the root is created; a later change to this prop is not
|
|
50
|
+
* applied. Their tools join `tools`, their decoration and page layers apply to every
|
|
51
|
+
* document, and their commands are placed with `InkCommand` or `useCommand`.
|
|
52
|
+
*/
|
|
53
|
+
plugins?: InkPlugin[] | undefined
|
|
54
|
+
/**
|
|
55
|
+
* Adds `data-*` attributes, classes and a screen-reader description to each annotation's
|
|
56
|
+
* element (see `DecorateAnnotation`). Decorations re-apply whenever the annotations change
|
|
57
|
+
* and when this prop changes, without rebuilding the viewer. Pass a new function when its
|
|
58
|
+
* output would change for any other reason.
|
|
59
|
+
*/
|
|
60
|
+
decorateAnnotation?: DecorateAnnotation | undefined
|
|
42
61
|
/**
|
|
43
62
|
* The font families text boxes offer, replacing the PDF standard families
|
|
44
63
|
* (`FONT_FAMILIES`). Fonts beyond those are the PDF writer's to embed.
|
|
@@ -79,8 +98,11 @@
|
|
|
79
98
|
createSnapshotHistory,
|
|
80
99
|
InkError as InkErrorClass,
|
|
81
100
|
openDocument,
|
|
101
|
+
readonly,
|
|
102
|
+
writable,
|
|
82
103
|
} from '@inkbar/core'
|
|
83
104
|
import {
|
|
105
|
+
createPluginHost,
|
|
84
106
|
createToolOptions,
|
|
85
107
|
cssVariableDefaults,
|
|
86
108
|
FONT_FAMILIES,
|
|
@@ -94,7 +116,8 @@
|
|
|
94
116
|
import { setInkContext, type InkContext, type InkHistory } from '../context.js'
|
|
95
117
|
import { useReadable } from '../use-readable.svelte.js'
|
|
96
118
|
|
|
97
|
-
import type {
|
|
119
|
+
import type { PluginHistory } from '@inkbar/core'
|
|
120
|
+
import type { PluginHost, ToolController, Viewport } from '@inkbar/core/dom'
|
|
98
121
|
|
|
99
122
|
let {
|
|
100
123
|
src,
|
|
@@ -107,6 +130,8 @@
|
|
|
107
130
|
tool = $bindable(),
|
|
108
131
|
onToolChange,
|
|
109
132
|
tools: hostTools,
|
|
133
|
+
plugins,
|
|
134
|
+
decorateAnnotation,
|
|
110
135
|
fonts,
|
|
111
136
|
signatures: signatureStore,
|
|
112
137
|
signatureFonts,
|
|
@@ -138,6 +163,7 @@
|
|
|
138
163
|
const IDLE: InkStatus = { state: 'idle' }
|
|
139
164
|
const NO_ANNOTATIONS: readonly Annotation[] = []
|
|
140
165
|
const NO_IDS: readonly string[] = []
|
|
166
|
+
const noop = (): void => undefined
|
|
141
167
|
|
|
142
168
|
/** Signed URLs change; the key does not. Bytes and Blobs are their own identity. */
|
|
143
169
|
function identity(source: DocumentSource | null): unknown {
|
|
@@ -152,6 +178,8 @@
|
|
|
152
178
|
}
|
|
153
179
|
|
|
154
180
|
let document = $state.raw<InkDocument | null>(null)
|
|
181
|
+
/** The same document outside the reactive graph, for the plugins' history. */
|
|
182
|
+
let documentNow: InkDocument | null = null
|
|
155
183
|
/** Overrides the document's status while opening, and when opening itself failed. */
|
|
156
184
|
let override = $state.raw<InkStatus | null>(null)
|
|
157
185
|
let activated = $state<string | null>(null)
|
|
@@ -198,6 +226,8 @@
|
|
|
198
226
|
const pw = sourcePassword
|
|
199
227
|
let cancelled = false
|
|
200
228
|
let opened: InkDocument | null = null
|
|
229
|
+
/** The snapshot history's hold on a controlled document's store. */
|
|
230
|
+
let detach: () => void = noop
|
|
201
231
|
untrack(() => snapshotHistory.clear())
|
|
202
232
|
const source = untrack(() => src)
|
|
203
233
|
if (source === null) {
|
|
@@ -241,7 +271,13 @@
|
|
|
241
271
|
const current = untrack(() => annotations)
|
|
242
272
|
if (doc.annotations.mode === 'controlled' && current !== undefined)
|
|
243
273
|
doc.annotations.setControlledValue(current)
|
|
274
|
+
documentNow = doc
|
|
244
275
|
document = doc
|
|
276
|
+
// Controlled edits run the plugins' reactions inside their own snapshot step.
|
|
277
|
+
if (doc.annotations.mode === 'controlled')
|
|
278
|
+
detach = snapshotHistory.attach(doc.annotations)
|
|
279
|
+
// The document is current, so the host reads its history when it hears of it.
|
|
280
|
+
hostDocument.set(doc)
|
|
245
281
|
override = null
|
|
246
282
|
setTestHook(ref, doc)
|
|
247
283
|
const s = doc.status.get()
|
|
@@ -264,7 +300,11 @@
|
|
|
264
300
|
})()
|
|
265
301
|
return () => {
|
|
266
302
|
cancelled = true
|
|
303
|
+
// Cleared first, so the plugins close their stores while the document is still alive.
|
|
304
|
+
hostDocument.set(null)
|
|
305
|
+
detach()
|
|
267
306
|
opened?.destroy()
|
|
307
|
+
documentNow = null
|
|
268
308
|
document = null
|
|
269
309
|
setTestHook(ref, undefined)
|
|
270
310
|
}
|
|
@@ -279,12 +319,15 @@
|
|
|
279
319
|
})
|
|
280
320
|
|
|
281
321
|
function setTool(id: ToolId): void {
|
|
322
|
+
// Picking the active tool again starts it afresh, as after a one-shot tool's use.
|
|
323
|
+
if (currentTool === id && tools?.active.get() === id) tools.set(id)
|
|
282
324
|
tool = id
|
|
283
325
|
onToolChange?.(id)
|
|
284
326
|
}
|
|
285
327
|
function setActivated(id: string | null): void {
|
|
286
328
|
activated = id
|
|
287
329
|
activatedNow = id
|
|
330
|
+
hostActivated.set(id)
|
|
288
331
|
if (id) onActivate?.(id)
|
|
289
332
|
}
|
|
290
333
|
function reportZoom(z: ZoomValue): void {
|
|
@@ -315,8 +358,65 @@
|
|
|
315
358
|
else if (document) document.history.batch(fn)
|
|
316
359
|
else fn()
|
|
317
360
|
},
|
|
361
|
+
track: (store) => pluginHistory.track(store),
|
|
362
|
+
react: (fn) => pluginHistory.react(fn),
|
|
318
363
|
}
|
|
319
364
|
|
|
365
|
+
/**
|
|
366
|
+
* The history the plugins reach, picked by the open document's mode when they call. The host
|
|
367
|
+
* reads it as soon as a document opens, so it goes by `documentNow`, which is set by then.
|
|
368
|
+
*/
|
|
369
|
+
const activeHistory = (): PluginHistory | undefined => {
|
|
370
|
+
const doc = documentNow
|
|
371
|
+
if (!doc) return undefined
|
|
372
|
+
return doc.annotations.mode === 'controlled' ? snapshotHistory : doc.history
|
|
373
|
+
}
|
|
374
|
+
const pluginHistory: PluginHistory = {
|
|
375
|
+
batch: (fn) => {
|
|
376
|
+
const h = activeHistory()
|
|
377
|
+
if (h) h.batch(fn)
|
|
378
|
+
else fn()
|
|
379
|
+
},
|
|
380
|
+
track: (store) => activeHistory()?.track(store) ?? noop,
|
|
381
|
+
react: (fn) => activeHistory()?.react(fn) ?? noop,
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/*
|
|
385
|
+
* One plugin host for the root's life, built in an effect so that no `setup` runs on the
|
|
386
|
+
* server, where effects never run and nothing would clean it up. Until then `pluginHost` is
|
|
387
|
+
* null and InkCommand renders its command disabled. The open effect above runs first, but
|
|
388
|
+
* the document it opens arrives after an await, so the host is in place by then. It follows
|
|
389
|
+
* these writables rather than the root's state: the open effect sets `hostDocument` once
|
|
390
|
+
* `documentNow` is current.
|
|
391
|
+
*/
|
|
392
|
+
const hostDocument = writable<InkDocument | null>(null)
|
|
393
|
+
const hostActivated = writable<string | null>(null)
|
|
394
|
+
const viewportEl = writable<HTMLElement | null>(null)
|
|
395
|
+
let pluginHost = $state.raw<PluginHost | null>(null)
|
|
396
|
+
$effect(() => {
|
|
397
|
+
const host = untrack(() =>
|
|
398
|
+
createPluginHost({
|
|
399
|
+
// Read once, as documented on the prop.
|
|
400
|
+
plugins: plugins ?? [],
|
|
401
|
+
document: readonly(hostDocument),
|
|
402
|
+
history: () => pluginHistory,
|
|
403
|
+
activated: readonly(hostActivated),
|
|
404
|
+
// As in `createViewer`: an id not in the open document is ignored.
|
|
405
|
+
setActivated: (id) => {
|
|
406
|
+
if (id === null || documentNow?.annotations.get(id)) setActivated(id)
|
|
407
|
+
},
|
|
408
|
+
root: readonly(viewportEl),
|
|
409
|
+
decorate: () => decorateAnnotation,
|
|
410
|
+
viewport: () => viewport,
|
|
411
|
+
})
|
|
412
|
+
)
|
|
413
|
+
pluginHost = host
|
|
414
|
+
// Destroyed after InkViewport's engine and its plugin layers, as in `createViewer`: Svelte
|
|
415
|
+
// creates a component's effects after its template and tears them down in creation order,
|
|
416
|
+
// so the children's teardowns run first.
|
|
417
|
+
return () => host.destroy()
|
|
418
|
+
})
|
|
419
|
+
|
|
320
420
|
/** The document's tool style; it batches through `inkHistory`, whichever mode is on. */
|
|
321
421
|
const styleTracker = $derived.by(() => {
|
|
322
422
|
const doc = document
|
|
@@ -325,7 +425,8 @@
|
|
|
325
425
|
trackToolStyle({
|
|
326
426
|
store: doc.annotations,
|
|
327
427
|
history: { batch: (fn) => inkHistory.batch(fn) },
|
|
328
|
-
tools
|
|
428
|
+
// The plugins' tools too, so a plugin tool's style group applies.
|
|
429
|
+
tools: [...(hostTools ?? []), ...(pluginHost?.tools ?? [])],
|
|
329
430
|
tool: currentTool,
|
|
330
431
|
})
|
|
331
432
|
)
|
|
@@ -351,6 +452,10 @@
|
|
|
351
452
|
get selection() {
|
|
352
453
|
return selection.current
|
|
353
454
|
},
|
|
455
|
+
get pluginHost() {
|
|
456
|
+
return pluginHost
|
|
457
|
+
},
|
|
458
|
+
viewportEl,
|
|
354
459
|
get viewport() {
|
|
355
460
|
return viewport
|
|
356
461
|
},
|
|
@@ -364,6 +469,9 @@
|
|
|
364
469
|
get hostTools() {
|
|
365
470
|
return hostTools
|
|
366
471
|
},
|
|
472
|
+
get decorateAnnotation() {
|
|
473
|
+
return decorateAnnotation
|
|
474
|
+
},
|
|
367
475
|
get fonts() {
|
|
368
476
|
return fonts ?? FONT_FAMILIES
|
|
369
477
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ChildSnippet } from './child-snippet.js';
|
|
2
2
|
import type { Annotation, AnnotationChange, AnnotationDefaults, DocumentSource, InkDocument, InkError, InkStatus, PdfAssets, SignatureStore } from '@inkbar/core';
|
|
3
|
-
import type { Tool, ToolId, ZoomValue } from '@inkbar/core/dom';
|
|
3
|
+
import type { DecorateAnnotation, InkPlugin, 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'> {
|
|
@@ -24,6 +24,19 @@ export interface InkRootProps extends Omit<HTMLAttributes<HTMLDivElement>, 'chil
|
|
|
24
24
|
* document opens.
|
|
25
25
|
*/
|
|
26
26
|
tools?: Tool[] | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* Plugins, set up once when the root is created; a later change to this prop is not
|
|
29
|
+
* applied. Their tools join `tools`, their decoration and page layers apply to every
|
|
30
|
+
* document, and their commands are placed with `InkCommand` or `useCommand`.
|
|
31
|
+
*/
|
|
32
|
+
plugins?: InkPlugin[] | undefined;
|
|
33
|
+
/**
|
|
34
|
+
* Adds `data-*` attributes, classes and a screen-reader description to each annotation's
|
|
35
|
+
* element (see `DecorateAnnotation`). Decorations re-apply whenever the annotations change
|
|
36
|
+
* and when this prop changes, without rebuilding the viewer. Pass a new function when its
|
|
37
|
+
* output would change for any other reason.
|
|
38
|
+
*/
|
|
39
|
+
decorateAnnotation?: DecorateAnnotation | undefined;
|
|
27
40
|
/**
|
|
28
41
|
* The font families text boxes offer, replacing the PDF standard families
|
|
29
42
|
* (`FONT_FAMILIES`). Fonts beyond those are the PDF writer's to embed.
|
|
@@ -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,EACT,cAAc,EACf,MAAM,cAAc,CAAA;AACrB,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"InkRoot.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/InkRoot.svelte.ts"],"names":[],"mappings":"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"}
|
|
@@ -18,9 +18,7 @@
|
|
|
18
18
|
|
|
19
19
|
<script lang="ts">
|
|
20
20
|
import {
|
|
21
|
-
focusInitialMenuItem,
|
|
22
21
|
handleMenuKeys,
|
|
23
|
-
menuItems,
|
|
24
22
|
SHAPE_COLUMNS,
|
|
25
23
|
SHAPE_ICONS,
|
|
26
24
|
SHAPE_KINDS,
|
|
@@ -35,12 +33,15 @@
|
|
|
35
33
|
import { useToolOptions } from '../hooks/useToolOptions.svelte.js'
|
|
36
34
|
|
|
37
35
|
import InkIcon from './InkIcon.svelte'
|
|
36
|
+
import { createMenuOpenFocus } from './menu-open-focus.js'
|
|
38
37
|
|
|
39
38
|
let { class: className, children, ...rest }: InkShapeMenuProps = $props()
|
|
40
39
|
|
|
41
40
|
const current = useTool()
|
|
42
41
|
const shape = useToolOptions<ShapeOptions>('shape')
|
|
43
42
|
let open = $state(false)
|
|
43
|
+
/** The split button: the panel lines up under it rather than the chevron. */
|
|
44
|
+
let group = $state<HTMLElement | null>(null)
|
|
44
45
|
|
|
45
46
|
const model = $derived(shapeMenuModel(shape.options, SHAPE_KINDS))
|
|
46
47
|
const active = $derived(current.tool === 'shape')
|
|
@@ -48,15 +49,14 @@
|
|
|
48
49
|
let menu = $state<HTMLElement | null>(null)
|
|
49
50
|
|
|
50
51
|
/** ArrowDown opens on the first item; a click opens on the checked one. */
|
|
51
|
-
|
|
52
|
-
// Bits runs the open-focus callback more than once, so the flag outlives it; reset on close.
|
|
52
|
+
const openFocus = createMenuOpenFocus()
|
|
53
53
|
$effect(() => {
|
|
54
|
-
if (!open)
|
|
54
|
+
if (!open) openFocus.reset()
|
|
55
55
|
})
|
|
56
56
|
function onTriggerKeydown(e: KeyboardEvent): void {
|
|
57
57
|
if (e.key !== 'ArrowDown' || e.defaultPrevented || open) return
|
|
58
58
|
e.preventDefault()
|
|
59
|
-
|
|
59
|
+
openFocus.first()
|
|
60
60
|
open = true
|
|
61
61
|
}
|
|
62
62
|
|
|
@@ -68,6 +68,7 @@
|
|
|
68
68
|
</script>
|
|
69
69
|
|
|
70
70
|
<div
|
|
71
|
+
bind:this={group}
|
|
71
72
|
role="group"
|
|
72
73
|
aria-label="Shape"
|
|
73
74
|
class={['ink-split-button ink-shape-menu', className]}
|
|
@@ -115,17 +116,13 @@
|
|
|
115
116
|
class="ink-select-content ink-menu-content"
|
|
116
117
|
data-ink-select-content=""
|
|
117
118
|
data-ink-menu="shape"
|
|
119
|
+
customAnchor={group}
|
|
118
120
|
side="bottom"
|
|
119
121
|
align="start"
|
|
120
122
|
sideOffset={4}
|
|
121
123
|
collisionPadding={8}
|
|
122
|
-
onOpenAutoFocus={(e) =>
|
|
123
|
-
|
|
124
|
-
if (menu) {
|
|
125
|
-
if (focusFirst) menuItems(menu)[0]?.focus({ preventScroll: true })
|
|
126
|
-
else focusInitialMenuItem(menu)
|
|
127
|
-
}
|
|
128
|
-
}}
|
|
124
|
+
onOpenAutoFocus={(e) => openFocus.onOpenAutoFocus(e, menu)}
|
|
125
|
+
onfocusin={openFocus.onfocusin}
|
|
129
126
|
onkeydown={(e) => menu && handleMenuKeys(e, menu)}
|
|
130
127
|
>
|
|
131
128
|
<div
|
|
@@ -1 +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;
|
|
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;AA+FH,QAAA,MAAM,YAAY,uDAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
|
|
@@ -21,9 +21,7 @@
|
|
|
21
21
|
|
|
22
22
|
<script lang="ts">
|
|
23
23
|
import {
|
|
24
|
-
focusInitialMenuItem,
|
|
25
24
|
handleMenuKeys,
|
|
26
|
-
menuItems,
|
|
27
25
|
SIGNATURE_LABELS,
|
|
28
26
|
signatureMenuModel,
|
|
29
27
|
signaturePreview,
|
|
@@ -39,6 +37,7 @@
|
|
|
39
37
|
|
|
40
38
|
import InkIcon from './InkIcon.svelte'
|
|
41
39
|
import InkSignatureDialog from './InkSignatureDialog.svelte'
|
|
40
|
+
import { createMenuOpenFocus } from './menu-open-focus.js'
|
|
42
41
|
|
|
43
42
|
import type { SignatureOptions, SignatureTemplate } from '@inkbar/core'
|
|
44
43
|
|
|
@@ -58,15 +57,16 @@
|
|
|
58
57
|
const model = $derived(signatureMenuModel(templates.current, signature.options))
|
|
59
58
|
const active = $derived(current.tool === 'signature')
|
|
60
59
|
let open = $state(false)
|
|
60
|
+
/** The split button: the panel lines up under it rather than the chevron. */
|
|
61
|
+
let group = $state<HTMLElement | null>(null)
|
|
61
62
|
let creating = $state(false)
|
|
62
63
|
let menu = $state<HTMLElement | null>(null)
|
|
63
64
|
let main = $state<HTMLElement | null>(null)
|
|
64
65
|
|
|
65
66
|
/** ArrowDown opens on the first item; a click opens on the checked one. */
|
|
66
|
-
|
|
67
|
-
// Bits runs the open-focus callback more than once, so the flag outlives it; reset on close.
|
|
67
|
+
const openFocus = createMenuOpenFocus()
|
|
68
68
|
$effect(() => {
|
|
69
|
-
if (!open)
|
|
69
|
+
if (!open) openFocus.reset()
|
|
70
70
|
})
|
|
71
71
|
/** Set while the menu closes for the dialog, which takes focus instead of the trigger. */
|
|
72
72
|
let toDialog = false
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
function onTriggerKeydown(e: KeyboardEvent): void {
|
|
75
75
|
if (e.key !== 'ArrowDown' || e.defaultPrevented || open) return
|
|
76
76
|
e.preventDefault()
|
|
77
|
-
|
|
77
|
+
openFocus.first()
|
|
78
78
|
open = true
|
|
79
79
|
}
|
|
80
80
|
|
|
@@ -115,6 +115,7 @@
|
|
|
115
115
|
</script>
|
|
116
116
|
|
|
117
117
|
<div
|
|
118
|
+
bind:this={group}
|
|
118
119
|
role="group"
|
|
119
120
|
aria-label={SIGNATURE_LABELS.sign}
|
|
120
121
|
class={['ink-split-button ink-signature-menu', className]}
|
|
@@ -160,17 +161,13 @@
|
|
|
160
161
|
class="ink-select-content ink-menu-content"
|
|
161
162
|
data-ink-select-content=""
|
|
162
163
|
data-ink-menu="signature"
|
|
164
|
+
customAnchor={group}
|
|
163
165
|
side="bottom"
|
|
164
166
|
align="start"
|
|
165
167
|
sideOffset={4}
|
|
166
168
|
collisionPadding={8}
|
|
167
|
-
onOpenAutoFocus={(e) =>
|
|
168
|
-
|
|
169
|
-
if (menu) {
|
|
170
|
-
if (focusFirst) menuItems(menu)[0]?.focus({ preventScroll: true })
|
|
171
|
-
else focusInitialMenuItem(menu)
|
|
172
|
-
}
|
|
173
|
-
}}
|
|
169
|
+
onOpenAutoFocus={(e) => openFocus.onOpenAutoFocus(e, menu)}
|
|
170
|
+
onfocusin={openFocus.onfocusin}
|
|
174
171
|
onCloseAutoFocus={(e) => {
|
|
175
172
|
if (toDialog) e.preventDefault()
|
|
176
173
|
toDialog = false
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InkSignatureMenu.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/InkSignatureMenu.svelte.ts"],"names":[],"mappings":"AAGE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAA;AACrC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAErD;;;;;GAKG;AACH,MAAM,WAAW,qBAAsB,SAAQ,IAAI,CACjD,cAAc,CAAC,cAAc,CAAC,EAC9B,UAAU,CACX;IACC,uCAAuC;IACvC,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IAC9B,mFAAmF;IACnF,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAA;CACtC;
|
|
1
|
+
{"version":3,"file":"InkSignatureMenu.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/InkSignatureMenu.svelte.ts"],"names":[],"mappings":"AAGE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAA;AACrC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAErD;;;;;GAKG;AACH,MAAM,WAAW,qBAAsB,SAAQ,IAAI,CACjD,cAAc,CAAC,cAAc,CAAC,EAC9B,UAAU,CACX;IACC,uCAAuC;IACvC,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IAC9B,mFAAmF;IACnF,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAA;CACtC;AAkLH,QAAA,MAAM,gBAAgB,2DAAwC,CAAC;AAC/D,KAAK,gBAAgB,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC5D,eAAe,gBAAgB,CAAC"}
|
|
@@ -137,6 +137,13 @@
|
|
|
137
137
|
}
|
|
138
138
|
</script>
|
|
139
139
|
|
|
140
|
+
<svelte:document
|
|
141
|
+
onpointerdowncapture={(e) =>
|
|
142
|
+
open && focusReturn.onPressOutside(e, '[data-ink-thread-popover]', close)}
|
|
143
|
+
onpointerup={focusReturn.onPressEnd}
|
|
144
|
+
onpointercancel={focusReturn.onPressEnd}
|
|
145
|
+
/>
|
|
146
|
+
|
|
140
147
|
<Popover.Root bind:open={() => open, onOpenChange}>
|
|
141
148
|
<Popover.Portal>
|
|
142
149
|
{#if note && anchor}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InkThreadPopover.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/InkThreadPopover.svelte.ts"],"names":[],"mappings":"AAGE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAA;AAC9D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAA;AAErC,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,EAAE,OAAO,CAAC,CAAC,sBAAsB,CAAC,CAAC,GAAG,SAAS,CAAA;CACzD;
|
|
1
|
+
{"version":3,"file":"InkThreadPopover.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/InkThreadPopover.svelte.ts"],"names":[],"mappings":"AAGE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAA;AAC9D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAA;AAErC,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,EAAE,OAAO,CAAC,CAAC,sBAAsB,CAAC,CAAC,GAAG,SAAS,CAAA;CACzD;AAgMH,QAAA,MAAM,gBAAgB,2DAAwC,CAAC;AAC/D,KAAK,gBAAgB,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC5D,eAAe,gBAAgB,CAAC"}
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
} from '@inkbar/icons'
|
|
28
28
|
import { Toolbar } from 'bits-ui'
|
|
29
29
|
|
|
30
|
+
import { useInkContext } from '../context.js'
|
|
30
31
|
import { useTool } from '../hooks/useTool.svelte.js'
|
|
31
32
|
|
|
32
33
|
import { asBitsProps } from './child-snippet.js'
|
|
@@ -56,11 +57,18 @@
|
|
|
56
57
|
...rest
|
|
57
58
|
}: InkToolButtonProps = $props()
|
|
58
59
|
|
|
60
|
+
const ctx = useInkContext('InkToolButton')
|
|
59
61
|
const current = useTool()
|
|
60
62
|
const active = $derived(current.tool === tool)
|
|
61
|
-
|
|
62
|
-
const
|
|
63
|
-
|
|
63
|
+
/** A host or plugin tool by this id, for the name and icon core has none for. */
|
|
64
|
+
const own = $derived(
|
|
65
|
+
[...(ctx.hostTools ?? []), ...(ctx.pluginHost?.tools ?? [])].find(
|
|
66
|
+
(t) => t.id === tool
|
|
67
|
+
)
|
|
68
|
+
)
|
|
69
|
+
// `label` and `children` win; then core's name and icon; then the tool's own.
|
|
70
|
+
const name = $derived(label ?? TOOL_LABELS[tool] ?? own?.label ?? tool)
|
|
71
|
+
const icon = $derived(ICONS[tool] ?? own?.icon)
|
|
64
72
|
</script>
|
|
65
73
|
|
|
66
74
|
<Toolbar.Button
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InkToolButton.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/InkToolButton.svelte.ts"],"names":[],"mappings":"AAGE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAA;AACrC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAA;AAE3D,MAAM,WAAW,kBAAmB,SAAQ,IAAI,CAAC,oBAAoB,EAAE,UAAU,CAAC;IAChF,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAC,CAAC;QAAE,MAAM,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,GAAG,SAAS,CAAA;IACpE,KAAK,CAAC,EAAE,YAAY,GAAG,SAAS,CAAA;CACjC;
|
|
1
|
+
{"version":3,"file":"InkToolButton.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/InkToolButton.svelte.ts"],"names":[],"mappings":"AAGE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAA;AACrC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAA;AAE3D,MAAM,WAAW,kBAAmB,SAAQ,IAAI,CAAC,oBAAoB,EAAE,UAAU,CAAC;IAChF,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAC,CAAC;QAAE,MAAM,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,GAAG,SAAS,CAAA;IACpE,KAAK,CAAC,EAAE,YAAY,GAAG,SAAS,CAAA;CACjC;AAqFH,QAAA,MAAM,aAAa,wDAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
import InkPage from './InkPage.svelte'
|
|
44
44
|
|
|
45
45
|
import type { InkDocument, InkStatus } from '@inkbar/core'
|
|
46
|
-
import type { PageMount, ViewerEngine, ZoomValue } from '@inkbar/core/dom'
|
|
46
|
+
import type { PageMount, ToolId, ViewerEngine, ZoomValue } from '@inkbar/core/dom'
|
|
47
47
|
|
|
48
48
|
let {
|
|
49
49
|
mode = 'continuous',
|
|
@@ -126,6 +126,11 @@
|
|
|
126
126
|
buffer,
|
|
127
127
|
tool: ctx.tool,
|
|
128
128
|
...(ctx.hostTools ? { tools: ctx.hostTools } : {}),
|
|
129
|
+
// The engine adds the plugins' tools and layers, and decorates through the host, which
|
|
130
|
+
// reads `decorateAnnotation` first.
|
|
131
|
+
...(ctx.pluginHost ? { plugins: ctx.pluginHost } : {}),
|
|
132
|
+
// Read through, so the effect below can re-apply a new function without a rebuild.
|
|
133
|
+
decorateAnnotation: (a) => ctx.decorateAnnotation?.(a),
|
|
129
134
|
...(ctx.toolStyle ? { toolStyle: ctx.toolStyle } : {}),
|
|
130
135
|
toolHistory: { batch: (fn) => ctx.history.batch(fn) },
|
|
131
136
|
toolOptions: ctx.toolOptions,
|
|
@@ -155,7 +160,15 @@
|
|
|
155
160
|
lastReportedPage = p
|
|
156
161
|
ctx.reportPage(p)
|
|
157
162
|
}
|
|
158
|
-
|
|
163
|
+
// A tool that switches itself (a one-shot tool once used) is reported as a pick.
|
|
164
|
+
const followTool = (id: ToolId): void => {
|
|
165
|
+
if (id !== ctx.tool) ctx.setTool(id)
|
|
166
|
+
}
|
|
167
|
+
stops = [
|
|
168
|
+
vp.zoom.subscribe(reportZoom),
|
|
169
|
+
vp.currentPage.subscribe(reportPage),
|
|
170
|
+
tc.active.subscribe(followTool),
|
|
171
|
+
]
|
|
159
172
|
// Whatever the build restored is reported once; nothing is when it matched.
|
|
160
173
|
reportZoom(vp.zoom.get())
|
|
161
174
|
reportPage(vp.currentPage.get())
|
|
@@ -181,6 +194,16 @@
|
|
|
181
194
|
})
|
|
182
195
|
}
|
|
183
196
|
|
|
197
|
+
// The plugins' `root`. Before the build below, so it is set when the engine mounts.
|
|
198
|
+
$effect(() => {
|
|
199
|
+
const el = scroll
|
|
200
|
+
const { viewportEl } = ctx
|
|
201
|
+
viewportEl.set(el)
|
|
202
|
+
return () => {
|
|
203
|
+
if (viewportEl.get() === el) viewportEl.set(null)
|
|
204
|
+
}
|
|
205
|
+
})
|
|
206
|
+
|
|
184
207
|
// Build for a new document or status; tear down on the next change and on unmount. Only the
|
|
185
208
|
// values read before `untrack` are dependencies, each through a derived, which notifies only
|
|
186
209
|
// when the value changes: the status is a new object on every engine report.
|
|
@@ -229,6 +252,13 @@
|
|
|
229
252
|
})
|
|
230
253
|
})
|
|
231
254
|
|
|
255
|
+
// A new decorateAnnotation re-applies to the mounted annotation elements at once.
|
|
256
|
+
const decorate = $derived(ctx.decorateAnnotation)
|
|
257
|
+
$effect(() => {
|
|
258
|
+
void decorate
|
|
259
|
+
untrack(() => engine?.redecorate())
|
|
260
|
+
})
|
|
261
|
+
|
|
232
262
|
// The setters below run untracked: core relays out inside them and the engine's page
|
|
233
263
|
// callbacks read and write `pages`. Tracked, each effect would depend on the list it changes
|
|
234
264
|
// and run again, without end when the host holds a zoom the viewport clamps.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InkViewport.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/InkViewport.svelte.ts"],"names":[],"mappings":"AAGE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAC5C,OAAO,KAAK,EAAE,mBAAmB,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AACrF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAA;AACrC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAErD,MAAM,WAAW,gBAAiB,SAAQ,IAAI,CAC5C,cAAc,CAAC,cAAc,CAAC,EAC9B,UAAU,CACX;IACC,IAAI,CAAC,EAAE,UAAU,CAAA;IACjB,QAAQ,CAAC,EAAE,YAAY,CAAA;IACvB,iCAAiC;IACjC,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IAC7B,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAC,CAAC;QAAE,KAAK,EAAE,QAAQ,CAAA;KAAE,CAAC,CAAC,GAAG,SAAS,CAAA;IAClD,UAAU,CAAC,EAAE,OAAO,CAAC,CAAC,mBAAmB,CAAC,CAAC,GAAG,SAAS,CAAA;IACvD,wFAAwF;IACxF,SAAS,CAAC,EAAE,OAAO,CAAC,CAAC;QAAE,KAAK,EAAE,QAAQ,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,GAAG,SAAS,CAAA;CACrE;
|
|
1
|
+
{"version":3,"file":"InkViewport.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/InkViewport.svelte.ts"],"names":[],"mappings":"AAGE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAC5C,OAAO,KAAK,EAAE,mBAAmB,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AACrF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAA;AACrC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAErD,MAAM,WAAW,gBAAiB,SAAQ,IAAI,CAC5C,cAAc,CAAC,cAAc,CAAC,EAC9B,UAAU,CACX;IACC,IAAI,CAAC,EAAE,UAAU,CAAA;IACjB,QAAQ,CAAC,EAAE,YAAY,CAAA;IACvB,iCAAiC;IACjC,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IAC7B,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAC,CAAC;QAAE,KAAK,EAAE,QAAQ,CAAA;KAAE,CAAC,CAAC,GAAG,SAAS,CAAA;IAClD,UAAU,CAAC,EAAE,OAAO,CAAC,CAAC,mBAAmB,CAAC,CAAC,GAAG,SAAS,CAAA;IACvD,wFAAwF;IACxF,SAAS,CAAC,EAAE,OAAO,CAAC,CAAC;QAAE,KAAK,EAAE,QAAQ,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,GAAG,SAAS,CAAA;CACrE;AA4TH,QAAA,MAAM,WAAW,sDAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface MenuOpenFocus {
|
|
2
|
+
/** Makes the next open start on the first item (ArrowDown on the trigger). */
|
|
3
|
+
first: () => void;
|
|
4
|
+
/** For the content's `onOpenAutoFocus`. */
|
|
5
|
+
onOpenAutoFocus: (e: Event, menu: HTMLElement | null) => void;
|
|
6
|
+
/** For the content's `onfocusin`: remembers where the user is. */
|
|
7
|
+
onfocusin: (e: FocusEvent) => void;
|
|
8
|
+
/** Call when the menu closes. */
|
|
9
|
+
reset: () => void;
|
|
10
|
+
}
|
|
11
|
+
export declare function createMenuOpenFocus(): MenuOpenFocus;
|
|
12
|
+
//# sourceMappingURL=menu-open-focus.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"menu-open-focus.d.ts","sourceRoot":"","sources":["../../src/lib/components/menu-open-focus.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,aAAa;IAC5B,8EAA8E;IAC9E,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,2CAA2C;IAC3C,eAAe,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI,CAAA;IAC7D,kEAAkE;IAClE,SAAS,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,CAAA;IAClC,iCAAiC;IACjC,KAAK,EAAE,MAAM,IAAI,CAAA;CAClB;AAED,wBAAgB,mBAAmB,IAAI,aAAa,CAsBnD"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Where a toolbar menu puts focus as it opens: the first item when ArrowDown opened it, else the
|
|
3
|
+
* checked one. Bits can remount a popover's focus scope just after it opens, which sends focus
|
|
4
|
+
* to the trigger and runs the open-focus callback again; by then the user may have moved on, so
|
|
5
|
+
* a repeat run goes back to the item they last focused.
|
|
6
|
+
*/
|
|
7
|
+
import { focusInitialMenuItem, menuItems } from '@inkbar/core/dom';
|
|
8
|
+
export function createMenuOpenFocus() {
|
|
9
|
+
let first = false;
|
|
10
|
+
let last = null;
|
|
11
|
+
return {
|
|
12
|
+
first: () => {
|
|
13
|
+
first = true;
|
|
14
|
+
},
|
|
15
|
+
onOpenAutoFocus: (e, menu) => {
|
|
16
|
+
e.preventDefault();
|
|
17
|
+
if (!menu)
|
|
18
|
+
return;
|
|
19
|
+
if (last && menu.contains(last))
|
|
20
|
+
last.focus({ preventScroll: true });
|
|
21
|
+
else if (first)
|
|
22
|
+
menuItems(menu)[0]?.focus({ preventScroll: true });
|
|
23
|
+
else
|
|
24
|
+
focusInitialMenuItem(menu);
|
|
25
|
+
},
|
|
26
|
+
onfocusin: (e) => {
|
|
27
|
+
if (e.target instanceof HTMLElement)
|
|
28
|
+
last = e.target;
|
|
29
|
+
},
|
|
30
|
+
reset: () => {
|
|
31
|
+
first = false;
|
|
32
|
+
last = null;
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
|
@@ -5,6 +5,18 @@ export interface PopoverFocusReturn {
|
|
|
5
5
|
beforeRemove: FocusReturn['beforeRemove'];
|
|
6
6
|
/** Bits UI's `onOpenAutoFocus` handler. Leaves the default alone: focus moves into the popover. */
|
|
7
7
|
onOpenAutoFocus: (event: Event) => void;
|
|
8
|
+
/**
|
|
9
|
+
* A document-level pointer press, captured. `inside` selects the popover's content. A press on
|
|
10
|
+
* the viewer's own scroll element, outside the popover, that will not activate an annotation
|
|
11
|
+
* closes it now, through `close`, before the press moves focus. Bits UI closes it a beat
|
|
12
|
+
* later, and its focus trap pulls focus back into the popover in between, which ends a text
|
|
13
|
+
* selection the press has just begun. Nothing is focused when it closes this way: the press
|
|
14
|
+
* places focus. Every other press (a toolbar, a host's menu portaled out of the popover) is
|
|
15
|
+
* left to Bits UI, whose layer stack knows what belongs to the popover.
|
|
16
|
+
*/
|
|
17
|
+
onPressOutside: (event: PointerEvent, inside: string, close: () => void) => void;
|
|
18
|
+
/** A pointer release or cancel, captured. */
|
|
19
|
+
onPressEnd: () => void;
|
|
8
20
|
/** Bits UI's `onCloseAutoFocus` handler. Prevents the default; the planner places focus. */
|
|
9
21
|
onCloseAutoFocus: (event: Event, anchor: HTMLElement | null) => void;
|
|
10
22
|
}
|
|
@@ -21,8 +33,10 @@ export declare function keepOpenOnAnnotation(event: PointerEvent): void;
|
|
|
21
33
|
* close reaches the planner one microtask late, and only when no open was reported after it.
|
|
22
34
|
*
|
|
23
35
|
* This relies on Bits UI reporting a remount as a close and then an open within one synchronous
|
|
24
|
-
* call (observed in bits-ui 2.19.5, `FocusScope.mount`).
|
|
25
|
-
*
|
|
36
|
+
* call (observed in bits-ui 2.19.5, `FocusScope.mount`). The unit case 'a close followed by an
|
|
37
|
+
* open in the same tick moves no focus and uses up the removal plan' pins the planner's side, and
|
|
38
|
+
* the browser case 'a popover opened without passing focus through the annotation takes focus'
|
|
39
|
+
* checks that an open moves focus straight into the popover.
|
|
26
40
|
*
|
|
27
41
|
* A close that is superseded this way moves no focus, but it still uses up whatever
|
|
28
42
|
* `beforeRemove` planned for it, so the plan cannot leak into a later close. A close that is
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"popover-focus.d.ts","sourceRoot":"","sources":["../../src/lib/components/popover-focus.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,WAAW,EACjB,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"popover-focus.d.ts","sourceRoot":"","sources":["../../src/lib/components/popover-focus.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,WAAW,EACjB,MAAM,kBAAkB,CAAA;AAKzB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAE/C,iFAAiF;AACjF,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,WAAW,CAAC,cAAc,CAAC,CAAA;IACzC,mGAAmG;IACnG,eAAe,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;IACvC;;;;;;;;OAQG;IACH,cAAc,EAAE,CAAC,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,IAAI,KAAK,IAAI,CAAA;IAChF,6CAA6C;IAC7C,UAAU,EAAE,MAAM,IAAI,CAAA;IACtB,4FAA4F;IAC5F,gBAAgB,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI,CAAA;CACrE;AAED,8GAA8G;AAC9G,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAE9D;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,UAAU,GAAG,kBAAkB,CAiDlE"}
|