@inkbar/vue 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/README.md +23 -7
  2. package/dist/components/InkAnnotation.js.map +1 -1
  3. package/dist/components/InkAnnotation.vue.d.ts.map +1 -1
  4. package/dist/components/InkAnnotation.vue_vue_type_script_setup_true_lang.js +16 -24
  5. package/dist/components/InkAnnotation.vue_vue_type_script_setup_true_lang.js.map +1 -1
  6. package/dist/components/InkColorMenu.js.map +1 -1
  7. package/dist/components/InkColorMenu.vue.d.ts +2 -0
  8. package/dist/components/InkColorMenu.vue.d.ts.map +1 -1
  9. package/dist/components/InkColorMenu.vue_vue_type_script_setup_true_lang.js +3 -2
  10. package/dist/components/InkColorMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
  11. package/dist/components/InkCommand.js +7 -0
  12. package/dist/components/InkCommand.js.map +1 -0
  13. package/dist/components/InkCommand.vue.d.ts +23 -0
  14. package/dist/components/InkCommand.vue.d.ts.map +1 -0
  15. package/dist/components/InkCommand.vue_vue_type_script_setup_true_lang.js +51 -0
  16. package/dist/components/InkCommand.vue_vue_type_script_setup_true_lang.js.map +1 -0
  17. package/dist/components/InkHighlightMenu.js.map +1 -1
  18. package/dist/components/InkHighlightMenu.vue.d.ts +2 -2
  19. package/dist/components/InkHighlightMenu.vue.d.ts.map +1 -1
  20. package/dist/components/InkHighlightMenu.vue_vue_type_script_setup_true_lang.js +118 -108
  21. package/dist/components/InkHighlightMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
  22. package/dist/components/InkPageInput.js.map +1 -1
  23. package/dist/components/InkPageInput.vue.d.ts.map +1 -1
  24. package/dist/components/InkPageInput.vue_vue_type_script_setup_true_lang.js +1 -1
  25. package/dist/components/InkPageInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
  26. package/dist/components/InkRoot.js.map +1 -1
  27. package/dist/components/InkRoot.vue.d.ts +415 -424
  28. package/dist/components/InkRoot.vue.d.ts.map +1 -1
  29. package/dist/components/InkRoot.vue_vue_type_script_setup_true_lang.js +145 -102
  30. package/dist/components/InkRoot.vue_vue_type_script_setup_true_lang.js.map +1 -1
  31. package/dist/components/InkShapeMenu.js.map +1 -1
  32. package/dist/components/InkShapeMenu.vue.d.ts +2 -2
  33. package/dist/components/InkShapeMenu.vue.d.ts.map +1 -1
  34. package/dist/components/InkShapeMenu.vue_vue_type_script_setup_true_lang.js +99 -91
  35. package/dist/components/InkShapeMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
  36. package/dist/components/InkSignatureMenu.js.map +1 -1
  37. package/dist/components/InkSignatureMenu.vue.d.ts +2 -2
  38. package/dist/components/InkSignatureMenu.vue.d.ts.map +1 -1
  39. package/dist/components/InkSignatureMenu.vue_vue_type_script_setup_true_lang.js +156 -151
  40. package/dist/components/InkSignatureMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
  41. package/dist/components/InkToolButton.js.map +1 -1
  42. package/dist/components/InkToolButton.vue.d.ts.map +1 -1
  43. package/dist/components/InkToolButton.vue_vue_type_script_setup_true_lang.js +36 -35
  44. package/dist/components/InkToolButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
  45. package/dist/components/InkViewport.js.map +1 -1
  46. package/dist/components/InkViewport.vue.d.ts.map +1 -1
  47. package/dist/components/InkViewport.vue_vue_type_script_setup_true_lang.js +14 -4
  48. package/dist/components/InkViewport.vue_vue_type_script_setup_true_lang.js.map +1 -1
  49. package/dist/composables/useAnnotations.d.ts +915 -1386
  50. package/dist/composables/useAnnotations.d.ts.map +1 -1
  51. package/dist/composables/useAnnotations.js +13 -18
  52. package/dist/composables/useAnnotations.js.map +1 -1
  53. package/dist/composables/useCommand.d.ts +23 -0
  54. package/dist/composables/useCommand.d.ts.map +1 -0
  55. package/dist/composables/useCommand.js +22 -0
  56. package/dist/composables/useCommand.js.map +1 -0
  57. package/dist/context.d.ts +22 -4
  58. package/dist/context.d.ts.map +1 -1
  59. package/dist/context.js.map +1 -1
  60. package/dist/index.d.ts +4 -2
  61. package/dist/index.d.ts.map +1 -1
  62. package/dist/index.js +27 -26
  63. package/dist/ref-history.d.ts +12 -3
  64. package/dist/ref-history.d.ts.map +1 -1
  65. package/dist/ref-history.js +27 -16
  66. package/dist/ref-history.js.map +1 -1
  67. package/package.json +5 -5
  68. package/dist/components/InkSuggestionCard.js +0 -7
  69. package/dist/components/InkSuggestionCard.js.map +0 -1
  70. package/dist/components/InkSuggestionCard.vue.d.ts +0 -16
  71. package/dist/components/InkSuggestionCard.vue.d.ts.map +0 -1
  72. package/dist/components/InkSuggestionCard.vue_vue_type_script_setup_true_lang.js +0 -85
  73. package/dist/components/InkSuggestionCard.vue_vue_type_script_setup_true_lang.js.map +0 -1
@@ -1,140 +1,150 @@
1
- import { useTool as e } from "../composables/useTool.js";
2
- import { useToolOptions as t } from "../composables/useToolOptions.js";
3
- import n from "./InkIcon.js";
4
- import r from "./InkColorMenu.js";
5
- import { Fragment as i, computed as a, createElementBlock as o, createElementVNode as s, createTextVNode as c, createVNode as l, defineComponent as u, guardReactiveProps as d, mergeProps as f, normalizeProps as p, openBlock as m, ref as h, renderList as g, renderSlot as _, toDisplayString as v, unref as y, withCtx as b } from "vue";
6
- import { MARKUP_ICONS as x, MARKUP_KINDS as S, focusInitialMenuItem as C, handleMenuKeys as w, highlightMenuModel as T, menuItems as E } from "@inkbar/core/dom";
7
- import { PopoverContent as D, PopoverPortal as O, PopoverRoot as k, PopoverTrigger as A, ToolbarButton as j } from "reka-ui";
8
- import { ChevronDown as M } from "@inkbar/icons";
1
+ import { useDocument as e } from "../composables/useDocument.js";
2
+ import { useTool as t } from "../composables/useTool.js";
3
+ import { useToolOptions as n } from "../composables/useToolOptions.js";
4
+ import r from "./InkIcon.js";
5
+ import i from "./InkColorMenu.js";
6
+ import { Fragment as a, computed as o, createBlock as s, createElementBlock as c, createElementVNode as l, createTextVNode as u, createVNode as d, defineComponent as f, guardReactiveProps as p, mergeProps as m, normalizeProps as h, openBlock as g, ref as _, renderList as v, renderSlot as y, toDisplayString as b, unref as x, withCtx as S } from "vue";
7
+ import { MARKUP_ICONS as C, MARKUP_KINDS as w, focusInitialMenuItem as T, handleMenuKeys as E, highlightMenuModel as D, menuItems as O } from "@inkbar/core/dom";
8
+ import { PopoverAnchor as k, PopoverContent as A, PopoverPortal as j, PopoverRoot as M, PopoverTrigger as N, ToolbarButton as P } from "reka-ui";
9
+ import { ChevronDown as F } from "@inkbar/icons";
9
10
  //#region src/components/InkHighlightMenu.vue?vue&type=script&setup=true&lang.ts
