@inkbar/svelte 0.6.0 → 0.8.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.
Files changed (44) hide show
  1. package/README.md +13 -0
  2. package/dist/components/InkFindBar.svelte +213 -0
  3. package/dist/components/InkFindBar.svelte.d.ts +6 -0
  4. package/dist/components/InkFindBar.svelte.d.ts.map +1 -0
  5. package/dist/components/InkFormAlert.svelte +108 -0
  6. package/dist/components/InkFormAlert.svelte.d.ts +13 -0
  7. package/dist/components/InkFormAlert.svelte.d.ts.map +1 -0
  8. package/dist/components/InkRoot.svelte +136 -4
  9. package/dist/components/InkRoot.svelte.d.ts +22 -2
  10. package/dist/components/InkRoot.svelte.d.ts.map +1 -1
  11. package/dist/components/InkSearchButton.svelte +56 -0
  12. package/dist/components/InkSearchButton.svelte.d.ts +5 -0
  13. package/dist/components/InkSearchButton.svelte.d.ts.map +1 -0
  14. package/dist/components/InkSignFieldPopover.svelte +187 -0
  15. package/dist/components/InkSignFieldPopover.svelte.d.ts +10 -0
  16. package/dist/components/InkSignFieldPopover.svelte.d.ts.map +1 -0
  17. package/dist/components/InkSignatureDialog.svelte +11 -3
  18. package/dist/components/InkSignatureDialog.svelte.d.ts +9 -3
  19. package/dist/components/InkSignatureDialog.svelte.d.ts.map +1 -1
  20. package/dist/components/InkSignatureMenu.svelte +10 -99
  21. package/dist/components/InkSignatureMenu.svelte.d.ts.map +1 -1
  22. package/dist/components/InkViewport.svelte +46 -1
  23. package/dist/components/InkViewport.svelte.d.ts.map +1 -1
  24. package/dist/components/SignatureForm.svelte +7 -2
  25. package/dist/components/SignatureForm.svelte.d.ts +2 -0
  26. package/dist/components/SignatureForm.svelte.d.ts.map +1 -1
  27. package/dist/components/SignatureMenuPanel.svelte +127 -0
  28. package/dist/components/SignatureMenuPanel.svelte.d.ts +13 -0
  29. package/dist/components/SignatureMenuPanel.svelte.d.ts.map +1 -0
  30. package/dist/components/search-button.d.ts +10 -0
  31. package/dist/components/search-button.d.ts.map +1 -0
  32. package/dist/components/search-button.js +1 -0
  33. package/dist/context.d.ts +14 -2
  34. package/dist/context.d.ts.map +1 -1
  35. package/dist/hooks/useForm.svelte.d.ts +17 -0
  36. package/dist/hooks/useForm.svelte.d.ts.map +1 -0
  37. package/dist/hooks/useForm.svelte.js +20 -0
  38. package/dist/hooks/useSearch.svelte.d.ts +11 -0
  39. package/dist/hooks/useSearch.svelte.d.ts.map +1 -0
  40. package/dist/hooks/useSearch.svelte.js +31 -0
  41. package/dist/index.d.ts +7 -0
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +4 -0
  44. package/package.json +6 -5
@@ -1,5 +1,5 @@
1
1
  import type { ChildSnippet } from './child-snippet.js';
2
- import type { Annotation, AnnotationChange, AnnotationDefaults, DocumentSource, InkDocument, InkError, InkStatus, PdfAssets, SignatureStore } from '@inkbar/core';
2
+ import type { Annotation, AnnotationChange, AnnotationDefaults, DocumentSource, FieldsChange, FieldValues, FormAction, InkDocument, InkError, InkStatus, PdfAssets, SignatureStore } from '@inkbar/core';
3
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';
@@ -17,6 +17,21 @@ export interface InkRootProps extends Omit<HTMLAttributes<HTMLDivElement>, 'chil
17
17
  annotations?: Annotation[] | undefined;
18
18
  onAnnotationsChange?: ((next: Annotation[]) => void) | undefined;
19
19
  onChange?: ((change: AnnotationChange) => void) | undefined;
