@inkbar/svelte 0.6.0 → 0.7.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 CHANGED
@@ -175,6 +175,12 @@ A plugin from `definePlugin` (in `@inkbar/core/dom`) adds commands, tools, decor
175
175
 
176
176
  Plugin stores undo with annotations. In controlled mode with `history`, each undo step also snapshots the plugin stores, so accepting something and undoing it restores both.
177
177
 
178
+ ## Search
179
+
180
+ `InkFindBar` is the find bar and `InkSearchButton` opens it. Place the bar anywhere inside `InkRoot`, once `InkViewport` is there; Ctrl/Cmd+F opens it while it is mounted. `useSearch()` returns the search `state` and its actions (`open`, `setQuery`, `setMatchCase`, `next`, `previous`, `close`) for your own control. See the [`@inkbar/core` README](https://github.com/inkbar/inkbar/tree/main/packages/core#search) for the API.
181
+
182
+ The bar handles Escape itself and stops it there, so an `onkeydown` you pass to `InkFindBar` never sees Escape.
183
+
178
184
  ## Custom rendering
179
185
 
180
186
  Slots are snippets. `InkViewport` takes `loading`, `empty`, `error`, `annotation` and `pageError`. `InkThreadPopover` takes `children` as a snippet that receives the popover's props. `InkToolButton` takes `children` as a snippet of `{ active, label }`, and `InkCommand` one of `{ label, busy }`. The props each receives are typed as `AnnotationSlotProps` and `ThreadPopoverSlotProps`, the same types the Vue and React packages export.
@@ -0,0 +1,213 @@
1
+ <script module lang="ts">
2
+ import type { HTMLAttributes } from 'svelte/elements'
3
+
4
+ export type InkFindBarProps = Omit<HTMLAttributes<HTMLDivElement>, 'children'>
5
+ </script>
6
+
7
+ <script lang="ts">
8
+ /*
9
+ * The find bar: a field, the match count, previous and next, a match-case toggle and close,
10
+ * a view of the root's search state. Place it anywhere inside `InkRoot`: it portals itself
11
+ * into `[data-ink-viewport-root]`, the positioned ancestor the theme floats it from over the
12
+ * top-right of the pages (as `InkThreadPopover` anchors to the root's overlay rather than
13
+ * where it is written). It renders nothing until `InkViewport` has mounted, and is hidden
14
+ * while the search is closed. While it is mounted it registers with the search controller,
15
+ * which is what lets Ctrl/Cmd+F open it.
16
+ *
17
+ * Enter in the field steps to the next match, Shift+Enter to the previous, Escape closes.
18
+ * Closing returns focus to where it was before the bar opened, else to the document.
19
+ */
20
+ import { findAnnouncer, findCountText } from '@inkbar/core/dom'
21
+ import { CaseSensitive, ChevronDown, ChevronUp, X } from '@inkbar/icons'
22
+ import { untrack } from 'svelte'
23
+
24
+ import { useInkContext } from '../context.js'
25
+ import { useSearch } from '../hooks/useSearch.svelte.js'
26
+ import { useReadable } from '../use-readable.svelte.js'
27
+
28
+ import InkIcon from './InkIcon.svelte'
29
+
30
+ import type { SearchState } from '@inkbar/core/dom'
31
+
32
+ let { class: className, ...rest }: InkFindBarProps = $props()
33
+
34
+ const ctx = useInkContext('InkFindBar')
35
+ const search = useSearch()
36
+ const scroll = useReadable(() => ctx.viewportEl, null)
37
+ /** The viewport root: the scroll element's parent, once InkViewport has mounted. */
38
+ const target = $derived(scroll.current?.parentElement ?? null)
39
+
40
+ let bar = $state<HTMLDivElement | null>(null)
41
+ let field = $state<HTMLInputElement | null>(null)
42
+ let live = $state<HTMLDivElement | null>(null)
43
+ /** Where focus was when the bar opened, and whether it was open on the last pass. */
44
+ let before: HTMLElement | null = null
45
+ let wasOpen = false
46
+
47
+ const open = $derived(search.state.open)
48
+ const query = $derived(search.state.query)
49
+
50
+ // After the update, so the bar is shown (and can take focus) when it opens.
51
+ $effect(() => {
52
+ const el = bar
53
+ const input = field
54
+ const isOpen = open
55
+ const text = query
56
+ if (!el || !input) return
57
+ untrack(() => {
58
+ if (isOpen !== wasOpen) {
59
+ wasOpen = isOpen
60
+ const doc = el.ownerDocument
61
+ if (isOpen) {
62
+ const active = doc.activeElement
63
+ before =
64
+ active instanceof HTMLElement && active !== doc.body && !el.contains(active)
65
+ ? active
66
+ : null
67
+ input.focus()
68
+ input.select()
69
+ } else {
70
+ // Focus inside the bar is about to be lost with it; focus elsewhere is left alone.
71
+ const hadFocus =
72
+ el.contains(doc.activeElement) || doc.activeElement === doc.body
73
+ if (hadFocus) {
74
+ const to =
75
+ before?.isConnected && !el.contains(before) ? before : scroll.current
76
+ to?.focus({ preventScroll: true })
77
+ }
78
+ before = null
79
+ }
80
+ }
81
+ if (input.value !== text) {
82
+ input.value = text
83
+ // A query set from code arrives after the bar opened: keep the new text selected.
84
+ if (el.ownerDocument.activeElement === input) input.select()
85
+ }
86
+ })
87
+ })
88
+
89
+ // Registered while mounted.
90
+ $effect(() => {
91
+ const controller = ctx.search
92
+ if (!controller || !target) return
93
+ return controller.attachBar()
94
+ })
95
+
96
+ // The live region follows the controller's state change by change, as the vanilla bar does,
97
+ // and is written directly. An update shows only the last of the changes batched into it, so
98
+ // two steps in one task that end where they began would otherwise say nothing.
99
+ $effect(() => {
100
+ const controller = ctx.search
101
+ const el = live
102
+ if (!controller || !el) return
103
+ return untrack(() => {
104
+ const announce = findAnnouncer()
105
+ const say = (s: SearchState): void => {
106
+ const text = announce(s)
107
+ if (el.textContent !== text) el.textContent = text
108
+ }
109
+ say(controller.state.get())
110
+ return controller.state.subscribe(say)
111
+ })
112
+ })
113
+
114
+ // A native listener, so Escape stops at the bar as it does in the vanilla and Vue bars;
115
+ // Svelte's delegated events would stop it only after the root's own listeners saw it.
116
+ $effect(() => {
117
+ const controller = ctx.search
118
+ const el = bar
119
+ if (!controller || !el) return
120
+ const onKeydown = (e: KeyboardEvent): void => {
121
+ if (e.key !== 'Escape' || e.defaultPrevented || e.isComposing) return
122
+ e.preventDefault()
123
+ e.stopPropagation()
124
+ controller.close()
125
+ }
126
+ el.addEventListener('keydown', onKeydown)
127
+ return () => el.removeEventListener('keydown', onKeydown)
128
+ })
129
+
130
+ /**
131
+ * Moves the bar itself into the viewport root, leaving nothing where it is written. Svelte
132
+ * removes it when its own `{#if}` branch goes, but not when an ancestor's block goes and
133
+ * takes only the nodes still in place, so the cleanup removes it too. A keyed `{#each}` that
134
+ * reorders would move the bar back to where it is written, so keep `InkFindBar` out of one.
135
+ */
136
+ const into = (to: Element) => (el: HTMLElement) => {
137
+ to.appendChild(el)
138
+ return () => el.remove()
139
+ }
140
+ </script>
141
+
142
+ {#if target}
143
+ <div
144
+ {...rest}
145
+ bind:this={bar}
146
+ class={['ink-find-bar', className]}
147
+ data-ink-find-bar=""
148
+ role="search"
149
+ hidden={!open}
150
+ {@attach into(target)}
151
+ >
152
+ <input
153
+ bind:this={field}
154
+ type="text"
155
+ aria-label="Find in document"
156
+ autocomplete="off"
157
+ spellcheck={false}
158
+ oninput={(e) => search.setQuery(e.currentTarget.value)}
159
+ onkeydown={(e) => {
160
+ if (e.key !== 'Enter' || e.isComposing) return
161
+ e.preventDefault()
162
+ if (e.shiftKey) search.previous()
163
+ else search.next()
164
+ }}
165
+ />
166
+ <span class="ink-find-count" data-ink-find-count=""
167
+ >{findCountText(search.state)}</span
168
+ >
169
+ <button
170
+ type="button"
171
+ data-ink-find-previous=""
172
+ aria-label="Previous match"
173
+ title="Previous match"
174
+ onclick={() => search.previous()}
175
+ >
176
+ <InkIcon icon={ChevronUp} />
177
+ </button>
178
+ <button
179
+ type="button"
180
+ data-ink-find-next=""
181
+ aria-label="Next match"
182
+ title="Next match"
183
+ onclick={() => search.next()}
184
+ >
185
+ <InkIcon icon={ChevronDown} />
186
+ </button>
187
+ <button
188
+ type="button"
189
+ data-ink-find-match-case=""
190
+ aria-label="Match case"
191
+ title="Match case"
192
+ aria-pressed={search.state.matchCase}
193
+ onclick={() => search.setMatchCase(!search.state.matchCase)}
194
+ >
195
+ <InkIcon icon={CaseSensitive} />
196
+ </button>
197
+ <button
198
+ type="button"
199
+ data-ink-find-close=""
200
+ aria-label="Close find"
201
+ title="Close find"
202
+ onclick={() => search.close()}
203
+ >
204
+ <InkIcon icon={X} />
205
+ </button>
206
+ <div
207
+ bind:this={live}
208
+ class="ink-visually-hidden"
209
+ data-ink-find-status=""
210
+ aria-live="polite"
211
+ ></div>
212
+ </div>
213
+ {/if}
@@ -0,0 +1,6 @@
1
+ import type { HTMLAttributes } from 'svelte/elements';
2
+ export type InkFindBarProps = Omit<HTMLAttributes<HTMLDivElement>, 'children'>;
3
+ declare const InkFindBar: import("svelte").Component<InkFindBarProps, {}, "">;
4
+ type InkFindBar = ReturnType<typeof InkFindBar>;
5
+ export default InkFindBar;
6
+ //# sourceMappingURL=InkFindBar.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InkFindBar.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/InkFindBar.svelte.ts"],"names":[],"mappings":"AAGE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAErD,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC,CAC/E;AAmLD,QAAA,MAAM,UAAU,qDAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
@@ -103,11 +103,15 @@
103
103
  } from '@inkbar/core'
104
104
  import {
105
105
  createPluginHost,
106
+ createSearchController,
106
107
  createToolOptions,
107
108
  cssVariableDefaults,
108
109
  FONT_FAMILIES,
110
+ handleFindKey,
111
+ pageSelectionText,
109
112
  SIGNATURE_FONTS,
110
113
  trackToolStyle,
114
+ viewerSearchOf,
111
115
  } from '@inkbar/core/dom'
112
116
  import { DEV } from 'esm-env'
113
117
  import { untrack } from 'svelte'
@@ -117,7 +121,12 @@
117
121
  import { useReadable } from '../use-readable.svelte.js'
118
122
 
119
123
  import type { PluginHistory } from '@inkbar/core'
120
- import type { PluginHost, ToolController, Viewport } from '@inkbar/core/dom'
124
+ import type {
125
+ PluginHost,
126
+ SearchController,
127
+ ToolController,
128
+ Viewport,
129
+ } from '@inkbar/core/dom'
121
130
 
122
131
  let {
123
132
  src,
@@ -393,7 +402,15 @@
393
402
  const hostActivated = writable<string | null>(null)
394
403
  const viewportEl = writable<HTMLElement | null>(null)
395
404
  let pluginHost = $state.raw<PluginHost | null>(null)
405
+ /** One search controller for the root's life, built with the plugin host that shares it. */
406
+ let search = $state.raw<SearchController | null>(null)
396
407
  $effect(() => {
408
+ const controller = untrack(() =>
409
+ createSearchController({
410
+ document: readonly(hostDocument),
411
+ viewport: () => viewport,
412
+ })
413
+ )
397
414
  const host = untrack(() =>
398
415
  createPluginHost({
399
416
  // Read once, as documented on the prop.
@@ -408,13 +425,33 @@
408
425
  root: readonly(viewportEl),
409
426
  decorate: () => decorateAnnotation,
410
427
  viewport: () => viewport,
428
+ search: viewerSearchOf(controller),
411
429
  })
412
430
  )
431
+ search = controller
413
432
  pluginHost = host
414
433
  // Destroyed after InkViewport's engine and its plugin layers, as in `createViewer`: Svelte
415
434
  // creates a component's effects after its template and tears them down in creation order,
416
435
  // so the children's teardowns run first.
417
- return () => host.destroy()
436
+ return () => {
437
+ host.destroy()
438
+ controller.destroy()
439
+ }
440
+ })
441
+
442
+ /*
443
+ * Ctrl/Cmd+F while focus is in the root and a find bar is mounted; else the browser's. A
444
+ * native listener: the handler reads the event's `currentTarget`, which is the root here.
445
+ */
446
+ $effect(() => {
447
+ const el = ref
448
+ const controller = search
449
+ if (!el || !controller) return
450
+ const onKeydown = (e: KeyboardEvent): void => {
451
+ handleFindKey(e, controller, () => pageSelectionText(el))
452
+ }
453
+ el.addEventListener('keydown', onKeydown)
454
+ return () => el.removeEventListener('keydown', onKeydown)
418
455
  })
419
456
 
420
457
  /** The document's tool style; it batches through `inkHistory`, whichever mode is on. */
@@ -455,6 +492,9 @@
455
492
  get pluginHost() {
456
493
  return pluginHost
457
494
  },
495
+ get search() {
496
+ return search
497
+ },
458
498
  viewportEl,
459
499
  get viewport() {
460
500
  return viewport
@@ -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"}
@@ -129,6 +129,8 @@
129
129
  // The engine adds the plugins' tools and layers, and decorates through the host, which
130
130
  // reads `decorateAnnotation` first.
131
131
  ...(ctx.pluginHost ? { plugins: ctx.pluginHost } : {}),
132
+ // The highlights draw from the shared search.
133
+ ...(ctx.search ? { search: ctx.search } : {}),
132
134
  // Read through, so the effect below can re-apply a new function without a rebuild.
133
135
  decorateAnnotation: (a) => ctx.decorateAnnotation?.(a),
134
136
  ...(ctx.toolStyle ? { toolStyle: ctx.toolStyle } : {}),
@@ -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;AA8TH,QAAA,MAAM,WAAW,sDAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { ChildSnippet } from './child-snippet.js';
2
+ import type { Snippet } from 'svelte';
3
+ import type { HTMLButtonAttributes } from 'svelte/elements';
4
+ /** Props of `InkSearchButton`: a toolbar button that may render through `child`. */
5
+ export interface InkSearchButtonProps extends Omit<HTMLButtonAttributes, 'children'> {
6
+ children?: Snippet | undefined;
7
+ /** Render your own button: spread `props` on it. */
8
+ child?: ChildSnippet | undefined;
9
+ }
10
+ //# sourceMappingURL=search-button.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-button.d.ts","sourceRoot":"","sources":["../../src/lib/components/search-button.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACtD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAA;AACrC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAA;AAE3D,oFAAoF;AACpF,MAAM,WAAW,oBAAqB,SAAQ,IAAI,CAAC,oBAAoB,EAAE,UAAU,CAAC;IAClF,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IAC9B,oDAAoD;IACpD,KAAK,CAAC,EAAE,YAAY,GAAG,SAAS,CAAA;CACjC"}
@@ -0,0 +1 @@
1
+ export {};
package/dist/context.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { Annotation, InkDocument, InkStatus, PdfAssets, PluginHistory, SignatureLibrary, Writable } from '@inkbar/core';
2
- import type { DecorateAnnotation, PluginHost, Tool, ToolController, ToolId, ToolOptions, ToolStyle, Viewport, ZoomValue } from '@inkbar/core/dom';
2
+ import type { DecorateAnnotation, PluginHost, SearchController, Tool, ToolController, ToolId, ToolOptions, ToolStyle, Viewport, ZoomValue } from '@inkbar/core/dom';
3
3
  export type { InkStatus };
4
4
  /**
5
5
  * Undo and redo for the current document, whichever mode its annotations are in. `track` and
@@ -36,6 +36,12 @@ export interface InkContext {
36
36
  * InkCommand places its commands.
37
37
  */
38
38
  readonly pluginHost: PluginHost | null;
39
+ /**
40
+ * The root's search controller, built with the plugin host and kept for its life; `null`
41
+ * before the root has mounted, and on the server. InkViewport hands it to the engine, which
42
+ * draws the highlights; `useSearch` and the find bar read it.
43
+ */
44
+ readonly search: SearchController | null;
39
45
  /** InkViewport's scroll element while it is mounted: the plugins' `root`. */
40
46
  readonly viewportEl: Writable<HTMLElement | null>;
41
47
  /** Set by InkViewport once it has built its viewport and tool controller. */
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/lib/context.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/lib/context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { SearchState, ViewerSearch } from '@inkbar/core/dom';
2
+ /**
3
+ * The document search for hosts building their own control: the state, and the actions the
4
+ * find bar uses. Search is set up once InkRoot has mounted, so until then (and on the server)
5
+ * the state is closed and the actions do nothing. `open()` runs the search and draws the
6
+ * highlights even when no find bar is mounted.
7
+ */
8
+ export declare function useSearch(): {
9
+ readonly state: SearchState;
10
+ } & Omit<ViewerSearch, 'state'>;
11
+ //# sourceMappingURL=useSearch.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSearch.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/hooks/useSearch.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAWjE;;;;;GAKG;AACH,wBAAgB,SAAS,IAAI;IAAE,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAA;CAAE,GAAG,IAAI,CACjE,YAAY,EACZ,OAAO,CACR,CAcA"}
@@ -0,0 +1,31 @@
1
+ import { useInkContext } from '../context.js';
2
+ import { useReadable } from '../use-readable.svelte.js';
3
+ const CLOSED = {
4
+ open: false,
5
+ query: '',
6
+ matchCase: false,
7
+ hits: [],
8
+ current: -1,
9
+ scanning: false,
10
+ };
11
+ /**
12
+ * The document search for hosts building their own control: the state, and the actions the
13
+ * find bar uses. Search is set up once InkRoot has mounted, so until then (and on the server)
14
+ * the state is closed and the actions do nothing. `open()` runs the search and draws the
15
+ * highlights even when no find bar is mounted.
16
+ */
17
+ export function useSearch() {
18
+ const ctx = useInkContext('useSearch()');
19
+ const state = useReadable(() => ctx.search?.state, CLOSED);
20
+ return {
21
+ get state() {
22
+ return state.current;
23
+ },
24
+ open: (query) => ctx.search?.open(query),
25
+ setQuery: (query) => ctx.search?.setQuery(query),
26
+ setMatchCase: (on) => ctx.search?.setMatchCase(on),
27
+ next: () => ctx.search?.next(),
28
+ previous: () => ctx.search?.previous(),
29
+ close: () => ctx.search?.close(),
30
+ };
31
+ }
package/dist/index.d.ts CHANGED
@@ -15,6 +15,7 @@ export { useSelection } from './hooks/useSelection.svelte.js';
15
15
  export { useZoom } from './hooks/useZoom.svelte.js';
16
16
  export { usePage } from './hooks/usePage.svelte.js';
17
17
  export { useHistory } from './hooks/useHistory.svelte.js';
18
+ export { useSearch } from './hooks/useSearch.svelte.js';
18
19
  export { useEmbedded } from './hooks/useEmbedded.svelte.js';
19
20
  export { useCommand } from './hooks/useCommand.svelte.js';
20
21
  export type { CommandHandle } from './hooks/useCommand.svelte.js';
@@ -43,6 +44,10 @@ export type { InkHistoryButtonProps } from './components/history-button.js';
43
44
  export { default as InkZoomIn } from './components/InkZoomIn.svelte';
44
45
  export { default as InkZoomOut } from './components/InkZoomOut.svelte';
45
46
  export type { InkZoomButtonProps } from './components/zoom-button.js';
47
+ export { default as InkSearchButton } from './components/InkSearchButton.svelte';
48
+ export type { InkSearchButtonProps } from './components/search-button.js';
49
+ export { default as InkFindBar } from './components/InkFindBar.svelte';
50
+ export type { InkFindBarProps } from './components/InkFindBar.svelte';
46
51
  export { default as InkColorMenu } from './components/InkColorMenu.svelte';
47
52
  export type { InkColorMenuProps } from './components/InkColorMenu.svelte';
48
53
  export { default as InkShapeMenu } from './components/InkShapeMenu.svelte';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/lib/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/lib/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -9,6 +9,7 @@ export { useSelection } from './hooks/useSelection.svelte.js';
9
9
  export { useZoom } from './hooks/useZoom.svelte.js';
10
10
  export { usePage } from './hooks/usePage.svelte.js';
11
11
  export { useHistory } from './hooks/useHistory.svelte.js';
12
+ export { useSearch } from './hooks/useSearch.svelte.js';
12
13
  export { useEmbedded } from './hooks/useEmbedded.svelte.js';
13
14
  export { useCommand } from './hooks/useCommand.svelte.js';
14
15
  export { default as InkRoot } from './components/InkRoot.svelte';
@@ -24,6 +25,8 @@ export { default as InkUndo } from './components/InkUndo.svelte';
24
25
  export { default as InkRedo } from './components/InkRedo.svelte';
25
26
  export { default as InkZoomIn } from './components/InkZoomIn.svelte';
26
27
  export { default as InkZoomOut } from './components/InkZoomOut.svelte';
28
+ export { default as InkSearchButton } from './components/InkSearchButton.svelte';
29
+ export { default as InkFindBar } from './components/InkFindBar.svelte';
27
30
  export { default as InkColorMenu } from './components/InkColorMenu.svelte';
28
31
  export { default as InkShapeMenu } from './components/InkShapeMenu.svelte';
29
32
  export { default as InkSignatureMenu } from './components/InkSignatureMenu.svelte';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inkbar/svelte",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "Svelte 5 components and hooks for Inkbar, the browser PDF viewer and editor.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://inkbar.dev",
@@ -26,22 +26,23 @@
26
26
  "./package.json": "./package.json"
27
27
  },
28
28
  "dependencies": {
29
- "@inkbar/icons": "^0.6.0",
29
+ "@inkbar/icons": "^0.7.0",
30
30
  "@internationalized/date": "^3.12.4",
31
31
  "bits-ui": "^2.19.5",
32
32
  "esm-env": "^1.2.0"
33
33
  },
34
34
  "peerDependencies": {
35
- "@inkbar/core": "^0.6.0",
35
+ "@inkbar/core": "^0.7.0",
36
36
  "svelte": "^5.46.4"
37
37
  },
38
38
  "devDependencies": {
39
- "@inkbar/core": "0.6.0",
39
+ "@inkbar/core": "0.7.0",
40
40
  "@inkbar/fixtures": "0.0.0",
41
- "@inkbar/theme": "0.6.0",
41
+ "@inkbar/theme": "0.7.0",
42
42
  "@sveltejs/package": "^3.0.0",
43
43
  "@sveltejs/vite-plugin-svelte": "^7.3.1",
44
44
  "@vitest/browser-playwright": "^5.0.4",
45
+ "axe-core": "^4.13.0",
45
46
  "playwright": "1.62.1",
46
47
  "svelte": "^5.57.2",
47
48
  "svelte-check": "^4.7.6",