10
- var N = {
11
- role: "group",
12
- "aria-label": "Highlight",
13
- class: "ink-split-button ink-highlight-menu",
14
- "data-ink-highlight-menu": ""
15
- }, P = ["data-state"], F = {
11
+ var ee = ["data-state"], I = {
16
12
  role: "group",
17
13
  "aria-label": "Kinds",
18
14
  class: "ink-highlight-kinds"
19
- }, ee = [
15
+ }, L = [
20
16
  "data-key",
21
17
  "aria-checked",
22
18
  "data-state",
23
19
  "onClick"
24
- ], I = {
20
+ ], R = {
25
21
  role: "group",
26
22
  "aria-label": "Colour",
27
23
  class: "ink-highlight-colour"
28
- }, L = /*@__PURE__*/ u({
24
+ }, z = /*@__PURE__*/ f({
25
+ inheritAttrs: !1,
29
26
  __name: "InkHighlightMenu",
30
- setup(u) {
31
- let { tool: L, setTool: R } = e(), { options: z, setOptions: B } = t("highlight"), V = h(!1), H = a(() => T(z.value, S)), U = a(() => L.value === "highlight"), W = a(() => x[H.value.kind]), G = !1;
32
- function K(e) {
33
- e.key !== "ArrowDown" || e.defaultPrevented || V.value || (e.preventDefault(), G = !0, V.value = !0);
27
+ setup(f) {
28
+ let { tool: z, setTool: B } = t(), { options: V, setOptions: H } = n("highlight"), { document: U } = e(), W = _(!1), G = o(() => D(V.value, w)), K = o(() => z.value === "highlight"), q = o(() => U.value?.annotations.defaults.color(G.value.kind)), J = o(() => C[G.value.kind]), Y = !1;
29
+ function X(e) {
30
+ e.key !== "ArrowDown" || e.defaultPrevented || W.value || (e.preventDefault(), Y = !0, W.value = !0);
34
31
  }
35
- function q(e) {
32
+ function Z(e) {
36
33
  e.preventDefault();
37
34
  let t = document.querySelector("[data-ink-menu=\"highlight\"] [role=\"menu\"]");
38
- t && (G ? E(t)[0]?.focus({ preventScroll: !0 }) : C(t)), G = !1;
35
+ t && (Y ? O(t)[0]?.focus({ preventScroll: !0 }) : T(t)), Y = !1;
39
36
  }
40
- function J(e) {
41
- B({ kind: e }), R("highlight"), V.value = !1;
37
+ function Q(e) {
38
+ H({ kind: e }), B("highlight"), W.value = !1;
42
39
  }
43
- let Y = a(() => ({
44
- "aria-pressed": String(U.value),
45
- "aria-label": H.value.label,
46
- title: H.value.label,
47
- onClick: () => R("highlight")
48
- })), X = {
40
+ let $ = o(() => ({
41
+ "aria-pressed": String(K.value),
42
+ "aria-label": G.value.label,
43
+ title: G.value.label,
44
+ onClick: () => B("highlight")
45
+ })), te = {
49
46
  "aria-label": "Choose highlight",
50
47
  title: "Choose highlight",
51
48
  "aria-haspopup": "menu",
52
- onKeydown: K
53
- }, Z = { "aria-label": "Highlights" }, Q = {
49
+ onKeydown: X
50
+ }, ne = { "aria-label": "Highlights" }, re = {
54
51
  role: "menuitem",
55
52
  tabindex: -1
56
- }, $ = {
53
+ }, ie = {
57
54
  role: "menu",
58
55
  "aria-label": "Highlights",
59
- onKeydownCapture: (e) => w(e, e.currentTarget)
56
+ onKeydownCapture: (e) => E(e, e.currentTarget)
60
57
  };
61
- return (e, t) => (m(), o("div", N, [l(y(j), f({
62
- class: "ink-tool-button ink-highlight-button",
63
- "data-ink-tool-button": "",
64
- "data-ink-highlight-button": "",
65
- "data-tool": "highlight",
66
- "data-kind": H.value.kind,
67
- "data-state": U.value ? "on" : "off"
68
- }, Y.value), {
69
- default: b(() => [_(e.$slots, "default", {
70
- active: U.value,
71
- kind: H.value.kind
72
- }, () => [l(n, { icon: W.value }, null, 8, ["icon"])])]),
73
- _: 3
74
- }, 16, ["data-kind", "data-state"]), l(y(k), {
75
- open: V.value,
76
- "onUpdate:open": t[0] ||= (e) => V.value = e
58
+ return (e, t) => (g(), s(x(M), {
59
+ open: W.value,
60
+ "onUpdate:open": t[0] ||= (e) => W.value = e
77
61
  }, {
78
- default: b(() => [l(y(j), { "as-child": "" }, {
79
- default: b(() => [l(y(A), { "as-child": "" }, {
80
- default: b(() => [s("button", f({
81
- type: "button",
82
- class: "ink-menu-trigger ink-highlight-menu-trigger",
83
- "data-ink-highlight-menu-trigger": "",
84
- "data-state": V.value ? "open" : "closed"
85
- }, X), [l(n, { icon: y(M) }, null, 8, ["icon"])], 16, P)]),
86
- _: 1
87
- })]),
88
- _: 1
89
- }), l(y(O), null, {
90
- default: b(() => [l(y(D), f({
91
- class: "ink-select-content ink-menu-content",
92
- "data-ink-select-content": "",
93
- "data-ink-menu": "highlight",
94
- side: "bottom",
95
- align: "start",
96
- "side-offset": 4,
97
- "collision-padding": 8
98
- }, Z, { onOpenAutoFocus: q }), {
99
- default: b(() => [s("div", p(d($)), [
100
- s("div", F, [(m(!0), o(i, null, g(H.value.items, (e) => (m(), o("button", {
101
- key: e.kind,
102
- type: "button",
103
- role: "menuitemradio",
104
- class: "ink-select-item ink-menu-item ink-highlight-item",
105
- "data-ink-select-item": "",
106
- tabindex: "-1",
107
- "data-key": e.kind,
108
- "aria-checked": e.checked,
109
- "data-state": e.checked ? "checked" : "unchecked",
110
- onClick: (t) => J(e.kind)
111
- }, [l(n, {
112
- icon: y(x)[e.kind],
113
- size: 16
114
- }, null, 8, ["icon"]), c(" " + v(e.label), 1)], 8, ee))), 128))]),
115
- t[2] ||= s("div", {
116
- role: "separator",
117
- class: "ink-select-separator"
118
- }, null, -1),
119
- s("div", I, [t[1] ||= s("span", {
120
- class: "ink-highlight-colour-label",
121
- "aria-hidden": "true"
122
- }, "Colour", -1), l(r, f({
123
- property: "border",
124
- group: "markup",
125
- label: "Highlight colour",
126
- standalone: ""
127
- }, Q), null, 16)])
128
- ], 16)]),
129
- _: 1
130
- }, 16)]),
131
- _: 1
62
+ default: S(() => [d(x(k), { "as-child": "" }, {
63
+ default: S(() => [l("div", m({
64
+ role: "group",
65
+ "aria-label": "Highlight",
66
+ class: "ink-split-button ink-highlight-menu",
67
+ "data-ink-highlight-menu": ""
68
+ }, e.$attrs), [
69
+ d(x(P), m({
70
+ class: "ink-tool-button ink-highlight-button",
71
+ "data-ink-tool-button": "",
72
+ "data-ink-highlight-button": "",
73
+ "data-tool": "highlight",
74
+ "data-kind": G.value.kind,
75
+ "data-state": K.value ? "on" : "off"
76
+ }, $.value), {
77
+ default: S(() => [y(e.$slots, "default", {
78
+ active: K.value,
79
+ kind: G.value.kind
80
+ }, () => [d(r, { icon: J.value }, null, 8, ["icon"])])]),
81
+ _: 3
82
+ }, 16, ["data-kind", "data-state"]),
83
+ d(x(P), { "as-child": "" }, {
84
+ default: S(() => [d(x(N), { "as-child": "" }, {
85
+ default: S(() => [l("button", m({
86
+ type: "button",
87
+ class: "ink-menu-trigger ink-highlight-menu-trigger",
88
+ "data-ink-highlight-menu-trigger": "",
89
+ "data-state": W.value ? "open" : "closed"
90
+ }, te), [d(r, { icon: x(F) }, null, 8, ["icon"])], 16, ee)]),
91
+ _: 1
92
+ })]),
93
+ _: 1
94
+ }),
95
+ d(x(j), null, {
96
+ default: S(() => [d(x(A), m({
97
+ class: "ink-select-content ink-menu-content",
98
+ "data-ink-select-content": "",
99
+ "data-ink-menu": "highlight",
100
+ side: "bottom",
101
+ align: "start",
102
+ "side-offset": 4,
103
+ "collision-padding": 8
104
+ }, ne, { onOpenAutoFocus: Z }), {
105
+ default: S(() => [l("div", h(p(ie)), [
106
+ l("div", I, [(g(!0), c(a, null, v(G.value.items, (e) => (g(), c("button", {
107
+ key: e.kind,
108
+ type: "button",
109
+ role: "menuitemradio",
110
+ class: "ink-select-item ink-menu-item ink-highlight-item",
111
+ "data-ink-select-item": "",
112
+ tabindex: "-1",
113
+ "data-key": e.kind,
114
+ "aria-checked": e.checked,
115
+ "data-state": e.checked ? "checked" : "unchecked",
116
+ onClick: (t) => Q(e.kind)
117
+ }, [d(r, {
118
+ icon: x(C)[e.kind],
119
+ size: 16
120
+ }, null, 8, ["icon"]), u(" " + b(e.label), 1)], 8, L))), 128))]),
121
+ t[2] ||= l("div", {
122
+ role: "separator",
123
+ class: "ink-select-separator"
124
+ }, null, -1),
125
+ l("div", R, [t[1] ||= l("span", {
126
+ class: "ink-highlight-colour-label",
127
+ "aria-hidden": "true"
128
+ }, "Colour", -1), d(i, m({
129
+ property: "border",
130
+ group: "markup",
131
+ label: "Highlight colour",
132
+ standalone: "",
133
+ fallback: q.value
134
+ }, re), null, 16, ["fallback"])])
135
+ ], 16)]),
136
+ _: 1
137
+ }, 16)]),
138
+ _: 1
139
+ })
140
+ ], 16)]),
141
+ _: 3
132
142
  })]),
133
- _: 1
134
- }, 8, ["open"])]));
143
+ _: 3
144
+ }, 8, ["open"]));
135
145
  }
136
146
  });
137
147
  //#endregion
138
- export { L as default };
148
+ export { z as default };
139
149
 
140
150
  //# sourceMappingURL=InkHighlightMenu.vue_vue_type_script_setup_true_lang.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"InkHighlightMenu.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createElementBlock","_createVNode","_unref","_mergeProps","_withCtx","_renderSlot","InkIcon","_createElementVNode","_normalizeProps","_guardReactiveProps","_Fragment","_renderList","_createTextVNode","_toDisplayString","InkColorMenu","InkIcon_default","InkColorMenu_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","InkHighlightMenu_vue_vue_type_script_setup_true_lang_default","useTool","useToolOptions","open","ref","model","computed","highlightMenuModel","options","MARKUP_KINDS","active","tool","icon","MARKUP_ICONS","focusFirst","onTriggerKeydown","onOpenAutoFocus","menu","menuItems","focusInitialMenuItem","choose","setOptions","setTool","mainAttrs","triggerAttrs","menuAttrs","colourAttrs","innerAttrs","handleMenuKeys","openBlock","createElementBlock","createVNode","unref","ToolbarButton","mergeProps","withCtx","renderSlot","_ctx","PopoverRoot","_cache","$event","PopoverTrigger","createElementVNode","ChevronDown","PopoverPortal","PopoverContent","normalizeProps","guardReactiveProps","Fragment","renderList","item","createTextVNode","toDisplayString"],"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 PopoverContent,\n PopoverPortal,\n PopoverRoot,\n PopoverTrigger,\n ToolbarButton,\n} from 'reka-ui'\nimport { computed, ref } from 'vue'\n\nimport { useTool } from '../composables/useTool'\nimport { useToolOptions } from '../composables/useToolOptions'\n\nimport InkColorMenu from './InkColorMenu.vue'\nimport InkIcon from './InkIcon.vue'\n\nconst { tool, setTool } = useTool()\nconst { options, setOptions } = useToolOptions<HighlightOptions>('highlight')\nconst open = ref(false)\n\nconst model = computed(() => highlightMenuModel(options.value, MARKUP_KINDS))\nconst active = computed(() => tool.value === 'highlight')\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 <div\n role=\"group\"\n aria-label=\"Highlight\"\n class=\"ink-split-button ink-highlight-menu\"\n data-ink-highlight-menu\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 <PopoverRoot v-model:open=\"open\">\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 v-bind=\"colourAttrs\"\n />\n </div>\n </div>\n </PopoverContent>\n </PopoverPortal>\n </PopoverRoot>\n </div>\n</template>\n"],"mappings":"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"}
1
+ {"version":3,"file":"InkHighlightMenu.vue_vue_type_script_setup_true_lang.js","names":["$attrs","_openBlock","_createBlock","_unref","_withCtx","_createVNode","_createElementVNode","_mergeProps","_renderSlot","InkIcon","_normalizeProps","_guardReactiveProps","_createElementBlock","_Fragment","_renderList","_createTextVNode","_toDisplayString","InkColorMenu","InkIcon_default","InkColorMenu_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","InkHighlightMenu_vue_vue_type_script_setup_true_lang_default","useTool","useToolOptions","doc","useDocument","open","ref","model","computed","highlightMenuModel","options","MARKUP_KINDS","active","tool","fallback","icon","MARKUP_ICONS","focusFirst","onTriggerKeydown","onOpenAutoFocus","menu","menuItems","focusInitialMenuItem","choose","setOptions","setTool","mainAttrs","triggerAttrs","menuAttrs","colourAttrs","innerAttrs","handleMenuKeys","openBlock","createBlock","unref","PopoverRoot","_cache","$event","withCtx","createVNode","PopoverAnchor","createElementVNode","mergeProps","_ctx","ToolbarButton","renderSlot","PopoverTrigger","ChevronDown","PopoverPortal","PopoverContent","normalizeProps","guardReactiveProps","createElementBlock","Fragment","renderList","item","createTextVNode","toDisplayString"],"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 { useToolOptions } from '../composables/useToolOptions'\n\nimport InkColorMenu from './InkColorMenu.vue'\nimport InkIcon from './InkIcon.vue'\n\ndefineOptions({ inheritAttrs: false })\nconst { tool, setTool } = useTool()\nconst { options, setOptions } = useToolOptions<HighlightOptions>('highlight')\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-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":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"InkPageInput.js","names":["_sfc_main","InkPageInput_vue_vue_type_script_setup_true_lang_default","InkPageInput_default"],"sources":["../../src/components/InkPageInput.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, watch } from 'vue'\n\nimport { usePage } from '../composables/usePage'\n\nconst { current, count, goTo } = usePage()\n// `v-model` on a number input hands back a number once the user types.\nconst draft = ref<string | number>(String(current.value + 1))\nwatch(current, (c) => (draft.value = String(c + 1)))\n\n/** 1-based in the input, 0-based in the viewport. Out of range resets to the current page. */\nfunction commit(): void {\n const n = Number(draft.value)\n if (Number.isInteger(n) && n >= 1 && n <= count.value) goTo(n - 1)\n else draft.value = String(current.value + 1)\n}\n</script>\n\n<template>\n <input\n v-model=\"draft\"\n class=\"ink-page-input\"\n data-ink-page-input\n type=\"number\"\n inputmode=\"numeric\"\n aria-label=\"Page\"\n :min=\"1\"\n :max=\"count\"\n @change=\"commit\"\n @keydown.enter.prevent=\"commit\"\n />\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"InkPageInput.js","names":["_sfc_main","InkPageInput_vue_vue_type_script_setup_true_lang_default","InkPageInput_default"],"sources":["../../src/components/InkPageInput.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, watch } from 'vue'\n\nimport { usePage } from '../composables/usePage'\n\nconst { current, count, goTo } = usePage()\n// `v-model` on a number input hands back a number once the user types.\nconst draft = ref<string | number>(String(current.value + 1))\nwatch(current, (c) => (draft.value = String(c + 1)))\n\n/**\n * 1-based in the input, 0-based in the viewport. Out of range resets to the current page. The\n * page on show is left alone, so the `change` that a blur fires never scrolls back to its top.\n */\nfunction commit(): void {\n const n = Number(draft.value)\n if (Number.isInteger(n) && n >= 1 && n <= count.value) {\n if (n - 1 !== current.value) goTo(n - 1)\n } else draft.value = String(current.value + 1)\n}\n</script>\n\n<template>\n <input\n v-model=\"draft\"\n class=\"ink-page-input\"\n data-ink-page-input\n type=\"number\"\n inputmode=\"numeric\"\n aria-label=\"Page\"\n :min=\"1\"\n :max=\"count\"\n @change=\"commit\"\n @keydown.enter.prevent=\"commit\"\n />\n</template>\n"],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"InkPageInput.vue.d.ts","sourceRoot":"","sources":["../../src/components/InkPageInput.vue"],"names":[],"mappings":"AAuEA,QAAA,MAAM,YAAY,+QAChB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
1
+ {"version":3,"file":"InkPageInput.vue.d.ts","sourceRoot":"","sources":["../../src/components/InkPageInput.vue"],"names":[],"mappings":"AA+EA,QAAA,MAAM,YAAY,+QAChB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
@@ -8,7 +8,7 @@ var d = ["max", "onKeydown"], f = /*@__PURE__*/ n({
8
8
  s(f, (e) => h.value = String(e + 1));
9
9
  function g() {
10
10
  let e = Number(h.value);
11
- Number.isInteger(e) && e >= 1 && e <= p.value ? m(e - 1) : h.value = String(f.value + 1);
11
+ Number.isInteger(e) && e >= 1 && e <= p.value ? e - 1 !== f.value && m(e - 1) : h.value = String(f.value + 1);
12
12
  }
13
13
  return (e, n) => c((r(), t("input", {
14
14
  "onUpdate:modelValue": n[0] ||= (e) => h.value = e,
@@ -1 +1 @@
1
- {"version":3,"file":"InkPageInput.vue_vue_type_script_setup_true_lang.js","names":["_withDirectives","_openBlock","_createElementBlock","_unref","_withKeys","_withModifiers","_vModelText","_hoisted_1","InkPageInput_vue_vue_type_script_setup_true_lang_default","usePage","draft","ref","current","c","commit","n","count","goTo","withDirectives","openBlock","createElementBlock","_cache","$event","unref","withKeys","withModifiers","vModelText"],"sources":["../../src/components/InkPageInput.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, watch } from 'vue'\n\nimport { usePage } from '../composables/usePage'\n\nconst { current, count, goTo } = usePage()\n// `v-model` on a number input hands back a number once the user types.\nconst draft = ref<string | number>(String(current.value + 1))\nwatch(current, (c) => (draft.value = String(c + 1)))\n\n/** 1-based in the input, 0-based in the viewport. Out of range resets to the current page. */\nfunction commit(): void {\n const n = Number(draft.value)\n if (Number.isInteger(n) && n >= 1 && n <= count.value) goTo(n - 1)\n else draft.value = String(current.value + 1)\n}\n</script>\n\n<template>\n <input\n v-model=\"draft\"\n class=\"ink-page-input\"\n data-ink-page-input\n type=\"number\"\n inputmode=\"numeric\"\n aria-label=\"Page\"\n :min=\"1\"\n :max=\"count\"\n @change=\"commit\"\n @keydown.enter.prevent=\"commit\"\n />\n</template>\n"],"mappings":";;;;;;EAKA,IAAM,EAAE,YAAS,UAAO,YAASS,EAAQ,GAEnCC,IAAQC,EAAqB,OAAOC,EAAQ,QAAQ,CAAC,CAAC;EAC5D,EAAMA,IAAU,MAAO,EAAM,QAAQ,OAAOC,IAAI,CAAC,CAAE;EAGnD,SAASC,IAAe;GACtB,IAAMC,IAAI,OAAOL,EAAM,KAAK;GAC5B,AAAI,OAAO,UAAUK,CAAC,KAAKA,KAAK,KAAKA,KAAKC,EAAM,QAAOC,EAAKF,IAAI,CAAC,IAC5D,EAAM,QAAQ,OAAOH,EAAQ,QAAQ,CAAC;EAC7C;mBAIEZ,GAAAC,EAAA,GAAAC,EAWE,SAAA;GAVS,uBAAA,AAAAmB,EAAA,QAAA,MAAA,EAAK,QAAAC;GACd,OAAM;GACN,uBAAA;GACA,MAAK;GACL,WAAU;GACV,cAAW;GACV,KAAK;GACL,KAAKnB,EAAAa,CAAA;GACL,UAAQF;GACR,WAAOV,EAAAC,EAAgBS,GAAM,CAAA,SAAA,CAAA,GAAA,CAAA,OAAA,CAAA;EATrB,GAAA,MAAA,IAAAP,CAAA,IAAA,CAAA,CAAAD,GAAAI,EAAA,KAAK,CAAA,CAAA"}
1
+ {"version":3,"file":"InkPageInput.vue_vue_type_script_setup_true_lang.js","names":["_withDirectives","_openBlock","_createElementBlock","_unref","_withKeys","_withModifiers","_vModelText","_hoisted_1","InkPageInput_vue_vue_type_script_setup_true_lang_default","usePage","draft","ref","current","c","commit","n","count","goTo","withDirectives","openBlock","createElementBlock","_cache","$event","unref","withKeys","withModifiers","vModelText"],"sources":["../../src/components/InkPageInput.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, watch } from 'vue'\n\nimport { usePage } from '../composables/usePage'\n\nconst { current, count, goTo } = usePage()\n// `v-model` on a number input hands back a number once the user types.\nconst draft = ref<string | number>(String(current.value + 1))\nwatch(current, (c) => (draft.value = String(c + 1)))\n\n/**\n * 1-based in the input, 0-based in the viewport. Out of range resets to the current page. The\n * page on show is left alone, so the `change` that a blur fires never scrolls back to its top.\n */\nfunction commit(): void {\n const n = Number(draft.value)\n if (Number.isInteger(n) && n >= 1 && n <= count.value) {\n if (n - 1 !== current.value) goTo(n - 1)\n } else draft.value = String(current.value + 1)\n}\n</script>\n\n<template>\n <input\n v-model=\"draft\"\n class=\"ink-page-input\"\n data-ink-page-input\n type=\"number\"\n inputmode=\"numeric\"\n aria-label=\"Page\"\n :min=\"1\"\n :max=\"count\"\n @change=\"commit\"\n @keydown.enter.prevent=\"commit\"\n />\n</template>\n"],"mappings":";;;;;;EAKA,IAAM,EAAE,YAAS,UAAO,YAASS,EAAQ,GAEnCC,IAAQC,EAAqB,OAAOC,EAAQ,QAAQ,CAAC,CAAC;EAC5D,EAAMA,IAAU,MAAO,EAAM,QAAQ,OAAOC,IAAI,CAAC,CAAE;EAMnD,SAASC,IAAe;GACtB,IAAMC,IAAI,OAAOL,EAAM,KAAK;GAC5B,AAAI,OAAO,UAAUK,CAAC,KAAKA,KAAK,KAAKA,KAAKC,EAAM,QAC1CD,IAAI,MAAMH,EAAQ,SAAOK,EAAKF,IAAI,CAAC,IAClC,EAAM,QAAQ,OAAOH,EAAQ,QAAQ,CAAC;EAC/C;mBAIEZ,GAAAC,EAAA,GAAAC,EAWE,SAAA;GAVS,uBAAA,AAAAmB,EAAA,QAAA,MAAA,EAAK,QAAAC;GACd,OAAM;GACN,uBAAA;GACA,MAAK;GACL,WAAU;GACV,cAAW;GACV,KAAK;GACL,KAAKnB,EAAAa,CAAA;GACL,UAAQF;GACR,WAAOV,EAAAC,EAAgBS,GAAM,CAAA,SAAA,CAAA,GAAA,CAAA,OAAA,CAAA;EATrB,GAAA,MAAA,IAAAP,CAAA,IAAA,CAAA,CAAAD,GAAAI,EAAA,KAAK,CAAA,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"InkRoot.js","names":["_sfc_main","InkRoot_vue_vue_type_script_setup_true_lang_default","InkRoot_default"],"sources":["../../src/components/InkRoot.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n createMemorySignatureStore,\n createSignatureLibrary,\n InkError,\n openDocument,\n} from '@inkbar/core'\nimport {\n createToolOptions,\n cssVariableDefaults,\n FONT_FAMILIES,\n SIGNATURE_FONTS,\n trackToolStyle,\n} from '@inkbar/core/dom'\nimport { Primitive } from 'reka-ui'\nimport {\n computed,\n onBeforeUnmount,\n onMounted,\n onUpdated,\n ref,\n shallowRef,\n useTemplateRef,\n watch,\n} from 'vue'\n\nimport { provideInkContext, type InkHistory, type InkStatus } from '../context'\nimport { createRefHistory } from '../ref-history'\nimport { useReadable } from '../use-readable'\n\nimport type {\n Annotation,\n AnnotationChange,\n AnnotationDefaults,\n DocumentSource,\n InkDocument,\n PdfAssets,\n SignatureStore,\n} from '@inkbar/core'\nimport type {\n Tool,\n ToolController,\n ToolId,\n ToolStyle,\n Viewport,\n ZoomValue,\n} from '@inkbar/core/dom'\n\nconst props = withDefaults(\n defineProps<{\n src: DocumentSource | null\n assets: PdfAssets\n password?: string | undefined\n /** Colour defaults. Without it, the theme's CSS variables on the root element apply. */\n defaults?: AnnotationDefaults | undefined\n /**\n * Pass (with v-model) to put annotations under the host's control. The mode is fixed when a\n * document opens: passing or dropping this prop later takes effect on the next open.\n */\n annotations?: Annotation[] | undefined\n tool?: ToolId | undefined\n /**\n * Host tools, added to the built-ins; one with a built-in's id replaces it. Read when a\n * document opens.\n */\n tools?: Tool[] | undefined\n /**\n * The font families text boxes offer, replacing the PDF standard families\n * (`FONT_FAMILIES`). Fonts beyond those are the PDF writer's to embed.\n */\n fonts?: string[] | undefined\n /**\n * Where saved signatures live. Default: memory, gone on reload.\n * `createLocalSignatureStore` keeps them in the browser; a host can keep them anywhere.\n * A new store takes effect at once, for the menus and the `signature` tool alike.\n */\n signatures?: SignatureStore | undefined\n /** The handwriting fonts a typed signature offers; the host loads them. */\n signatureFonts?: string[] | undefined\n page?: number | undefined\n zoom?: ZoomValue | undefined\n /** Undo history. Defaults to on for uncontrolled, off for controlled. */\n history?: boolean | undefined\n asChild?: boolean\n }>(),\n {\n password: undefined,\n defaults: undefined,\n annotations: undefined,\n tool: undefined,\n tools: undefined,\n fonts: undefined,\n signatures: undefined,\n signatureFonts: undefined,\n page: undefined,\n zoom: undefined,\n history: undefined,\n asChild: false,\n }\n)\n\nconst emit = defineEmits<{\n 'update:annotations': [next: Annotation[]]\n change: [change: AnnotationChange]\n 'update:tool': [tool: ToolId]\n 'update:page': [page: number]\n 'update:zoom': [zoom: ZoomValue]\n ready: [doc: InkDocument]\n error: [error: InkError]\n activate: [id: string]\n}>()\n\ntype TestHookElement = HTMLElement & { __inkDocument?: InkDocument | undefined }\n\n// A template ref on Primitive is a component instance; the context needs its element.\nconst primitive = useTemplateRef<{ $el: unknown }>('primitive')\nconst rootEl = shallowRef<HTMLElement | null>(null)\nfunction syncRootEl(): void {\n const el = primitive.value?.$el\n rootEl.value = el instanceof HTMLElement ? el : null\n}\n\nconst document = shallowRef<InkDocument | null>(null)\n/** Overrides the document's status while opening, and when opening itself failed. */\nconst override = shallowRef<InkStatus | null>(null)\nconst idle: InkStatus = { state: 'idle' }\nconst documentStatus = useReadable<InkStatus>(() => document.value?.status ?? null, idle)\nconst status = computed<InkStatus>(() => override.value ?? documentStatus.value)\nconst annotationList = useReadable<readonly Annotation[]>(\n () => document.value?.annotations.list ?? null,\n []\n)\nconst selection = useReadable<readonly string[]>(\n () => document.value?.annotations.selection ?? null,\n []\n)\nconst viewport = shallowRef<Viewport | null>(null)\nconst toolController = shallowRef<ToolController | null>(null)\nconst internalTool = ref<ToolId>(props.tool ?? 'select-text')\nconst activated = ref<string | null>(null)\n\nconst controlled = computed(() => props.annotations !== undefined)\n\n/** Signed URLs change; the key does not. Bytes and Blobs are their own identity. */\nfunction identity(src: DocumentSource | null): unknown {\n if (src === null) return null\n if (typeof src === 'string') return src\n if ('key' in src) return src.key\n return src\n}\n\nfunction setTestHook(doc: InkDocument | undefined): void {\n if (import.meta.env.DEV && rootEl.value)\n (rootEl.value as TestHookElement).__inkDocument = doc\n}\n\nlet generation = 0\nfunction release(): void {\n document.value?.destroy()\n document.value = null\n setTestHook(undefined)\n}\n\nasync function open(): Promise<void> {\n const gen = ++generation\n const src = props.src\n release()\n refHistory.clear()\n if (src === null) {\n override.value = null\n return\n }\n override.value = { state: 'loading' }\n syncRootEl()\n let doc: InkDocument\n try {\n doc = await openDocument(src, {\n assets: props.assets,\n password: props.password,\n defaults:\n props.defaults ?? (rootEl.value ? cssVariableDefaults(rootEl.value) : undefined),\n // Controlled hosts get the ref history below; core's own stack stays off.\n history: controlled.value ? false : (props.history ?? true),\n annotations: controlled.value\n ? {\n mode: 'controlled',\n initial: props.annotations ?? [],\n onChange: (next, change) => {\n emit('update:annotations', next)\n emit('change', change)\n },\n }\n : { mode: 'uncontrolled' },\n })\n } catch (cause) {\n if (gen !== generation) return\n const error =\n cause instanceof InkError\n ? cause\n : new InkError(\n 'InvalidPdf',\n cause instanceof Error ? cause.message : String(cause),\n {},\n cause\n )\n override.value = { state: 'error', error }\n emit('error', error)\n return\n }\n if (gen !== generation) {\n doc.destroy()\n return\n }\n // The prop may have changed while the file loaded, when there was no store to apply it to.\n if (doc.annotations.mode === 'controlled' && props.annotations !== undefined)\n doc.annotations.setControlledValue(props.annotations)\n document.value = doc\n override.value = null\n setTestHook(doc)\n const s = doc.status.get()\n if (s.state === 'ready') emit('ready', doc)\n else if (s.state === 'error') emit('error', s.error)\n}\n\nconst refHistory = createRefHistory({\n source: () => props.annotations,\n apply: (list) => document.value?.annotations.replaceAll(list, 'history'),\n enabled: computed(() => controlled.value && props.history === true),\n})\nconst coreCanUndo = useReadable(() => document.value?.history.canUndo ?? null, false)\nconst coreCanRedo = useReadable(() => document.value?.history.canRedo ?? null, false)\nconst inkHistory: InkHistory = {\n canUndo: computed(() =>\n controlled.value ? refHistory.canUndo.value : coreCanUndo.value\n ),\n canRedo: computed(() =>\n controlled.value ? refHistory.canRedo.value : coreCanRedo.value\n ),\n undo: () => (controlled.value ? refHistory.undo() : document.value?.history.undo()),\n redo: () => (controlled.value ? refHistory.redo() : document.value?.history.redo()),\n clear: () => (controlled.value ? refHistory.clear() : document.value?.history.clear()),\n batch: (fn) => {\n if (controlled.value) refHistory.batch(fn)\n else if (document.value) document.value.history.batch(fn)\n else fn()\n },\n}\n\n/** The document's tool style; it batches through `inkHistory`, whichever mode is on. */\nconst toolStyle = shallowRef<ToolStyle | null>(null)\nlet setStyleTool: ((id: ToolId) => void) | undefined\nwatch(\n document,\n (doc) => {\n if (!doc) {\n toolStyle.value = null\n setStyleTool = undefined\n return\n }\n const tracker = trackToolStyle({\n store: doc.annotations,\n history: { batch: (fn) => inkHistory.batch(fn) },\n tools: props.tools,\n tool: internalTool.value,\n })\n setStyleTool = (id) => tracker.setTool(id)\n toolStyle.value = tracker.toolStyle\n },\n // Sync: the style is in place before InkViewport's watcher mounts the engine with it.\n { immediate: true, flush: 'sync' }\n)\nwatch(internalTool, (id) => setStyleTool?.(id))\n\n// Open on the client only: on the server InkRoot renders its empty slot.\nonMounted(() => {\n syncRootEl()\n void open()\n})\nonUpdated(syncRootEl)\n\n// Separate sources, so a new `{ url, key }` object with the same key compares equal.\nwatch([() => identity(props.src), () => props.password], () => void open())\n\nwatch(\n () => props.annotations,\n (next) => {\n if (next && document.value?.annotations.mode === 'controlled')\n document.value.annotations.setControlledValue(next)\n }\n)\n\nwatch(\n () => props.tool,\n (t) => {\n if (t) internalTool.value = t\n }\n)\n\nfunction setTool(id: ToolId): void {\n internalTool.value = id\n emit('update:tool', id)\n}\n\nonBeforeUnmount(() => {\n generation++\n release()\n})\n\nconst signatures = computed(() =>\n createSignatureLibrary(props.signatures ?? createMemorySignatureStore())\n)\nwatch(signatures, (lib) => void lib.refresh(), { immediate: true })\n/** Tool options last as long as the root; the tool style is per document. */\nconst toolOptions = createToolOptions()\n\nprovideInkContext({\n assets: computed(() => props.assets),\n document,\n status,\n annotations: annotationList,\n selection,\n viewport,\n tools: toolController,\n tool: internalTool,\n setTool,\n hostTools: computed(() => props.tools),\n fonts: computed(() => props.fonts ?? FONT_FAMILIES),\n toolOptions,\n signatures,\n signatureFonts: computed(() => props.signatureFonts ?? SIGNATURE_FONTS),\n toolStyle,\n zoomModel: computed(() => props.zoom),\n pageModel: computed(() => props.page),\n reportZoom: (z) => emit('update:zoom', z),\n reportPage: (p) => emit('update:page', p),\n activated,\n setActivated(id) {\n activated.value = id\n if (id) emit('activate', id)\n },\n history: inkHistory,\n rootEl,\n})\n\n// `history` is what `useHistory()` returns inside the root, for hosts that hold a template ref:\n// a controlled host calls `history.clear()` after loading its saved list.\ndefineExpose({ document, status, rootEl, history: inkHistory })\n</script>\n\n<template>\n <Primitive\n ref=\"primitive\"\n :as-child=\"props.asChild\"\n as=\"div\"\n data-ink-root\n :data-state=\"status.state\"\n >\n <slot :status=\"status\" :document=\"document\" />\n </Primitive>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"InkRoot.js","names":["_sfc_main","InkRoot_vue_vue_type_script_setup_true_lang_default","InkRoot_default"],"sources":["../../src/components/InkRoot.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n createMemorySignatureStore,\n createSignatureLibrary,\n InkError,\n openDocument,\n readonly,\n writable,\n} from '@inkbar/core'\nimport {\n createPluginHost,\n createToolOptions,\n cssVariableDefaults,\n FONT_FAMILIES,\n SIGNATURE_FONTS,\n trackToolStyle,\n} from '@inkbar/core/dom'\nimport { Primitive } from 'reka-ui'\nimport {\n computed,\n onBeforeUnmount,\n onUnmounted,\n onMounted,\n onUpdated,\n ref,\n shallowRef,\n useTemplateRef,\n watch,\n} from 'vue'\n\nimport { provideInkContext, type InkHistory, type InkStatus } from '../context'\nimport { createRefHistory } from '../ref-history'\nimport { useReadable } from '../use-readable'\n\nimport type {\n Annotation,\n AnnotationChange,\n AnnotationDefaults,\n DocumentSource,\n InkDocument,\n PdfAssets,\n SignatureStore,\n} from '@inkbar/core'\nimport type {\n DecorateAnnotation,\n InkPlugin,\n PluginHost,\n Tool,\n ToolController,\n ToolId,\n ToolStyle,\n Viewport,\n ZoomValue,\n} from '@inkbar/core/dom'\n\nconst props = withDefaults(\n defineProps<{\n src: DocumentSource | null\n assets: PdfAssets\n password?: string | undefined\n /** Colour defaults. Without it, the theme's CSS variables on the root element apply. */\n defaults?: AnnotationDefaults | undefined\n /**\n * Pass (with v-model) to put annotations under the host's control. The mode is fixed when a\n * document opens: passing or dropping this prop later takes effect on the next open.\n */\n annotations?: Annotation[] | undefined\n tool?: ToolId | undefined\n /**\n * Host tools, added to the built-ins; one with a built-in's id replaces it. Read when a\n * document opens.\n */\n tools?: Tool[] | undefined\n /**\n * Plugins, set up once when the root is created; a later change to this prop is not\n * applied. Their tools join `tools`, their decoration and page layers apply to every\n * document, and their commands are placed with `InkCommand` or `useCommand`.\n */\n plugins?: InkPlugin[] | undefined\n /**\n * Adds `data-*` attributes, classes and a screen-reader description to each annotation's\n * element (see `DecorateAnnotation`). Decorations re-apply whenever the annotations change\n * and when this prop changes, without rebuilding the viewer. Pass a new function when its\n * output would change for any other reason.\n */\n decorateAnnotation?: DecorateAnnotation | undefined\n /**\n * The font families text boxes offer, replacing the PDF standard families\n * (`FONT_FAMILIES`). Fonts beyond those are the PDF writer's to embed.\n */\n fonts?: string[] | undefined\n /**\n * Where saved signatures live. Default: memory, gone on reload.\n * `createLocalSignatureStore` keeps them in the browser; a host can keep them anywhere.\n * A new store takes effect at once, for the menus and the `signature` tool alike.\n */\n signatures?: SignatureStore | undefined\n /** The handwriting fonts a typed signature offers; the host loads them. */\n signatureFonts?: string[] | undefined\n page?: number | undefined\n zoom?: ZoomValue | undefined\n /** Undo history. Defaults to on for uncontrolled, off for controlled. */\n history?: boolean | undefined\n asChild?: boolean\n }>(),\n {\n password: undefined,\n defaults: undefined,\n annotations: undefined,\n tool: undefined,\n tools: undefined,\n plugins: undefined,\n decorateAnnotation: undefined,\n fonts: undefined,\n signatures: undefined,\n signatureFonts: undefined,\n page: undefined,\n zoom: undefined,\n history: undefined,\n asChild: false,\n }\n)\n\nconst emit = defineEmits<{\n 'update:annotations': [next: Annotation[]]\n change: [change: AnnotationChange]\n 'update:tool': [tool: ToolId]\n 'update:page': [page: number]\n 'update:zoom': [zoom: ZoomValue]\n ready: [doc: InkDocument]\n error: [error: InkError]\n activate: [id: string]\n}>()\n\ntype TestHookElement = HTMLElement & { __inkDocument?: InkDocument | undefined }\n\n// A template ref on Primitive is a component instance; the context needs its element.\nconst primitive = useTemplateRef<{ $el: unknown }>('primitive')\nconst rootEl = shallowRef<HTMLElement | null>(null)\nfunction syncRootEl(): void {\n const el = primitive.value?.$el\n rootEl.value = el instanceof HTMLElement ? el : null\n}\n\nconst document = shallowRef<InkDocument | null>(null)\n/** Overrides the document's status while opening, and when opening itself failed. */\nconst override = shallowRef<InkStatus | null>(null)\nconst idle: InkStatus = { state: 'idle' }\nconst documentStatus = useReadable<InkStatus>(() => document.value?.status ?? null, idle)\nconst status = computed<InkStatus>(() => override.value ?? documentStatus.value)\nconst annotationList = useReadable<readonly Annotation[]>(\n () => document.value?.annotations.list ?? null,\n []\n)\nconst selection = useReadable<readonly string[]>(\n () => document.value?.annotations.selection ?? null,\n []\n)\nconst viewport = shallowRef<Viewport | null>(null)\nconst toolController = shallowRef<ToolController | null>(null)\nconst internalTool = ref<ToolId>(props.tool ?? 'select-text')\nconst activated = ref<string | null>(null)\n\nconst controlled = computed(() => props.annotations !== undefined)\n\nfunction setActivated(id: string | null): void {\n activated.value = id\n if (id) emit('activate', id)\n}\n\nconst noop = () => {}\n\n/** Signed URLs change; the key does not. Bytes and Blobs are their own identity. */\nfunction identity(src: DocumentSource | null): unknown {\n if (src === null) return null\n if (typeof src === 'string') return src\n if ('key' in src) return src.key\n return src\n}\n\nfunction setTestHook(doc: InkDocument | undefined): void {\n if (import.meta.env.DEV && rootEl.value)\n (rootEl.value as TestHookElement).__inkDocument = doc\n}\n\nlet generation = 0\nfunction release(): void {\n // Cleared first, so the plugins close their stores while the document is still alive.\n const doc = document.value\n document.value = null\n doc?.destroy()\n setTestHook(undefined)\n}\n\nasync function open(): Promise<void> {\n const gen = ++generation\n const src = props.src\n release()\n refHistory.clear()\n if (src === null) {\n override.value = null\n return\n }\n override.value = { state: 'loading' }\n syncRootEl()\n let doc: InkDocument\n try {\n doc = await openDocument(src, {\n assets: props.assets,\n password: props.password,\n defaults:\n props.defaults ?? (rootEl.value ? cssVariableDefaults(rootEl.value) : undefined),\n // Controlled hosts get the ref history below; core's own stack stays off.\n history: controlled.value ? false : (props.history ?? true),\n annotations: controlled.value\n ? {\n mode: 'controlled',\n initial: props.annotations ?? [],\n onChange: (next, change) => {\n emit('update:annotations', next)\n emit('change', change)\n },\n }\n : { mode: 'uncontrolled' },\n })\n } catch (cause) {\n if (gen !== generation) return\n const error =\n cause instanceof InkError\n ? cause\n : new InkError(\n 'InvalidPdf',\n cause instanceof Error ? cause.message : String(cause),\n {},\n cause\n )\n override.value = { state: 'error', error }\n emit('error', error)\n return\n }\n if (gen !== generation) {\n doc.destroy()\n return\n }\n // The prop may have changed while the file loaded, when there was no store to apply it to.\n if (doc.annotations.mode === 'controlled' && props.annotations !== undefined)\n doc.annotations.setControlledValue(props.annotations)\n document.value = doc\n override.value = null\n setTestHook(doc)\n const s = doc.status.get()\n if (s.state === 'ready') emit('ready', doc)\n else if (s.state === 'error') emit('error', s.error)\n}\n\nconst refHistory = createRefHistory({\n source: () => props.annotations,\n apply: (list) => document.value?.annotations.replaceAll(list, 'history'),\n enabled: computed(() => controlled.value && props.history === true),\n store: () =>\n document.value?.annotations.mode === 'controlled' ? document.value.annotations : null,\n})\nconst coreCanUndo = useReadable(() => document.value?.history.canUndo ?? null, false)\nconst coreCanRedo = useReadable(() => document.value?.history.canRedo ?? null, false)\nconst inkHistory: InkHistory = {\n canUndo: computed(() =>\n controlled.value ? refHistory.canUndo.value : coreCanUndo.value\n ),\n canRedo: computed(() =>\n controlled.value ? refHistory.canRedo.value : coreCanRedo.value\n ),\n undo: () => (controlled.value ? refHistory.undo() : document.value?.history.undo()),\n redo: () => (controlled.value ? refHistory.redo() : document.value?.history.redo()),\n clear: () => (controlled.value ? refHistory.clear() : document.value?.history.clear()),\n batch: (fn) => {\n if (controlled.value) refHistory.batch(fn)\n else if (document.value) document.value.history.batch(fn)\n else fn()\n },\n track: (store) =>\n controlled.value\n ? refHistory.track(store)\n : (document.value?.history.track(store) ?? noop),\n react: (fn) =>\n controlled.value ? refHistory.react(fn) : (document.value?.history.react(fn) ?? noop),\n}\n\n/*\n * One plugin host for the root's life, built once mounted so that no `setup` runs on the\n * server, where nothing would clean it up. Until then `pluginHost` is null, and InkCommand\n * renders its command disabled. The host follows `hostDocument`, which is set after `document`\n * (a sync watch): when the host reads `inkHistory` for a new document, it is that document's\n * history.\n */\nconst hostDocument = writable<InkDocument | null>(null)\nwatch(document, (doc) => hostDocument.set(doc), { flush: 'sync' })\nconst viewportEl = shallowRef<HTMLElement | null>(null)\nconst hostRoot = writable<HTMLElement | null>(null)\nwatch(viewportEl, (el) => hostRoot.set(el), { flush: 'sync' })\nconst hostActivated = writable<string | null>(null)\nwatch(activated, (id) => hostActivated.set(id), { flush: 'sync' })\nconst pluginHost = shallowRef<PluginHost | null>(null)\nfunction setUpPlugins(): void {\n pluginHost.value = createPluginHost({\n plugins: props.plugins ?? [],\n document: readonly(hostDocument),\n history: () => inkHistory,\n activated: readonly(hostActivated),\n // As in `createViewer`: an id not in the open document is ignored.\n setActivated: (id) => {\n if (id === null || document.value?.annotations.get(id)) setActivated(id)\n },\n root: readonly(hostRoot),\n decorate: () => props.decorateAnnotation,\n viewport: () => viewport.value,\n })\n}\n\n/** The document's tool style; it batches through `inkHistory`, whichever mode is on. */\nconst toolStyle = shallowRef<ToolStyle | null>(null)\nlet setStyleTool: ((id: ToolId) => void) | undefined\nwatch(\n document,\n (doc) => {\n if (!doc) {\n toolStyle.value = null\n setStyleTool = undefined\n return\n }\n const tracker = trackToolStyle({\n store: doc.annotations,\n history: { batch: (fn) => inkHistory.batch(fn) },\n // The plugins' tools too, so a plugin tool's style group applies (the host is set by now:\n // it is built on mount, before the first document opens).\n tools: [...(props.tools ?? []), ...(pluginHost.value?.tools ?? [])],\n tool: internalTool.value,\n })\n setStyleTool = (id) => tracker.setTool(id)\n toolStyle.value = tracker.toolStyle\n },\n // Sync: the style is in place before InkViewport's watcher mounts the engine with it.\n { immediate: true, flush: 'sync' }\n)\nwatch(internalTool, (id) => setStyleTool?.(id))\n\n// Plugins and the document on the client only: on the server InkRoot renders its empty slot.\n// The plugins first, so the first document opens with their stores and reactions.\nonMounted(() => {\n syncRootEl()\n // A plugin whose setup throws still leaves the document to open; the error then goes to\n // Vue's error handling (`onErrorCaptured`, `app.config.errorHandler`).\n try {\n setUpPlugins()\n } finally {\n void open()\n }\n})\nonUpdated(syncRootEl)\n\n// Separate sources, so a new `{ url, key }` object with the same key compares equal.\nwatch([() => identity(props.src), () => props.password], () => void open())\n\nwatch(\n () => props.annotations,\n (next) => {\n if (next && document.value?.annotations.mode === 'controlled')\n document.value.annotations.setControlledValue(next)\n }\n)\n\nwatch(\n () => props.tool,\n (t) => {\n if (t) internalTool.value = t\n }\n)\n\nfunction setTool(id: ToolId): void {\n // Picking the active tool again starts it afresh, as after a one-shot tool's use.\n const tc = toolController.value\n if (internalTool.value === id && tc?.active.get() === id) tc.set(id)\n internalTool.value = id\n emit('update:tool', id)\n}\n\nonBeforeUnmount(() => {\n generation++\n release()\n})\n\n// After the children: InkViewport's engine, and the plugin layers with it, are gone by now, as\n// in `createViewer`, so no layer `destroy` runs after the plugins' cleanups.\nonUnmounted(() => {\n pluginHost.value?.destroy()\n pluginHost.value = null\n})\n\nconst signatures = computed(() =>\n createSignatureLibrary(props.signatures ?? createMemorySignatureStore())\n)\nwatch(signatures, (lib) => void lib.refresh(), { immediate: true })\n/** Tool options last as long as the root; the tool style is per document. */\nconst toolOptions = createToolOptions()\n\nprovideInkContext({\n assets: computed(() => props.assets),\n document,\n status,\n annotations: annotationList,\n selection,\n viewport,\n tools: toolController,\n tool: internalTool,\n setTool,\n hostTools: computed(() => props.tools),\n decorateAnnotation: computed(() => props.decorateAnnotation),\n fonts: computed(() => props.fonts ?? FONT_FAMILIES),\n toolOptions,\n signatures,\n signatureFonts: computed(() => props.signatureFonts ?? SIGNATURE_FONTS),\n toolStyle,\n zoomModel: computed(() => props.zoom),\n pageModel: computed(() => props.page),\n reportZoom: (z) => emit('update:zoom', z),\n reportPage: (p) => emit('update:page', p),\n activated,\n setActivated,\n pluginHost,\n viewportEl,\n history: inkHistory,\n rootEl,\n})\n\n// `history` is what `useHistory()` returns inside the root, for hosts that hold a template ref:\n// a controlled host calls `history.clear()` after loading its saved list.\ndefineExpose({ document, status, rootEl, history: inkHistory })\n</script>\n\n<template>\n <Primitive\n ref=\"primitive\"\n :as-child=\"props.asChild\"\n as=\"div\"\n data-ink-root\n :data-state=\"status.state\"\n >\n <slot :status=\"status\" :document=\"document\" />\n </Primitive>\n</template>\n"],"mappings":""}