20
+ /**
21
+ * Pass (with `bind:`) to put the form's field values under the host's control. A commit
22
+ * shows at once and is reported after; the host's push wins. The mode is fixed when a
23
+ * document opens, as for `annotations`.
24
+ */
25
+ fields?: FieldValues | undefined;
26
+ /**
27
+ * Committed field values, in full, with what changed them. Called only while the fields
28
+ * are controlled, after the bound value is written.
29
+ */
30
+ onFieldsChange?: ((next: FieldValues, change: FieldsChange) => void) | undefined;
31
+ /** The form asked to submit, open a link, send mail, print or prompt. Inkbar does none. */
32
+ onformaction?: ((action: FormAction) => void) | undefined;
33
+ /** Tints fillable form fields. Default true. A change applies to the open document in place. */
34
+ formHighlight?: boolean | undefined;
20
35
  tool?: ToolId | undefined;
21
36
  onToolChange?: ((tool: ToolId) => void) | undefined;
22
37
  /**
@@ -57,6 +72,11 @@ export interface InkRootProps extends Omit<HTMLAttributes<HTMLDivElement>, 'chil
57
72
  /** Undo history. Defaults to on for uncontrolled, off for controlled. */
58
73
  history?: boolean | undefined;
59
74
  onReady?: ((doc: InkDocument) => void) | undefined;
75
+ /**
76
+ * Opening failed, or later: a form script failed (`FormScriptError`; the form stays
77
+ * fillable), or a signature field refused its signing (`FieldSigned`, `FieldReadOnly`).
78
+ * An error from while the document opened comes after `onReady`.
79
+ */
60
80
  onError?: ((error: InkError) => void) | undefined;
61
81
  onActivate?: ((id: string) => void) | undefined;
62
82
  /** The root element, for hosts that bind it. */
@@ -76,7 +96,7 @@ declare const InkRoot: import("svelte").Component<InkRootProps, {
76
96
  history: InkHistory;
77
97
  getDocument: () => InkDocument | null;
78
98
  getStatus: () => InkStatus;
79
- }, "page" | "annotations" | "tool" | "zoom" | "ref">;
99
+ }, "page" | "annotations" | "fields" | "tool" | "zoom" | "ref">;
80
100
  type InkRoot = ReturnType<typeof InkRoot>;
81
101
  export default InkRoot;
