@inkbar/vue 0.10.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/README.md +67 -12
  2. package/dist/components/InkBack.js +7 -0
  3. package/dist/components/InkBack.js.map +1 -0
  4. package/dist/components/InkBack.vue.d.ts +19 -0
  5. package/dist/components/InkBack.vue.d.ts.map +1 -0
  6. package/dist/components/InkBack.vue_vue_type_script_setup_true_lang.js +34 -0
  7. package/dist/components/InkBack.vue_vue_type_script_setup_true_lang.js.map +1 -0
  8. package/dist/components/InkForward.js +7 -0
  9. package/dist/components/InkForward.js.map +1 -0
  10. package/dist/components/InkForward.vue.d.ts +19 -0
  11. package/dist/components/InkForward.vue.d.ts.map +1 -0
  12. package/dist/components/InkForward.vue_vue_type_script_setup_true_lang.js +34 -0
  13. package/dist/components/InkForward.vue_vue_type_script_setup_true_lang.js.map +1 -0
  14. package/dist/components/InkOutline.js +7 -0
  15. package/dist/components/InkOutline.js.map +1 -0
  16. package/dist/components/InkOutline.vue.d.ts +23 -0
  17. package/dist/components/InkOutline.vue.d.ts.map +1 -0
  18. package/dist/components/InkOutline.vue_vue_type_script_setup_true_lang.js +67 -0
  19. package/dist/components/InkOutline.vue_vue_type_script_setup_true_lang.js.map +1 -0
  20. package/dist/components/InkOutlineNodes.js +7 -0
  21. package/dist/components/InkOutlineNodes.js.map +1 -0
  22. package/dist/components/InkOutlineNodes.vue.d.ts +27 -0
  23. package/dist/components/InkOutlineNodes.vue.d.ts.map +1 -0
  24. package/dist/components/InkOutlineNodes.vue_vue_type_script_setup_true_lang.js +70 -0
  25. package/dist/components/InkOutlineNodes.vue_vue_type_script_setup_true_lang.js.map +1 -0
  26. package/dist/components/InkRoot.js.map +1 -1
  27. package/dist/components/InkRoot.vue.d.ts +16 -6
  28. package/dist/components/InkRoot.vue.d.ts.map +1 -1
  29. package/dist/components/InkRoot.vue_vue_type_script_setup_true_lang.js +163 -155
  30. package/dist/components/InkRoot.vue_vue_type_script_setup_true_lang.js.map +1 -1
  31. package/dist/components/InkSidebar.js.map +1 -1
  32. package/dist/components/InkSidebar.vue.d.ts +30 -0
  33. package/dist/components/InkSidebar.vue.d.ts.map +1 -1
  34. package/dist/components/InkSidebar.vue_vue_type_script_setup_true_lang.js +88 -50
  35. package/dist/components/InkSidebar.vue_vue_type_script_setup_true_lang.js.map +1 -1
  36. package/dist/components/InkViewport.js.map +1 -1
  37. package/dist/components/InkViewport.vue.d.ts +3 -0
  38. package/dist/components/InkViewport.vue.d.ts.map +1 -1
  39. package/dist/components/InkViewport.vue_vue_type_script_setup_true_lang.js +15 -5
  40. package/dist/components/InkViewport.vue_vue_type_script_setup_true_lang.js.map +1 -1
  41. package/dist/context.d.ts +15 -5
  42. package/dist/context.d.ts.map +1 -1
  43. package/dist/context.js.map +1 -1
  44. package/dist/index.d.ts +3 -0
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/index.js +15 -12
  47. package/package.json +5 -5
package/README.md CHANGED
@@ -69,6 +69,7 @@ const tools = [highlightTool(), redactAreaTool(), noteTool()]
69
69
  :assets="assets"
70
70
  :tools="tools"
71
71
  v-model:annotations="annotations"
72
+ :history="true"
72
73
  >
73
74
  <InkToolbar>
74
75
  <InkToolButton tool="select-text" />
@@ -93,11 +94,19 @@ const tools = [highlightTool(), redactAreaTool(), noteTool()]
93
94
  </template>
94
95
  ```
95
96
 
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
+ `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 empty and disabled, and is hidden from assistive technology but still takes its place in the layout. The highlight, shape and signature menus render nothing. 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
 
98
99
  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.
99
100
 
