@inkbar/vue 0.8.0 → 0.10.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 +70 -4
- package/dist/components/InkDownloadButton.js +7 -0
- package/dist/components/InkDownloadButton.js.map +1 -0
- package/dist/components/InkDownloadButton.vue.d.ts +21 -0
- package/dist/components/InkDownloadButton.vue.d.ts.map +1 -0
- package/dist/components/InkDownloadButton.vue_vue_type_script_setup_true_lang.js +42 -0
- package/dist/components/InkDownloadButton.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/InkFindBar.js.map +1 -1
- package/dist/components/InkFindBar.vue.d.ts.map +1 -1
- package/dist/components/InkFindBar.vue_vue_type_script_setup_true_lang.js +48 -48
- package/dist/components/InkFindBar.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/InkHighlightMenu.js.map +1 -1
- package/dist/components/InkHighlightMenu.vue.d.ts.map +1 -1
- package/dist/components/InkHighlightMenu.vue_vue_type_script_setup_true_lang.js +67 -65
- package/dist/components/InkHighlightMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/InkPanel.js +7 -0
- package/dist/components/InkPanel.js.map +1 -0
- package/dist/components/InkPanel.vue.d.ts +21 -0
- package/dist/components/InkPanel.vue.d.ts.map +1 -0
- package/dist/components/InkPanel.vue_vue_type_script_setup_true_lang.js +48 -0
- package/dist/components/InkPanel.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/InkPrintButton.js +7 -0
- package/dist/components/InkPrintButton.js.map +1 -0
- package/dist/components/InkPrintButton.vue.d.ts +19 -0
- package/dist/components/InkPrintButton.vue.d.ts.map +1 -0
- package/dist/components/InkPrintButton.vue_vue_type_script_setup_true_lang.js +39 -0
- package/dist/components/InkPrintButton.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/InkRecordList.js +7 -0
- package/dist/components/InkRecordList.js.map +1 -0
- package/dist/components/InkRecordList.vue.d.ts +35 -0
- package/dist/components/InkRecordList.vue.d.ts.map +1 -0
- package/dist/components/InkRecordList.vue_vue_type_script_setup_true_lang.js +41 -0
- package/dist/components/InkRecordList.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/InkRoot.js.map +1 -1
- package/dist/components/InkRoot.vue.d.ts +48 -4
- package/dist/components/InkRoot.vue.d.ts.map +1 -1
- package/dist/components/InkRoot.vue_vue_type_script_setup_true_lang.js +177 -164
- package/dist/components/InkRoot.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/InkSearchResults.js +7 -0
- package/dist/components/InkSearchResults.js.map +1 -0
- package/dist/components/InkSearchResults.vue.d.ts +9 -0
- package/dist/components/InkSearchResults.vue.d.ts.map +1 -0
- package/dist/components/InkSearchResults.vue_vue_type_script_setup_true_lang.js +52 -0
- package/dist/components/InkSearchResults.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/InkShapeMenu.js.map +1 -1
- package/dist/components/InkShapeMenu.vue.d.ts.map +1 -1
- package/dist/components/InkShapeMenu.vue_vue_type_script_setup_true_lang.js +58 -56
- package/dist/components/InkShapeMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/InkSidebar.js +7 -0
- package/dist/components/InkSidebar.js.map +1 -0
- package/dist/components/InkSidebar.vue.d.ts +34 -0
- package/dist/components/InkSidebar.vue.d.ts.map +1 -0
- package/dist/components/InkSidebar.vue_vue_type_script_setup_true_lang.js +95 -0
- package/dist/components/InkSidebar.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/InkSignatureDialog.js.map +1 -1
- package/dist/components/InkSignatureDialog.vue.d.ts +3 -2
- package/dist/components/InkSignatureDialog.vue.d.ts.map +1 -1
- package/dist/components/InkSignatureDialog.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/InkSignatureMenu.js.map +1 -1
- package/dist/components/InkSignatureMenu.vue.d.ts.map +1 -1
- package/dist/components/InkSignatureMenu.vue_vue_type_script_setup_true_lang.js +77 -75
- package/dist/components/InkSignatureMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/InkThumbnail.js +7 -0
- package/dist/components/InkThumbnail.js.map +1 -0
- package/dist/components/InkThumbnail.vue.d.ts +18 -0
- package/dist/components/InkThumbnail.vue.d.ts.map +1 -0
- package/dist/components/InkThumbnail.vue_vue_type_script_setup_true_lang.js +49 -0
- package/dist/components/InkThumbnail.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/InkThumbnails.js +7 -0
- package/dist/components/InkThumbnails.js.map +1 -0
- package/dist/components/InkThumbnails.vue.d.ts +27 -0
- package/dist/components/InkThumbnails.vue.d.ts.map +1 -0
- package/dist/components/InkThumbnails.vue_vue_type_script_setup_true_lang.js +107 -0
- package/dist/components/InkThumbnails.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/InkToolButton.js.map +1 -1
- package/dist/components/InkToolButton.vue.d.ts.map +1 -1
- package/dist/components/InkToolButton.vue_vue_type_script_setup_true_lang.js +39 -36
- package/dist/components/InkToolButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/InkToolbarButton.js +7 -0
- package/dist/components/InkToolbarButton.js.map +1 -0
- package/dist/components/InkToolbarButton.vue.d.ts +22 -0
- package/dist/components/InkToolbarButton.vue.d.ts.map +1 -0
- package/dist/components/InkToolbarButton.vue_vue_type_script_setup_true_lang.js +32 -0
- package/dist/components/InkToolbarButton.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/InkViewport.js.map +1 -1
- package/dist/components/InkViewport.vue.d.ts.map +1 -1
- package/dist/components/InkViewport.vue_vue_type_script_setup_true_lang.js +37 -36
- package/dist/components/InkViewport.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/InkZoomSelect.js.map +1 -1
- package/dist/components/InkZoomSelect.vue.d.ts.map +1 -1
- package/dist/components/InkZoomSelect.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/InkZoomSelect.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/RecordCards.js +7 -0
- package/dist/components/RecordCards.js.map +1 -0
- package/dist/components/RecordCards.vue.d.ts +25 -0
- package/dist/components/RecordCards.vue.d.ts.map +1 -0
- package/dist/components/RecordCards.vue_vue_type_script_setup_true_lang.js +120 -0
- package/dist/components/RecordCards.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/SidebarTrigger.js +7 -0
- package/dist/components/SidebarTrigger.js.map +1 -0
- package/dist/components/SidebarTrigger.vue.d.ts +9 -0
- package/dist/components/SidebarTrigger.vue.d.ts.map +1 -0
- package/dist/components/SidebarTrigger.vue_vue_type_script_setup_true_lang.js +33 -0
- package/dist/components/SidebarTrigger.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/SignatureForm.js.map +1 -1
- package/dist/components/SignatureForm.vue.d.ts.map +1 -1
- package/dist/components/SignatureForm.vue_vue_type_script_setup_true_lang.js +56 -55
- package/dist/components/SignatureForm.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/sidebar-context.d.ts +21 -0
- package/dist/components/sidebar-context.d.ts.map +1 -0
- package/dist/components/sidebar-context.js +7 -0
- package/dist/components/sidebar-context.js.map +1 -0
- package/dist/composables/useAnnotations.d.ts +91 -0
- package/dist/composables/useAnnotations.d.ts.map +1 -1
- package/dist/composables/useRecordSelection.d.ts +12 -0
- package/dist/composables/useRecordSelection.d.ts.map +1 -0
- package/dist/composables/useRecordSelection.js +15 -0
- package/dist/composables/useRecordSelection.js.map +1 -0
- package/dist/composables/useRecords.d.ts +14 -0
- package/dist/composables/useRecords.d.ts.map +1 -0
- package/dist/composables/useRecords.js +16 -0
- package/dist/composables/useRecords.js.map +1 -0
- package/dist/composables/useRegisteredTool.d.ts +21 -0
- package/dist/composables/useRegisteredTool.d.ts.map +1 -0
- package/dist/composables/useRegisteredTool.js +25 -0
- package/dist/composables/useRegisteredTool.js.map +1 -0
- package/dist/composables/useSearch.d.ts.map +1 -1
- package/dist/composables/useSearch.js +1 -0
- package/dist/composables/useSearch.js.map +1 -1
- package/dist/composables/useToolOptions.d.ts +8 -0
- package/dist/composables/useToolOptions.d.ts.map +1 -1
- package/dist/composables/useToolOptions.js +10 -5
- package/dist/composables/useToolOptions.js.map +1 -1
- package/dist/context.d.ts +5 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js.map +1 -1
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +40 -29
- package/dist/to-readable.d.ts +7 -0
- package/dist/to-readable.d.ts.map +1 -0
- package/dist/to-readable.js +11 -0
- package/dist/to-readable.js.map +1 -0
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -52,6 +52,7 @@ import {
|
|
|
52
52
|
InkZoomSelect,
|
|
53
53
|
InkThreadPopover,
|
|
54
54
|
} from '@inkbar/vue'
|
|
55
|
+
import { highlightTool, noteTool, redactAreaTool } from '@inkbar/core/dom'
|
|
55
56
|
import type { Annotation } from '@inkbar/core'
|
|
56
57
|
import { assets } from 'virtual:inkbar-assets'
|
|
57
58
|
import '@inkbar/theme/theme.css'
|
|
@@ -59,12 +60,14 @@ import '@inkbar/theme/theme.css'
|
|
|
59
60
|
defineProps<{ signedUrl: string; documentId: string }>()
|
|
60
61
|
|
|
61
62
|
const annotations = ref<Annotation[]>([])
|
|
63
|
+
const tools = [highlightTool(), redactAreaTool(), noteTool()]
|
|
62
64
|
</script>
|
|
63
65
|
|
|
64
66
|
<template>
|
|
65
67
|
<InkRoot
|
|
66
68
|
:src="{ url: signedUrl, key: documentId }"
|
|
67
69
|
:assets="assets"
|
|
70
|
+
:tools="tools"
|
|
68
71
|
v-model:annotations="annotations"
|
|
69
72
|
>
|
|
70
73
|
<InkToolbar>
|
|
@@ -90,7 +93,9 @@ const annotations = ref<Annotation[]>([])
|
|
|
90
93
|
</template>
|
|
91
94
|
```
|
|
92
95
|
|
|
93
|
-
|
|
96
|
+
`select-text` and `select` are always there. Every other tool is opt-in: pass the ones you offer through `tools`, from the tool factories in `@inkbar/core/dom`, or `allTools()` for all of them. A button for a tool you did not pass renders disabled and hidden, a tool menu renders nothing, and each logs an `InkError('UnknownTool')` to the console once. If the active tool leaves `tools`, the viewer switches to `select-text` and reports it through `update:tool`.
|
|
97
|
+
|
|
98
|
+
Each control is a separate component, so put them in any order or leave some out. Buttons show icons from `@inkbar/icons`. Put your own in a button's default slot to replace one, and use `InkIcon` to put the same icons on your own buttons. For a button of your own, such as `<InkToolbarButton @click="download">Download</InkToolbarButton>`, use `InkToolbarButton`: it joins the toolbar's arrow-key focus and looks like the other buttons.
|
|
94
99
|
|
|
95
100
|
`v-model:annotations` makes your list the source of truth. Leave it off and Inkbar keeps the state itself, with undo and redo.
|
|
96
101
|
|
|
@@ -130,7 +135,7 @@ The highlight tool leaves `contents` free for the comment. `doc.text(page)` retu
|
|
|
130
135
|
|
|
131
136
|
## Signatures
|
|
132
137
|
|
|
133
|
-
`InkSignatureMenu` lists saved signatures, picks one for the `signature` tool, removes them, and opens `InkSignatureDialog` to draw, type or upload a new one. These are marks on the page, not cryptographic signatures. Pass `signatures` to `InkRoot` to keep them somewhere: `createLocalSignatureStore(key)` from `@inkbar/core` uses `localStorage`, and without it they last until reload. `signatureFonts` lists the handwriting fonts the Type tab offers; load them with `@font-face`. A placed signature keeps its aspect ratio when resized.
|
|
138
|
+
`InkSignatureMenu` lists saved signatures, picks one for the `signature` tool, removes them, and opens `InkSignatureDialog` to draw, type or upload a new one. The menu needs `signatureTool()` in `tools`. The dialog and signature form fields work without it; the dialog then only saves the signature. These are marks on the page, not cryptographic signatures. Pass `signatures` to `InkRoot` to keep them somewhere: `createLocalSignatureStore(key)` from `@inkbar/core` uses `localStorage`, and without it they last until reload. `signatureFonts` lists the handwriting fonts the Type tab offers; load them with `@font-face`. A placed signature keeps its aspect ratio when resized.
|
|
134
139
|
|
|
135
140
|
## Plugins
|
|
136
141
|
|
|
@@ -154,11 +159,71 @@ Plugin stores undo with annotations. In controlled mode with `:history="true"`,
|
|
|
154
159
|
|
|
155
160
|
`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.
|
|
156
161
|
|
|
162
|
+
## Sidebars
|
|
163
|
+
|
|
164
|
+
`InkSidebar` holds `InkPanel`s and places nothing itself: put it beside `InkViewport` with your own flex or grid layout. Each panel has an `id`, a `label`, an optional `icon` (an `IconNode` from `@inkbar/icons`) and an optional `badge`, a number or short string hidden when empty or 0. Its default slot is the panel's content, your own component or one of Inkbar's.
|
|
165
|
+
|
|
166
|
+
```vue
|
|
167
|
+
<InkRoot :src="src" :assets="assets">
|
|
168
|
+
<div class="app">
|
|
169
|
+
<InkSidebar side="left" layout="rail" v-model:open="open">
|
|
170
|
+
<InkPanel id="pages" label="Pages" :icon="Square">
|
|
171
|
+
<InkThumbnails />
|
|
172
|
+
</InkPanel>
|
|
173
|
+
<InkPanel id="notes" label="Notes" :icon="MessageSquare" :badge="noteCount">
|
|
174
|
+
<MyNotes />
|
|
175
|
+
</InkPanel>
|
|
176
|
+
</InkSidebar>
|
|
177
|
+
<InkViewport />
|
|
178
|
+
</div>
|
|
179
|
+
</InkRoot>
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
`layout` is `rail` (default: icon buttons beside the document, and activating the open panel's button closes it), `tabs` (labelled tabs, one panel open) or `stack` (a header per panel, any number expanded). `side` (`left` by default) decides which edge the rail and border sit on. `v-model:open` is the open panel's id, or `null`, for rail and tabs, and the expanded ids for stack. Left unbound, the first panel starts open. When the open panel goes (a `v-if`), rail and tabs open the first one left and stack drops it, and `v-model:open` receives the new value. In the rail, the open panel shows its label as a title above its content. `visible` (default `true`) shows or hides the whole sidebar; it keeps the open panel, its content and its scroll for when it shows again. Your code decides when: `:visible="hits > 0"` keeps a results sidebar out of the way until a search finds something.
|
|
183
|
+
|
|
184
|
+
Panels take their place in the order they appear in the template, including one added later with `v-if`. A closed panel stays mounted and hidden, so its content keeps its state and scroll position, across layout changes too. The keys and ARIA are core's: see the [`@inkbar/core` README](https://github.com/inkbar/inkbar/tree/main/packages/core#sidebars). The sidebar needs no document and works outside `InkRoot`. On the server it renders its frame with the open panel showing, and the stack headers; rail and tab buttons follow once it has mounted.
|
|
185
|
+
|
|
186
|
+
## Thumbnails
|
|
187
|
+
|
|
188
|
+
`InkThumbnail` draws one page (0-based `page`) as a small image, with its annotations and plugin marks. Give it a `width` or a `height` and the other follows the page; with neither it is 120px wide. `:annotations="false"` and `:marks="false"` leave those out, and `label` replaces its accessible name ("Page 4" for page 3). It is an image with no focus or click behaviour, so wrap it in the control you need, a checkbox label in a dialog for instance.
|
|
189
|
+
|
|
190
|
+
`InkThumbnails` lists the pages as thumbnails, each a button that scrolls the viewport to its page, with the current page marked `aria-current="page"`. It fills its parent's height and scrolls. `pages` lists the pages to show, in order. The thumbnails fill the list's width less a 16px gutter each side and follow it as it resizes; `width` fixes them at that many pixels instead. `annotations` and `marks` pass to each thumbnail. Only the items near the visible part are mounted. The `item` slot adds to each item after its page number:
|
|
191
|
+
|
|
192
|
+
```vue
|
|
193
|
+
<InkThumbnails>
|
|
194
|
+
<template #item="{ page, current }">
|
|
195
|
+
<span class="page-count">{{ counts[page] }}</span>
|
|
196
|
+
</template>
|
|
197
|
+
</InkThumbnails>
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
An item's height is worked out from its page alone, so position what you add absolutely. The `item` slot renders inside the item's `<button>`: keep it non-interactive, with no links, buttons or inputs. Both need `InkRoot` and render empty on the server.
|
|
201
|
+
|
|
202
|
+
## Record lists
|
|
203
|
+
|
|
204
|
+
`InkRecordList` lists a plugin's records as cards, the same cards their marks open, with the same actions. Name the records `<plugin>.<name>`:
|
|
205
|
+
|
|
206
|
+
```vue
|
|
207
|
+
<InkPanel id="suggestions" label="Suggestions" :icon="MessageSquare" :badge="count">
|
|
208
|
+
<InkRecordList records="review.suggestions" @update:count="count = $event">
|
|
209
|
+
<template #empty>No suggestions left.</template>
|
|
210
|
+
</InkRecordList>
|
|
211
|
+
</InkPanel>
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
The list and the marks share one selection: choosing a card selects its mark and scrolls the viewer there, and activating a mark selects its card. Each action runs in one undo step. `card`, `where` and `sort` replace the marks' card, filter and reading order. Changing one rebuilds the list, so define them once in your script, not inline in the template. `update:count` gives the number listed whenever it changes, ready for a panel badge. The `empty` slot replaces "Nothing here yet.". To list something of your own, pass a `source` (a `RecordListSource`, as core's `recordsSource` and `searchSource` build) in place of `records`: it gets the same cards, keys and selection. With both, `source` wins.
|
|
215
|
+
|
|
216
|
+
`InkSearchResults` is the same list over the document search: one card per hit, titled with its page ("Page 2"), with its place on that page ("Match 3") and the text around it. Choosing a card makes its hit current, as the find bar's next and previous do. It has its own field, labelled "Find in document", above the cards and the find bar's match count in a footer below them; `:field="false"` leaves the field out when a find bar is on the page. Field and find bar share the search state, so they never disagree.
|
|
217
|
+
|
|
218
|
+
To build your own, `useRecords<T>(name)` returns the live `records` and the `handle` to read and write them, each write one undo step, and `useRecordSelection(name)` returns `selected` and `select(id | null)`. Both need `InkRoot`. Plugins are set up once it has mounted, so until then `handle` is null, `records` is empty and nothing is selected. Both lists fill their parent's height and render empty on the server. The keys, focus and announcements are core's: see the [`@inkbar/core` README](https://github.com/inkbar/inkbar/tree/main/packages/core#record-lists).
|
|
219
|
+
|
|
157
220
|
## Custom rendering
|
|
158
221
|
|
|
159
222
|
Slots let you render parts yourself. `InkViewport` has `loading`, `empty`, `error`, `annotation` and `page-error` slots. `InkThreadPopover` has a scoped default slot that receives the popover's props, and the default slot of `InkToolButton` receives `{ active, label }`. The props are typed as `AnnotationSlotProps` and `ThreadPopoverSlotProps`, the same types the React and Svelte packages export.
|
|
160
223
|
|
|
161
|
-
`
|
|
224
|
+
`InkDownloadButton` and `InkPrintButton` download and print the open PDF; `filename` names the download (the opened `File`'s name, else the URL's last segment, else `document.pdf`). Printing loads the file into a hidden frame and opens the browser's print dialog for it; on iOS the PDF opens in a new tab instead. Until saving into the PDF ships, both give the file as it was opened, without this session's annotations.
|
|
225
|
+
|
|
226
|
+
`InkRoot`, `InkToolbar`, `InkToolButton`, `InkCommand`, `InkUndo`, `InkRedo`, `InkDownloadButton`, `InkPrintButton`, `InkPrevPage`, `InkNextPage`, `InkZoomIn` and `InkZoomOut` take `as-child` to render your own element in place of theirs, such as a button from your design system. Put that element in the default slot. The control keeps its behaviour and accessible name.
|
|
162
227
|
|
|
163
228
|
## Keyboard
|
|
164
229
|
|
|
@@ -168,6 +233,7 @@ The scroll area takes focus. From there:
|
|
|
168
233
|
- With the `note` tool active, `Enter` places a note at the centre of the current page and opens it.
|
|
169
234
|
- With the `signature` tool active, `Enter` places the chosen signature at the centre of the current page.
|
|
170
235
|
- `Ctrl` or `Cmd` + `Z` undoes. `Ctrl` or `Cmd` + `Shift` + `Z`, or `Ctrl` + `Y`, redoes. `Ctrl` and `Cmd` both work on every platform. The keys do what `InkUndo` and `InkRedo` do, from anywhere in `InkRoot`, toolbars included, and act only while that button is enabled. In a text field or editable content the keys stay with the element, so a field keeps its own text undo. In a `<select>` they are left to the browser, which does nothing with them.
|
|
236
|
+
- `Ctrl` or `Cmd` + `P` prints the PDF and `Ctrl` or `Cmd` + `S` downloads it, as `InkPrintButton` and `InkDownloadButton` do, from anywhere in `InkRoot` once the document is ready. Outside `InkRoot` the browser keeps them.
|
|
171
237
|
|
|
172
238
|
On a focused annotation:
|
|
173
239
|
|
|
@@ -185,7 +251,7 @@ Components carry state on data attributes, for example `[data-annotation][data-s
|
|
|
185
251
|
|
|
186
252
|
## Composables
|
|
187
253
|
|
|
188
|
-
`useDocument`, `useAnnotations`, `useTool`, `useSelection`, `useZoom`, `usePage`, `useHistory`, `useEmbedded` and `
|
|
254
|
+
`useDocument`, `useAnnotations`, `useTool`, `useSelection`, `useZoom`, `usePage`, `useHistory`, `useEmbedded`, `useCommand`, `useRecords` and `useRecordSelection` read the state of the nearest `InkRoot`. Build your own toolbar or side panel from them. Tool options, such as the shape kind, last as long as `InkRoot`. The tool style that `useToolStyle` reads and sets (colours, line style, text style) belongs to the document: opening another one starts again from the theme's defaults.
|
|
189
255
|
|
|
190
256
|
## Licence
|
|
191
257
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InkDownloadButton.js","names":["_sfc_main","InkDownloadButton_vue_vue_type_script_setup_true_lang_default","InkDownloadButton_default"],"sources":["../../src/components/InkDownloadButton.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/*\n * Saves the open document's file through the browser's download, under its `fileName` or\n * `filename`. Disabled until the document is ready. Today that is the file as it was\n * opened, without this session's annotations.\n */\nimport { downloadDocument } from '@inkbar/core/dom'\nimport { Download } from '@inkbar/icons'\nimport { ToolbarButton } from 'reka-ui'\nimport { computed } from 'vue'\n\nimport { useInkContext } from '../context'\n\nimport InkIcon from './InkIcon.vue'\n\nconst props = withDefaults(\n defineProps<{ asChild?: boolean; filename?: string | undefined }>(),\n {\n asChild: false,\n filename: undefined,\n }\n)\nconst ctx = useInkContext('InkDownloadButton')\nconst ready = computed(\n () => ctx.document.value !== null && ctx.status.value.state === 'ready'\n)\n\nfunction run(): void {\n const doc = ctx.document.value\n if (doc)\n void downloadDocument(\n doc,\n props.filename === undefined ? {} : { filename: props.filename }\n ).catch(() => undefined)\n}\n// Reka's typed props stop at its own; ARIA and listeners go through a bound object.\nconst attrs = { 'aria-label': 'Download', title: 'Download', onClick: run }\n</script>\n\n<template>\n <ToolbarButton\n :as-child=\"asChild\"\n :disabled=\"!ready\"\n class=\"ink-download\"\n data-ink-download\n v-bind=\"attrs\"\n >\n <slot><InkIcon :icon=\"Download\" /></slot>\n </ToolbarButton>\n</template>\n"],"mappings":""}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
asChild?: boolean;
|
|
3
|
+
filename?: string | undefined;
|
|
4
|
+
};
|
|
5
|
+
declare var __VLS_7: {};
|
|
6
|
+
type __VLS_Slots = {} & {
|
|
7
|
+
default?: (props: typeof __VLS_7) => any;
|
|
8
|
+
};
|
|
9
|
+
declare const __VLS_base: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
10
|
+
asChild: boolean;
|
|
11
|
+
filename: string | undefined;
|
|
12
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
13
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
14
|
+
declare const _default: typeof __VLS_export;
|
|
15
|
+
export default _default;
|
|
16
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
17
|
+
new (): {
|
|
18
|
+
$slots: S;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=InkDownloadButton.vue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InkDownloadButton.vue.d.ts","sourceRoot":"","sources":["../../src/components/InkDownloadButton.vue"],"names":[],"mappings":"AAmEA,KAAK,WAAW,GAAG;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AA0ExE,QAAA,IAAI,OAAO,IAAW,CAAC;AACvB,KAAK,WAAW,GAAG,EAAE,GACnB;IAAE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,OAAO,KAAK,GAAG,CAAA;CAAE,CAAC;AAG/C,QAAA,MAAM,UAAU;;;6EAGd,CAAC;AACH,QAAA,MAAM,YAAY,EAAS,eAAe,CAAC,OAAO,UAAU,EAAE,WAAW,CAAC,CAAC;wBACtD,OAAO,YAAY;AAAxC,wBAAyC;AAWzC,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { useInkContext as e } from "../context.js";
|
|
2
|
+
import t from "./InkIcon.js";
|
|
3
|
+
import { computed as n, createBlock as r, createVNode as i, defineComponent as a, mergeProps as o, openBlock as s, renderSlot as c, unref as l, withCtx as u } from "vue";
|
|
4
|
+
import { downloadDocument as d } from "@inkbar/core/dom";
|
|
5
|
+
import { ToolbarButton as f } from "reka-ui";
|
|
6
|
+
import { Download as p } from "@inkbar/icons";
|
|
7
|
+
//#region src/components/InkDownloadButton.vue?vue&type=script&setup=true&lang.ts
|
|
8
|
+
var m = /*@__PURE__*/ a({
|
|
9
|
+
__name: "InkDownloadButton",
|
|
10
|
+
props: {
|
|
11
|
+
asChild: {
|
|
12
|
+
type: Boolean,
|
|
13
|
+
default: !1
|
|
14
|
+
},
|
|
15
|
+
filename: { default: void 0 }
|
|
16
|
+
},
|
|
17
|
+
setup(a) {
|
|
18
|
+
let m = a, h = e("InkDownloadButton"), g = n(() => h.document.value !== null && h.status.value.state === "ready");
|
|
19
|
+
function _() {
|
|
20
|
+
let e = h.document.value;
|
|
21
|
+
e && d(e, m.filename === void 0 ? {} : { filename: m.filename }).catch(() => void 0);
|
|
22
|
+
}
|
|
23
|
+
let v = {
|
|
24
|
+
"aria-label": "Download",
|
|
25
|
+
title: "Download",
|
|
26
|
+
onClick: _
|
|
27
|
+
};
|
|
28
|
+
return (e, n) => (s(), r(l(f), o({
|
|
29
|
+
"as-child": a.asChild,
|
|
30
|
+
disabled: !g.value,
|
|
31
|
+
class: "ink-download",
|
|
32
|
+
"data-ink-download": ""
|
|
33
|
+
}, v), {
|
|
34
|
+
default: u(() => [c(e.$slots, "default", {}, () => [i(t, { icon: l(p) }, null, 8, ["icon"])])]),
|
|
35
|
+
_: 3
|
|
36
|
+
}, 16, ["as-child", "disabled"]));
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
//#endregion
|
|
40
|
+
export { m as default };
|
|
41
|
+
|
|
42
|
+
//# sourceMappingURL=InkDownloadButton.vue_vue_type_script_setup_true_lang.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InkDownloadButton.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createBlock","_unref","_mergeProps","_withCtx","_renderSlot","_createVNode","InkIcon","InkIcon_default","InkDownloadButton_vue_vue_type_script_setup_true_lang_default","props","__props","ctx","useInkContext","ready","computed","run","doc","downloadDocument","attrs","openBlock","createBlock","unref","ToolbarButton","mergeProps","withCtx","renderSlot","_ctx","createVNode","Download"],"sources":["../../src/components/InkDownloadButton.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/*\n * Saves the open document's file through the browser's download, under its `fileName` or\n * `filename`. Disabled until the document is ready. Today that is the file as it was\n * opened, without this session's annotations.\n */\nimport { downloadDocument } from '@inkbar/core/dom'\nimport { Download } from '@inkbar/icons'\nimport { ToolbarButton } from 'reka-ui'\nimport { computed } from 'vue'\n\nimport { useInkContext } from '../context'\n\nimport InkIcon from './InkIcon.vue'\n\nconst props = withDefaults(\n defineProps<{ asChild?: boolean; filename?: string | undefined }>(),\n {\n asChild: false,\n filename: undefined,\n }\n)\nconst ctx = useInkContext('InkDownloadButton')\nconst ready = computed(\n () => ctx.document.value !== null && ctx.status.value.state === 'ready'\n)\n\nfunction run(): void {\n const doc = ctx.document.value\n if (doc)\n void downloadDocument(\n doc,\n props.filename === undefined ? {} : { filename: props.filename }\n ).catch(() => undefined)\n}\n// Reka's typed props stop at its own; ARIA and listeners go through a bound object.\nconst attrs = { 'aria-label': 'Download', title: 'Download', onClick: run }\n</script>\n\n<template>\n <ToolbarButton\n :as-child=\"asChild\"\n :disabled=\"!ready\"\n class=\"ink-download\"\n data-ink-download\n v-bind=\"attrs\"\n >\n <slot><InkIcon :icon=\"Download\" /></slot>\n </ToolbarButton>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;EAeA,IAAMU,IAAQC,GAORC,IAAMC,EAAc,mBAAmB,GACvCC,IAAQC,QACNH,EAAI,SAAS,UAAU,QAAQA,EAAI,OAAO,MAAM,UAAU,OAClE;EAEA,SAASI,IAAY;GACnB,IAAMC,IAAML,EAAI,SAAS;GACzB,AAAIK,KACFC,EACED,GACAP,EAAM,aAAa,KAAA,IAAY,CAAC,IAAI,EAAE,UAAUA,EAAM,SAAS,CACjE,CAAC,CAAC,YAAY,KAAA,CAAS;EAC3B;EAEA,IAAMS,IAAQ;GAAE,cAAc;GAAY,OAAO;GAAY,SAASH;EAAI;oBAIxEhB,EAAA,GAAAC,EAQgBC,EAAAqB,CAAA,GARhBpB,EAQgB;GAPb,YAAUQ,EAAA;GACV,UAAQ,CAAGG,EAAA;GACZ,OAAM;GACN,qBAAA;EACQ,GAAAK,CAAK,GAAA;GAEb,SAAAf,QAAyC,CAAzCC,EAAyCsB,EAAA,QAAA,WAAA,CAAA,SAAA,CAAnCrB,EAA4BC,GAAA,EAAlB,MAAML,EAAA2B,CAAA,EAAQ,GAAA,MAAA,GAAA,CAAA,MAAA,CAAA,CAAA,CAAA,CAAA,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InkFindBar.js","names":["_sfc_main","InkFindBar_vue_vue_type_script_setup_true_lang_default","InkFindBar_default"],"sources":["../../src/components/InkFindBar.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/*\n * The find bar: a field, the match count, previous and next, a match-case toggle and close,\n * a view of the root's search state. Place it anywhere inside `InkRoot`: it teleports itself\n * into `[data-ink-viewport-root]`, the positioned ancestor the theme floats it from over the\n * top-right of the pages (as `InkThreadPopover` anchors to the root's overlay rather than\n * where it is written). It is hidden while the search is closed. While it is mounted it\n * registers with the search controller, which is what lets Ctrl/Cmd+F open it.\n *\n * Enter in the field steps to the next match, Shift+Enter to the previous, Escape closes.\n * Closing returns focus to where it was before the bar opened, else to the document.\n */\nimport { findAnnouncer, findCountText } from '@inkbar/core/dom'\nimport { CaseSensitive, ChevronDown, ChevronUp, X } from '@inkbar/icons'\nimport { computed, onBeforeUnmount, useTemplateRef, watch } from 'vue'\n\nimport { useSearch } from '../composables/useSearch'\nimport { useInkContext } from '../context'\n\nimport InkIcon from './InkIcon.vue'\n\nimport type { SearchState } from '@inkbar/core/dom'\n\n// The root is a Teleport, so attributes such as `class` are bound to the bar itself.\ndefineOptions({ inheritAttrs: false })\n\nconst ctx = useInkContext('InkFindBar')\nconst { state, setQuery, setMatchCase, next, previous, close } = useSearch()\n\n/** The viewport root: the scroll element's parent, once InkViewport has mounted. */\nconst target = computed(() => ctx.viewportEl.value?.parentElement ?? null)\nconst bar = useTemplateRef<HTMLElement>('bar')\nconst field = useTemplateRef<HTMLInputElement>('field')\nconst live = useTemplateRef<HTMLElement>('live')\n\nconst count = computed(() => findCountText(state.value))\n\n// The live region follows the controller's state change by change, as the vanilla bar does,\n// and is written directly. A render shows only the last of the changes since the one before,\n// so two steps in one tick that end where they began would otherwise say nothing.\nwatch(\n [() => ctx.search.value, live],\n ([controller, el], _, onCleanup) => {\n if (!controller || !el) return\n const announce = findAnnouncer()\n const say = (s: SearchState): void => {\n const text = announce(s)\n if (el.textContent !== text) el.textContent = text\n }\n say(controller.state.get())\n onCleanup(controller.state.subscribe(say))\n },\n { flush: 'post', immediate: true }\n)\n\nfunction onFieldKeydown(e: KeyboardEvent): void {\n if (e.key !== 'Enter' || e.isComposing) return\n e.preventDefault()\n if (e.shiftKey) previous()\n else next()\n}\nfunction onBarKeydown(e: KeyboardEvent): void {\n if (e.key !== 'Escape' || e.defaultPrevented || e.isComposing) return\n e.preventDefault()\n e.stopPropagation()\n close()\n}\n\n/** Where focus was when the bar opened. */\nlet before: HTMLElement | null = null\nlet wasOpen = false\n\nfunction restoreFocus(): void {\n const el = bar.value\n const scroll = ctx.viewportEl.value\n const to = before?.isConnected && !el?.contains(before) ? before : scroll\n before = null\n to?.focus({ preventScroll: true })\n}\n\nfunction show(s: SearchState): void {\n const el = bar.value\n const input = field.value\n if (!el || !input) return\n if (s.open !== wasOpen) {\n wasOpen = s.open\n const doc = el.ownerDocument\n if (s.open) {\n const active = doc.activeElement\n before =\n active instanceof HTMLElement && active !== doc.body && !el.contains(active)\n ? active\n : null\n input.focus()\n input.select()\n } else {\n // Focus inside the bar is about to be lost with it; focus elsewhere is left alone.\n const hadFocus = el.contains(doc.activeElement) || doc.activeElement === doc.body\n if (hadFocus) restoreFocus()\n else before = null\n }\n }\n if (input.value !== s.query) {\n input.value = s.query\n // A query set from code arrives after the bar opened: keep the new text selected.\n if (el.ownerDocument.activeElement === input) input.select()\n }\n}\n\n// After the render, so the bar is shown (and can take focus) when it opens, and the field is\n// updated once it exists.\nwatch([state, bar, field], ([s]) => show(s), { flush: 'post', immediate: true })\n\n// Registered while mounted.\nlet detach: (() => void) | null = null\nwatch(\n [() => ctx.search.value, bar],\n ([controller, el]) => {\n detach?.()\n detach = controller && el ? controller.attachBar() : null\n },\n { flush: 'post', immediate: true }\n)\nonBeforeUnmount(() => {\n detach?.()\n detach = null\n})\n</script>\n\n<template>\n <Teleport v-if=\"target\" :to=\"target\">\n <div\n v-bind=\"$attrs\"\n ref=\"bar\"\n class=\"ink-find-bar\"\n data-ink-find-bar\n role=\"search\"\n :hidden=\"!state.open\"\n @keydown=\"onBarKeydown\"\n >\n <input\n ref=\"field\"\n
|
|
1
|
+
{"version":3,"file":"InkFindBar.js","names":["_sfc_main","InkFindBar_vue_vue_type_script_setup_true_lang_default","InkFindBar_default"],"sources":["../../src/components/InkFindBar.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/*\n * The find bar: a field, the match count, previous and next, a match-case toggle and close,\n * a view of the root's search state. Place it anywhere inside `InkRoot`: it teleports itself\n * into `[data-ink-viewport-root]`, the positioned ancestor the theme floats it from over the\n * top-right of the pages (as `InkThreadPopover` anchors to the root's overlay rather than\n * where it is written). It is hidden while the search is closed. While it is mounted it\n * registers with the search controller, which is what lets Ctrl/Cmd+F open it.\n *\n * Enter in the field steps to the next match, Shift+Enter to the previous, Escape closes.\n * Closing returns focus to where it was before the bar opened, else to the document.\n */\nimport { findAnnouncer, findCountText } from '@inkbar/core/dom'\nimport { CaseSensitive, ChevronDown, ChevronUp, Search, X } from '@inkbar/icons'\nimport { computed, onBeforeUnmount, useTemplateRef, watch } from 'vue'\n\nimport { useSearch } from '../composables/useSearch'\nimport { useInkContext } from '../context'\n\nimport InkIcon from './InkIcon.vue'\n\nimport type { SearchState } from '@inkbar/core/dom'\n\n// The root is a Teleport, so attributes such as `class` are bound to the bar itself.\ndefineOptions({ inheritAttrs: false })\n\nconst ctx = useInkContext('InkFindBar')\nconst { state, setQuery, setMatchCase, next, previous, close } = useSearch()\n\n/** The viewport root: the scroll element's parent, once InkViewport has mounted. */\nconst target = computed(() => ctx.viewportEl.value?.parentElement ?? null)\nconst bar = useTemplateRef<HTMLElement>('bar')\nconst field = useTemplateRef<HTMLInputElement>('field')\nconst live = useTemplateRef<HTMLElement>('live')\n\nconst count = computed(() => findCountText(state.value))\n\n// The live region follows the controller's state change by change, as the vanilla bar does,\n// and is written directly. A render shows only the last of the changes since the one before,\n// so two steps in one tick that end where they began would otherwise say nothing.\nwatch(\n [() => ctx.search.value, live],\n ([controller, el], _, onCleanup) => {\n if (!controller || !el) return\n const announce = findAnnouncer()\n const say = (s: SearchState): void => {\n const text = announce(s)\n if (el.textContent !== text) el.textContent = text\n }\n say(controller.state.get())\n onCleanup(controller.state.subscribe(say))\n },\n { flush: 'post', immediate: true }\n)\n\nfunction onFieldKeydown(e: KeyboardEvent): void {\n if (e.key !== 'Enter' || e.isComposing) return\n e.preventDefault()\n if (e.shiftKey) previous()\n else next()\n}\nfunction onBarKeydown(e: KeyboardEvent): void {\n if (e.key !== 'Escape' || e.defaultPrevented || e.isComposing) return\n e.preventDefault()\n e.stopPropagation()\n close()\n}\n\n/** Where focus was when the bar opened. */\nlet before: HTMLElement | null = null\nlet wasOpen = false\n\nfunction restoreFocus(): void {\n const el = bar.value\n const scroll = ctx.viewportEl.value\n const to = before?.isConnected && !el?.contains(before) ? before : scroll\n before = null\n to?.focus({ preventScroll: true })\n}\n\nfunction show(s: SearchState): void {\n const el = bar.value\n const input = field.value\n if (!el || !input) return\n if (s.open !== wasOpen) {\n wasOpen = s.open\n const doc = el.ownerDocument\n if (s.open) {\n const active = doc.activeElement\n before =\n active instanceof HTMLElement && active !== doc.body && !el.contains(active)\n ? active\n : null\n input.focus()\n input.select()\n } else {\n // Focus inside the bar is about to be lost with it; focus elsewhere is left alone.\n const hadFocus = el.contains(doc.activeElement) || doc.activeElement === doc.body\n if (hadFocus) restoreFocus()\n else before = null\n }\n }\n if (input.value !== s.query) {\n input.value = s.query\n // A query set from code arrives after the bar opened: keep the new text selected.\n if (el.ownerDocument.activeElement === input) input.select()\n }\n}\n\n// After the render, so the bar is shown (and can take focus) when it opens, and the field is\n// updated once it exists.\nwatch([state, bar, field], ([s]) => show(s), { flush: 'post', immediate: true })\n\n// Registered while mounted.\nlet detach: (() => void) | null = null\nwatch(\n [() => ctx.search.value, bar],\n ([controller, el]) => {\n detach?.()\n detach = controller && el ? controller.attachBar() : null\n },\n { flush: 'post', immediate: true }\n)\nonBeforeUnmount(() => {\n detach?.()\n detach = null\n})\n</script>\n\n<template>\n <Teleport v-if=\"target\" :to=\"target\">\n <div\n v-bind=\"$attrs\"\n ref=\"bar\"\n class=\"ink-find-bar\"\n data-ink-find-bar\n role=\"search\"\n :hidden=\"!state.open\"\n @keydown=\"onBarKeydown\"\n >\n <div class=\"ink-input-group\">\n <span class=\"ink-input-accessory\"><InkIcon :icon=\"Search\" /></span>\n <input\n ref=\"field\"\n type=\"text\"\n aria-label=\"Find in document\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n @input=\"setQuery(($event.target as HTMLInputElement).value)\"\n @keydown=\"onFieldKeydown\"\n />\n </div>\n <span class=\"ink-find-count\" data-ink-find-count>{{ count }}</span>\n <button\n type=\"button\"\n data-ink-find-previous\n aria-label=\"Previous match\"\n title=\"Previous match\"\n @click=\"previous()\"\n >\n <InkIcon :icon=\"ChevronUp\" />\n </button>\n <button\n type=\"button\"\n data-ink-find-next\n aria-label=\"Next match\"\n title=\"Next match\"\n @click=\"next()\"\n >\n <InkIcon :icon=\"ChevronDown\" />\n </button>\n <button\n type=\"button\"\n data-ink-find-match-case\n aria-label=\"Match case\"\n title=\"Match case\"\n :aria-pressed=\"state.matchCase\"\n @click=\"setMatchCase(!state.matchCase)\"\n >\n <InkIcon :icon=\"CaseSensitive\" />\n </button>\n <button\n type=\"button\"\n data-ink-find-close\n aria-label=\"Close find\"\n title=\"Close find\"\n @click=\"close()\"\n >\n <InkIcon :icon=\"X\" />\n </button>\n <div\n ref=\"live\"\n class=\"ink-visually-hidden\"\n data-ink-find-status\n aria-live=\"polite\"\n />\n </div>\n </Teleport>\n</template>\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InkFindBar.vue.d.ts","sourceRoot":"","sources":["../../src/components/InkFindBar.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"InkFindBar.vue.d.ts","sourceRoot":"","sources":["../../src/components/InkFindBar.vue"],"names":[],"mappings":"AAifA,QAAA,MAAM,YAAY,+QAChB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
|
|
@@ -3,17 +3,17 @@ import { useSearch as t } from "../composables/useSearch.js";
|
|
|
3
3
|
import n from "./InkIcon.js";
|
|
4
4
|
import { Teleport as r, computed as i, createBlock as a, createCommentVNode as o, createElementVNode as s, createVNode as c, defineComponent as l, mergeProps as u, onBeforeUnmount as d, openBlock as f, toDisplayString as p, unref as m, useTemplateRef as h, watch as g } from "vue";
|
|
5
5
|
import { findAnnouncer as _, findCountText as v } from "@inkbar/core/dom";
|
|
6
|
-
import { CaseSensitive as y, ChevronDown as b, ChevronUp as x,
|
|
6
|
+
import { CaseSensitive as y, ChevronDown as b, ChevronUp as x, Search as S, X as C } from "@inkbar/icons";
|
|
7
7
|
//#region src/components/InkFindBar.vue?vue&type=script&setup=true&lang.ts
|
|
8
|
-
var
|
|
8
|
+
var w = ["hidden"], T = { class: "ink-input-group" }, E = { class: "ink-input-accessory" }, D = {
|
|
9
9
|
class: "ink-find-count",
|
|
10
10
|
"data-ink-find-count": ""
|
|
11
|
-
},
|
|
11
|
+
}, O = ["aria-pressed"], k = /*@__PURE__*/ l({
|
|
12
12
|
inheritAttrs: !1,
|
|
13
13
|
__name: "InkFindBar",
|
|
14
14
|
setup(l) {
|
|
15
|
-
let
|
|
16
|
-
g([() =>
|
|
15
|
+
let k = e("InkFindBar"), { state: A, setQuery: j, setMatchCase: M, next: N, previous: P, close: F } = t(), I = i(() => k.viewportEl.value?.parentElement ?? null), L = h("bar"), R = h("field"), z = h("live"), B = i(() => v(A.value));
|
|
16
|
+
g([() => k.search.value, z], ([e, t], n, r) => {
|
|
17
17
|
if (!e || !t) return;
|
|
18
18
|
let i = _(), a = (e) => {
|
|
19
19
|
let n = i(e);
|
|
@@ -24,110 +24,110 @@ var C = ["hidden"], w = {
|
|
|
24
24
|
flush: "post",
|
|
25
25
|
immediate: !0
|
|
26
26
|
});
|
|
27
|
-
function
|
|
28
|
-
e.key !== "Enter" || e.isComposing || (e.preventDefault(), e.shiftKey ?
|
|
27
|
+
function V(e) {
|
|
28
|
+
e.key !== "Enter" || e.isComposing || (e.preventDefault(), e.shiftKey ? P() : N());
|
|
29
29
|
}
|
|
30
|
-
function
|
|
31
|
-
e.key !== "Escape" || e.defaultPrevented || e.isComposing || (e.preventDefault(), e.stopPropagation(),
|
|
30
|
+
function H(e) {
|
|
31
|
+
e.key !== "Escape" || e.defaultPrevented || e.isComposing || (e.preventDefault(), e.stopPropagation(), F());
|
|
32
32
|
}
|
|
33
|
-
let
|
|
34
|
-
function
|
|
35
|
-
let e =
|
|
36
|
-
|
|
33
|
+
let U = null, W = !1;
|
|
34
|
+
function G() {
|
|
35
|
+
let e = L.value, t = k.viewportEl.value, n = U?.isConnected && !e?.contains(U) ? U : t;
|
|
36
|
+
U = null, n?.focus({ preventScroll: !0 });
|
|
37
37
|
}
|
|
38
|
-
function
|
|
39
|
-
let t =
|
|
38
|
+
function K(e) {
|
|
39
|
+
let t = L.value, n = R.value;
|
|
40
40
|
if (t && n) {
|
|
41
|
-
if (e.open !==
|
|
42
|
-
|
|
41
|
+
if (e.open !== W) {
|
|
42
|
+
W = e.open;
|
|
43
43
|
let r = t.ownerDocument;
|
|
44
44
|
if (e.open) {
|
|
45
45
|
let e = r.activeElement;
|
|
46
|
-
|
|
47
|
-
} else t.contains(r.activeElement) || r.activeElement === r.body ?
|
|
46
|
+
U = e instanceof HTMLElement && e !== r.body && !t.contains(e) ? e : null, n.focus(), n.select();
|
|
47
|
+
} else t.contains(r.activeElement) || r.activeElement === r.body ? G() : U = null;
|
|
48
48
|
}
|
|
49
49
|
n.value !== e.query && (n.value = e.query, t.ownerDocument.activeElement === n && n.select());
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
g([
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
], ([e]) =>
|
|
53
|
+
A,
|
|
54
|
+
L,
|
|
55
|
+
R
|
|
56
|
+
], ([e]) => K(e), {
|
|
57
57
|
flush: "post",
|
|
58
58
|
immediate: !0
|
|
59
59
|
});
|
|
60
|
-
let
|
|
61
|
-
return g([() =>
|
|
62
|
-
|
|
60
|
+
let q = null;
|
|
61
|
+
return g([() => k.search.value, L], ([e, t]) => {
|
|
62
|
+
q?.(), q = e && t ? e.attachBar() : null;
|
|
63
63
|
}, {
|
|
64
64
|
flush: "post",
|
|
65
65
|
immediate: !0
|
|
66
66
|
}), d(() => {
|
|
67
|
-
|
|
68
|
-
}), (e, t) =>
|
|
67
|
+
q?.(), q = null;
|
|
68
|
+
}), (e, t) => I.value ? (f(), a(r, {
|
|
69
69
|
key: 0,
|
|
70
|
-
to:
|
|
70
|
+
to: I.value
|
|
71
71
|
}, [s("div", u(e.$attrs, {
|
|
72
72
|
ref_key: "bar",
|
|
73
|
-
ref:
|
|
73
|
+
ref: L,
|
|
74
74
|
class: "ink-find-bar",
|
|
75
75
|
"data-ink-find-bar": "",
|
|
76
76
|
role: "search",
|
|
77
|
-
hidden: !m(
|
|
78
|
-
onKeydown:
|
|
77
|
+
hidden: !m(A).open,
|
|
78
|
+
onKeydown: H
|
|
79
79
|
}), [
|
|
80
|
-
s("input", {
|
|
80
|
+
s("div", T, [s("span", E, [c(n, { icon: m(S) }, null, 8, ["icon"])]), s("input", {
|
|
81
81
|
ref_key: "field",
|
|
82
|
-
ref:
|
|
82
|
+
ref: R,
|
|
83
83
|
type: "text",
|
|
84
84
|
"aria-label": "Find in document",
|
|
85
85
|
autocomplete: "off",
|
|
86
86
|
spellcheck: "false",
|
|
87
|
-
onInput: t[0] ||= (e) => m(
|
|
88
|
-
onKeydown:
|
|
89
|
-
}, null, 544),
|
|
90
|
-
s("span",
|
|
87
|
+
onInput: t[0] ||= (e) => m(j)(e.target.value),
|
|
88
|
+
onKeydown: V
|
|
89
|
+
}, null, 544)]),
|
|
90
|
+
s("span", D, p(B.value), 1),
|
|
91
91
|
s("button", {
|
|
92
92
|
type: "button",
|
|
93
93
|
"data-ink-find-previous": "",
|
|
94
94
|
"aria-label": "Previous match",
|
|
95
95
|
title: "Previous match",
|
|
96
|
-
onClick: t[1] ||= (e) => m(
|
|
96
|
+
onClick: t[1] ||= (e) => m(P)()
|
|
97
97
|
}, [c(n, { icon: m(x) }, null, 8, ["icon"])]),
|
|
98
98
|
s("button", {
|
|
99
99
|
type: "button",
|
|
100
100
|
"data-ink-find-next": "",
|
|
101
101
|
"aria-label": "Next match",
|
|
102
102
|
title: "Next match",
|
|
103
|
-
onClick: t[2] ||= (e) => m(
|
|
103
|
+
onClick: t[2] ||= (e) => m(N)()
|
|
104
104
|
}, [c(n, { icon: m(b) }, null, 8, ["icon"])]),
|
|
105
105
|
s("button", {
|
|
106
106
|
type: "button",
|
|
107
107
|
"data-ink-find-match-case": "",
|
|
108
108
|
"aria-label": "Match case",
|
|
109
109
|
title: "Match case",
|
|
110
|
-
"aria-pressed": m(
|
|
111
|
-
onClick: t[3] ||= (e) => m(
|
|
112
|
-
}, [c(n, { icon: m(y) }, null, 8, ["icon"])], 8,
|
|
110
|
+
"aria-pressed": m(A).matchCase,
|
|
111
|
+
onClick: t[3] ||= (e) => m(M)(!m(A).matchCase)
|
|
112
|
+
}, [c(n, { icon: m(y) }, null, 8, ["icon"])], 8, O),
|
|
113
113
|
s("button", {
|
|
114
114
|
type: "button",
|
|
115
115
|
"data-ink-find-close": "",
|
|
116
116
|
"aria-label": "Close find",
|
|
117
117
|
title: "Close find",
|
|
118
|
-
onClick: t[4] ||= (e) => m(
|
|
119
|
-
}, [c(n, { icon: m(
|
|
118
|
+
onClick: t[4] ||= (e) => m(F)()
|
|
119
|
+
}, [c(n, { icon: m(C) }, null, 8, ["icon"])]),
|
|
120
120
|
s("div", {
|
|
121
121
|
ref_key: "live",
|
|
122
|
-
ref:
|
|
122
|
+
ref: z,
|
|
123
123
|
class: "ink-visually-hidden",
|
|
124
124
|
"data-ink-find-status": "",
|
|
125
125
|
"aria-live": "polite"
|
|
126
126
|
}, null, 512)
|
|
127
|
-
], 16,
|
|
127
|
+
], 16, w)], 8, ["to"])) : o("", !0);
|
|
128
128
|
}
|
|
129
129
|
});
|
|
130
130
|
//#endregion
|
|
131
|
-
export {
|
|
131
|
+
export { k as default };
|
|
132
132
|
|
|
133
133
|
//# sourceMappingURL=InkFindBar.vue_vue_type_script_setup_true_lang.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InkFindBar.vue_vue_type_script_setup_true_lang.js","names":["$attrs","_openBlock","_createBlock","_Teleport","_createElementVNode","_mergeProps","_unref","_toDisplayString","_createVNode","InkIcon","_createCommentVNode","InkIcon_default","_hoisted_1","_hoisted_2","_hoisted_3","InkFindBar_vue_vue_type_script_setup_true_lang_default","ctx","useInkContext","useSearch","target","computed","bar","useTemplateRef","field","live","count","findCountText","state","controller","el","announce","findAnnouncer","say","text","s","onCleanup","onFieldKeydown","previous","next","onBarKeydown","close","before","wasOpen","restoreFocus","scroll","to","show","input","doc","active","detach","watch","onBeforeUnmount","openBlock","createBlock","Teleport","createElementVNode","mergeProps","_ctx","unref","_cache","setQuery","$event","toDisplayString","createVNode","ChevronUp","ChevronDown","setMatchCase","CaseSensitive","X","createCommentVNode"],"sources":["../../src/components/InkFindBar.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/*\n * The find bar: a field, the match count, previous and next, a match-case toggle and close,\n * a view of the root's search state. Place it anywhere inside `InkRoot`: it teleports itself\n * into `[data-ink-viewport-root]`, the positioned ancestor the theme floats it from over the\n * top-right of the pages (as `InkThreadPopover` anchors to the root's overlay rather than\n * where it is written). It is hidden while the search is closed. While it is mounted it\n * registers with the search controller, which is what lets Ctrl/Cmd+F open it.\n *\n * Enter in the field steps to the next match, Shift+Enter to the previous, Escape closes.\n * Closing returns focus to where it was before the bar opened, else to the document.\n */\nimport { findAnnouncer, findCountText } from '@inkbar/core/dom'\nimport { CaseSensitive, ChevronDown, ChevronUp, X } from '@inkbar/icons'\nimport { computed, onBeforeUnmount, useTemplateRef, watch } from 'vue'\n\nimport { useSearch } from '../composables/useSearch'\nimport { useInkContext } from '../context'\n\nimport InkIcon from './InkIcon.vue'\n\nimport type { SearchState } from '@inkbar/core/dom'\n\n// The root is a Teleport, so attributes such as `class` are bound to the bar itself.\ndefineOptions({ inheritAttrs: false })\n\nconst ctx = useInkContext('InkFindBar')\nconst { state, setQuery, setMatchCase, next, previous, close } = useSearch()\n\n/** The viewport root: the scroll element's parent, once InkViewport has mounted. */\nconst target = computed(() => ctx.viewportEl.value?.parentElement ?? null)\nconst bar = useTemplateRef<HTMLElement>('bar')\nconst field = useTemplateRef<HTMLInputElement>('field')\nconst live = useTemplateRef<HTMLElement>('live')\n\nconst count = computed(() => findCountText(state.value))\n\n// The live region follows the controller's state change by change, as the vanilla bar does,\n// and is written directly. A render shows only the last of the changes since the one before,\n// so two steps in one tick that end where they began would otherwise say nothing.\nwatch(\n [() => ctx.search.value, live],\n ([controller, el], _, onCleanup) => {\n if (!controller || !el) return\n const announce = findAnnouncer()\n const say = (s: SearchState): void => {\n const text = announce(s)\n if (el.textContent !== text) el.textContent = text\n }\n say(controller.state.get())\n onCleanup(controller.state.subscribe(say))\n },\n { flush: 'post', immediate: true }\n)\n\nfunction onFieldKeydown(e: KeyboardEvent): void {\n if (e.key !== 'Enter' || e.isComposing) return\n e.preventDefault()\n if (e.shiftKey) previous()\n else next()\n}\nfunction onBarKeydown(e: KeyboardEvent): void {\n if (e.key !== 'Escape' || e.defaultPrevented || e.isComposing) return\n e.preventDefault()\n e.stopPropagation()\n close()\n}\n\n/** Where focus was when the bar opened. */\nlet before: HTMLElement | null = null\nlet wasOpen = false\n\nfunction restoreFocus(): void {\n const el = bar.value\n const scroll = ctx.viewportEl.value\n const to = before?.isConnected && !el?.contains(before) ? before : scroll\n before = null\n to?.focus({ preventScroll: true })\n}\n\nfunction show(s: SearchState): void {\n const el = bar.value\n const input = field.value\n if (!el || !input) return\n if (s.open !== wasOpen) {\n wasOpen = s.open\n const doc = el.ownerDocument\n if (s.open) {\n const active = doc.activeElement\n before =\n active instanceof HTMLElement && active !== doc.body && !el.contains(active)\n ? active\n : null\n input.focus()\n input.select()\n } else {\n // Focus inside the bar is about to be lost with it; focus elsewhere is left alone.\n const hadFocus = el.contains(doc.activeElement) || doc.activeElement === doc.body\n if (hadFocus) restoreFocus()\n else before = null\n }\n }\n if (input.value !== s.query) {\n input.value = s.query\n // A query set from code arrives after the bar opened: keep the new text selected.\n if (el.ownerDocument.activeElement === input) input.select()\n }\n}\n\n// After the render, so the bar is shown (and can take focus) when it opens, and the field is\n// updated once it exists.\nwatch([state, bar, field], ([s]) => show(s), { flush: 'post', immediate: true })\n\n// Registered while mounted.\nlet detach: (() => void) | null = null\nwatch(\n [() => ctx.search.value, bar],\n ([controller, el]) => {\n detach?.()\n detach = controller && el ? controller.attachBar() : null\n },\n { flush: 'post', immediate: true }\n)\nonBeforeUnmount(() => {\n detach?.()\n detach = null\n})\n</script>\n\n<template>\n <Teleport v-if=\"target\" :to=\"target\">\n <div\n v-bind=\"$attrs\"\n ref=\"bar\"\n class=\"ink-find-bar\"\n data-ink-find-bar\n role=\"search\"\n :hidden=\"!state.open\"\n @keydown=\"onBarKeydown\"\n >\n <input\n ref=\"field\"\n type=\"text\"\n aria-label=\"Find in document\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n @input=\"setQuery(($event.target as HTMLInputElement).value)\"\n @keydown=\"onFieldKeydown\"\n />\n <span class=\"ink-find-count\" data-ink-find-count>{{ count }}</span>\n <button\n type=\"button\"\n data-ink-find-previous\n aria-label=\"Previous match\"\n title=\"Previous match\"\n @click=\"previous()\"\n >\n <InkIcon :icon=\"ChevronUp\" />\n </button>\n <button\n type=\"button\"\n data-ink-find-next\n aria-label=\"Next match\"\n title=\"Next match\"\n @click=\"next()\"\n >\n <InkIcon :icon=\"ChevronDown\" />\n </button>\n <button\n type=\"button\"\n data-ink-find-match-case\n aria-label=\"Match case\"\n title=\"Match case\"\n :aria-pressed=\"state.matchCase\"\n @click=\"setMatchCase(!state.matchCase)\"\n >\n <InkIcon :icon=\"CaseSensitive\" />\n </button>\n <button\n type=\"button\"\n data-ink-find-close\n aria-label=\"Close find\"\n title=\"Close find\"\n @click=\"close()\"\n >\n <InkIcon :icon=\"X\" />\n </button>\n <div\n ref=\"live\"\n class=\"ink-visually-hidden\"\n data-ink-find-status\n aria-live=\"polite\"\n />\n </div>\n </Teleport>\n</template>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"InkFindBar.vue_vue_type_script_setup_true_lang.js","names":["$attrs","_openBlock","_createBlock","_Teleport","_createElementVNode","_mergeProps","_unref","_createVNode","InkIcon","_toDisplayString","_createCommentVNode","InkIcon_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","InkFindBar_vue_vue_type_script_setup_true_lang_default","ctx","useInkContext","useSearch","target","computed","bar","useTemplateRef","field","live","count","findCountText","state","controller","el","announce","findAnnouncer","say","text","s","onCleanup","onFieldKeydown","previous","next","onBarKeydown","close","before","wasOpen","restoreFocus","scroll","to","show","input","doc","active","detach","watch","onBeforeUnmount","openBlock","createBlock","Teleport","createElementVNode","mergeProps","_ctx","unref","createVNode","Search","_cache","setQuery","$event","toDisplayString","ChevronUp","ChevronDown","setMatchCase","CaseSensitive","X","createCommentVNode"],"sources":["../../src/components/InkFindBar.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/*\n * The find bar: a field, the match count, previous and next, a match-case toggle and close,\n * a view of the root's search state. Place it anywhere inside `InkRoot`: it teleports itself\n * into `[data-ink-viewport-root]`, the positioned ancestor the theme floats it from over the\n * top-right of the pages (as `InkThreadPopover` anchors to the root's overlay rather than\n * where it is written). It is hidden while the search is closed. While it is mounted it\n * registers with the search controller, which is what lets Ctrl/Cmd+F open it.\n *\n * Enter in the field steps to the next match, Shift+Enter to the previous, Escape closes.\n * Closing returns focus to where it was before the bar opened, else to the document.\n */\nimport { findAnnouncer, findCountText } from '@inkbar/core/dom'\nimport { CaseSensitive, ChevronDown, ChevronUp, Search, X } from '@inkbar/icons'\nimport { computed, onBeforeUnmount, useTemplateRef, watch } from 'vue'\n\nimport { useSearch } from '../composables/useSearch'\nimport { useInkContext } from '../context'\n\nimport InkIcon from './InkIcon.vue'\n\nimport type { SearchState } from '@inkbar/core/dom'\n\n// The root is a Teleport, so attributes such as `class` are bound to the bar itself.\ndefineOptions({ inheritAttrs: false })\n\nconst ctx = useInkContext('InkFindBar')\nconst { state, setQuery, setMatchCase, next, previous, close } = useSearch()\n\n/** The viewport root: the scroll element's parent, once InkViewport has mounted. */\nconst target = computed(() => ctx.viewportEl.value?.parentElement ?? null)\nconst bar = useTemplateRef<HTMLElement>('bar')\nconst field = useTemplateRef<HTMLInputElement>('field')\nconst live = useTemplateRef<HTMLElement>('live')\n\nconst count = computed(() => findCountText(state.value))\n\n// The live region follows the controller's state change by change, as the vanilla bar does,\n// and is written directly. A render shows only the last of the changes since the one before,\n// so two steps in one tick that end where they began would otherwise say nothing.\nwatch(\n [() => ctx.search.value, live],\n ([controller, el], _, onCleanup) => {\n if (!controller || !el) return\n const announce = findAnnouncer()\n const say = (s: SearchState): void => {\n const text = announce(s)\n if (el.textContent !== text) el.textContent = text\n }\n say(controller.state.get())\n onCleanup(controller.state.subscribe(say))\n },\n { flush: 'post', immediate: true }\n)\n\nfunction onFieldKeydown(e: KeyboardEvent): void {\n if (e.key !== 'Enter' || e.isComposing) return\n e.preventDefault()\n if (e.shiftKey) previous()\n else next()\n}\nfunction onBarKeydown(e: KeyboardEvent): void {\n if (e.key !== 'Escape' || e.defaultPrevented || e.isComposing) return\n e.preventDefault()\n e.stopPropagation()\n close()\n}\n\n/** Where focus was when the bar opened. */\nlet before: HTMLElement | null = null\nlet wasOpen = false\n\nfunction restoreFocus(): void {\n const el = bar.value\n const scroll = ctx.viewportEl.value\n const to = before?.isConnected && !el?.contains(before) ? before : scroll\n before = null\n to?.focus({ preventScroll: true })\n}\n\nfunction show(s: SearchState): void {\n const el = bar.value\n const input = field.value\n if (!el || !input) return\n if (s.open !== wasOpen) {\n wasOpen = s.open\n const doc = el.ownerDocument\n if (s.open) {\n const active = doc.activeElement\n before =\n active instanceof HTMLElement && active !== doc.body && !el.contains(active)\n ? active\n : null\n input.focus()\n input.select()\n } else {\n // Focus inside the bar is about to be lost with it; focus elsewhere is left alone.\n const hadFocus = el.contains(doc.activeElement) || doc.activeElement === doc.body\n if (hadFocus) restoreFocus()\n else before = null\n }\n }\n if (input.value !== s.query) {\n input.value = s.query\n // A query set from code arrives after the bar opened: keep the new text selected.\n if (el.ownerDocument.activeElement === input) input.select()\n }\n}\n\n// After the render, so the bar is shown (and can take focus) when it opens, and the field is\n// updated once it exists.\nwatch([state, bar, field], ([s]) => show(s), { flush: 'post', immediate: true })\n\n// Registered while mounted.\nlet detach: (() => void) | null = null\nwatch(\n [() => ctx.search.value, bar],\n ([controller, el]) => {\n detach?.()\n detach = controller && el ? controller.attachBar() : null\n },\n { flush: 'post', immediate: true }\n)\nonBeforeUnmount(() => {\n detach?.()\n detach = null\n})\n</script>\n\n<template>\n <Teleport v-if=\"target\" :to=\"target\">\n <div\n v-bind=\"$attrs\"\n ref=\"bar\"\n class=\"ink-find-bar\"\n data-ink-find-bar\n role=\"search\"\n :hidden=\"!state.open\"\n @keydown=\"onBarKeydown\"\n >\n <div class=\"ink-input-group\">\n <span class=\"ink-input-accessory\"><InkIcon :icon=\"Search\" /></span>\n <input\n ref=\"field\"\n type=\"text\"\n aria-label=\"Find in document\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n @input=\"setQuery(($event.target as HTMLInputElement).value)\"\n @keydown=\"onFieldKeydown\"\n />\n </div>\n <span class=\"ink-find-count\" data-ink-find-count>{{ count }}</span>\n <button\n type=\"button\"\n data-ink-find-previous\n aria-label=\"Previous match\"\n title=\"Previous match\"\n @click=\"previous()\"\n >\n <InkIcon :icon=\"ChevronUp\" />\n </button>\n <button\n type=\"button\"\n data-ink-find-next\n aria-label=\"Next match\"\n title=\"Next match\"\n @click=\"next()\"\n >\n <InkIcon :icon=\"ChevronDown\" />\n </button>\n <button\n type=\"button\"\n data-ink-find-match-case\n aria-label=\"Match case\"\n title=\"Match case\"\n :aria-pressed=\"state.matchCase\"\n @click=\"setMatchCase(!state.matchCase)\"\n >\n <InkIcon :icon=\"CaseSensitive\" />\n </button>\n <button\n type=\"button\"\n data-ink-find-close\n aria-label=\"Close find\"\n title=\"Close find\"\n @click=\"close()\"\n >\n <InkIcon :icon=\"X\" />\n </button>\n <div\n ref=\"live\"\n class=\"ink-visually-hidden\"\n data-ink-find-status\n aria-live=\"polite\"\n />\n </div>\n </Teleport>\n</template>\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InkHighlightMenu.js","names":["_sfc_main","InkHighlightMenu_vue_vue_type_script_setup_true_lang_default","InkHighlightMenu_default"],"sources":["../../src/components/InkHighlightMenu.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/*\n * A split button for the highlight tool. The main part activates the tool with the current\n * markup kind and draws that kind's icon; the chevron opens a menu of the four kinds plus\n * the markup colour. Choosing a kind switches to the tool with it. The colour is a nested\n * `InkColorMenu` scoped to the `markup` style group, so it works whatever tool is active.\n */\nimport {\n focusInitialMenuItem,\n handleMenuKeys,\n highlightMenuModel,\n MARKUP_ICONS,\n MARKUP_KINDS,\n menuItems,\n type HighlightOptions,\n type MarkupKind,\n} from '@inkbar/core/dom'\nimport { ChevronDown } from '@inkbar/icons'\nimport {\n PopoverAnchor,\n PopoverContent,\n PopoverPortal,\n PopoverRoot,\n PopoverTrigger,\n ToolbarButton,\n} from 'reka-ui'\nimport { computed, ref } from 'vue'\n\nimport { useDocument } from '../composables/useDocument'\nimport { useTool } from '../composables/useTool'\nimport {
|
|
1
|
+
{"version":3,"file":"InkHighlightMenu.js","names":["_sfc_main","InkHighlightMenu_vue_vue_type_script_setup_true_lang_default","InkHighlightMenu_default"],"sources":["../../src/components/InkHighlightMenu.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/*\n * A split button for the highlight tool. The main part activates the tool with the current\n * markup kind and draws that kind's icon; the chevron opens a menu of the four kinds plus\n * the markup colour. Choosing a kind switches to the tool with it. The colour is a nested\n * `InkColorMenu` scoped to the `markup` style group, so it works whatever tool is active.\n */\nimport {\n focusInitialMenuItem,\n handleMenuKeys,\n highlightMenuModel,\n MARKUP_ICONS,\n MARKUP_KINDS,\n menuItems,\n type HighlightOptions,\n type MarkupKind,\n} from '@inkbar/core/dom'\nimport { ChevronDown } from '@inkbar/icons'\nimport {\n PopoverAnchor,\n PopoverContent,\n PopoverPortal,\n PopoverRoot,\n PopoverTrigger,\n ToolbarButton,\n} from 'reka-ui'\nimport { computed, ref } from 'vue'\n\nimport { useDocument } from '../composables/useDocument'\nimport { useRegisteredTool } from '../composables/useRegisteredTool'\nimport { useTool } from '../composables/useTool'\nimport { useToolOptionsWhile } from '../composables/useToolOptions'\n\nimport InkColorMenu from './InkColorMenu.vue'\nimport InkIcon from './InkIcon.vue'\n\ndefineOptions({ inheritAttrs: false })\nconst { tool, setTool } = useTool()\n// Nothing renders while no `highlight` tool is registered.\nconst registered = useRegisteredTool('highlight')\nconst { options, setOptions } = useToolOptionsWhile<HighlightOptions>(\n 'highlight',\n registered\n)\nconst { document: doc } = useDocument()\nconst open = ref(false)\n\nconst model = computed(() => highlightMenuModel(options.value, MARKUP_KINDS))\nconst active = computed(() => tool.value === 'highlight')\n/** The colour the chosen kind gets while the markup style leaves it unset. */\nconst fallback = computed(() => doc.value?.annotations.defaults.color(model.value.kind))\nconst icon = computed(() => MARKUP_ICONS[model.value.kind])\n\n/** ArrowDown opens on the first item; a click opens on the checked one. */\nlet focusFirst = false\nfunction onTriggerKeydown(e: KeyboardEvent): void {\n if (e.key !== 'ArrowDown' || e.defaultPrevented || open.value) return\n e.preventDefault()\n focusFirst = true\n open.value = true\n}\n\nfunction onOpenAutoFocus(e: Event): void {\n e.preventDefault()\n // One highlight menu is open at a time.\n const menu = document.querySelector('[data-ink-menu=\"highlight\"] [role=\"menu\"]')\n if (menu) {\n if (focusFirst) menuItems(menu)[0]?.focus({ preventScroll: true })\n else focusInitialMenuItem(menu)\n }\n focusFirst = false\n}\n\nfunction choose(kind: MarkupKind): void {\n setOptions({ kind })\n setTool('highlight')\n open.value = false\n}\n\n// Reka's typed props stop at its own; ARIA and listeners go through bound objects.\nconst mainAttrs = computed(() => ({\n 'aria-pressed': String(active.value),\n 'aria-label': model.value.label,\n title: model.value.label,\n onClick: () => setTool('highlight'),\n}))\nconst triggerAttrs = {\n 'aria-label': 'Choose highlight',\n title: 'Choose highlight',\n 'aria-haspopup': 'menu' as const,\n onKeydown: onTriggerKeydown,\n}\nconst menuAttrs = { 'aria-label': 'Highlights' }\n/** The colour trigger is an item of this menu, reached with the arrow keys. */\nconst colourAttrs = { role: 'menuitem', tabindex: -1 }\nconst innerAttrs = {\n role: 'menu',\n 'aria-label': 'Highlights',\n // Capture, so the arrow keys move on from the colour item before its own ArrowDown\n // opens the nested menu.\n onKeydownCapture: (e: KeyboardEvent) =>\n handleMenuKeys(e, e.currentTarget as HTMLElement),\n}\n</script>\n\n<template>\n <PopoverRoot v-if=\"registered\" v-model:open=\"open\">\n <PopoverAnchor as-child>\n <div\n role=\"group\"\n aria-label=\"Highlight\"\n class=\"ink-split-button ink-highlight-menu\"\n data-ink-highlight-menu\n v-bind=\"$attrs\"\n >\n <ToolbarButton\n class=\"ink-tool-button ink-highlight-button\"\n data-ink-tool-button\n data-ink-highlight-button\n data-tool=\"highlight\"\n :data-kind=\"model.kind\"\n :data-state=\"active ? 'on' : 'off'\"\n v-bind=\"mainAttrs\"\n >\n <slot :active=\"active\" :kind=\"model.kind\"><InkIcon :icon=\"icon\" /></slot>\n </ToolbarButton>\n <ToolbarButton as-child>\n <PopoverTrigger as-child>\n <button\n type=\"button\"\n class=\"ink-menu-trigger ink-highlight-menu-trigger\"\n data-ink-highlight-menu-trigger\n :data-state=\"open ? 'open' : 'closed'\"\n v-bind=\"triggerAttrs\"\n >\n <InkIcon :icon=\"ChevronDown\" />\n </button>\n </PopoverTrigger>\n </ToolbarButton>\n <PopoverPortal>\n <PopoverContent\n class=\"ink-select-content ink-menu-content\"\n data-ink-select-content\n data-ink-menu=\"highlight\"\n side=\"bottom\"\n align=\"start\"\n :side-offset=\"4\"\n :collision-padding=\"8\"\n v-bind=\"menuAttrs\"\n @open-auto-focus=\"onOpenAutoFocus\"\n >\n <div v-bind=\"innerAttrs\">\n <div role=\"group\" aria-label=\"Kinds\" class=\"ink-highlight-kinds\">\n <button\n v-for=\"item in model.items\"\n :key=\"item.kind\"\n type=\"button\"\n role=\"menuitemradio\"\n class=\"ink-select-item ink-menu-item ink-highlight-item\"\n data-ink-select-item\n tabindex=\"-1\"\n :data-key=\"item.kind\"\n :aria-checked=\"item.checked\"\n :data-state=\"item.checked ? 'checked' : 'unchecked'\"\n @click=\"choose(item.kind)\"\n >\n <InkIcon :icon=\"MARKUP_ICONS[item.kind]\" :size=\"16\" />\n {{ item.label }}\n </button>\n </div>\n <div role=\"separator\" class=\"ink-select-separator\" />\n <div role=\"group\" aria-label=\"Colour\" class=\"ink-highlight-colour\">\n <span class=\"ink-highlight-colour-label\" aria-hidden=\"true\">Colour</span>\n <InkColorMenu\n property=\"border\"\n group=\"markup\"\n label=\"Highlight colour\"\n standalone\n :fallback=\"fallback\"\n v-bind=\"colourAttrs\"\n />\n </div>\n </div>\n </PopoverContent>\n </PopoverPortal>\n </div>\n </PopoverAnchor>\n </PopoverRoot>\n</template>\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InkHighlightMenu.vue.d.ts","sourceRoot":"","sources":["../../src/components/InkHighlightMenu.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"InkHighlightMenu.vue.d.ts","sourceRoot":"","sources":["../../src/components/InkHighlightMenu.vue"],"names":[],"mappings":"AAgjBA,QAAA,IAAI,QAAQ;;;CAAY,CAAC;AACzB,KAAK,WAAW,GAAG,EAAE,GACnB;IAAE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,QAAQ,KAAK,GAAG,CAAA;CAAE,CAAC;AAGhD,QAAA,MAAM,UAAU,+QACd,CAAC;AACH,QAAA,MAAM,YAAY,EAAS,eAAe,CAAC,OAAO,UAAU,EAAE,WAAW,CAAC,CAAC;wBACtD,OAAO,YAAY;AAAxC,wBAAyC;AACzC,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"}
|