82
102
  //# sourceMappingURL=InkRoot.svelte.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"InkRoot.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/InkRoot.svelte.ts"],"names":[],"mappings":"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"}
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,56 @@
1
+ <script lang="ts">
2
+ /*
3
+ * Opens the find bar; pressed while it is open. Pressing it again focuses the field. Place
4
+ * it in a toolbar next to `InkFindBar`, which it needs for the field to focus. Disabled until
5
+ * a document is open.
6
+ */
7
+ import { Search } from '@inkbar/icons'
8
+ import { Toolbar } from 'bits-ui'
9
+ import { tick } from 'svelte'
10
+
11
+ import { useInkContext } from '../context.js'
12
+ import { useDocument } from '../hooks/useDocument.svelte.js'
13
+ import { useSearch } from '../hooks/useSearch.svelte.js'
14
+
15
+ import { asBitsProps } from './child-snippet.js'
16
+ import InkIcon from './InkIcon.svelte'
17
+
18
+ import type { InkSearchButtonProps } from './search-button.js'
19
+
20
+ let {
21
+ class: className,
22
+ children,
23
+ child,
24
+ disabled,
25
+ onclick,
26
+ ...rest
27
+ }: InkSearchButtonProps = $props()
28
+
29
+ const ctx = useInkContext('InkSearchButton')
30
+ const search = useSearch()
31
+ const doc = useDocument()
32
+ </script>
33
+
34
+ <Toolbar.Button
35
+ {...asBitsProps(rest)}
36
+ class={['ink-search-button', className]}
37
+ data-ink-search-button=""
38
+ aria-label="Find"
39
+ title="Find"
40
+ aria-pressed={search.state.open}
41
+ data-state={search.state.open ? 'on' : 'off'}
42
+ disabled={!doc.isReady || !!disabled}
43
+ {...child ? { child } : {}}
44
+ onclick={async (e) => {
45
+ onclick?.(e)
46
+ if (e.defaultPrevented) return
47
+ search.open()
48
+ // The bar shows once this update lands; its field takes focus then.
49
+ await tick()
50
+ const field = ctx.rootEl?.querySelector<HTMLInputElement>('[data-ink-find-bar] input')
51
+ field?.focus()
52
+ field?.select()
53
+ }}
54
+ >
55
+ {#if children}{@render children()}{:else}<InkIcon icon={Search} />{/if}
56
+ </Toolbar.Button>
@@ -0,0 +1,5 @@
1
+ import type { InkSearchButtonProps } from './search-button.js';
2
+ declare const InkSearchButton: import("svelte").Component<InkSearchButtonProps, {}, "">;
3
+ type InkSearchButton = ReturnType<typeof InkSearchButton>;
4
+ export default InkSearchButton;
5
+ //# sourceMappingURL=InkSearchButton.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InkSearchButton.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/InkSearchButton.svelte.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AA8C/D,QAAA,MAAM,eAAe,0DAAwC,CAAC;AAC9D,KAAK,eAAe,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;AAC1D,eAAe,eAAe,CAAC"}
@@ -0,0 +1,187 @@
1
+ <script lang="ts">
2
+ /*
3
+ * The signature menu for a signature field, opened from the field's "Sign" button and
4
+ * anchored to its box. It lists the saved signatures and "Create signature", as
5
+ * `InkSignatureMenu` does. Picking one signs the field with it (`signField`); a signature
6
+ * made in `InkSignatureDialog` signs the field once saved, without picking the signature
7
+ * tool. Focus returns to the field. InkViewport mounts it, one per document; hosts compose
8
+ * nothing.
9
+ */
10
+ import { InkError, signField } from '@inkbar/core'
11
+ import {
12
+ handleMenuKeys,
13
+ SIGNATURE_LABELS,
14
+ signatureMenuModel,
15
+ watchDetached,
16
+ } from '@inkbar/core/dom'
17
+ import { Popover } from 'bits-ui'
18
+ import { untrack } from 'svelte'
19
+
20
+ import { useInkContext } from '../context.js'
21
+ import { useReadable } from '../use-readable.svelte.js'
22
+
23
+ import InkSignatureDialog from './InkSignatureDialog.svelte'
24
+ import { createMenuOpenFocus } from './menu-open-focus.js'
25
+ import SignatureMenuPanel from './SignatureMenuPanel.svelte'
26
+
27
+ import type { InkDocument, SignatureTemplate } from '@inkbar/core'
28
+ import type { SignFieldRequest } from '@inkbar/core/dom'
29
+
30
+ let {
31
+ request,
32
+ onClose,
33
+ }: {
34
+ /** The field to sign; `null` while the menu is closed. */
35
+ request: SignFieldRequest | null
36
+ onClose: () => void
37
+ } = $props()
38
+
39
+ const NO_TEMPLATES: readonly SignatureTemplate[] = []
40
+
41
+ const ctx = useInkContext('InkSignFieldPopover')
42
+ const templates = useReadable(() => ctx.signatures.templates, NO_TEMPLATES)
43
+ // No signature is "chosen" here: each signing picks its own.
44
+ const model = $derived(signatureMenuModel(templates.current, {}))
45
+ const open = $derived(request !== null)
46
+ let menu = $state<HTMLElement | null>(null)
47
+ /** The field the dialog signs once its signature is saved, and the document it is in. */
48
+ let creatingFor = $state.raw<{ req: SignFieldRequest; doc: InkDocument } | null>(null)
49
+ /**
50
+ * The request the menu last opened for, kept to return focus once it closes. Untracked:
51
+ * Bits UI reports the close from an effect teardown, where a reactive read of `request`
52
+ * returns the value from before the close.
53
+ */
54
+ let last: SignFieldRequest | null = null
55
+ /** Set while the menu closes for the dialog, which takes focus instead of the field. */
56
+ let toDialog = false
57
+ /** Cleared on destroy, so a dialog save that settles after the document went signs nothing. */
58
+ let alive = true
59
+ $effect(() => () => {
60
+ alive = false
61
+ })
62
+
63
+ $effect(() => {
64
+ if (request) last = request
65
+ })
66
+ // The field's box went (its page unmounted, its layer rebuilt): the menu has nothing to
67
+ // stand by.
68
+ $effect(() => {
69
+ const req = request
70
+ if (!req) return
71
+ return watchDetached(req.anchor, () => untrack(onClose))
72
+ })
73
+ // An old removal error is not news when the menu opens again.
74
+ $effect(() => {
75
+ if (open) untrack(() => ctx.signatures.clearRemoveError())
76
+ })
77
+ const openFocus = createMenuOpenFocus()
78
+ $effect(() => {
79
+ if (!open) openFocus.reset()
80
+ })
81
+
82
+ /** The field's own button, which focus returns to. */
83
+ const control = (req: SignFieldRequest | null): HTMLElement | null =>
84
+ req?.anchor.querySelector<HTMLElement>('button.ink-form-control') ?? null
85
+
86
+ /** Focus goes back to the field's button, or to the scroll element once the field's box has gone. */
87
+ function returnFocus(req: SignFieldRequest | null): void {
88
+ const c = control(req)
89
+ ;(c?.isConnected ? c : ctx.viewportEl.get())?.focus({ preventScroll: true })
90
+ }
91
+
92
+ /** Signs the request's field with `t`; a refusal (signed, read-only by now) goes to `onError`. */
93
+ function sign(req: SignFieldRequest, doc: InkDocument, t: SignatureTemplate): void {
94
+ // The document the request came from is still the open one.
95
+ if (!alive || ctx.document !== doc) return
96
+ try {
97
+ signField(doc, req.field, req.widget, t)
98
+ } catch (e) {
99
+ if (!(e instanceof InkError)) throw e
100
+ ctx.reportError(e)
101
+ }
102
+ }
103
+
104
+ function choose(t: SignatureTemplate): void {
105
+ const req = request
106
+ const doc = ctx.document
107
+ onClose()
108
+ if (req && doc) sign(req, doc, t)
109
+ }
110
+
111
+ function create(): void {
112
+ const req = request
113
+ const doc = ctx.document
114
+ if (!req || !doc) return
115
+ toDialog = true
116
+ creatingFor = { req, doc }
117
+ onClose()
118
+ }
119
+
120
+ function onInteractOutside(e: PointerEvent): void {
121
+ // A press on this field's own button toggles the menu through the engine; it must not
122
+ // also close it here first, or the click would open it again.
123
+ const target = e.target
124
+ if (target instanceof Node && request?.anchor.contains(target)) e.preventDefault()
125
+ }
126
+ </script>
127
+
128
+ <Popover.Root
129
+ bind:open={
130
+ () => open,
131
+ (next) => {
132
+ if (!next) onClose()
133
+ }
134
+ }
135
+ >
136
+ <Popover.Portal>
137
+ {#if request}
138
+ <Popover.Content
139
+ bind:ref={menu}
140
+ role="menu"
141
+ aria-label={SIGNATURE_LABELS.menu}
142
+ class="ink-select-content ink-menu-content"
143
+ data-ink-select-content=""
144
+ data-ink-menu="signature"
145
+ data-ink-sign-field-menu={request.field}
146
+ customAnchor={request.anchor}
147
+ side="bottom"
148
+ align="start"
149
+ sideOffset={4}
150
+ collisionPadding={8}
151
+ onOpenAutoFocus={(e) => openFocus.onOpenAutoFocus(e, menu)}
152
+ onfocusin={openFocus.onfocusin}
153
+ onCloseAutoFocus={(e) => {
154
+ e.preventDefault()
155
+ if (!toDialog) returnFocus(last)
156
+ toDialog = false
157
+ }}
158
+ {onInteractOutside}
159
+ onkeydown={(e) => menu && handleMenuKeys(e, menu)}
160
+ >
161
+ <SignatureMenuPanel
162
+ items={model.items}
163
+ menu={() => menu}
164
+ onChoose={choose}
165
+ onCreate={create}
166
+ />
167
+ </Popover.Content>
168
+ {/if}
169
+ </Popover.Portal>
170
+ </Popover.Root>
171
+ <InkSignatureDialog
172
+ bind:open={
173
+ () => creatingFor !== null,
174
+ (next) => {
175
+ if (!next) creatingFor = null
176
+ }
177
+ }
178
+ select={false}
179
+ onSave={(t) => {
180
+ const c = creatingFor
181
+ if (c) sign(c.req, c.doc, t)
182
+ }}
183
+ onCloseAutoFocus={(e) => {
184
+ e.preventDefault()
185
+ returnFocus(last)
186
+ }}
187
+ />
@@ -0,0 +1,10 @@
1
+ import type { SignFieldRequest } from '@inkbar/core/dom';
2
+ type $$ComponentProps = {
3
+ /** The field to sign; `null` while the menu is closed. */
4
+ request: SignFieldRequest | null;
5
+ onClose: () => void;
6
+ };
7
+ declare const InkSignFieldPopover: import("svelte").Component<$$ComponentProps, {}, "">;
8
+ type InkSignFieldPopover = ReturnType<typeof InkSignFieldPopover>;
9
+ export default InkSignFieldPopover;
10
+ //# sourceMappingURL=InkSignFieldPopover.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InkSignFieldPopover.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/InkSignFieldPopover.svelte.ts"],"names":[],"mappings":"AA6BA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAExD,KAAK,gBAAgB,GAAI;IACtB,0DAA0D;IAC1D,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAAA;IAChC,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB,CAAC;AA2IJ,QAAA,MAAM,mBAAmB,sDAAwC,CAAC;AAClE,KAAK,mBAAmB,GAAG,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAClE,eAAe,mBAAmB,CAAC"}
@@ -4,15 +4,21 @@
4
4
  /**
5
5
  * "Create signature": a modal with Draw, Type and Image tabs. Draw is a pad with the draw
6
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.
7
+ * or JPEG scan. Save stores the template through InkRoot's signature store and, unless
8
+ * `select` is false, selects it for the `signature` tool. Escape, Cancel or a press outside
9
+ * closes it.
9
10
  */
10
11
  export interface InkSignatureDialogProps {
11
12
  open?: boolean
12
13
  onOpenChange?: ((open: boolean) => void) | undefined
13
14
  /** The fonts the Type tab offers. Default: InkRoot's `signatureFonts`. */
14
15
  fonts?: readonly string[] | undefined
15
- /** Called with the new template once it is saved and selected. */
16
+ /**
17
+ * Whether saving selects the new signature for the `signature` tool. Default true. False
18
+ * leaves the tool alone, for a dialog that signs a field with it through `onSave`.
19
+ */
20
+ select?: boolean | undefined
21
+ /** Called with the new template once it is saved (and selected, with `select`). */
16
22
  onSave?: ((template: SignatureTemplate) => void) | undefined
17
23
  /** Where focus goes on close; by default, back to what had it before. */
18
24
  onCloseAutoFocus?: ((event: Event) => void) | undefined
@@ -30,6 +36,7 @@
30
36
  open = $bindable(false),
31
37
  onOpenChange,
32
38
  fonts,
39
+ select = true,
33
40
  onSave,
34
41
  onCloseAutoFocus,
35
42
  class: className,
@@ -62,6 +69,7 @@
62
69
  <Dialog.Title class="ink-dialog-title">{SIGNATURE_LABELS.dialog}</Dialog.Title>
63
70
  <SignatureForm
64
71
  {fonts}
72
+ {select}
65
73
  onSaved={(t) => onSave?.(t)}
66
74
  onClose={() => setOpen(false)}
67
75
  />
@@ -2,15 +2,21 @@ import type { SignatureTemplate } from '@inkbar/core';
2
2
  /**
3
3
  * "Create signature": a modal with Draw, Type and Image tabs. Draw is a pad with the draw
4
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.
5
+ * or JPEG scan. Save stores the template through InkRoot's signature store and, unless
6
+ * `select` is false, selects it for the `signature` tool. Escape, Cancel or a press outside
7
+ * closes it.
7
8
  */
8
9
  export interface InkSignatureDialogProps {
9
10
  open?: boolean;
10
11
  onOpenChange?: ((open: boolean) => void) | undefined;
11
12
  /** The fonts the Type tab offers. Default: InkRoot's `signatureFonts`. */
12
13
  fonts?: readonly string[] | undefined;
13
- /** Called with the new template once it is saved and selected. */
14
+ /**
15
+ * Whether saving selects the new signature for the `signature` tool. Default true. False
16
+ * leaves the tool alone, for a dialog that signs a field with it through `onSave`.
17
+ */
18
+ select?: boolean | undefined;
19
+ /** Called with the new template once it is saved (and selected, with `select`). */
14
20
  onSave?: ((template: SignatureTemplate) => void) | undefined;
15
21
  /** Where focus goes on close; by default, back to what had it before. */
16
22
  onCloseAutoFocus?: ((event: Event) => void) | undefined;
@@ -1 +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"}
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;;;;;;GAMG;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;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IAC5B,mFAAmF;IACnF,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;AAmDH,QAAA,MAAM,kBAAkB,iEAAwC,CAAC;AACjE,KAAK,kBAAkB,GAAG,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAChE,eAAe,kBAAkB,CAAC"}
@@ -20,15 +20,10 @@
20
20
  </script>
21
21
 
22
22
  <script lang="ts">
23
- import {
24
- handleMenuKeys,
25
- SIGNATURE_LABELS,
26
- signatureMenuModel,
27
- signaturePreview,
28
- } from '@inkbar/core/dom'
29
- import { ChevronDown, Plus, Signature, Trash2 } from '@inkbar/icons'
23
+ import { handleMenuKeys, SIGNATURE_LABELS, signatureMenuModel } from '@inkbar/core/dom'
24
+ import { ChevronDown, Signature } from '@inkbar/icons'
30
25
  import { Popover, Toolbar } from 'bits-ui'
31
- import { tick, untrack } from 'svelte'
26
+ import { untrack } from 'svelte'
32
27
 
33
28
  import { useInkContext } from '../context.js'
34
29
  import { useTool } from '../hooks/useTool.svelte.js'
@@ -38,6 +33,7 @@
38
33
  import InkIcon from './InkIcon.svelte'
39
34
  import InkSignatureDialog from './InkSignatureDialog.svelte'
40
35
  import { createMenuOpenFocus } from './menu-open-focus.js'
36
+ import SignatureMenuPanel from './SignatureMenuPanel.svelte'
41
37
 
42
38
  import type { SignatureOptions, SignatureTemplate } from '@inkbar/core'
43
39
 
@@ -49,7 +45,6 @@
49
45
  const current = useTool()
50
46
  const signature = useToolOptions<SignatureOptions>('signature')
51
47
  const templates = useReadable(() => ctx.signatures.templates, NO_TEMPLATES)
52
- const removeError = useReadable(() => ctx.signatures.removeError, undefined)
53
48
  // An old removal error is not news when the menu opens again.
54
49
  $effect(() => {
55
50
  if (open) untrack(() => ctx.signatures.clearRemoveError())
@@ -89,24 +84,6 @@
89
84
  open = false
90
85
  }
91
86
 
92
- /** Removes a template; focus moves to the signature now in its row, else "Create signature". */
93
- function remove(id: string, row: number): void {
94
- ctx.signatures.remove(id).then(
95
- async () => {
96
- await tick()
97
- if (!menu) return
98
- const rows = menu.querySelectorAll<HTMLElement>('.ink-signature-item')
99
- const next =
100
- rows[Math.min(row, rows.length - 1)] ??
101
- menu.querySelector<HTMLElement>('[data-ink-signature-create]')
102
- next?.focus({ preventScroll: true })
103
- },
104
- () => {
105
- // The host's store refused: the signature stays.
106
- }
107
- )
108
- }
109
-
110
87
  function create(): void {
111
88
  toDialog = true
112
89
  open = false
@@ -174,78 +151,12 @@
174
151
  }}
175
152
  onkeydown={(e) => menu && handleMenuKeys(e, menu)}
176
153
  >
177
- {#if model.items.length > 0}
178
- <div
179
- role="group"
180
- aria-label={SIGNATURE_LABELS.saved}
181
- class="ink-signature-list"
182
- data-ink-menu-columns="2"
183
- >
184
- {#each model.items as item, row (item.id)}
185
- {@const preview =
186
- item.template.kind === 'ink' ? signaturePreview(item.template) : null}
187
- <button
188
- type="button"
189
- role="menuitemradio"
190
- aria-checked={item.checked}
191
- aria-label={item.label}
192
- tabindex={-1}
193
- class="ink-select-item ink-menu-item ink-signature-item"
194
- data-ink-select-item=""
195
- data-key={item.id}
196
- data-state={item.checked ? 'checked' : 'unchecked'}
197
- onclick={() => choose(item.id)}
198
- >
199
- <span class="ink-signature-preview" data-kind={item.template.kind}>
200
- {#if item.template.kind === 'image'}
201
- <img src={item.template.imagedata} alt="" draggable="false" />
202
- {:else if preview}
203
- <svg viewBox={preview.viewBox} aria-hidden="true">
204
- {#each preview.paths as d, i (i)}
205
- <path {d} fill="currentColor" />
206
- {/each}
207
- </svg>
208
- {/if}
209
- </span>
210
- </button>
211
- <button
212
- type="button"
213
- role="menuitem"
214
- aria-label={item.removeLabel}
215
- title={item.removeLabel}
216
- tabindex={-1}
217
- class="ink-menu-item ink-signature-remove"
218
- data-ink-signature-remove=""
219
- data-key={item.id}
220
- onclick={() => remove(item.id, row)}
221
- >
222
- <InkIcon icon={Trash2} size={16} />
223
- </button>
224
- {/each}
225
- </div>
226
- <div role="separator" class="ink-select-separator"></div>
227
- {/if}
228
- <button
229
- type="button"
230
- role="menuitem"
231
- tabindex={-1}
232
- class="ink-select-item ink-menu-item ink-signature-create"
233
- data-ink-select-item=""
234
- data-ink-signature-create=""
235
- onclick={create}
236
- >
237
- <InkIcon icon={Plus} size={16} />
238
- {SIGNATURE_LABELS.create}
239
- </button>
240
- {#if removeError.current}
241
- <p
242
- class="ink-field-error ink-signature-remove-error"
243
- role="alert"
244
- data-ink-signature-remove-error=""
245
- >
246
- {removeError.current}
247
- </p>
248
- {/if}
154
+ <SignatureMenuPanel
155
+ items={model.items}
156
+ menu={() => menu}
157
+ onChoose={(t) => choose(t.id)}
158
+ onCreate={create}
159
+ />
249
160
  </Popover.Content>
250
161
  </Popover.Portal>
251
162
  </Popover.Root>
@@ -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;AAkLH,QAAA,MAAM,gBAAgB,2DAAwC,CAAC;AAC/D,KAAK,gBAAgB,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC5D,eAAe,gBAAgB,CAAC"}
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;AA2HH,QAAA,MAAM,gBAAgB,2DAAwC,CAAC;AAC/D,KAAK,gBAAgB,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC5D,eAAe,gBAAgB,CAAC"}
@@ -34,16 +34,28 @@
34
34
  * Two-way zoom and page: the viewport's own changes are reported through the context, and
35
35
  * the host's props are applied only when they differ from the viewport's state, so the echo
36
36
  * of a reported value does nothing.
37
+ *
38
+ * Form fields render in the engine's form layer. A signature field's "Sign" opens
39
+ * `InkSignFieldPopover`, and a form script's alert shows in `InkFormAlert`; both are mounted
40
+ * here, so hosts compose nothing for them.
37
41
  */
38
42
  import { mountViewer } from '@inkbar/core/dom'
39
43
  import { untrack } from 'svelte'
40
44
 
41
45
  import { useInkContext } from '../context.js'
42
46
 
47
+ import InkFormAlert from './InkFormAlert.svelte'
43
48
  import InkPage from './InkPage.svelte'
49
+ import InkSignFieldPopover from './InkSignFieldPopover.svelte'
44
50
 
45
51
  import type { InkDocument, InkStatus } from '@inkbar/core'
46
- import type { PageMount, ToolId, ViewerEngine, ZoomValue } from '@inkbar/core/dom'
52
+ import type {
53
+ PageMount,
54
+ SignFieldRequest,
55
+ ToolId,
56
+ ViewerEngine,
57
+ ZoomValue,
58
+ } from '@inkbar/core/dom'
47
59
 
48
60
  let {
49
61
  mode = 'continuous',
@@ -74,6 +86,10 @@
74
86
  let scroll = $state<HTMLDivElement | null>(null)
75
87
  /** Page hosts, mounts and errors the engine reported; InkPage renders portals for them. */
76
88
  let pages = $state.raw<MountedPage[]>([])
89
+ /** The signature field whose menu is open. */
90
+ let signRequest = $state.raw<SignFieldRequest | null>(null)
91
+ /** The form script's message on show, and how many have been shown. */
92
+ let alert = $state.raw<{ message: string; shown: number } | null>(null)
77
93
 
78
94
  let engine: ViewerEngine | null = null
79
95
  /**
@@ -101,6 +117,9 @@
101
117
  builtWith = null
102
118
  ctx.setViewport(null, null)
103
119
  if (pages.length > 0) pages = []
120
+ // Their fields and the document they came from are gone.
121
+ signRequest = null
122
+ alert = null
104
123
  }
105
124
 
106
125
  function setup(
@@ -129,6 +148,8 @@
129
148
  // The engine adds the plugins' tools and layers, and decorates through the host, which
130
149
  // reads `decorateAnnotation` first.
131
150
  ...(ctx.pluginHost ? { plugins: ctx.pluginHost } : {}),
151
+ // The highlights draw from the shared search.
152
+ ...(ctx.search ? { search: ctx.search } : {}),
132
153
  // Read through, so the effect below can re-apply a new function without a rebuild.
133
154
  decorateAnnotation: (a) => ctx.decorateAnnotation?.(a),
134
155
  ...(ctx.toolStyle ? { toolStyle: ctx.toolStyle } : {}),
@@ -138,6 +159,15 @@
138
159
  // Read through, so a new `signatures` store reaches the tool as well as the menus.
139
160
  signatureLibrary: () => ctx.signatures,
140
161
  customAnnotations: custom,
162
+ ...(ctx.formHighlight === undefined ? {} : { formHighlight: ctx.formHighlight }),
163
+ // The field's own button again, while its menu is open, closes the menu.
164
+ onSignField: (req) => {
165
+ signRequest = signRequest?.widget === req.widget ? null : req
166
+ },
167
+ onFormAction: (a) => ctx.reportFormAction(a),
168
+ onFormAlert: (message) => {
169
+ alert = { message, shown: (alert?.shown ?? 0) + 1 }
170
+ },
141
171
  onActivate: (id) => ctx.setActivated(id),
142
172
  onBuild: (vp, tc) => {
143
173
  ctx.setViewport(vp, tc)
@@ -278,6 +308,11 @@
278
308
  const tc = engine?.tools
279
309
  if (tc && tc.active.get() !== t) untrack(() => tc.set(t))
280
310
  })
311
+ // The tint follows `formHighlight` in place, without a new document.
312
+ $effect(() => {
313
+ const on = ctx.formHighlight ?? true
314
+ untrack(() => engine?.setFormHighlight(on))
315
+ })
281
316
  // The build applied both; these only act on a later change, not on mount.
282
317
  $effect(() => {
283
318
  const m = mode
@@ -340,4 +375,14 @@
340
375
  {pageError}
341
376
  />
342
377
  {/each}
378
+ <!-- Keyed by document, so the menu and its dialog start afresh for each one. -->
379
+ {#key buildDocument}
380
+ <InkSignFieldPopover request={signRequest} onClose={() => (signRequest = null)} />
381
+ {/key}
382
+ <InkFormAlert
383
+ message={alert?.message ?? null}
384
+ shown={alert?.shown ?? 0}
385
+ fallback={() => scroll}
386
+ onClose={() => (alert = null)}
387
+ />
343
388
  </div>
@@ -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;AA4TH,QAAA,MAAM,WAAW,sDAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
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;AAsWH,QAAA,MAAM,WAAW,sDAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}