100
- `v-model:annotations` makes your list the source of truth. Leave it off and Inkbar keeps the state itself, with undo and redo.
101
+ `v-model:annotations` makes your list the source of truth. Leave it off and Inkbar keeps the state itself, with undo and redo on by default. In controlled mode undo and redo need `:history="true"`, as in the example; see Controlled mode.
102
+
103
+ `InkRoot` also takes `password` for an encrypted file, `storage` for what the viewer keeps between visits (see [Storage](#storage)), `defaults` for annotation colours, `fonts` for the families the text style menu offers, `decorateAnnotation` (a `DecorateAnnotation` function that adds `data-*` attributes, classes and a screen-reader description to each annotation), and `v-model:tool`, `v-model:page` and `v-model:zoom`. It emits `ready` with the `InkDocument`, `error` with an `InkError`, `change` with each annotation change and `activate` with an annotation id. Its default slot receives `{ status, document }`.
104
+
105
+ ## Viewport
106
+
107
+ `InkViewport` takes `mode`, `rotation`, `gap` (CSS pixels between pages, 16), `buffer` (pages kept mounted either side of the visible ones, 2) and `pinchZoom` (default `true`; `false` leaves pinches to the browser, which zooms the whole page). Changing `gap`, `buffer` or `pinchZoom` rebuilds the engine.
108
+
109
+ On a touch screen, two fingers pinch to zoom the document and scroll it. With `draw`, `sketch`, `shape`, `redact-area` and `freetext`, one finger draws; a finger tap draws nothing, and a pen that lands while a palm rests on the screen takes over. A shape, area redaction or text box gives one-finger scrolling back once it has made something.
101
110
 
102
111
  ## Controlled mode
103
112
 
@@ -106,6 +115,10 @@ With `v-model:annotations`, Inkbar proposes each change through `update:annotati
106
115
  Undo and redo are off in controlled mode unless you pass `:history="true"`. Inkbar then keeps a stack of your list's past values and applies undo and redo through `v-model`. Every change to the list is a step, including the list you load from your server when the document opens. Clear the history once that load has reached the viewer, so the first undo does not empty the list:
107
116
 
108
117
  ```ts
118
+ import { nextTick, useTemplateRef } from 'vue'
119
+ import type { InkDocument } from '@inkbar/core'
120
+
121
+ // <InkRoot ref="root" @ready="onReady" ...>
109
122
  const root = useTemplateRef<InstanceType<typeof InkRoot>>('root')
110
123
 
111
124
  async function onReady(doc: InkDocument) {
@@ -121,7 +134,7 @@ Inside `InkRoot`, `useHistory()` returns the same object. Its `batch(fn)` runs `
121
134
 
122
135
  ## Forms
123
136
 
124
- `InkViewport` fills the PDF's form fields and runs the form's scripts. `useForm()` returns the fields, their values, and `set` and `reset`. Bind `v-model:fields` to hold the values in your own state. The form never submits, opens a link, sends mail or prints: `@form-action` hands each request to you. `:form-highlight="false"` turns off the field tint, and a change applies to the open document in place.
137
+ `InkViewport` fills the PDF's form fields and runs the form's scripts; the form props belong to `InkRoot`. `useForm()` returns the fields, their values, and `set` and `reset`. Bind `v-model:fields` on `InkRoot` to hold the values in your own state. The form never submits, opens a link, sends mail or prints: `@action` on `InkRoot` hands each request to you; so does a link to a URL. `@form-action` still works until 0.13.0. `:form-highlight="false"` turns off the field tint, and a change applies to the open document in place. A form script that fails is reported through `InkRoot`'s `error` event.
125
138
 
126
139
  The [forms guide](https://inkbar.dev/docs/guides/forms/) covers controlled fields, form actions, scripts, signature fields and saving values as Gloss.
127
140
 
@@ -131,11 +144,24 @@ The [forms guide](https://inkbar.dev/docs/guides/forms/) covers controlled field
131
144
 
132
145
  A root note with no text and no replies is removed when its popover closes, or when activation moves to another annotation, so abandoned notes do not stay on the page. A highlight stays: the mark is the point. Locked annotations are never removed. If you add notes yourself (`add({ type: 'text', ... })`), give them `contents`, or they will be removed the first time someone opens and closes them.
133
146
 
134
- The highlight tool leaves `contents` free for the comment. `doc.text(page)` returns the page's text items; match the markup's `quads` against them to get the marked text. `InkHighlightMenu` is a split button for the tool: it picks the markup kind and its colour.
147
+ The highlight tool leaves `contents` free for the comment. `await doc.text(page)` returns the page's text content; match the markup's `quads` against its `items` to get the marked text. `InkHighlightMenu` is a split button for the tool: it picks the markup kind and its colour.
135
148
 
136
149
  ## Signatures
137
150
 
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.
151
+ `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. `InkRoot` keeps them in its `storage` under the key `signatures`, so without a store they last until reload. A `signatures` store of your own still works and wins over `storage` until 0.13.0, which removes it. `signatureFonts` lists the handwriting fonts the Type tab offers; load them with `@font-face`. A placed signature keeps its aspect ratio when resized.
152
+
153
+ ## Storage
154
+
155
+ `InkRoot` keeps a few small things between visits: saved signatures, sidebar widths and plugin settings. Pass `storage` to choose where. `createLocalStorage()` from `@inkbar/core` keeps them in `localStorage`, and any `InkStorage` works, including an async one that talks to your server. The default is `createMemoryStorage()`, which forgets everything on reload. Inkbar never touches `localStorage`, cookies or the network unless the store you pass does. The root reads `storage` once, when it is created. See the [`@inkbar/core` README](https://github.com/inkbar/inkbar/tree/main/packages/core#storage) for the keys.
156
+
157
+ ```vue
158
+ <script setup lang="ts">
159
+ import { createLocalStorage } from '@inkbar/core'
160
+ const storage = createLocalStorage()
161
+ </script>
162
+
163
+ <InkRoot :src="src" :assets="assets" :storage="storage">
164
+ ```
139
165
 
140
166
  ## Plugins
141
167
 
@@ -157,13 +183,17 @@ Plugin stores undo with annotations. In controlled mode with `:history="true"`,
157
183
 
158
184
  ## Search
159
185
 
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.
186
+ `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(query?)`, `setQuery`, `setMatchCase`, `next`, `previous`, `select(index)`, `close`) for your own control. See the [`@inkbar/core` README](https://github.com/inkbar/inkbar/tree/main/packages/core#search) for the API.
161
187
 
162
188
  ## Sidebars
163
189
 
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.
190
+ `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`, which you install alongside `@inkbar/vue`) 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
191
 
166
192
  ```vue
193
+ <script setup lang="ts">
194
+ import { Square, MessageSquare } from '@inkbar/icons'
195
+ </script>
196
+
167
197
  <InkRoot :src="src" :assets="assets">
168
198
  <div class="app">
169
199
  <InkSidebar side="left" layout="rail" v-model:open="open">
@@ -181,7 +211,13 @@ Plugin stores undo with annotations. In controlled mode with `:history="true"`,
181
211
 
182
212
  `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
213
 
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.
214
+ 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 at its width with the open panel showing, the stack headers and the resize handle; rail and tab buttons follow once it has mounted.
215
+
216
+ Each sidebar has a resize handle on its inner edge. Drag it, or focus it and use the arrow keys (16px a step), Home and End. Enter or a double-click resets the width. The width starts at `defaultWidth` (320) and stays between `minWidth` (240) and `maxWidth` (480), and never past half of the sidebar's container. The sidebar sets `--ink-sidebar-width` inline, so a CSS override of it no longer applies. Pass `defaultWidth` instead. Inside `InkRoot` the sidebar saves its width in the root's `storage` under `sidebar.<name>.width`, where `name` defaults to the side; give two sidebars on one side different names. Pass `storage` to the sidebar to use another store, or to save its width outside `InkRoot`. The sidebar reads `storage` and `name` once, when it is created. `v-model:width` hands you the width: bind it to a number. The handle then only updates the model, and the sidebar neither reads nor writes storage. A model that starts `undefined` becomes controlled after the first change and stops saving.
217
+
218
+ ```vue
219
+ <InkSidebar name="tools" side="right" :default-width="360" v-model:width="toolsWidth">
220
+ ```
185
221
 
186
222
  ## Thumbnails
187
223
 
@@ -199,6 +235,20 @@ Panels take their place in the order they appear in the template, including one
199
235
 
200
236
  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
237
 
238
+ ## Outline and Back
239
+
240
+ `InkOutline` shows the document's outline as a tree. Clicking an item, or Enter on it, follows it: a destination scrolls there (without changing the zoom), a web address goes to the host as an `open-url` action. The chevron expands and collapses an item without following it. The item the reader has reached is marked `aria-current="location"` and kept in view. It fills its parent's height and scrolls, so put it in a panel:
241
+
242
+ ```vue
243
+ <InkPanel id="outline" label="Outline" :icon="List">
244
+ <InkOutline empty-text="No outline" />
245
+ </InkPanel>
246
+ ```
247
+
248
+ `empty-text` is shown when the document has no outline. The `item` slot, given `{ item, current, expanded }`, replaces an item's title. The keys and ARIA are core's, as in the thumbnails. Needs `InkRoot`; the tree renders empty on the server.
249
+
250
+ `InkBack` and `InkForward` return to where the view was before a jump (a link, an outline item) and undo that. Each is disabled until there is somewhere to go, and takes `as-child`. Put them in an `InkToolbar`.
251
+
202
252
  ## Record lists
203
253
 
204
254
  `InkRecordList` lists a plugin's records as cards, the same cards their marks open, with the same actions. Name the records `<plugin>.<name>`:
@@ -219,11 +269,11 @@ To build your own, `useRecords<T>(name)` returns the live `records` and the `han
219
269
 
220
270
  ## Custom rendering
221
271
 
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.
272
+ Slots let you render parts yourself. `InkViewport` has `loading`, `empty`, `error`, `annotation` and `page-error` slots. `InkThreadPopover` has a scoped default slot that receives `{ root, replies, reply, update, remove, close }`, 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.
223
273
 
224
274
  `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
275
 
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.
276
+ `InkRoot`, `InkToolbar`, `InkToolButton`, `InkCommand`, `InkUndo`, `InkRedo`, `InkDownloadButton`, `InkPrintButton`, `InkPrevPage`, `InkNextPage`, `InkBack`, `InkForward`, `InkZoomIn`, `InkZoomOut`, `InkSearchButton` and `InkToolbarButton` 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.
227
277
 
228
278
  ## Keyboard
229
279
 
@@ -237,21 +287,26 @@ The scroll area takes focus. From there:
237
287
 
238
288
  On a focused annotation:
239
289
 
240
- - `Enter` or `Space` selects and activates it. A note or text markup opens its thread; other types are only selected.
290
+ - `Enter` or `Space` selects and activates it. A note or text markup opens its thread; other types are only selected. `Enter` on an editable text box opens its editor instead.
241
291
  - `ArrowUp` and `ArrowDown` move to the previous or next annotation on the page.
242
292
  - `Shift` + arrow moves it by 1 pt, or by 10 pt with `Alt` as well.
243
293
  - `Ctrl` or `Cmd` + `Shift` + arrow resizes an area redaction, text box or shape.
244
294
  - `Delete` or `Backspace` removes it.
295
+ - `Escape` clears the selection.
245
296
 
246
297
  The full table, with the zoom and page keys, is in the [`@inkbar/core` README](https://github.com/inkbar/inkbar/tree/main/packages/core#tools-and-keyboard).
247
298
 
299
+ ## Style menus
300
+
301
+ `InkColorMenu` (with `property="border"`, `"fill"` or `"text"`), `InkLineStyleMenu` (weight, dashes, arrowheads) and `InkTextStyleMenu` (font, size, colour, bold, italic, underline, alignment) edit the selection, or the active tool's style when nothing is selected. They disable when nothing supports their properties. `InkShapeMenu` is a split button for the `shape` tool and renders nothing unless `shapeTool` is in `tools`. `fonts` on `InkRoot` sets the families the text style menu offers.
302
+
248
303
  ## Styling
249
304
 
250
305
  Components carry state on data attributes, for example `[data-annotation][data-state="selected"]` and `[data-tool="highlight"][data-state="on"]`. `@inkbar/theme` gives a default look. Your own CSS overrides it without `!important`.
251
306
 
252
307
  ## Composables
253
308
 
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.
309
+ `useDocument`, `useAnnotations`, `useTool`, `useSelection`, `useZoom`, `usePage`, `useHistory`, `useEmbedded`, `useCommand`, `useRecords`, `useRecordSelection`, `useSearch`, `useForm`, `useToolStyle` and `useToolOptions` read the state of the nearest `InkRoot`. Build your own toolbar or side panel from them. `useToolOptions(id)` reads and sets a tool's options, such as the shape kind, without switching tools; they 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.
255
310
 
256
311
  ## Licence
257
312
 
@@ -0,0 +1,7 @@
1
+ import e from "./InkBack.vue_vue_type_script_setup_true_lang.js";
2
+ //#region src/components/InkBack.vue
3
+ var t = e;
4
+ //#endregion
5
+ export { t as default };
6
+
7
+ //# sourceMappingURL=InkBack.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InkBack.js","names":["_sfc_main","InkBack_vue_vue_type_script_setup_true_lang_default","InkBack_default"],"sources":["../../src/components/InkBack.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ArrowLeft } from '@inkbar/icons'\nimport { ToolbarButton } from 'reka-ui'\n\nimport { injectInkContext } from '../context'\nimport { useReadable } from '../use-readable'\n\nimport InkIcon from './InkIcon.vue'\n\nwithDefaults(defineProps<{ asChild?: boolean }>(), { asChild: false })\nconst ctx = injectInkContext()\n// Returns to where the view was before the last jump; disabled while there is nowhere to go.\nconst canGoBack = useReadable<boolean>(\n () => ctx.navigation.value?.canGoBack ?? null,\n false\n)\n// Reka's typed props stop at its own; ARIA and listeners go through a bound object.\nconst attrs = {\n 'aria-label': 'Back',\n title: 'Back',\n onClick: () => ctx.navigation.value?.back(),\n}\n</script>\n\n<template>\n <ToolbarButton\n :as-child=\"asChild\"\n :disabled=\"!canGoBack\"\n class=\"ink-back\"\n data-ink-back\n v-bind=\"attrs\"\n >\n <slot><InkIcon :icon=\"ArrowLeft\" /></slot>\n </ToolbarButton>\n</template>\n"],"mappings":""}
@@ -0,0 +1,19 @@
1
+ type __VLS_Props = {
2
+ asChild?: boolean;
3
+ };
4
+ declare var __VLS_7: {};
5
+ type __VLS_Slots = {} & {
6
+ default?: (props: typeof __VLS_7) => any;
7
+ };
8
+ declare const __VLS_base: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
9
+ asChild: boolean;
10
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
11
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
12
+ declare const _default: typeof __VLS_export;
13
+ export default _default;
14
+ type __VLS_WithSlots<T, S> = T & {
15
+ new (): {
16
+ $slots: S;
17
+ };
18
+ };
19
+ //# sourceMappingURL=InkBack.vue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InkBack.vue.d.ts","sourceRoot":"","sources":["../../src/components/InkBack.vue"],"names":[],"mappings":"AA8CA,KAAK,WAAW,GAAG;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AA8DzC,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,34 @@
1
+ import { injectInkContext as e } from "../context.js";
2
+ import { useReadable as t } from "../use-readable.js";
3
+ import n from "./InkIcon.js";
4
+ import { 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";
5
+ import { ToolbarButton as d } from "reka-ui";
6
+ import { ArrowLeft as f } from "@inkbar/icons";
7
+ //#region src/components/InkBack.vue?vue&type=script&setup=true&lang.ts
8
+ var p = /*@__PURE__*/ a({
9
+ __name: "InkBack",
10
+ props: { asChild: {
11
+ type: Boolean,
12
+ default: !1
13
+ } },
14
+ setup(a) {
15
+ let p = e(), m = t(() => p.navigation.value?.canGoBack ?? null, !1), h = {
16
+ "aria-label": "Back",
17
+ title: "Back",
18
+ onClick: () => p.navigation.value?.back()
19
+ };
20
+ return (e, t) => (s(), r(l(d), o({
21
+ "as-child": a.asChild,
22
+ disabled: !l(m),
23
+ class: "ink-back",
24
+ "data-ink-back": ""
25
+ }, h), {
26
+ default: u(() => [c(e.$slots, "default", {}, () => [i(n, { icon: l(f) }, null, 8, ["icon"])])]),
27
+ _: 3
28
+ }, 16, ["as-child", "disabled"]));
29
+ }
30
+ });
31
+ //#endregion
32
+ export { p as default };
33
+
34
+ //# sourceMappingURL=InkBack.vue_vue_type_script_setup_true_lang.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InkBack.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createBlock","_unref","_mergeProps","_withCtx","_renderSlot","_createVNode","InkIcon","InkIcon_default","InkBack_vue_vue_type_script_setup_true_lang_default","ctx","injectInkContext","canGoBack","useReadable","attrs","openBlock","createBlock","unref","ToolbarButton","mergeProps","__props","withCtx","renderSlot","_ctx","createVNode","ArrowLeft"],"sources":["../../src/components/InkBack.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ArrowLeft } from '@inkbar/icons'\nimport { ToolbarButton } from 'reka-ui'\n\nimport { injectInkContext } from '../context'\nimport { useReadable } from '../use-readable'\n\nimport InkIcon from './InkIcon.vue'\n\nwithDefaults(defineProps<{ asChild?: boolean }>(), { asChild: false })\nconst ctx = injectInkContext()\n// Returns to where the view was before the last jump; disabled while there is nowhere to go.\nconst canGoBack = useReadable<boolean>(\n () => ctx.navigation.value?.canGoBack ?? null,\n false\n)\n// Reka's typed props stop at its own; ARIA and listeners go through a bound object.\nconst attrs = {\n 'aria-label': 'Back',\n title: 'Back',\n onClick: () => ctx.navigation.value?.back(),\n}\n</script>\n\n<template>\n <ToolbarButton\n :as-child=\"asChild\"\n :disabled=\"!canGoBack\"\n class=\"ink-back\"\n data-ink-back\n v-bind=\"attrs\"\n >\n <slot><InkIcon :icon=\"ArrowLeft\" /></slot>\n </ToolbarButton>\n</template>\n"],"mappings":";;;;;;;;;;;;;;EAUA,IAAMU,IAAMC,EAAiB,GAEvBC,IAAYC,QACVH,EAAI,WAAW,OAAO,aAAa,MACzC,EACF,GAEMI,IAAQ;GACZ,cAAc;GACd,OAAO;GACP,eAAeJ,EAAI,WAAW,OAAO,KAAK;EAC5C;oBAIEV,EAAA,GAAAC,EAQgBC,EAAAgB,CAAA,GARhBf,EAQgB;GAPb,YAAUiB,EAAA;GACV,UAAQ,CAAGlB,EAAAU,CAAA;GACZ,OAAM;GACN,iBAAA;EACQ,GAAAE,CAAK,GAAA;GAEb,SAAAV,QAA0C,CAA1CC,EAA0CkB,EAAA,QAAA,WAAA,CAAA,SAAA,CAApCjB,EAA6BC,GAAA,EAAnB,MAAML,EAAAuB,CAAA,EAAS,GAAA,MAAA,GAAA,CAAA,MAAA,CAAA,CAAA,CAAA,CAAA,CAAA"}
@@ -0,0 +1,7 @@
1
+ import e from "./InkForward.vue_vue_type_script_setup_true_lang.js";
2
+ //#region src/components/InkForward.vue
3
+ var t = e;
4
+ //#endregion
5
+ export { t as default };
6
+
7
+ //# sourceMappingURL=InkForward.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InkForward.js","names":["_sfc_main","InkForward_vue_vue_type_script_setup_true_lang_default","InkForward_default"],"sources":["../../src/components/InkForward.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ArrowRight } from '@inkbar/icons'\nimport { ToolbarButton } from 'reka-ui'\n\nimport { injectInkContext } from '../context'\nimport { useReadable } from '../use-readable'\n\nimport InkIcon from './InkIcon.vue'\n\nwithDefaults(defineProps<{ asChild?: boolean }>(), { asChild: false })\nconst ctx = injectInkContext()\n// Goes forward again after Back; disabled until Back is used.\nconst canGoForward = useReadable<boolean>(\n () => ctx.navigation.value?.canGoForward ?? null,\n false\n)\n// Reka's typed props stop at its own; ARIA and listeners go through a bound object.\nconst attrs = {\n 'aria-label': 'Forward',\n title: 'Forward',\n onClick: () => ctx.navigation.value?.forward(),\n}\n</script>\n\n<template>\n <ToolbarButton\n :as-child=\"asChild\"\n :disabled=\"!canGoForward\"\n class=\"ink-forward\"\n data-ink-forward\n v-bind=\"attrs\"\n >\n <slot><InkIcon :icon=\"ArrowRight\" /></slot>\n </ToolbarButton>\n</template>\n"],"mappings":""}
@@ -0,0 +1,19 @@
1
+ type __VLS_Props = {
2
+ asChild?: boolean;
3
+ };
4
+ declare var __VLS_7: {};
5
+ type __VLS_Slots = {} & {
6
+ default?: (props: typeof __VLS_7) => any;
7
+ };
8
+ declare const __VLS_base: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
9
+ asChild: boolean;
10
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
11
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
12
+ declare const _default: typeof __VLS_export;
13
+ export default _default;
14
+ type __VLS_WithSlots<T, S> = T & {
15
+ new (): {
16
+ $slots: S;
17
+ };
18
+ };
19
+ //# sourceMappingURL=InkForward.vue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InkForward.vue.d.ts","sourceRoot":"","sources":["../../src/components/InkForward.vue"],"names":[],"mappings":"AA8CA,KAAK,WAAW,GAAG;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AA8DzC,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,34 @@
1
+ import { injectInkContext as e } from "../context.js";
2
+ import { useReadable as t } from "../use-readable.js";
3
+ import n from "./InkIcon.js";
4
+ import { 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";
5
+ import { ToolbarButton as d } from "reka-ui";
6
+ import { ArrowRight as f } from "@inkbar/icons";
7
+ //#region src/components/InkForward.vue?vue&type=script&setup=true&lang.ts
8
+ var p = /*@__PURE__*/ a({
9
+ __name: "InkForward",
10
+ props: { asChild: {
11
+ type: Boolean,
12
+ default: !1
13
+ } },
14
+ setup(a) {
15
+ let p = e(), m = t(() => p.navigation.value?.canGoForward ?? null, !1), h = {
16
+ "aria-label": "Forward",
17
+ title: "Forward",
18
+ onClick: () => p.navigation.value?.forward()
19
+ };
20
+ return (e, t) => (s(), r(l(d), o({
21
+ "as-child": a.asChild,
22
+ disabled: !l(m),
23
+ class: "ink-forward",
24
+ "data-ink-forward": ""
25
+ }, h), {
26
+ default: u(() => [c(e.$slots, "default", {}, () => [i(n, { icon: l(f) }, null, 8, ["icon"])])]),
27
+ _: 3
28
+ }, 16, ["as-child", "disabled"]));
29
+ }
30
+ });
31
+ //#endregion
32
+ export { p as default };
33
+
34
+ //# sourceMappingURL=InkForward.vue_vue_type_script_setup_true_lang.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InkForward.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createBlock","_unref","_mergeProps","_withCtx","_renderSlot","_createVNode","InkIcon","InkIcon_default","InkForward_vue_vue_type_script_setup_true_lang_default","ctx","injectInkContext","canGoForward","useReadable","attrs","openBlock","createBlock","unref","ToolbarButton","mergeProps","__props","withCtx","renderSlot","_ctx","createVNode","ArrowRight"],"sources":["../../src/components/InkForward.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ArrowRight } from '@inkbar/icons'\nimport { ToolbarButton } from 'reka-ui'\n\nimport { injectInkContext } from '../context'\nimport { useReadable } from '../use-readable'\n\nimport InkIcon from './InkIcon.vue'\n\nwithDefaults(defineProps<{ asChild?: boolean }>(), { asChild: false })\nconst ctx = injectInkContext()\n// Goes forward again after Back; disabled until Back is used.\nconst canGoForward = useReadable<boolean>(\n () => ctx.navigation.value?.canGoForward ?? null,\n false\n)\n// Reka's typed props stop at its own; ARIA and listeners go through a bound object.\nconst attrs = {\n 'aria-label': 'Forward',\n title: 'Forward',\n onClick: () => ctx.navigation.value?.forward(),\n}\n</script>\n\n<template>\n <ToolbarButton\n :as-child=\"asChild\"\n :disabled=\"!canGoForward\"\n class=\"ink-forward\"\n data-ink-forward\n v-bind=\"attrs\"\n >\n <slot><InkIcon :icon=\"ArrowRight\" /></slot>\n </ToolbarButton>\n</template>\n"],"mappings":";;;;;;;;;;;;;;EAUA,IAAMU,IAAMC,EAAiB,GAEvBC,IAAeC,QACbH,EAAI,WAAW,OAAO,gBAAgB,MAC5C,EACF,GAEMI,IAAQ;GACZ,cAAc;GACd,OAAO;GACP,eAAeJ,EAAI,WAAW,OAAO,QAAQ;EAC/C;oBAIEV,EAAA,GAAAC,EAQgBC,EAAAgB,CAAA,GARhBf,EAQgB;GAPb,YAAUiB,EAAA;GACV,UAAQ,CAAGlB,EAAAU,CAAA;GACZ,OAAM;GACN,oBAAA;EACQ,GAAAE,CAAK,GAAA;GAEb,SAAAV,QAA2C,CAA3CC,EAA2CkB,EAAA,QAAA,WAAA,CAAA,SAAA,CAArCjB,EAA8BC,GAAA,EAApB,MAAML,EAAAuB,CAAA,EAAU,GAAA,MAAA,GAAA,CAAA,MAAA,CAAA,CAAA,CAAA,CAAA,CAAA"}
@@ -0,0 +1,7 @@
1
+ import e from "./InkOutline.vue_vue_type_script_setup_true_lang.js";
2
+ //#region src/components/InkOutline.vue
3
+ var t = e;
4
+ //#endregion
5
+ export { t as default };
6
+
7
+ //# sourceMappingURL=InkOutline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InkOutline.js","names":["_sfc_main","InkOutline_vue_vue_type_script_setup_true_lang_default","InkOutline_default"],"sources":["../../src/components/InkOutline.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/*\n * The open document's outline as a tree: `createOutline`'s markup on core's outline controller,\n * which holds what is expanded, the Tab stop, the keys, the current item and Back's history.\n * Clicking an item, or Enter on it, follows it; its chevron expands and collapses it. It fills\n * its parent's height and scrolls, and keeps the item the reader has reached in view.\n *\n * The `item` slot, given `{ item, current, expanded }`, replaces an item's title. `emptyText`\n * is shown when the document has no outline. Inside `InkRoot`; the tree is empty on the server.\n */\nimport {\n createOutlineController,\n outlineTreeAttrs,\n type OutlineController,\n} from '@inkbar/core/dom'\nimport { onBeforeUnmount, onMounted, shallowRef, useTemplateRef } from 'vue'\n\nimport { injectInkContext } from '../context'\nimport { toReadable } from '../to-readable'\n\nimport InkOutlineNodes from './InkOutlineNodes.vue'\n\nimport type { OutlineItem } from '@inkbar/core'\n\nwithDefaults(defineProps<{ emptyText?: string | undefined }>(), {\n emptyText: 'This document has no outline',\n})\n\ndefineSlots<{\n item?(props: { item: OutlineItem; current: boolean; expanded: boolean }): unknown\n}>()\n\nconst ctx = injectInkContext()\nconst deps = {\n document: toReadable(() => ctx.document.value),\n viewport: toReadable(() => ctx.viewport.value),\n navigation: toReadable(() => ctx.navigation.value),\n}\n\n/** The tree's role and label, from core so every binding names it alike. */\nconst treeAttrs = outlineTreeAttrs()\n\n// The controller is built on mount, as the other controller-backed components do: it\n// subscribes to the document, so nothing is created while rendering on the server.\nconst controller = shallowRef<OutlineController | null>(null)\nconst items = shallowRef<readonly OutlineItem[]>([])\nconst loading = shallowRef(false)\nconst expanded = shallowRef<ReadonlySet<string>>(new Set())\nconst current = shallowRef<string | null>(null)\nconst focused = shallowRef<string | null>(null)\n\n/** The item's attributes. Reading the stores here makes a render follow them. */\nfunction attrs(id: string): Record<string, string | undefined> {\n void [expanded.value, current.value, focused.value]\n return controller.value?.itemAttrs(id) ?? {}\n}\n\nconst root = useTemplateRef<HTMLElement>('root')\nlet stops: (() => void)[] = []\nonMounted(() => {\n const c = createOutlineController(deps)\n controller.value = c\n items.value = c.items.get()\n loading.value = c.loading.get()\n expanded.value = c.expanded.get()\n current.value = c.current.get()\n focused.value = c.focused.get()\n stops = [\n c.items.subscribe((v) => (items.value = v)),\n c.loading.subscribe((v) => (loading.value = v)),\n c.expanded.subscribe((v) => (expanded.value = v)),\n c.current.subscribe((v) => (current.value = v)),\n c.focused.subscribe((v) => (focused.value = v)),\n c.bindScroll(root.value!),\n ]\n})\nonBeforeUnmount(() => {\n for (const stop of stops) stop()\n stops = []\n controller.value?.destroy()\n controller.value = null\n})\n</script>\n\n<template>\n <div\n ref=\"root\"\n class=\"ink-outline\"\n data-ink-outline\n :aria-busy=\"loading ? 'true' : undefined\"\n >\n <ul\n class=\"ink-outline-tree\"\n v-bind=\"treeAttrs\"\n :hidden=\"items.length === 0\"\n @keydown=\"controller?.onKeydown($event)\"\n >\n <InkOutlineNodes\n v-if=\"controller\"\n :items=\"items\"\n :controller=\"controller\"\n :attrs=\"attrs\"\n :expanded=\"expanded\"\n :current=\"current\"\n >\n <template v-if=\"$slots.item\" #item=\"slotProps\">\n <slot name=\"item\" v-bind=\"slotProps\" />\n </template>\n </InkOutlineNodes>\n </ul>\n <p v-if=\"controller && !loading && items.length === 0\" class=\"ink-outline-empty\">\n {{ emptyText }}\n </p>\n </div>\n</template>\n"],"mappings":""}
@@ -0,0 +1,23 @@
1
+ import { OutlineItem } from '@inkbar/core';
2
+ type __VLS_Props = {
3
+ emptyText?: string | undefined;
4
+ };
5
+ type __VLS_Slots = {
6
+ item?(props: {
7
+ item: OutlineItem;
8
+ current: boolean;
9
+ expanded: boolean;
10
+ }): unknown;
11
+ };
12
+ declare const __VLS_base: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
13
+ emptyText: string | undefined;
14
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
15
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
16
+ declare const _default: typeof __VLS_export;
17
+ export default _default;
18
+ type __VLS_WithSlots<T, S> = T & {
19
+ new (): {
20
+ $slots: S;
21
+ };
22
+ };
23
+ //# sourceMappingURL=InkOutline.vue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InkOutline.vue.d.ts","sourceRoot":"","sources":["../../src/components/InkOutline.vue"],"names":[],"mappings":"AA0IA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAG/C,KAAK,WAAW,GAAG;IAAE,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AAKtD,KAAK,WAAW,GAAG;IACjB,IAAI,CAAC,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,WAAW,CAAC;QAAC,OAAO,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAA;CAClF,CAAC;AAyIF,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,67 @@
1
+ import { injectInkContext as e } from "../context.js";
2
+ import { toReadable as t } from "../to-readable.js";
3
+ import n from "./InkOutlineNodes.js";
4
+ import { createBlock as r, createCommentVNode as i, createElementBlock as a, createElementVNode as o, createSlots as s, defineComponent as c, guardReactiveProps as l, mergeProps as u, normalizeProps as d, onBeforeUnmount as f, onMounted as p, openBlock as m, renderSlot as h, shallowRef as g, toDisplayString as _, unref as v, useTemplateRef as y, withCtx as b } from "vue";
5
+ import { createOutlineController as x, outlineTreeAttrs as S } from "@inkbar/core/dom";
6
+ //#region src/components/InkOutline.vue?vue&type=script&setup=true&lang.ts
7
+ var C = ["aria-busy"], w = ["hidden"], T = {
8
+ key: 0,
9
+ class: "ink-outline-empty"
10
+ }, E = /*@__PURE__*/ c({
11
+ __name: "InkOutline",
12
+ props: { emptyText: { default: "This document has no outline" } },
13
+ setup(c) {
14
+ let E = e(), D = {
15
+ document: t(() => E.document.value),
16
+ viewport: t(() => E.viewport.value),
17
+ navigation: t(() => E.navigation.value)
18
+ }, O = S(), k = g(null), A = g([]), j = g(!1), M = g(/* @__PURE__ */ new Set()), N = g(null), P = g(null);
19
+ function F(e) {
20
+ return M.value, N.value, P.value, k.value?.itemAttrs(e) ?? {};
21
+ }
22
+ let I = y("root"), L = [];
23
+ return p(() => {
24
+ let e = x(D);
25
+ k.value = e, A.value = e.items.get(), j.value = e.loading.get(), M.value = e.expanded.get(), N.value = e.current.get(), P.value = e.focused.get(), L = [
26
+ e.items.subscribe((e) => A.value = e),
27
+ e.loading.subscribe((e) => j.value = e),
28
+ e.expanded.subscribe((e) => M.value = e),
29
+ e.current.subscribe((e) => N.value = e),
30
+ e.focused.subscribe((e) => P.value = e),
31
+ e.bindScroll(I.value)
32
+ ];
33
+ }), f(() => {
34
+ for (let e of L) e();
35
+ L = [], k.value?.destroy(), k.value = null;
36
+ }), (e, t) => (m(), a("div", {
37
+ ref_key: "root",
38
+ ref: I,
39
+ class: "ink-outline",
40
+ "data-ink-outline": "",
41
+ "aria-busy": j.value ? "true" : void 0
42
+ }, [o("ul", u({ class: "ink-outline-tree" }, v(O), {
43
+ hidden: A.value.length === 0,
44
+ onKeydown: t[0] ||= (e) => k.value?.onKeydown(e)
45
+ }), [k.value ? (m(), r(n, {
46
+ key: 0,
47
+ items: A.value,
48
+ controller: k.value,
49
+ attrs: F,
50
+ expanded: M.value,
51
+ current: N.value
52
+ }, s({ _: 2 }, [e.$slots.item ? {
53
+ name: "item",
54
+ fn: b((t) => [h(e.$slots, "item", d(l(t)))]),
55
+ key: "0"
56
+ } : void 0]), 1032, [
57
+ "items",
58
+ "controller",
59
+ "expanded",
60
+ "current"
61
+ ])) : i("", !0)], 16, w), k.value && !j.value && A.value.length === 0 ? (m(), a("p", T, _(c.emptyText), 1)) : i("", !0)], 8, C));
62
+ }
63
+ });
64
+ //#endregion
65
+ export { E as default };
66
+
67
+ //# sourceMappingURL=InkOutline.vue_vue_type_script_setup_true_lang.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InkOutline.vue_vue_type_script_setup_true_lang.js","names":["$slots","_openBlock","_createElementBlock","_createElementVNode","_mergeProps","_unref","_createBlock","InkOutlineNodes","_createSlots","_withCtx","_renderSlot","_normalizeProps","_guardReactiveProps","_createCommentVNode","_toDisplayString","InkOutlineNodes_default","_hoisted_1","_hoisted_2","_hoisted_3","InkOutline_vue_vue_type_script_setup_true_lang_default","ctx","injectInkContext","deps","toReadable","treeAttrs","outlineTreeAttrs","controller","shallowRef","items","loading","expanded","current","focused","attrs","id","root","useTemplateRef","stops","onMounted","c","createOutlineController","v","onBeforeUnmount","stop","openBlock","createElementBlock","createElementVNode","mergeProps","unref","_cache","$event","createBlock","createSlots","_ctx","withCtx","renderSlot","normalizeProps","guardReactiveProps","slotProps","createCommentVNode","toDisplayString","__props"],"sources":["../../src/components/InkOutline.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/*\n * The open document's outline as a tree: `createOutline`'s markup on core's outline controller,\n * which holds what is expanded, the Tab stop, the keys, the current item and Back's history.\n * Clicking an item, or Enter on it, follows it; its chevron expands and collapses it. It fills\n * its parent's height and scrolls, and keeps the item the reader has reached in view.\n *\n * The `item` slot, given `{ item, current, expanded }`, replaces an item's title. `emptyText`\n * is shown when the document has no outline. Inside `InkRoot`; the tree is empty on the server.\n */\nimport {\n createOutlineController,\n outlineTreeAttrs,\n type OutlineController,\n} from '@inkbar/core/dom'\nimport { onBeforeUnmount, onMounted, shallowRef, useTemplateRef } from 'vue'\n\nimport { injectInkContext } from '../context'\nimport { toReadable } from '../to-readable'\n\nimport InkOutlineNodes from './InkOutlineNodes.vue'\n\nimport type { OutlineItem } from '@inkbar/core'\n\nwithDefaults(defineProps<{ emptyText?: string | undefined }>(), {\n emptyText: 'This document has no outline',\n})\n\ndefineSlots<{\n item?(props: { item: OutlineItem; current: boolean; expanded: boolean }): unknown\n}>()\n\nconst ctx = injectInkContext()\nconst deps = {\n document: toReadable(() => ctx.document.value),\n viewport: toReadable(() => ctx.viewport.value),\n navigation: toReadable(() => ctx.navigation.value),\n}\n\n/** The tree's role and label, from core so every binding names it alike. */\nconst treeAttrs = outlineTreeAttrs()\n\n// The controller is built on mount, as the other controller-backed components do: it\n// subscribes to the document, so nothing is created while rendering on the server.\nconst controller = shallowRef<OutlineController | null>(null)\nconst items = shallowRef<readonly OutlineItem[]>([])\nconst loading = shallowRef(false)\nconst expanded = shallowRef<ReadonlySet<string>>(new Set())\nconst current = shallowRef<string | null>(null)\nconst focused = shallowRef<string | null>(null)\n\n/** The item's attributes. Reading the stores here makes a render follow them. */\nfunction attrs(id: string): Record<string, string | undefined> {\n void [expanded.value, current.value, focused.value]\n return controller.value?.itemAttrs(id) ?? {}\n}\n\nconst root = useTemplateRef<HTMLElement>('root')\nlet stops: (() => void)[] = []\nonMounted(() => {\n const c = createOutlineController(deps)\n controller.value = c\n items.value = c.items.get()\n loading.value = c.loading.get()\n expanded.value = c.expanded.get()\n current.value = c.current.get()\n focused.value = c.focused.get()\n stops = [\n c.items.subscribe((v) => (items.value = v)),\n c.loading.subscribe((v) => (loading.value = v)),\n c.expanded.subscribe((v) => (expanded.value = v)),\n c.current.subscribe((v) => (current.value = v)),\n c.focused.subscribe((v) => (focused.value = v)),\n c.bindScroll(root.value!),\n ]\n})\nonBeforeUnmount(() => {\n for (const stop of stops) stop()\n stops = []\n controller.value?.destroy()\n controller.value = null\n})\n</script>\n\n<template>\n <div\n ref=\"root\"\n class=\"ink-outline\"\n data-ink-outline\n :aria-busy=\"loading ? 'true' : undefined\"\n >\n <ul\n class=\"ink-outline-tree\"\n v-bind=\"treeAttrs\"\n :hidden=\"items.length === 0\"\n @keydown=\"controller?.onKeydown($event)\"\n >\n <InkOutlineNodes\n v-if=\"controller\"\n :items=\"items\"\n :controller=\"controller\"\n :attrs=\"attrs\"\n :expanded=\"expanded\"\n :current=\"current\"\n >\n <template v-if=\"$slots.item\" #item=\"slotProps\">\n <slot name=\"item\" v-bind=\"slotProps\" />\n </template>\n </InkOutlineNodes>\n </ul>\n <p v-if=\"controller && !loading && items.length === 0\" class=\"ink-outline-empty\">\n {{ emptyText }}\n </p>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;EAgCA,IAAMoB,IAAMC,EAAiB,GACvBC,IAAO;GACX,UAAUC,QAAiBH,EAAI,SAAS,KAAK;GAC7C,UAAUG,QAAiBH,EAAI,SAAS,KAAK;GAC7C,YAAYG,QAAiBH,EAAI,WAAW,KAAK;EACnD,GAGMI,IAAYC,EAAiB,GAI7BC,IAAaC,EAAqC,IAAI,GACtDC,IAAQD,EAAmC,CAAC,CAAC,GAC7CE,IAAUF,EAAW,EAAK,GAC1BG,IAAWH,kBAAgC,IAAI,IAAI,CAAC,GACpDI,IAAUJ,EAA0B,IAAI,GACxCK,IAAUL,EAA0B,IAAI;EAG9C,SAASM,EAAM,GAAgD;GAE7D,OADAH,EAAe,OAAOC,EAAQ,OAAOC,EAAQ,OACtCN,EAAW,OAAO,UAAUQ,CAAE,KAAK,CAAC;EAC7C;EAEA,IAAMC,IAAOC,EAA4B,MAAM,GAC3CC,IAAwB,CAAC;SAC7BC,QAAgB;GACd,IAAMC,IAAIC,EAAwBlB,CAAI;GAOtC,AANA,EAAW,QAAQiB,GACnB,EAAM,QAAQA,EAAE,MAAM,IAAI,GAC1B,EAAQ,QAAQA,EAAE,QAAQ,IAAI,GAC9B,EAAS,QAAQA,EAAE,SAAS,IAAI,GAChC,EAAQ,QAAQA,EAAE,QAAQ,IAAI,GAC9B,EAAQ,QAAQA,EAAE,QAAQ,IAAI,GAC9B,IAAQ;IACNA,EAAE,MAAM,WAAW,MAAO,EAAM,QAAQE,CAAE;IAC1CF,EAAE,QAAQ,WAAW,MAAO,EAAQ,QAAQE,CAAE;IAC9CF,EAAE,SAAS,WAAW,MAAO,EAAS,QAAQE,CAAE;IAChDF,EAAE,QAAQ,WAAW,MAAO,EAAQ,QAAQE,CAAE;IAC9CF,EAAE,QAAQ,WAAW,MAAO,EAAQ,QAAQE,CAAE;IAC9CF,EAAE,WAAWJ,EAAK,KAAM;GAC1B;EACF,CAAC,GACDO,QAAsB;GACpB,KAAK,IAAMC,KAAQN,GAAO,EAAK;GAG/B,AAFA,IAAQ,CAAC,GACTX,EAAW,OAAO,QAAQ,GAC1B,EAAW,QAAQ;EACrB,CAAC,cAICzB,EAAA,GAAAC,EA4BM,OAAA;GA3BA,SAAA;GAAJ,KAAIiC;GACJ,OAAM;GACN,oBAAA;GACC,aAAWN,EAAA,QAAO,SAAY,KAAA;EAE/B1B,GAAAA,CAAAA,EAkBK,MAlBLC,EAkBK,EAjBH,OAAM,mBAAkB,GAChBC,EAAAmB,CAAA,GAAS;GAChB,QAAQI,EAAA,MAAM,WAAM;GACpB,WAAO,AAAAqB,EAAA,QAAA,MAAEvB,EAAA,OAAY,UAAUwB,CAAM;EAG9B,CAAA,GAAA,CAAAxB,EAAA,SADRzB,EAAA,GAAAK,EAWkBC,GAAA;;GATf,OAAOqB,EAAA;GACP,YAAYF,EAAA;GACL;GACP,UAAUI,EAAA;GACV,SAASC,EAAA;EAEM/B,GAAAA,EAAAA,EAAAA,GAAAA,EAAAA,GAAAA,CAAAA,EAAAA,OAAO,OAAA;GAAO,MAAA;GAC5B,IAAAS,GADkC,MAAS,CAC3CC,EAAuC2C,EAAA,QAAA,QAAA1C,EAAAC,EAAb8C,CAAS,CAAA,CAAA,CAAA,CAAA;;;;;;;EAIhC,CAAA,KAAAC,EAAA,IAAA,EAAA,CAAA,GAAA,IAAA1C,CAAA,GAAAS,EAAA,SAAU,CAAKG,EAAA,SAAWD,EAAA,MAAM,WAAM,KAA/C3B,EAAA,GAAAC,EAEI,KAFJgB,GAEIJ,EADC+C,EAAA,SAAS,GAAA,CAAA,KAAAF,EAAA,IAAA,EAAA,CAAA,GAAA,GAAA3C,CAAA"}
@@ -0,0 +1,7 @@
1
+ import e from "./InkOutlineNodes.vue_vue_type_script_setup_true_lang.js";
2
+ //#region src/components/InkOutlineNodes.vue
3
+ var t = e;
4
+ //#endregion
5
+ export { t as default };
6
+
7
+ //# sourceMappingURL=InkOutlineNodes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InkOutlineNodes.js","names":["_sfc_main","InkOutlineNodes_vue_vue_type_script_setup_true_lang_default","InkOutlineNodes_default"],"sources":["../../src/components/InkOutlineNodes.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/*\n * One level of `InkOutline`'s tree, and below it the levels of the items that have children.\n * Internal: it renders the markup `OutlineController.itemAttrs` documents and spreads what the\n * controller gives it.\n */\nimport { ChevronRight } from '@inkbar/icons'\n\nimport InkIcon from './InkIcon.vue'\n\nimport type { OutlineItem } from '@inkbar/core'\nimport type { OutlineController } from '@inkbar/core/dom'\n\nconst props = defineProps<{\n items: readonly OutlineItem[]\n controller: OutlineController\n /** Reads the controller's stores so a render follows them. */\n attrs: (id: string) => Record<string, string | undefined>\n expanded: ReadonlySet<string>\n current: string | null\n}>()\n\nconst isOpen = (item: OutlineItem): boolean => props.expanded.has(item.id)\n\ndefineSlots<{\n item?(props: { item: OutlineItem; current: boolean; expanded: boolean }): unknown\n}>()\n</script>\n\n<template>\n <li\n v-for=\"item in items\"\n :key=\"item.id\"\n class=\"ink-outline-item\"\n :data-ink-outline-item=\"item.id\"\n :data-bold=\"item.bold ? '' : undefined\"\n :data-italic=\"item.italic ? '' : undefined\"\n :style=\"{ '--ink-outline-level': item.id.split('.').length - 1 }\"\n v-bind=\"attrs(item.id)\"\n >\n <div\n class=\"ink-outline-row\"\n v-bind=\"controller.rowAttrs(item.id)\"\n @click=\"controller.activate(item.id)\"\n >\n <span\n v-if=\"item.children.length > 0\"\n class=\"ink-outline-toggle\"\n aria-hidden=\"true\"\n @click.stop=\"controller.toggle(item.id)\"\n >\n <InkIcon :icon=\"ChevronRight\" />\n </span>\n <span v-else class=\"ink-outline-spacer\" aria-hidden=\"true\" />\n <span class=\"ink-outline-title\" v-bind=\"controller.titleAttrs(item.id)\">\n <slot\n name=\"item\"\n :item=\"item\"\n :current=\"current === item.id\"\n :expanded=\"isOpen(item)\"\n >\n {{ item.title }}\n </slot>\n </span>\n </div>\n <ul\n v-if=\"item.children.length > 0\"\n class=\"ink-outline-group\"\n role=\"group\"\n :hidden=\"!expanded.has(item.id)\"\n >\n <InkOutlineNodes\n :items=\"item.children\"\n :controller=\"controller\"\n :attrs=\"attrs\"\n :expanded=\"expanded\"\n :current=\"current\"\n >\n <template v-if=\"$slots.item\" #item=\"slotProps\">\n <slot name=\"item\" v-bind=\"slotProps\" />\n </template>\n </InkOutlineNodes>\n </ul>\n </li>\n</template>\n"],"mappings":""}
@@ -0,0 +1,27 @@
1
+ import { OutlineItem } from '@inkbar/core';
2
+ import { OutlineController } from '@inkbar/core/dom';
3
+ type __VLS_Props = {
4
+ items: readonly OutlineItem[];
5
+ controller: OutlineController;
6
+ /** Reads the controller's stores so a render follows them. */
7
+ attrs: (id: string) => Record<string, string | undefined>;
8
+ expanded: ReadonlySet<string>;
9
+ current: string | null;
10
+ };
11
+ type __VLS_Slots = {
12
+ item?(props: {
13
+ item: OutlineItem;
14
+ current: boolean;
15
+ expanded: boolean;
16
+ }): unknown;
17
+ };
18
+ declare const __VLS_base: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
19
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
20
+ declare const _default: typeof __VLS_export;
21
+ export default _default;
22
+ type __VLS_WithSlots<T, S> = T & {
23
+ new (): {
24
+ $slots: S;
25
+ };
26
+ };
27
+ //# sourceMappingURL=InkOutlineNodes.vue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InkOutlineNodes.vue.d.ts","sourceRoot":"","sources":["../../src/components/InkOutlineNodes.vue"],"names":[],"mappings":"AAgGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AAGzD,KAAK,WAAW,GAAG;IACjB,KAAK,EAAE,SAAS,WAAW,EAAE,CAAA;IAC7B,UAAU,EAAE,iBAAiB,CAAA;IAC7B,8DAA8D;IAC9D,KAAK,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;IACzD,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IAC7B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CACvB,CAAC;AAKF,KAAK,WAAW,GAAG;IACjB,IAAI,CAAC,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,WAAW,CAAC;QAAC,OAAO,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAA;CAClF,CAAC;AA8HF,QAAA,MAAM,UAAU,kSAEd,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"}
@@ -0,0 +1,70 @@
1
+ import e from "./InkIcon.js";
2
+ import { Fragment as t, createCommentVNode as n, createElementBlock as r, createElementVNode as i, createSlots as a, createTextVNode as o, createVNode as s, defineComponent as c, mergeProps as l, openBlock as u, renderList as d, renderSlot as f, resolveComponent as p, toDisplayString as m, unref as h, withCtx as g, withModifiers as _ } from "vue";
3
+ import { ChevronRight as v } from "@inkbar/icons";
4
+ //#region src/components/InkOutlineNodes.vue?vue&type=script&setup=true&lang.ts
5
+ var y = [
6
+ "data-ink-outline-item",
7
+ "data-bold",
8
+ "data-italic"
9
+ ], b = ["onClick"], x = ["onClick"], S = {
10
+ key: 1,
11
+ class: "ink-outline-spacer",
12
+ "aria-hidden": "true"
13
+ }, C = ["hidden"], w = /*@__PURE__*/ c({
14
+ __name: "InkOutlineNodes",
15
+ props: {
16
+ items: {},
17
+ controller: {},
18
+ attrs: { type: Function },
19
+ expanded: {},
20
+ current: {}
21
+ },
22
+ setup(c) {
23
+ let w = c, T = (e) => w.expanded.has(e.id);
24
+ return (w, E) => {
25
+ let D = p("InkOutlineNodes", !0);
26
+ return u(!0), r(t, null, d(c.items, (t) => (u(), r("li", l({
27
+ key: t.id,
28
+ class: "ink-outline-item",
29
+ "data-ink-outline-item": t.id,
30
+ "data-bold": t.bold ? "" : void 0,
31
+ "data-italic": t.italic ? "" : void 0,
32
+ style: { "--ink-outline-level": t.id.split(".").length - 1 }
33
+ }, { ref_for: !0 }, c.attrs(t.id)), [i("div", l({ class: "ink-outline-row" }, { ref_for: !0 }, c.controller.rowAttrs(t.id), { onClick: (e) => c.controller.activate(t.id) }), [t.children.length > 0 ? (u(), r("span", {
34
+ key: 0,
35
+ class: "ink-outline-toggle",
36
+ "aria-hidden": "true",
37
+ onClick: _((e) => c.controller.toggle(t.id), ["stop"])
38
+ }, [s(e, { icon: h(v) }, null, 8, ["icon"])], 8, x)) : (u(), r("span", S)), i("span", l({ class: "ink-outline-title" }, { ref_for: !0 }, c.controller.titleAttrs(t.id)), [f(w.$slots, "item", {
39
+ item: t,
40
+ current: c.current === t.id,
41
+ expanded: T(t)
42
+ }, () => [o(m(t.title), 1)])], 16)], 16, b), t.children.length > 0 ? (u(), r("ul", {
43
+ key: 0,
44
+ class: "ink-outline-group",
45
+ role: "group",
46
+ hidden: !c.expanded.has(t.id)
47
+ }, [s(D, {
48
+ items: t.children,
49
+ controller: c.controller,
50
+ attrs: c.attrs,
51
+ expanded: c.expanded,
52
+ current: c.current
53
+ }, a({ _: 2 }, [w.$slots.item ? {
54
+ name: "item",
55
+ fn: g((e) => [f(w.$slots, "item", l({ ref_for: !0 }, e))]),
56
+ key: "0"
57
+ } : void 0]), 1032, [
58
+ "items",
59
+ "controller",
60
+ "attrs",
61
+ "expanded",
62
+ "current"
63
+ ])], 8, C)) : n("", !0)], 16, y))), 128);
64
+ };
65
+ }
66
+ });
67
+ //#endregion
68
+ export { w as default };
69
+
70
+ //# sourceMappingURL=InkOutlineNodes.vue_vue_type_script_setup_true_lang.js.map