@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.
- package/README.md +23 -7
- package/dist/components/InkAnnotation.js.map +1 -1
- package/dist/components/InkAnnotation.vue.d.ts.map +1 -1
- package/dist/components/InkAnnotation.vue_vue_type_script_setup_true_lang.js +16 -24
- package/dist/components/InkAnnotation.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/InkColorMenu.js.map +1 -1
- package/dist/components/InkColorMenu.vue.d.ts +2 -0
- package/dist/components/InkColorMenu.vue.d.ts.map +1 -1
- package/dist/components/InkColorMenu.vue_vue_type_script_setup_true_lang.js +3 -2
- package/dist/components/InkColorMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/InkCommand.js +7 -0
- package/dist/components/InkCommand.js.map +1 -0
- package/dist/components/InkCommand.vue.d.ts +23 -0
- package/dist/components/InkCommand.vue.d.ts.map +1 -0
- package/dist/components/InkCommand.vue_vue_type_script_setup_true_lang.js +51 -0
- package/dist/components/InkCommand.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/InkHighlightMenu.js.map +1 -1
- package/dist/components/InkHighlightMenu.vue.d.ts +2 -2
- package/dist/components/InkHighlightMenu.vue.d.ts.map +1 -1
- package/dist/components/InkHighlightMenu.vue_vue_type_script_setup_true_lang.js +118 -108
- package/dist/components/InkHighlightMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/InkPageInput.js.map +1 -1
- package/dist/components/InkPageInput.vue.d.ts.map +1 -1
- package/dist/components/InkPageInput.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/InkPageInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/InkRoot.js.map +1 -1
- package/dist/components/InkRoot.vue.d.ts +415 -424
- package/dist/components/InkRoot.vue.d.ts.map +1 -1
- package/dist/components/InkRoot.vue_vue_type_script_setup_true_lang.js +145 -102
- package/dist/components/InkRoot.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/InkShapeMenu.js.map +1 -1
- package/dist/components/InkShapeMenu.vue.d.ts +2 -2
- package/dist/components/InkShapeMenu.vue.d.ts.map +1 -1
- package/dist/components/InkShapeMenu.vue_vue_type_script_setup_true_lang.js +99 -91
- package/dist/components/InkShapeMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/InkSignatureMenu.js.map +1 -1
- package/dist/components/InkSignatureMenu.vue.d.ts +2 -2
- package/dist/components/InkSignatureMenu.vue.d.ts.map +1 -1
- package/dist/components/InkSignatureMenu.vue_vue_type_script_setup_true_lang.js +156 -151
- package/dist/components/InkSignatureMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/InkToolButton.js.map +1 -1
- package/dist/components/InkToolButton.vue.d.ts.map +1 -1
- package/dist/components/InkToolButton.vue_vue_type_script_setup_true_lang.js +36 -35
- package/dist/components/InkToolButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/InkViewport.js.map +1 -1
- package/dist/components/InkViewport.vue.d.ts.map +1 -1
- package/dist/components/InkViewport.vue_vue_type_script_setup_true_lang.js +14 -4
- package/dist/components/InkViewport.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/composables/useAnnotations.d.ts +915 -1386
- package/dist/composables/useAnnotations.d.ts.map +1 -1
- package/dist/composables/useAnnotations.js +13 -18
- package/dist/composables/useAnnotations.js.map +1 -1
- package/dist/composables/useCommand.d.ts +23 -0
- package/dist/composables/useCommand.d.ts.map +1 -0
- package/dist/composables/useCommand.js +22 -0
- package/dist/composables/useCommand.js.map +1 -0
- package/dist/context.d.ts +22 -4
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +27 -26
- package/dist/ref-history.d.ts +12 -3
- package/dist/ref-history.d.ts.map +1 -1
- package/dist/ref-history.js +27 -16
- package/dist/ref-history.js.map +1 -1
- package/package.json +5 -5
- package/dist/components/InkSuggestionCard.js +0 -7
- package/dist/components/InkSuggestionCard.js.map +0 -1
- package/dist/components/InkSuggestionCard.vue.d.ts +0 -16
- package/dist/components/InkSuggestionCard.vue.d.ts.map +0 -1
- package/dist/components/InkSuggestionCard.vue_vue_type_script_setup_true_lang.js +0 -85
- package/dist/components/InkSuggestionCard.vue_vue_type_script_setup_true_lang.js.map +0 -1
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
|
|
21
21
|
---
|
|
22
22
|
|
|
23
|
-
Drop a PDF viewer into your Vue app and let people highlight text, leave notes with replies and
|
|
23
|
+
Drop a PDF viewer into your Vue app and let people highlight text, leave notes with replies and redact. `@inkbar/vue` gives you components and composables to build your own toolbars, plus a popover for comment threads, all styled by `@inkbar/theme`.
|
|
24
24
|
|
|
25
25
|
Annotations are plain typed objects. Bind them with `v-model` to keep them in your own state, or let Inkbar hold them with undo and redo.
|
|
26
26
|
|
|
@@ -51,7 +51,6 @@ import {
|
|
|
51
51
|
InkNextPage,
|
|
52
52
|
InkZoomSelect,
|
|
53
53
|
InkThreadPopover,
|
|
54
|
-
InkSuggestionCard,
|
|
55
54
|
} from '@inkbar/vue'
|
|
56
55
|
import type { Annotation } from '@inkbar/core'
|
|
57
56
|
import { assets } from 'virtual:inkbar-assets'
|
|
@@ -87,7 +86,6 @@ const annotations = ref<Annotation[]>([])
|
|
|
87
86
|
<InkZoomSelect />
|
|
88
87
|
</InkToolbar>
|
|
89
88
|
<InkThreadPopover />
|
|
90
|
-
<InkSuggestionCard />
|
|
91
89
|
</InkRoot>
|
|
92
90
|
</template>
|
|
93
91
|
```
|
|
@@ -128,11 +126,29 @@ The highlight tool leaves `contents` free for the comment. `doc.text(page)` retu
|
|
|
128
126
|
|
|
129
127
|
`InkSignatureMenu` lists saved signatures, picks one for the `signature` tool, removes them, and opens `InkSignatureDialog` to draw, type or upload a new one. These are marks on the page, not cryptographic signatures. Pass `signatures` to `InkRoot` to keep them somewhere: `createLocalSignatureStore(key)` from `@inkbar/core` uses `localStorage`, and without it they last until reload. `signatureFonts` lists the handwriting fonts the Type tab offers; load them with `@font-face`. A placed signature keeps its aspect ratio when resized.
|
|
130
128
|
|
|
129
|
+
## Plugins
|
|
130
|
+
|
|
131
|
+
A plugin from `definePlugin` (in `@inkbar/core/dom`) adds commands, tools, decorations, page layers and its own record stores. Pass plugins to `InkRoot` once: the prop is read when the root is created. Nothing a plugin registers shows until you place it:
|
|
132
|
+
|
|
133
|
+
```vue
|
|
134
|
+
<InkRoot :src="src" :assets="assets" :plugins="[suggestions]">
|
|
135
|
+
<InkToolbar>
|
|
136
|
+
<InkCommand id="sandbox.suggest" />
|
|
137
|
+
<InkToolButton tool="sandbox.stamp" />
|
|
138
|
+
</InkToolbar>
|
|
139
|
+
<InkViewport />
|
|
140
|
+
</InkRoot>
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
`InkCommand` is a button named by the command's label, disabled while the command is, and its status in a live region beside it. While the command runs, the button keeps focus and has `aria-busy` and `aria-disabled`, and pressing it does nothing. It shows the command's icon, or its label as text when the command has no icon. To build your own, `useCommand(id)` returns `run`, `enabled`, `busy`, `status`, `label` and `icon`. Plugins are set up once `InkRoot` has mounted in the browser, never on the server. Until then the command is disabled and has no label, and `InkCommand` keeps its button out of the accessibility tree (`aria-hidden`). `label` and `icon` are refs, like `enabled`, so they fill in then. An id no plugin registered stays that way: `InkCommand` and `useCommand` log an `InkError('UnknownCommand')` to the console once, naming the id and the registered ones, and nothing throws. A plugin whose `setup` throws is reported the same way, and the document still opens. `InkToolButton` takes a plugin tool's own label and icon.
|
|
144
|
+
|
|
145
|
+
Plugin stores undo with annotations. In controlled mode with `:history="true"`, each undo step also snapshots the plugin stores, so accepting something and undoing it restores both.
|
|
146
|
+
|
|
131
147
|
## Custom rendering
|
|
132
148
|
|
|
133
|
-
Slots let you render parts yourself. `InkViewport` has `loading`, `empty`, `error`, `annotation` and `page-error` slots. `InkThreadPopover`
|
|
149
|
+
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.
|
|
134
150
|
|
|
135
|
-
`InkRoot`, `InkToolbar`, `InkToolButton`, `InkUndo`, `InkRedo`, `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.
|
|
151
|
+
`InkRoot`, `InkToolbar`, `InkToolButton`, `InkCommand`, `InkUndo`, `InkRedo`, `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.
|
|
136
152
|
|
|
137
153
|
## Keyboard
|
|
138
154
|
|
|
@@ -144,7 +160,7 @@ The scroll area takes focus. From there:
|
|
|
144
160
|
|
|
145
161
|
On a focused annotation:
|
|
146
162
|
|
|
147
|
-
- `Enter` or `Space` selects and activates it. A note
|
|
163
|
+
- `Enter` or `Space` selects and activates it. A note or text markup opens its thread; other types are only selected.
|
|
148
164
|
- `ArrowUp` and `ArrowDown` move to the previous or next annotation on the page.
|
|
149
165
|
- `Shift` + arrow moves it by 1 pt, or by 10 pt with `Alt` as well.
|
|
150
166
|
- `Ctrl` or `Cmd` + `Shift` + arrow resizes an area redaction, text box or shape.
|
|
@@ -158,7 +174,7 @@ Components carry state on data attributes, for example `[data-annotation][data-s
|
|
|
158
174
|
|
|
159
175
|
## Composables
|
|
160
176
|
|
|
161
|
-
`useDocument`, `useAnnotations`, `useTool`, `useSelection`, `useZoom`, `usePage`, `useHistory` and `
|
|
177
|
+
`useDocument`, `useAnnotations`, `useTool`, `useSelection`, `useZoom`, `usePage`, `useHistory`, `useEmbedded` and `useCommand` 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.
|
|
162
178
|
|
|
163
179
|
## Licence
|
|
164
180
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InkAnnotation.js","names":["_sfc_main","InkAnnotation_vue_vue_type_script_setup_true_lang_default","InkAnnotation_default"],"sources":["../../src/components/InkAnnotation.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/*\n * Slot props for one annotation. It renders only its default slot: the overlay already draws\n * the default visual for every annotation that is not custom, so this never draws a second\n * one. InkPage teleports it into the annotation's overlay element.\n */\nimport {
|
|
1
|
+
{"version":3,"file":"InkAnnotation.js","names":["_sfc_main","InkAnnotation_vue_vue_type_script_setup_true_lang_default","InkAnnotation_default"],"sources":["../../src/components/InkAnnotation.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/*\n * Slot props for one annotation. It renders only its default slot: the overlay already draws\n * the default visual for every annotation that is not custom, so this never draws a second\n * one. InkPage teleports it into the annotation's overlay element.\n */\nimport { computed, onBeforeUnmount, shallowRef, watch } from 'vue'\n\nimport { injectInkContext } from '../context'\n\nimport type { AnnotationSlotProps, AnnotationState } from './annotation-slot'\nimport type { Annotation } from '@inkbar/core'\n\nconst props = withDefaults(\n defineProps<{\n annotation: Annotation\n /** The overlay element; its `data-state` (which includes hover) drives `state`. */\n element?: HTMLElement | undefined\n }>(),\n { element: undefined }\n)\n\ndefineSlots<{ default?(props: AnnotationSlotProps): unknown }>()\n\nconst ctx = injectInkContext()\n\nconst observed = shallowRef<AnnotationState | null>(null)\nlet observer: MutationObserver | undefined\nfunction readState(el: HTMLElement): AnnotationState | null {\n const s = el.dataset.state\n return s === 'idle' || s === 'hover' || s === 'selected' ? s : null\n}\nwatch(\n () => props.element,\n (el) => {\n observer?.disconnect()\n observer = undefined\n observed.value = el ? readState(el) : null\n if (!el) return\n observer = new MutationObserver(() => {\n observed.value = readState(el)\n })\n observer.observe(el, { attributes: true, attributeFilter: ['data-state'] })\n },\n { immediate: true }\n)\nonBeforeUnmount(() => observer?.disconnect())\n\nconst slotProps = computed<AnnotationSlotProps>(() => {\n const { id } = props.annotation\n const store = () => ctx.document.value?.annotations\n return {\n annotation: props.annotation,\n state: observed.value ?? (ctx.selection.value.includes(id) ? 'selected' : 'idle'),\n locked: props.annotation.locked === true,\n select: () => store()?.select([id]),\n remove: () => void store()?.remove(id),\n }\n})\n</script>\n\n<template>\n <slot v-bind=\"slotProps\" />\n</template>\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InkAnnotation.vue.d.ts","sourceRoot":"","sources":["../../src/components/InkAnnotation.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"InkAnnotation.vue.d.ts","sourceRoot":"","sources":["../../src/components/InkAnnotation.vue"],"names":[],"mappings":"AA2EA,OAAO,KAAK,EAAE,mBAAmB,EAAmB,MAAM,mBAAmB,CAAA;AAC7E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAG9C,KAAK,WAAW,GAAG;IACf,UAAU,EAAE,UAAU,CAAA;IACtB,mFAAmF;IACnF,OAAO,CAAC,EAAE,WAAW,GAAG,SAAS,CAAA;CAClC,CAAC;AAMJ,KAAK,WAAW,GAAG;IAAE,OAAO,CAAC,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAA;CAAE,CAAC;AA4DrE,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"}
|
|
@@ -1,48 +1,40 @@
|
|
|
1
1
|
import { injectInkContext as e } from "../context.js";
|
|
2
2
|
import { computed as t, defineComponent as n, guardReactiveProps as r, normalizeProps as i, onBeforeUnmount as a, renderSlot as o, shallowRef as s, watch as c } from "vue";
|
|
3
|
-
import { acceptSuggestion as l } from "@inkbar/core";
|
|
4
3
|
//#region src/components/InkAnnotation.vue?vue&type=script&setup=true&lang.ts
|
|
5
|
-
var
|
|
4
|
+
var l = /*@__PURE__*/ n({
|
|
6
5
|
__name: "InkAnnotation",
|
|
7
6
|
props: {
|
|
8
7
|
annotation: {},
|
|
9
8
|
element: { default: void 0 }
|
|
10
9
|
},
|
|
11
10
|
setup(n) {
|
|
12
|
-
let
|
|
13
|
-
function
|
|
11
|
+
let l = n, u = e(), d = s(null), f;
|
|
12
|
+
function p(e) {
|
|
14
13
|
let t = e.dataset.state;
|
|
15
14
|
return t === "idle" || t === "hover" || t === "selected" ? t : null;
|
|
16
15
|
}
|
|
17
|
-
c(() =>
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}),
|
|
16
|
+
c(() => l.element, (e) => {
|
|
17
|
+
f?.disconnect(), f = void 0, d.value = e ? p(e) : null, e && (f = new MutationObserver(() => {
|
|
18
|
+
d.value = p(e);
|
|
19
|
+
}), f.observe(e, {
|
|
21
20
|
attributes: !0,
|
|
22
21
|
attributeFilter: ["data-state"]
|
|
23
22
|
}));
|
|
24
|
-
}, { immediate: !0 }), a(() =>
|
|
25
|
-
let
|
|
26
|
-
let { id: e } =
|
|
23
|
+
}, { immediate: !0 }), a(() => f?.disconnect());
|
|
24
|
+
let m = t(() => {
|
|
25
|
+
let { id: e } = l.annotation, t = () => u.document.value?.annotations;
|
|
27
26
|
return {
|
|
28
|
-
annotation:
|
|
29
|
-
state:
|
|
30
|
-
locked:
|
|
27
|
+
annotation: l.annotation,
|
|
28
|
+
state: d.value ?? (u.selection.value.includes(e) ? "selected" : "idle"),
|
|
29
|
+
locked: l.annotation.locked === !0,
|
|
31
30
|
select: () => t()?.select([e]),
|
|
32
|
-
remove: () => void t()?.remove(e)
|
|
33
|
-
accept: () => {
|
|
34
|
-
let n = t();
|
|
35
|
-
n && h.value && l(n, e);
|
|
36
|
-
},
|
|
37
|
-
dismiss: () => {
|
|
38
|
-
h.value && t()?.remove(e);
|
|
39
|
-
}
|
|
31
|
+
remove: () => void t()?.remove(e)
|
|
40
32
|
};
|
|
41
33
|
});
|
|
42
|
-
return (e, t) => o(e.$slots, "default", i(r(
|
|
34
|
+
return (e, t) => o(e.$slots, "default", i(r(m.value)));
|
|
43
35
|
}
|
|
44
36
|
});
|
|
45
37
|
//#endregion
|
|
46
|
-
export {
|
|
38
|
+
export { l as default };
|
|
47
39
|
|
|
48
40
|
//# sourceMappingURL=InkAnnotation.vue_vue_type_script_setup_true_lang.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InkAnnotation.vue_vue_type_script_setup_true_lang.js","names":["_renderSlot","_normalizeProps","_guardReactiveProps","InkAnnotation_vue_vue_type_script_setup_true_lang_default","props","__props","ctx","injectInkContext","observed","shallowRef","observer","readState","s","el","watch","onBeforeUnmount","
|
|
1
|
+
{"version":3,"file":"InkAnnotation.vue_vue_type_script_setup_true_lang.js","names":["_renderSlot","_normalizeProps","_guardReactiveProps","InkAnnotation_vue_vue_type_script_setup_true_lang_default","props","__props","ctx","injectInkContext","observed","shallowRef","observer","readState","s","el","watch","onBeforeUnmount","slotProps","computed","store","id","renderSlot","_ctx","normalizeProps","guardReactiveProps"],"sources":["../../src/components/InkAnnotation.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/*\n * Slot props for one annotation. It renders only its default slot: the overlay already draws\n * the default visual for every annotation that is not custom, so this never draws a second\n * one. InkPage teleports it into the annotation's overlay element.\n */\nimport { computed, onBeforeUnmount, shallowRef, watch } from 'vue'\n\nimport { injectInkContext } from '../context'\n\nimport type { AnnotationSlotProps, AnnotationState } from './annotation-slot'\nimport type { Annotation } from '@inkbar/core'\n\nconst props = withDefaults(\n defineProps<{\n annotation: Annotation\n /** The overlay element; its `data-state` (which includes hover) drives `state`. */\n element?: HTMLElement | undefined\n }>(),\n { element: undefined }\n)\n\ndefineSlots<{ default?(props: AnnotationSlotProps): unknown }>()\n\nconst ctx = injectInkContext()\n\nconst observed = shallowRef<AnnotationState | null>(null)\nlet observer: MutationObserver | undefined\nfunction readState(el: HTMLElement): AnnotationState | null {\n const s = el.dataset.state\n return s === 'idle' || s === 'hover' || s === 'selected' ? s : null\n}\nwatch(\n () => props.element,\n (el) => {\n observer?.disconnect()\n observer = undefined\n observed.value = el ? readState(el) : null\n if (!el) return\n observer = new MutationObserver(() => {\n observed.value = readState(el)\n })\n observer.observe(el, { attributes: true, attributeFilter: ['data-state'] })\n },\n { immediate: true }\n)\nonBeforeUnmount(() => observer?.disconnect())\n\nconst slotProps = computed<AnnotationSlotProps>(() => {\n const { id } = props.annotation\n const store = () => ctx.document.value?.annotations\n return {\n annotation: props.annotation,\n state: observed.value ?? (ctx.selection.value.includes(id) ? 'selected' : 'idle'),\n locked: props.annotation.locked === true,\n select: () => store()?.select([id]),\n remove: () => void store()?.remove(id),\n }\n})\n</script>\n\n<template>\n <slot v-bind=\"slotProps\" />\n</template>\n"],"mappings":";;;;;;;;;;EAaA,IAAMI,IAAQC,GAWRC,IAAMC,EAAiB,GAEvBC,IAAWC,EAAmC,IAAI,GACpDC;EACJ,SAASC,EAAU,GAAyC;GAC1D,IAAMC,IAAIC,EAAG,QAAQ;GACrB,OAAOD,MAAM,UAAUA,MAAM,WAAWA,MAAM,aAAaA,IAAI;EACjE;EAeA,AAdAE,QACQV,EAAM,UACX,MAAO;GAIN,AAHAM,GAAU,WAAW,GACrB,IAAW,KAAA,GACX,EAAS,QAAQG,IAAKF,EAAUE,CAAE,IAAI,MACjCA,MACL,IAAW,IAAI,uBAAuB;IACpC,EAAS,QAAQF,EAAUE,CAAE;GAC/B,CAAC,GACDH,EAAS,QAAQG,GAAI;IAAE,YAAY;IAAM,iBAAiB,CAAC,YAAY;GAAE,CAAC;EAC5E,GACA,EAAE,WAAW,GAAK,CACpB,GACAE,QAAsBL,GAAU,WAAW,CAAC;EAE5C,IAAMM,IAAYC,QAAoC;GACpD,IAAM,EAAE,UAAOb,EAAM,YACfc,UAAcZ,EAAI,SAAS,OAAO;GACxC,OAAO;IACL,YAAYF,EAAM;IAClB,OAAOI,EAAS,UAAUF,EAAI,UAAU,MAAM,SAASa,CAAE,IAAI,aAAa;IAC1E,QAAQf,EAAM,WAAW,WAAW;IACpC,cAAcc,EAAM,CAAC,EAAE,OAAO,CAACC,CAAE,CAAC;IAClC,cAAc,KAAKD,EAAM,CAAC,EAAE,OAAOC,CAAE;GACvC;EACF,CAAC;mBAICnB,EAA2BqB,EAAA,QAAA,WAAApB,EAAAC,EAAbc,EAAA,KAAS,CAAA,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InkColorMenu.js","names":["_sfc_main","InkColorMenu_vue_vue_type_script_setup_true_lang_default","InkColorMenu_default"],"sources":["../../src/components/InkColorMenu.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/*\n * A colour menu for one colour property (border, fill or text) of the selection or the active\n * tool. The trigger shows the current colour as a swatch: split when the selection disagrees,\n * slashed for no fill. The panel is a palette grid, plus \"No fill\" for `fill` and \"Custom…\",\n * which opens a native colour input. The menu disables when nothing supports the property.\n */\nimport {\n COLOR_COLUMNS,\n colorMenuModel,\n focusInitialMenuItem,\n handleMenuKeys,\n menuItems,\n type ColorProperty,\n} from '@inkbar/core/dom'\nimport { Check } from '@inkbar/icons'\nimport {\n PopoverContent,\n PopoverPortal,\n PopoverRoot,\n PopoverTrigger,\n ToolbarButton,\n} from 'reka-ui'\nimport { computed, defineComponent, mergeProps, ref, useAttrs, watch } from 'vue'\n\nimport { useToolStyle } from '../composables/useToolStyle'\n\nimport InkIcon from './InkIcon.vue'\n\nimport type { StyleGroup } from '@inkbar/core'\n\ndefineOptions({ inheritAttrs: false })\nconst attrs = useAttrs()\n\n/** Stands in for the toolbar item when the menu is nested in another panel. */\nconst PassThrough = defineComponent({\n inheritAttrs: false,\n setup:\n (_, { slots }) =>\n () =>\n slots.default?.(),\n})\n\nconst props = defineProps<{\n /** The colour this menu sets. */\n property: ColorProperty\n /** Accessible name; defaults to \"Border colour\", \"Fill colour\" or \"Text colour\". */\n label?: string\n /**\n * Renders the trigger outside the toolbar's roving focus, for a menu nested in another\n * panel (the text style menu's text colour).\n */\n standalone?: boolean\n /**\n * Scopes the menu to one style group: it shows and sets that group's colour whatever tool\n * is active, and recolours the selection only when it is all in the group.\n */\n group?: StyleGroup | undefined\n}>()\n\nconst { current, supported, set } = useToolStyle(() => props.group)\nconst open = ref(false)\nconst customInput = ref<HTMLInputElement | null>(null)\n\nconst model = computed(() =>\n colorMenuModel(props.property, current.value, supported.value)\n)\nconst name = computed(() => props.label ?? model.value.label)\nconst trigger = computed(() => model.value.trigger)\n\n// The menu closes when the control disables (the selection cleared while it was open).\nwatch(\n () => model.value.enabled,\n (enabled) => {\n if (!enabled) open.value = false\n }\n)\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 || !model.value.enabled)\n return\n e.preventDefault()\n focusFirst = true\n open.value = true\n}\n\nfunction onOpenAutoFocus(e: Event): void {\n e.preventDefault()\n // One menu is open at a time.\n const menu = document.querySelector(\n `[data-ink-menu=\"color-${props.property}\"] [role=\"menu\"]`\n )\n if (menu) {\n if (focusFirst) menuItems(menu)[0]?.focus({ preventScroll: true })\n else focusInitialMenuItem(menu)\n }\n focusFirst = false\n}\n\n// Reka's typed props stop at its own; ARIA goes through bound objects.\nconst triggerAttrs = computed(() => ({\n 'aria-label': name.value,\n title: name.value,\n 'aria-haspopup': 'menu' as const,\n onKeydown: onTriggerKeydown,\n 'data-mixed': model.value.mixed ? '' : undefined,\n}))\n/**\n * The trigger's bindings over the host's: both keydown listeners run, the host's first, and a\n * host `disabled` can disable the trigger but not enable it.\n */\nconst triggerBindings = computed(() =>\n mergeProps(attrs, triggerAttrs.value, {\n disabled: (attrs.disabled ?? false) !== false || !model.value.enabled,\n })\n)\nconst menuAttrs = computed(() => ({ 'aria-label': name.value }))\nconst innerAttrs = computed(() => ({\n role: 'menu',\n 'aria-label': name.value,\n onKeydown: (e: KeyboardEvent) => handleMenuKeys(e, e.currentTarget as HTMLElement),\n}))\n</script>\n\n<template>\n <PopoverRoot v-model:open=\"open\">\n <component :is=\"standalone ? PassThrough : ToolbarButton\" as-child>\n <PopoverTrigger as-child>\n <button\n type=\"button\"\n class=\"ink-menu-trigger ink-color-menu\"\n :data-ink-color-menu=\"property\"\n :data-state=\"open ? 'open' : 'closed'\"\n v-bind=\"triggerBindings\"\n >\n <slot>\n <span\n class=\"ink-swatch\"\n data-ink-swatch\n aria-hidden=\"true\"\n :data-property=\"property\"\n :data-kind=\"trigger.kind\"\n :data-color=\"trigger.kind === 'color' ? trigger.color : undefined\"\n :style=\"\n trigger.kind === 'color' ? { '--ink-swatch': trigger.color } : undefined\n \"\n />\n </slot>\n </button>\n </PopoverTrigger>\n </component>\n <PopoverPortal>\n <PopoverContent\n class=\"ink-select-content ink-menu-content\"\n data-ink-select-content\n :data-ink-menu=\"`color-${property}`\"\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 <button\n v-if=\"model.noFill\"\n type=\"button\"\n role=\"menuitemradio\"\n class=\"ink-select-item ink-menu-item\"\n data-ink-select-item\n tabindex=\"-1\"\n :aria-checked=\"model.noFill.checked\"\n :data-state=\"model.noFill.checked ? 'checked' : 'unchecked'\"\n @click=\"set(model.noFill.patch)\"\n >\n No fill\n <span v-if=\"model.noFill.checked\" class=\"ink-select-indicator\">\n <InkIcon :icon=\"Check\" :size=\"16\" />\n </span>\n </button>\n <div\n role=\"group\"\n aria-label=\"Colours\"\n class=\"ink-color-grid\"\n :data-ink-menu-columns=\"COLOR_COLUMNS\"\n >\n <button\n v-for=\"sw in model.swatches\"\n :key=\"sw.key\"\n type=\"button\"\n role=\"menuitemradio\"\n class=\"ink-swatch-item\"\n tabindex=\"-1\"\n :aria-label=\"sw.label\"\n :aria-checked=\"sw.checked\"\n :data-state=\"sw.checked ? 'checked' : 'unchecked'\"\n :style=\"{ '--ink-swatch': sw.color }\"\n @click=\"set(sw.patch)\"\n />\n </div>\n <button\n type=\"button\"\n role=\"menuitem\"\n class=\"ink-select-item ink-menu-item\"\n data-ink-select-item\n tabindex=\"-1\"\n @click=\"customInput?.click()\"\n >\n Custom…\n </button>\n </div>\n </PopoverContent>\n </PopoverPortal>\n </PopoverRoot>\n <input\n ref=\"customInput\"\n type=\"color\"\n class=\"ink-color-input\"\n aria-label=\"Custom colour\"\n :data-ink-color-input=\"property\"\n tabindex=\"-1\"\n :value=\"model.customValue.toLowerCase()\"\n @change=\"set(model.custom(($event.target as HTMLInputElement).value))\"\n />\n</template>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"InkColorMenu.js","names":["_sfc_main","InkColorMenu_vue_vue_type_script_setup_true_lang_default","InkColorMenu_default"],"sources":["../../src/components/InkColorMenu.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/*\n * A colour menu for one colour property (border, fill or text) of the selection or the active\n * tool. The trigger shows the current colour as a swatch: split when the selection disagrees,\n * slashed for no fill. The panel is a palette grid, plus \"No fill\" for `fill` and \"Custom…\",\n * which opens a native colour input. The menu disables when nothing supports the property.\n */\nimport {\n COLOR_COLUMNS,\n colorMenuModel,\n focusInitialMenuItem,\n handleMenuKeys,\n menuItems,\n type ColorProperty,\n} from '@inkbar/core/dom'\nimport { Check } from '@inkbar/icons'\nimport {\n PopoverContent,\n PopoverPortal,\n PopoverRoot,\n PopoverTrigger,\n ToolbarButton,\n} from 'reka-ui'\nimport { computed, defineComponent, mergeProps, ref, useAttrs, watch } from 'vue'\n\nimport { useToolStyle } from '../composables/useToolStyle'\n\nimport InkIcon from './InkIcon.vue'\n\nimport type { StyleGroup } from '@inkbar/core'\n\ndefineOptions({ inheritAttrs: false })\nconst attrs = useAttrs()\n\n/** Stands in for the toolbar item when the menu is nested in another panel. */\nconst PassThrough = defineComponent({\n inheritAttrs: false,\n setup:\n (_, { slots }) =>\n () =>\n slots.default?.(),\n})\n\nconst props = defineProps<{\n /** The colour this menu sets. */\n property: ColorProperty\n /** Accessible name; defaults to \"Border colour\", \"Fill colour\" or \"Text colour\". */\n label?: string\n /**\n * Renders the trigger outside the toolbar's roving focus, for a menu nested in another\n * panel (the text style menu's text colour).\n */\n standalone?: boolean\n /**\n * Scopes the menu to one style group: it shows and sets that group's colour whatever tool\n * is active, and recolours the selection only when it is all in the group.\n */\n group?: StyleGroup | undefined\n /** The colour new annotations get while the style leaves it unset; the swatch shows it. */\n fallback?: string | undefined\n}>()\n\nconst { current, supported, set } = useToolStyle(() => props.group)\nconst open = ref(false)\nconst customInput = ref<HTMLInputElement | null>(null)\n\nconst model = computed(() =>\n colorMenuModel(props.property, current.value, supported.value, props.fallback)\n)\nconst name = computed(() => props.label ?? model.value.label)\nconst trigger = computed(() => model.value.trigger)\n\n// The menu closes when the control disables (the selection cleared while it was open).\nwatch(\n () => model.value.enabled,\n (enabled) => {\n if (!enabled) open.value = false\n }\n)\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 || !model.value.enabled)\n return\n e.preventDefault()\n focusFirst = true\n open.value = true\n}\n\nfunction onOpenAutoFocus(e: Event): void {\n e.preventDefault()\n // One menu is open at a time.\n const menu = document.querySelector(\n `[data-ink-menu=\"color-${props.property}\"] [role=\"menu\"]`\n )\n if (menu) {\n if (focusFirst) menuItems(menu)[0]?.focus({ preventScroll: true })\n else focusInitialMenuItem(menu)\n }\n focusFirst = false\n}\n\n// Reka's typed props stop at its own; ARIA goes through bound objects.\nconst triggerAttrs = computed(() => ({\n 'aria-label': name.value,\n title: name.value,\n 'aria-haspopup': 'menu' as const,\n onKeydown: onTriggerKeydown,\n 'data-mixed': model.value.mixed ? '' : undefined,\n}))\n/**\n * The trigger's bindings over the host's: both keydown listeners run, the host's first, and a\n * host `disabled` can disable the trigger but not enable it.\n */\nconst triggerBindings = computed(() =>\n mergeProps(attrs, triggerAttrs.value, {\n disabled: (attrs.disabled ?? false) !== false || !model.value.enabled,\n })\n)\nconst menuAttrs = computed(() => ({ 'aria-label': name.value }))\nconst innerAttrs = computed(() => ({\n role: 'menu',\n 'aria-label': name.value,\n onKeydown: (e: KeyboardEvent) => handleMenuKeys(e, e.currentTarget as HTMLElement),\n}))\n</script>\n\n<template>\n <PopoverRoot v-model:open=\"open\">\n <component :is=\"standalone ? PassThrough : ToolbarButton\" as-child>\n <PopoverTrigger as-child>\n <button\n type=\"button\"\n class=\"ink-menu-trigger ink-color-menu\"\n :data-ink-color-menu=\"property\"\n :data-state=\"open ? 'open' : 'closed'\"\n v-bind=\"triggerBindings\"\n >\n <slot>\n <span\n class=\"ink-swatch\"\n data-ink-swatch\n aria-hidden=\"true\"\n :data-property=\"property\"\n :data-kind=\"trigger.kind\"\n :data-color=\"trigger.kind === 'color' ? trigger.color : undefined\"\n :style=\"\n trigger.kind === 'color' ? { '--ink-swatch': trigger.color } : undefined\n \"\n />\n </slot>\n </button>\n </PopoverTrigger>\n </component>\n <PopoverPortal>\n <PopoverContent\n class=\"ink-select-content ink-menu-content\"\n data-ink-select-content\n :data-ink-menu=\"`color-${property}`\"\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 <button\n v-if=\"model.noFill\"\n type=\"button\"\n role=\"menuitemradio\"\n class=\"ink-select-item ink-menu-item\"\n data-ink-select-item\n tabindex=\"-1\"\n :aria-checked=\"model.noFill.checked\"\n :data-state=\"model.noFill.checked ? 'checked' : 'unchecked'\"\n @click=\"set(model.noFill.patch)\"\n >\n No fill\n <span v-if=\"model.noFill.checked\" class=\"ink-select-indicator\">\n <InkIcon :icon=\"Check\" :size=\"16\" />\n </span>\n </button>\n <div\n role=\"group\"\n aria-label=\"Colours\"\n class=\"ink-color-grid\"\n :data-ink-menu-columns=\"COLOR_COLUMNS\"\n >\n <button\n v-for=\"sw in model.swatches\"\n :key=\"sw.key\"\n type=\"button\"\n role=\"menuitemradio\"\n class=\"ink-swatch-item\"\n tabindex=\"-1\"\n :aria-label=\"sw.label\"\n :aria-checked=\"sw.checked\"\n :data-state=\"sw.checked ? 'checked' : 'unchecked'\"\n :style=\"{ '--ink-swatch': sw.color }\"\n @click=\"set(sw.patch)\"\n />\n </div>\n <button\n type=\"button\"\n role=\"menuitem\"\n class=\"ink-select-item ink-menu-item\"\n data-ink-select-item\n tabindex=\"-1\"\n @click=\"customInput?.click()\"\n >\n Custom…\n </button>\n </div>\n </PopoverContent>\n </PopoverPortal>\n </PopoverRoot>\n <input\n ref=\"customInput\"\n type=\"color\"\n class=\"ink-color-input\"\n aria-label=\"Custom colour\"\n :data-ink-color-input=\"property\"\n tabindex=\"-1\"\n :value=\"model.customValue.toLowerCase()\"\n @change=\"set(model.custom(($event.target as HTMLInputElement).value))\"\n />\n</template>\n"],"mappings":""}
|
|
@@ -15,6 +15,8 @@ type __VLS_Props = {
|
|
|
15
15
|
* is active, and recolours the selection only when it is all in the group.
|
|
16
16
|
*/
|
|
17
17
|
group?: StyleGroup | undefined;
|
|
18
|
+
/** The colour new annotations get while the style leaves it unset; the swatch shows it. */
|
|
19
|
+
fallback?: string | undefined;
|
|
18
20
|
};
|
|
19
21
|
declare var __VLS_21: {};
|
|
20
22
|
type __VLS_Slots = {} & {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InkColorMenu.vue.d.ts","sourceRoot":"","sources":["../../src/components/InkColorMenu.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"InkColorMenu.vue.d.ts","sourceRoot":"","sources":["../../src/components/InkColorMenu.vue"],"names":[],"mappings":"AA6OA,OAAO,EAML,KAAK,aAAa,EACnB,MAAM,kBAAkB,CAAA;AAezB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAe9C,KAAK,WAAW,GAAG;IACjB,iCAAiC;IACjC,QAAQ,EAAE,aAAa,CAAA;IACvB,oFAAoF;IACpF,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;;;OAGG;IACH,KAAK,CAAC,EAAE,UAAU,GAAG,SAAS,CAAA;IAC9B,2FAA2F;IAC3F,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAC9B,CAAC;AAqTF,QAAA,IAAI,QAAQ,IAAY,CAAC;AACzB,KAAK,WAAW,GAAG,EAAE,GACnB;IAAE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,QAAQ,KAAK,GAAG,CAAA;CAAE,CAAC;AAGhD,QAAA,MAAM,UAAU,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"}
|
|
@@ -24,13 +24,14 @@ var P = ["data-ink-color-menu", "data-state"], F = [
|
|
|
24
24
|
property: {},
|
|
25
25
|
label: {},
|
|
26
26
|
standalone: { type: Boolean },
|
|
27
|
-
group: {}
|
|
27
|
+
group: {},
|
|
28
|
+
fallback: {}
|
|
28
29
|
},
|
|
29
30
|
setup(V) {
|
|
30
31
|
let H = b(), U = l({
|
|
31
32
|
inheritAttrs: !1,
|
|
32
33
|
setup: (e, { slots: t }) => () => t.default?.()
|
|
33
|
-
}), W = V, { current: G, supported: K, set: q } = e(() => W.group), J = h(!1), Y = h(null), X = r(() => w(W.property, G.value, K.value)), Z = r(() => W.label ?? X.value.label), Q = r(() => X.value.trigger);
|
|
34
|
+
}), W = V, { current: G, supported: K, set: q } = e(() => W.group), J = h(!1), Y = h(null), X = r(() => w(W.property, G.value, K.value, W.fallback)), Z = r(() => W.label ?? X.value.label), Q = r(() => X.value.trigger);
|
|
34
35
|
x(() => X.value.enabled, (e) => {
|
|
35
36
|
e || (J.value = !1);
|
|
36
37
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InkColorMenu.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createElementBlock","_Fragment","_createVNode","_unref","_withCtx","_createBlock","_resolveDynamicComponent","_createElementVNode","_mergeProps","_renderSlot","_normalizeStyle","_normalizeProps","_guardReactiveProps","_createTextVNode","InkIcon","_createCommentVNode","_renderList","InkIcon_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","InkColorMenu_vue_vue_type_script_setup_true_lang_default","attrs","useAttrs","PassThrough","defineComponent","slots","props","__props","useToolStyle","open","ref","customInput","model","computed","colorMenuModel","current","supported","name","trigger","enabled","focusFirst","onTriggerKeydown","onOpenAutoFocus","menu","menuItems","focusInitialMenuItem","triggerAttrs","triggerBindings","mergeProps","menuAttrs","innerAttrs","handleMenuKeys","openBlock","createElementBlock","Fragment","createVNode","unref","PopoverRoot","_cache","$event","withCtx","createBlock","resolveDynamicComponent","ToolbarButton","PopoverTrigger","createElementVNode","renderSlot","_ctx","normalizeStyle","PopoverPortal","PopoverContent","normalizeProps","guardReactiveProps","set","createTextVNode","Check","createCommentVNode","COLOR_COLUMNS","renderList","sw"],"sources":["../../src/components/InkColorMenu.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/*\n * A colour menu for one colour property (border, fill or text) of the selection or the active\n * tool. The trigger shows the current colour as a swatch: split when the selection disagrees,\n * slashed for no fill. The panel is a palette grid, plus \"No fill\" for `fill` and \"Custom…\",\n * which opens a native colour input. The menu disables when nothing supports the property.\n */\nimport {\n COLOR_COLUMNS,\n colorMenuModel,\n focusInitialMenuItem,\n handleMenuKeys,\n menuItems,\n type ColorProperty,\n} from '@inkbar/core/dom'\nimport { Check } from '@inkbar/icons'\nimport {\n PopoverContent,\n PopoverPortal,\n PopoverRoot,\n PopoverTrigger,\n ToolbarButton,\n} from 'reka-ui'\nimport { computed, defineComponent, mergeProps, ref, useAttrs, watch } from 'vue'\n\nimport { useToolStyle } from '../composables/useToolStyle'\n\nimport InkIcon from './InkIcon.vue'\n\nimport type { StyleGroup } from '@inkbar/core'\n\ndefineOptions({ inheritAttrs: false })\nconst attrs = useAttrs()\n\n/** Stands in for the toolbar item when the menu is nested in another panel. */\nconst PassThrough = defineComponent({\n inheritAttrs: false,\n setup:\n (_, { slots }) =>\n () =>\n slots.default?.(),\n})\n\nconst props = defineProps<{\n /** The colour this menu sets. */\n property: ColorProperty\n /** Accessible name; defaults to \"Border colour\", \"Fill colour\" or \"Text colour\". */\n label?: string\n /**\n * Renders the trigger outside the toolbar's roving focus, for a menu nested in another\n * panel (the text style menu's text colour).\n */\n standalone?: boolean\n /**\n * Scopes the menu to one style group: it shows and sets that group's colour whatever tool\n * is active, and recolours the selection only when it is all in the group.\n */\n group?: StyleGroup | undefined\n}>()\n\nconst { current, supported, set } = useToolStyle(() => props.group)\nconst open = ref(false)\nconst customInput = ref<HTMLInputElement | null>(null)\n\nconst model = computed(() =>\n colorMenuModel(props.property, current.value, supported.value)\n)\nconst name = computed(() => props.label ?? model.value.label)\nconst trigger = computed(() => model.value.trigger)\n\n// The menu closes when the control disables (the selection cleared while it was open).\nwatch(\n () => model.value.enabled,\n (enabled) => {\n if (!enabled) open.value = false\n }\n)\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 || !model.value.enabled)\n return\n e.preventDefault()\n focusFirst = true\n open.value = true\n}\n\nfunction onOpenAutoFocus(e: Event): void {\n e.preventDefault()\n // One menu is open at a time.\n const menu = document.querySelector(\n `[data-ink-menu=\"color-${props.property}\"] [role=\"menu\"]`\n )\n if (menu) {\n if (focusFirst) menuItems(menu)[0]?.focus({ preventScroll: true })\n else focusInitialMenuItem(menu)\n }\n focusFirst = false\n}\n\n// Reka's typed props stop at its own; ARIA goes through bound objects.\nconst triggerAttrs = computed(() => ({\n 'aria-label': name.value,\n title: name.value,\n 'aria-haspopup': 'menu' as const,\n onKeydown: onTriggerKeydown,\n 'data-mixed': model.value.mixed ? '' : undefined,\n}))\n/**\n * The trigger's bindings over the host's: both keydown listeners run, the host's first, and a\n * host `disabled` can disable the trigger but not enable it.\n */\nconst triggerBindings = computed(() =>\n mergeProps(attrs, triggerAttrs.value, {\n disabled: (attrs.disabled ?? false) !== false || !model.value.enabled,\n })\n)\nconst menuAttrs = computed(() => ({ 'aria-label': name.value }))\nconst innerAttrs = computed(() => ({\n role: 'menu',\n 'aria-label': name.value,\n onKeydown: (e: KeyboardEvent) => handleMenuKeys(e, e.currentTarget as HTMLElement),\n}))\n</script>\n\n<template>\n <PopoverRoot v-model:open=\"open\">\n <component :is=\"standalone ? PassThrough : ToolbarButton\" as-child>\n <PopoverTrigger as-child>\n <button\n type=\"button\"\n class=\"ink-menu-trigger ink-color-menu\"\n :data-ink-color-menu=\"property\"\n :data-state=\"open ? 'open' : 'closed'\"\n v-bind=\"triggerBindings\"\n >\n <slot>\n <span\n class=\"ink-swatch\"\n data-ink-swatch\n aria-hidden=\"true\"\n :data-property=\"property\"\n :data-kind=\"trigger.kind\"\n :data-color=\"trigger.kind === 'color' ? trigger.color : undefined\"\n :style=\"\n trigger.kind === 'color' ? { '--ink-swatch': trigger.color } : undefined\n \"\n />\n </slot>\n </button>\n </PopoverTrigger>\n </component>\n <PopoverPortal>\n <PopoverContent\n class=\"ink-select-content ink-menu-content\"\n data-ink-select-content\n :data-ink-menu=\"`color-${property}`\"\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 <button\n v-if=\"model.noFill\"\n type=\"button\"\n role=\"menuitemradio\"\n class=\"ink-select-item ink-menu-item\"\n data-ink-select-item\n tabindex=\"-1\"\n :aria-checked=\"model.noFill.checked\"\n :data-state=\"model.noFill.checked ? 'checked' : 'unchecked'\"\n @click=\"set(model.noFill.patch)\"\n >\n No fill\n <span v-if=\"model.noFill.checked\" class=\"ink-select-indicator\">\n <InkIcon :icon=\"Check\" :size=\"16\" />\n </span>\n </button>\n <div\n role=\"group\"\n aria-label=\"Colours\"\n class=\"ink-color-grid\"\n :data-ink-menu-columns=\"COLOR_COLUMNS\"\n >\n <button\n v-for=\"sw in model.swatches\"\n :key=\"sw.key\"\n type=\"button\"\n role=\"menuitemradio\"\n class=\"ink-swatch-item\"\n tabindex=\"-1\"\n :aria-label=\"sw.label\"\n :aria-checked=\"sw.checked\"\n :data-state=\"sw.checked ? 'checked' : 'unchecked'\"\n :style=\"{ '--ink-swatch': sw.color }\"\n @click=\"set(sw.patch)\"\n />\n </div>\n <button\n type=\"button\"\n role=\"menuitem\"\n class=\"ink-select-item ink-menu-item\"\n data-ink-select-item\n tabindex=\"-1\"\n @click=\"customInput?.click()\"\n >\n Custom…\n </button>\n </div>\n </PopoverContent>\n </PopoverPortal>\n </PopoverRoot>\n <input\n ref=\"customInput\"\n type=\"color\"\n class=\"ink-color-input\"\n aria-label=\"Custom colour\"\n :data-ink-color-input=\"property\"\n tabindex=\"-1\"\n :value=\"model.customValue.toLowerCase()\"\n @change=\"set(model.custom(($event.target as HTMLInputElement).value))\"\n />\n</template>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"InkColorMenu.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createElementBlock","_Fragment","_createVNode","_unref","_withCtx","_createBlock","_resolveDynamicComponent","_createElementVNode","_mergeProps","_renderSlot","_normalizeStyle","_normalizeProps","_guardReactiveProps","_createTextVNode","InkIcon","_createCommentVNode","_renderList","InkIcon_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","InkColorMenu_vue_vue_type_script_setup_true_lang_default","attrs","useAttrs","PassThrough","defineComponent","slots","props","__props","useToolStyle","open","ref","customInput","model","computed","colorMenuModel","current","supported","name","trigger","enabled","focusFirst","onTriggerKeydown","onOpenAutoFocus","menu","menuItems","focusInitialMenuItem","triggerAttrs","triggerBindings","mergeProps","menuAttrs","innerAttrs","handleMenuKeys","openBlock","createElementBlock","Fragment","createVNode","unref","PopoverRoot","_cache","$event","withCtx","createBlock","resolveDynamicComponent","ToolbarButton","PopoverTrigger","createElementVNode","renderSlot","_ctx","normalizeStyle","PopoverPortal","PopoverContent","normalizeProps","guardReactiveProps","set","createTextVNode","Check","createCommentVNode","COLOR_COLUMNS","renderList","sw"],"sources":["../../src/components/InkColorMenu.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/*\n * A colour menu for one colour property (border, fill or text) of the selection or the active\n * tool. The trigger shows the current colour as a swatch: split when the selection disagrees,\n * slashed for no fill. The panel is a palette grid, plus \"No fill\" for `fill` and \"Custom…\",\n * which opens a native colour input. The menu disables when nothing supports the property.\n */\nimport {\n COLOR_COLUMNS,\n colorMenuModel,\n focusInitialMenuItem,\n handleMenuKeys,\n menuItems,\n type ColorProperty,\n} from '@inkbar/core/dom'\nimport { Check } from '@inkbar/icons'\nimport {\n PopoverContent,\n PopoverPortal,\n PopoverRoot,\n PopoverTrigger,\n ToolbarButton,\n} from 'reka-ui'\nimport { computed, defineComponent, mergeProps, ref, useAttrs, watch } from 'vue'\n\nimport { useToolStyle } from '../composables/useToolStyle'\n\nimport InkIcon from './InkIcon.vue'\n\nimport type { StyleGroup } from '@inkbar/core'\n\ndefineOptions({ inheritAttrs: false })\nconst attrs = useAttrs()\n\n/** Stands in for the toolbar item when the menu is nested in another panel. */\nconst PassThrough = defineComponent({\n inheritAttrs: false,\n setup:\n (_, { slots }) =>\n () =>\n slots.default?.(),\n})\n\nconst props = defineProps<{\n /** The colour this menu sets. */\n property: ColorProperty\n /** Accessible name; defaults to \"Border colour\", \"Fill colour\" or \"Text colour\". */\n label?: string\n /**\n * Renders the trigger outside the toolbar's roving focus, for a menu nested in another\n * panel (the text style menu's text colour).\n */\n standalone?: boolean\n /**\n * Scopes the menu to one style group: it shows and sets that group's colour whatever tool\n * is active, and recolours the selection only when it is all in the group.\n */\n group?: StyleGroup | undefined\n /** The colour new annotations get while the style leaves it unset; the swatch shows it. */\n fallback?: string | undefined\n}>()\n\nconst { current, supported, set } = useToolStyle(() => props.group)\nconst open = ref(false)\nconst customInput = ref<HTMLInputElement | null>(null)\n\nconst model = computed(() =>\n colorMenuModel(props.property, current.value, supported.value, props.fallback)\n)\nconst name = computed(() => props.label ?? model.value.label)\nconst trigger = computed(() => model.value.trigger)\n\n// The menu closes when the control disables (the selection cleared while it was open).\nwatch(\n () => model.value.enabled,\n (enabled) => {\n if (!enabled) open.value = false\n }\n)\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 || !model.value.enabled)\n return\n e.preventDefault()\n focusFirst = true\n open.value = true\n}\n\nfunction onOpenAutoFocus(e: Event): void {\n e.preventDefault()\n // One menu is open at a time.\n const menu = document.querySelector(\n `[data-ink-menu=\"color-${props.property}\"] [role=\"menu\"]`\n )\n if (menu) {\n if (focusFirst) menuItems(menu)[0]?.focus({ preventScroll: true })\n else focusInitialMenuItem(menu)\n }\n focusFirst = false\n}\n\n// Reka's typed props stop at its own; ARIA goes through bound objects.\nconst triggerAttrs = computed(() => ({\n 'aria-label': name.value,\n title: name.value,\n 'aria-haspopup': 'menu' as const,\n onKeydown: onTriggerKeydown,\n 'data-mixed': model.value.mixed ? '' : undefined,\n}))\n/**\n * The trigger's bindings over the host's: both keydown listeners run, the host's first, and a\n * host `disabled` can disable the trigger but not enable it.\n */\nconst triggerBindings = computed(() =>\n mergeProps(attrs, triggerAttrs.value, {\n disabled: (attrs.disabled ?? false) !== false || !model.value.enabled,\n })\n)\nconst menuAttrs = computed(() => ({ 'aria-label': name.value }))\nconst innerAttrs = computed(() => ({\n role: 'menu',\n 'aria-label': name.value,\n onKeydown: (e: KeyboardEvent) => handleMenuKeys(e, e.currentTarget as HTMLElement),\n}))\n</script>\n\n<template>\n <PopoverRoot v-model:open=\"open\">\n <component :is=\"standalone ? PassThrough : ToolbarButton\" as-child>\n <PopoverTrigger as-child>\n <button\n type=\"button\"\n class=\"ink-menu-trigger ink-color-menu\"\n :data-ink-color-menu=\"property\"\n :data-state=\"open ? 'open' : 'closed'\"\n v-bind=\"triggerBindings\"\n >\n <slot>\n <span\n class=\"ink-swatch\"\n data-ink-swatch\n aria-hidden=\"true\"\n :data-property=\"property\"\n :data-kind=\"trigger.kind\"\n :data-color=\"trigger.kind === 'color' ? trigger.color : undefined\"\n :style=\"\n trigger.kind === 'color' ? { '--ink-swatch': trigger.color } : undefined\n \"\n />\n </slot>\n </button>\n </PopoverTrigger>\n </component>\n <PopoverPortal>\n <PopoverContent\n class=\"ink-select-content ink-menu-content\"\n data-ink-select-content\n :data-ink-menu=\"`color-${property}`\"\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 <button\n v-if=\"model.noFill\"\n type=\"button\"\n role=\"menuitemradio\"\n class=\"ink-select-item ink-menu-item\"\n data-ink-select-item\n tabindex=\"-1\"\n :aria-checked=\"model.noFill.checked\"\n :data-state=\"model.noFill.checked ? 'checked' : 'unchecked'\"\n @click=\"set(model.noFill.patch)\"\n >\n No fill\n <span v-if=\"model.noFill.checked\" class=\"ink-select-indicator\">\n <InkIcon :icon=\"Check\" :size=\"16\" />\n </span>\n </button>\n <div\n role=\"group\"\n aria-label=\"Colours\"\n class=\"ink-color-grid\"\n :data-ink-menu-columns=\"COLOR_COLUMNS\"\n >\n <button\n v-for=\"sw in model.swatches\"\n :key=\"sw.key\"\n type=\"button\"\n role=\"menuitemradio\"\n class=\"ink-swatch-item\"\n tabindex=\"-1\"\n :aria-label=\"sw.label\"\n :aria-checked=\"sw.checked\"\n :data-state=\"sw.checked ? 'checked' : 'unchecked'\"\n :style=\"{ '--ink-swatch': sw.color }\"\n @click=\"set(sw.patch)\"\n />\n </div>\n <button\n type=\"button\"\n role=\"menuitem\"\n class=\"ink-select-item ink-menu-item\"\n data-ink-select-item\n tabindex=\"-1\"\n @click=\"customInput?.click()\"\n >\n Custom…\n </button>\n </div>\n </PopoverContent>\n </PopoverPortal>\n </PopoverRoot>\n <input\n ref=\"customInput\"\n type=\"color\"\n class=\"ink-color-input\"\n aria-label=\"Custom colour\"\n :data-ink-color-input=\"property\"\n tabindex=\"-1\"\n :value=\"model.customValue.toLowerCase()\"\n @change=\"set(model.custom(($event.target as HTMLInputElement).value))\"\n />\n</template>\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InkCommand.js","names":["_sfc_main","InkCommand_vue_vue_type_script_setup_true_lang_default","InkCommand_default"],"sources":["../../src/components/InkCommand.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/*\n * A plugin command as a toolbar button with its status beside it: the markup of core's\n * `createCommandButton`, so the theme styles both alike. The button is named by the command's\n * label and disabled while the command is, except while it runs: then it keeps focus, with\n * `aria-busy` and `aria-disabled`, and a press does nothing. The status is a live region. A command without an icon shows its label as the button's text. Until the plugins\n * are set up (once InkRoot has mounted; never on the server) the button is disabled and\n * `aria-hidden`. An id no plugin registered stays that way and logs `InkError('UnknownCommand')`\n * to the console once.\n */\nimport { ToolbarButton } from 'reka-ui'\nimport { computed } from 'vue'\n\nimport { useCommand } from '../composables/useCommand'\n\nimport InkIcon from './InkIcon.vue'\n\nconst props = withDefaults(defineProps<{ id: string; asChild?: boolean }>(), {\n asChild: false,\n})\n\n// The id is read once, as `useCommand` does: a different command is a different component.\nconst command = useCommand(props.id)\nconst { enabled, busy, status, label, icon } = command\n// Reka's typed props stop at its own; ARIA and listeners go through a bound object.\nconst attrs = computed(() => ({\n type: 'button',\n // No label until the plugins are set up: the disabled button stays out of the\n // accessibility tree rather than go unnamed.\n 'aria-label': label.value || undefined,\n title: label.value || undefined,\n 'aria-hidden': label.value ? undefined : 'true',\n 'aria-busy': String(busy.value),\n // Disabled while it runs, but not `disabled`, so the button keeps focus.\n 'aria-disabled': busy.value ? 'true' : undefined,\n onClick: () => void command.run(),\n}))\n</script>\n\n<template>\n <div class=\"ink-command\">\n <ToolbarButton\n :as-child=\"asChild\"\n :disabled=\"!enabled && !busy\"\n :data-command=\"id\"\n v-bind=\"attrs\"\n >\n <slot :label=\"label\" :busy=\"busy\">\n <InkIcon v-if=\"icon\" :icon=\"icon\" />\n <template v-else>{{ label }}</template>\n </slot>\n </ToolbarButton>\n <span class=\"ink-command-status\" role=\"status\">{{ status }}</span>\n </div>\n</template>\n"],"mappings":""}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
id: string;
|
|
3
|
+
asChild?: boolean;
|
|
4
|
+
};
|
|
5
|
+
declare var __VLS_7: {
|
|
6
|
+
label: string;
|
|
7
|
+
busy: boolean;
|
|
8
|
+
};
|
|
9
|
+
type __VLS_Slots = {} & {
|
|
10
|
+
default?: (props: typeof __VLS_7) => any;
|
|
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
|
+
asChild: boolean;
|
|
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=InkCommand.vue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InkCommand.vue.d.ts","sourceRoot":"","sources":["../../src/components/InkCommand.vue"],"names":[],"mappings":"AA0EA,KAAK,WAAW,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AA2FrD,QAAA,IAAI,OAAO;;;CAAW,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,51 @@
|
|
|
1
|
+
import { useCommand as e } from "../composables/useCommand.js";
|
|
2
|
+
import t from "./InkIcon.js";
|
|
3
|
+
import { Fragment as n, computed as r, createBlock as i, createElementBlock as a, createElementVNode as o, createTextVNode as s, createVNode as c, defineComponent as l, mergeProps as u, openBlock as d, renderSlot as f, toDisplayString as p, unref as m, withCtx as h } from "vue";
|
|
4
|
+
import { ToolbarButton as g } from "reka-ui";
|
|
5
|
+
//#region src/components/InkCommand.vue?vue&type=script&setup=true&lang.ts
|
|
6
|
+
var _ = { class: "ink-command" }, v = {
|
|
7
|
+
class: "ink-command-status",
|
|
8
|
+
role: "status"
|
|
9
|
+
}, y = /*@__PURE__*/ l({
|
|
10
|
+
__name: "InkCommand",
|
|
11
|
+
props: {
|
|
12
|
+
id: {},
|
|
13
|
+
asChild: {
|
|
14
|
+
type: Boolean,
|
|
15
|
+
default: !1
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
setup(l) {
|
|
19
|
+
let y = e(l.id), { enabled: b, busy: x, status: S, label: C, icon: w } = y, T = r(() => ({
|
|
20
|
+
type: "button",
|
|
21
|
+
"aria-label": C.value || void 0,
|
|
22
|
+
title: C.value || void 0,
|
|
23
|
+
"aria-hidden": C.value ? void 0 : "true",
|
|
24
|
+
"aria-busy": String(x.value),
|
|
25
|
+
"aria-disabled": x.value ? "true" : void 0,
|
|
26
|
+
onClick: () => void y.run()
|
|
27
|
+
}));
|
|
28
|
+
return (e, r) => (d(), a("div", _, [c(m(g), u({
|
|
29
|
+
"as-child": l.asChild,
|
|
30
|
+
disabled: !m(b) && !m(x),
|
|
31
|
+
"data-command": l.id
|
|
32
|
+
}, T.value), {
|
|
33
|
+
default: h(() => [f(e.$slots, "default", {
|
|
34
|
+
label: m(C),
|
|
35
|
+
busy: m(x)
|
|
36
|
+
}, () => [m(w) ? (d(), i(t, {
|
|
37
|
+
key: 0,
|
|
38
|
+
icon: m(w)
|
|
39
|
+
}, null, 8, ["icon"])) : (d(), a(n, { key: 1 }, [s(p(m(C)), 1)], 64))])]),
|
|
40
|
+
_: 3
|
|
41
|
+
}, 16, [
|
|
42
|
+
"as-child",
|
|
43
|
+
"disabled",
|
|
44
|
+
"data-command"
|
|
45
|
+
]), o("span", v, p(m(S)), 1)]));
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
//#endregion
|
|
49
|
+
export { y as default };
|
|
50
|
+
|
|
51
|
+
//# sourceMappingURL=InkCommand.vue_vue_type_script_setup_true_lang.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InkCommand.vue_vue_type_script_setup_true_lang.js","names":["props","_openBlock","_createElementBlock","_createVNode","_unref","_mergeProps","_withCtx","_renderSlot","_createBlock","InkIcon","_Fragment","_createTextVNode","_toDisplayString","_createElementVNode","InkIcon_default","_hoisted_1","_hoisted_2","InkCommand_vue_vue_type_script_setup_true_lang_default","command","useCommand","__props","attrs","computed","label","busy","openBlock","createElementBlock","createVNode","unref","ToolbarButton","mergeProps","enabled","withCtx","renderSlot","_ctx","icon","createBlock","Fragment","createTextVNode","toDisplayString","createElementVNode","status"],"sources":["../../src/components/InkCommand.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/*\n * A plugin command as a toolbar button with its status beside it: the markup of core's\n * `createCommandButton`, so the theme styles both alike. The button is named by the command's\n * label and disabled while the command is, except while it runs: then it keeps focus, with\n * `aria-busy` and `aria-disabled`, and a press does nothing. The status is a live region. A command without an icon shows its label as the button's text. Until the plugins\n * are set up (once InkRoot has mounted; never on the server) the button is disabled and\n * `aria-hidden`. An id no plugin registered stays that way and logs `InkError('UnknownCommand')`\n * to the console once.\n */\nimport { ToolbarButton } from 'reka-ui'\nimport { computed } from 'vue'\n\nimport { useCommand } from '../composables/useCommand'\n\nimport InkIcon from './InkIcon.vue'\n\nconst props = withDefaults(defineProps<{ id: string; asChild?: boolean }>(), {\n asChild: false,\n})\n\n// The id is read once, as `useCommand` does: a different command is a different component.\nconst command = useCommand(props.id)\nconst { enabled, busy, status, label, icon } = command\n// Reka's typed props stop at its own; ARIA and listeners go through a bound object.\nconst attrs = computed(() => ({\n type: 'button',\n // No label until the plugins are set up: the disabled button stays out of the\n // accessibility tree rather than go unnamed.\n 'aria-label': label.value || undefined,\n title: label.value || undefined,\n 'aria-hidden': label.value ? undefined : 'true',\n 'aria-busy': String(busy.value),\n // Disabled while it runs, but not `disabled`, so the button keeps focus.\n 'aria-disabled': busy.value ? 'true' : undefined,\n onClick: () => void command.run(),\n}))\n</script>\n\n<template>\n <div class=\"ink-command\">\n <ToolbarButton\n :as-child=\"asChild\"\n :disabled=\"!enabled && !busy\"\n :data-command=\"id\"\n v-bind=\"attrs\"\n >\n <slot :label=\"label\" :busy=\"busy\">\n <InkIcon v-if=\"icon\" :icon=\"icon\" />\n <template v-else>{{ label }}</template>\n </slot>\n </ToolbarButton>\n <span class=\"ink-command-status\" role=\"status\">{{ status }}</span>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;EAsBA,IAAMkB,IAAUC,EAAWnB,EAAM,EAAE,GAC7B,EAAE,YAAS,SAAM,WAAQ,UAAO,YAASkB,GAEzCG,IAAQC,SAAgB;GAC5B,MAAM;GAGN,cAAcC,EAAM,SAAS,KAAA;GAC7B,OAAOA,EAAM,SAAS,KAAA;GACtB,eAAeA,EAAM,QAAQ,KAAA,IAAY;GACzC,aAAa,OAAOC,EAAK,KAAK;GAE9B,iBAAiBA,EAAK,QAAQ,SAAS,KAAA;GACvC,eAAe,KAAKN,EAAQ,IAAI;EAClC,EAAE;oBAIAjB,EAAA,GAAAC,EAaM,OAbNa,GAaM,CAZJZ,EAUgBC,EAAAyB,CAAA,GAVhBxB,EAUgB;GATb,YAAUe,EAAA;GACV,UAAQ,CAAGhB,EAAA2B,CAAA,KAAO,CAAK3B,EAAAoB,CAAA;GACvB,gBAAcJ,EAAA;EACP,GAAAC,EAAA,KAAK,GAAA;GAEb,SAAAf,QAGO,CAHPC,EAGO2B,EAAA,QAAA,WAAA;IAHA,OAAO9B,EAAAmB,CAAA;IAAQ,MAAMnB,EAAAoB,CAAA;GAA5B,SAGO,CAFUpB,EAAA+B,CAAA,KAAflC,EAAA,GAAAO,EAAoCC,GAAA;;IAAd,MAAML,EAAA+B,CAAA;GAC5BlC,GAAAA,MAAAA,GAAAA,CAAAA,MAAAA,CAAAA,MAAAA,EAAA,GAAAC,EAAuCQ,GAAA,EAAA,KAAA,EAAA,GAAA,CAAnBC,EAAAC,EAAAR,EAAAmB,CAAA,CAAK,GAAA,CAAA,CAAA,GAAA,EAAA,EAAA,CAAA,CAAA,CAAA;;;;;;EAG7BV,CAAAA,GAAAA,EAAkE,QAAlEG,GAAkEJ,EAAhBR,EAAAqC,CAAA,CAAM,GAAA,CAAA,CAAA,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InkHighlightMenu.js","names":["_sfc_main","InkHighlightMenu_vue_vue_type_script_setup_true_lang_default","InkHighlightMenu_default"],"sources":["../../src/components/InkHighlightMenu.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/*\n * A split button for the highlight tool. The main part activates the tool with the current\n * markup kind and draws that kind's icon; the chevron opens a menu of the four kinds plus\n * the markup colour. Choosing a kind switches to the tool with it. The colour is a nested\n * `InkColorMenu` scoped to the `markup` style group, so it works whatever tool is active.\n */\nimport {\n focusInitialMenuItem,\n handleMenuKeys,\n highlightMenuModel,\n MARKUP_ICONS,\n MARKUP_KINDS,\n menuItems,\n type HighlightOptions,\n type MarkupKind,\n} from '@inkbar/core/dom'\nimport { ChevronDown } from '@inkbar/icons'\nimport {\n 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
|
|
1
|
+
{"version":3,"file":"InkHighlightMenu.js","names":["_sfc_main","InkHighlightMenu_vue_vue_type_script_setup_true_lang_default","InkHighlightMenu_default"],"sources":["../../src/components/InkHighlightMenu.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/*\n * A split button for the highlight tool. The main part activates the tool with the current\n * markup kind and draws that kind's icon; the chevron opens a menu of the four kinds plus\n * the markup colour. Choosing a kind switches to the tool with it. The colour is a nested\n * `InkColorMenu` scoped to the `markup` style group, so it works whatever tool is active.\n */\nimport {\n focusInitialMenuItem,\n handleMenuKeys,\n highlightMenuModel,\n MARKUP_ICONS,\n MARKUP_KINDS,\n menuItems,\n type HighlightOptions,\n type MarkupKind,\n} from '@inkbar/core/dom'\nimport { ChevronDown } from '@inkbar/icons'\nimport {\n PopoverAnchor,\n PopoverContent,\n PopoverPortal,\n PopoverRoot,\n PopoverTrigger,\n ToolbarButton,\n} from 'reka-ui'\nimport { computed, ref } from 'vue'\n\nimport { useDocument } from '../composables/useDocument'\nimport { useTool } from '../composables/useTool'\nimport { 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":""}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
declare var
|
|
1
|
+
declare var __VLS_21: {
|
|
2
2
|
active: boolean;
|
|
3
3
|
kind: "highlight" | "underline" | "strikeout" | "squiggly";
|
|
4
4
|
};
|
|
5
5
|
type __VLS_Slots = {} & {
|
|
6
|
-
default?: (props: typeof
|
|
6
|
+
default?: (props: typeof __VLS_21) => any;
|
|
7
7
|
};
|
|
8
8
|
declare const __VLS_base: import('vue').DefineComponent<{}, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>;
|
|
9
9
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InkHighlightMenu.vue.d.ts","sourceRoot":"","sources":["../../src/components/InkHighlightMenu.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"InkHighlightMenu.vue.d.ts","sourceRoot":"","sources":["../../src/components/InkHighlightMenu.vue"],"names":[],"mappings":"AA8hBA,QAAA,IAAI,QAAQ;;;CAAY,CAAC;AACzB,KAAK,WAAW,GAAG,EAAE,GACnB;IAAE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,QAAQ,KAAK,GAAG,CAAA;CAAE,CAAC;AAGhD,QAAA,MAAM,UAAU,+QACd,CAAC;AACH,QAAA,MAAM,YAAY,EAAS,eAAe,CAAC,OAAO,UAAU,EAAE,WAAW,CAAC,CAAC;wBACtD,OAAO,YAAY;AAAxC,wBAAyC;AACzC,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"}
|