@embedpdf/viewer-vue 0.0.0-stage → 3.0.0-next.15
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/LICENSE +192 -0
- package/README.md +81 -2
- package/dist/component.cjs +19 -0
- package/dist/component.d.cts +2 -0
- package/dist/component.d.ts +2 -0
- package/dist/component.js +2 -0
- package/dist/core.cjs +67 -0
- package/dist/core.cjs.map +1 -0
- package/dist/core.d.cts +14 -0
- package/dist/core.d.ts +14 -0
- package/dist/core.js +14 -0
- package/dist/core.js.map +1 -0
- package/dist/index.cjs +61 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +13 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/parts-BD781tPE.d.cts +155 -0
- package/dist/parts-BLlgtdE3.cjs +354 -0
- package/dist/parts-BLlgtdE3.cjs.map +1 -0
- package/dist/parts-BjrLWUIX.js +295 -0
- package/dist/parts-BjrLWUIX.js.map +1 -0
- package/dist/parts-o1y3y3_F.d.ts +155 -0
- package/package.json +71 -3
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { ElementConfig, EmbedPdfViewerElement, PanelResizeEvent, ToolbarItemContext, Viewer } from "@embedpdf/viewer/core";
|
|
2
|
+
import { ComponentOptionsMixin, CreateComponentPublicInstanceWithMixins, EmitsToProps, PublicProps, SetupContext, SlotsType, VNode } from "vue";
|
|
3
|
+
import { useCommand } from "@embedpdf/vue/commands";
|
|
4
|
+
//#region src/component.d.ts
|
|
5
|
+
/** The config keys the viewer calls back with: events here. */
|
|
6
|
+
type CallbackKey = 'onReady' | 'onDocumentChange' | 'onPanelResize';
|
|
7
|
+
/** A door's config as props: every key but the callbacks, which are events. */
|
|
8
|
+
type PDFViewerPropsOf<Config extends object> = Omit<Config, CallbackKey>;
|
|
9
|
+
/** The props of the shared setup: the kernel's config, the widest. */
|
|
10
|
+
type PDFViewerImplProps = PDFViewerPropsOf<ElementConfig>;
|
|
11
|
+
/** The events: the config's callbacks, by their Vue names. */
|
|
12
|
+
type PDFViewerEmits = {
|
|
13
|
+
/** The viewer is live, before any document has opened: its `viewer`, for code outside it. */
|
|
14
|
+
ready: (viewer: Viewer) => true;
|
|
15
|
+
/**
|
|
16
|
+
* The document that's showing: the first one, each one the user switches to, and `null` once
|
|
17
|
+
* the last one closes.
|
|
18
|
+
*/
|
|
19
|
+
'document-change': (documentId: string | null) => true;
|
|
20
|
+
/** The user resized a panel: its id and new width in px. */
|
|
21
|
+
'panel-resize': (event: PanelResizeEvent) => true;
|
|
22
|
+
};
|
|
23
|
+
/** Your components, shown where their slot says: `<ToolbarItem>`, `<Panel>`, `<Region>`. */
|
|
24
|
+
type PDFViewerSlots = SlotsType<{
|
|
25
|
+
default?: () => VNode[];
|
|
26
|
+
}>;
|
|
27
|
+
/** What a template ref on <PDFViewer> reads. */
|
|
28
|
+
interface PDFViewerExposed {
|
|
29
|
+
/** The `<embedpdf-viewer>` element, for its imperative surface; null before it mounts. */
|
|
30
|
+
readonly elementRef: EmbedPdfViewerElement | null;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* <PDFViewer> typed with a door's props. Vue's own type for a component made from a setup
|
|
34
|
+
* function says nothing of what it exposes, so this one adds what a template ref reads.
|
|
35
|
+
*/
|
|
36
|
+
type PDFViewerComponent<Props> = new (props: Props & EmitsToProps<PDFViewerEmits> & PublicProps) => CreateComponentPublicInstanceWithMixins<Props & EmitsToProps<PDFViewerEmits>, PDFViewerExposed, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, PDFViewerEmits, PublicProps, {}, false, {}, PDFViewerSlots>;
|
|
37
|
+
/** The options each entry defines <PDFViewer> with, next to {@link setupPDFViewer}. */
|
|
38
|
+
declare const PDF_VIEWER_OPTIONS: {
|
|
39
|
+
name: string;
|
|
40
|
+
props: {
|
|
41
|
+
src: null;
|
|
42
|
+
documents: null;
|
|
43
|
+
engine: null;
|
|
44
|
+
commands: null;
|
|
45
|
+
icons: null;
|
|
46
|
+
strings: null;
|
|
47
|
+
locale: null;
|
|
48
|
+
disable: null;
|
|
49
|
+
readOnly: {
|
|
50
|
+
type: (ObjectConstructor | BooleanConstructor)[];
|
|
51
|
+
default: undefined;
|
|
52
|
+
};
|
|
53
|
+
scope: null;
|
|
54
|
+
identity: null;
|
|
55
|
+
notAllowed: null;
|
|
56
|
+
layout: null;
|
|
57
|
+
plugins: null;
|
|
58
|
+
theme: null;
|
|
59
|
+
};
|
|
60
|
+
emits: string[];
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* The shared setup. Each entry defines <PDFViewer> from it, typed with its door's config: see
|
|
64
|
+
* `PDFViewer` in ./index.ts (engine optional) and ./core.ts (engine required).
|
|
65
|
+
*/
|
|
66
|
+
declare function setupPDFViewer(props: PDFViewerImplProps, { emit, slots, expose }: SetupContext<PDFViewerEmits, PDFViewerSlots>): () => VNode;
|
|
67
|
+
//#endregion
|
|
68
|
+
//#region src/composables.d.ts
|
|
69
|
+
/**
|
|
70
|
+
* The `viewer`, in a component inside <PDFViewer>: `get(name)`, `documents`, `commands`,
|
|
71
|
+
* `watch` and `forDocument`. Your components mount once the viewer is live, so it is always
|
|
72
|
+
* there. Outside the viewer, keep the one `@ready` gives you; called there, this throws.
|
|
73
|
+
*/
|
|
74
|
+
declare function usePDFViewer(): Viewer;
|
|
75
|
+
//#endregion
|
|
76
|
+
//#region src/slots.d.ts
|
|
77
|
+
/** What a place holds: your components. */
|
|
78
|
+
type DefaultSlot = SlotsType<{
|
|
79
|
+
default?: () => VNode[];
|
|
80
|
+
}>;
|
|
81
|
+
interface ToolbarItemProps {
|
|
82
|
+
/** The item's id: `{ custom: id }` in the layout. */
|
|
83
|
+
id: string;
|
|
84
|
+
}
|
|
85
|
+
/** Your component in the toolbar, where the layout's `{ custom: id }` makes room for it. */
|
|
86
|
+
declare const ToolbarItem: import("vue").DefineSetupFnComponent<ToolbarItemProps, {}, DefaultSlot, ToolbarItemProps & {}, import("vue").PublicProps>;
|
|
87
|
+
/**
|
|
88
|
+
* Where the toolbar item this component is in sits, as a reactive object: which way its bar
|
|
89
|
+
* runs (`orientation`), the bar's place (`edge`), which of the item's `variants` the toolbar
|
|
90
|
+
* picked (`variant`), and the viewer's size (`size`). Works inside a `ToolbarItem`.
|
|
91
|
+
*/
|
|
92
|
+
declare function useToolbarItem(): Readonly<ToolbarItemContext>;
|
|
93
|
+
interface PanelProps {
|
|
94
|
+
/** The panel's id, as `addPanel(id, …)` names it in the layout. */
|
|
95
|
+
id: string;
|
|
96
|
+
}
|
|
97
|
+
/** What goes inside a panel: the viewer draws its frame, header and the way it opens. */
|
|
98
|
+
declare const Panel: import("vue").DefineSetupFnComponent<PanelProps, {}, DefaultSlot, PanelProps & {}, import("vue").PublicProps>;
|
|
99
|
+
/**
|
|
100
|
+
* A place around the viewer for your own components: `header` above everything, `footer` below
|
|
101
|
+
* everything, `tabs` in place of the document tabs, `empty` over the pages while no document is
|
|
102
|
+
* open.
|
|
103
|
+
*/
|
|
104
|
+
type RegionName = 'header' | 'footer' | 'tabs' | 'empty';
|
|
105
|
+
interface RegionProps {
|
|
106
|
+
name: RegionName;
|
|
107
|
+
}
|
|
108
|
+
/** Your component in one of the viewer's regions. */
|
|
109
|
+
declare const Region: import("vue").DefineSetupFnComponent<RegionProps, {}, DefaultSlot, RegionProps & {}, import("vue").PublicProps>;
|
|
110
|
+
//#endregion
|
|
111
|
+
//#region src/viewer-components.d.ts
|
|
112
|
+
interface ButtonProps {
|
|
113
|
+
/** Makes it this command's button: its icon, tooltip and state, and it runs it. */
|
|
114
|
+
command?: string;
|
|
115
|
+
/** An icon by name, the viewer's or yours, for a button of your own. */
|
|
116
|
+
icon?: string;
|
|
117
|
+
/** The name of a button of your own, for its tooltip and screen readers. */
|
|
118
|
+
label?: string;
|
|
119
|
+
}
|
|
120
|
+
/** A toolbar button, the viewer's own. `@click` for a button of your own. */
|
|
121
|
+
declare const Button: import("vue").DefineSetupFnComponent<ButtonProps, {
|
|
122
|
+
click: (event: MouseEvent) => true;
|
|
123
|
+
}, {}, ButtonProps & {
|
|
124
|
+
onClick?: ((event: MouseEvent) => any) | undefined;
|
|
125
|
+
}, import("vue").PublicProps>;
|
|
126
|
+
interface MenuProps {
|
|
127
|
+
/** The icon of the button that opens it, by name. */
|
|
128
|
+
icon?: string;
|
|
129
|
+
/** Its name, for the button's tooltip and screen readers. */
|
|
130
|
+
label: string;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* A button that opens a menu of `MenuItem`s, the way the viewer's menus open: away from its bar,
|
|
134
|
+
* flipped when there's no room, and up from the bottom on a phone. Its rows go in its slot.
|
|
135
|
+
*/
|
|
136
|
+
declare const Menu: import("vue").DefineSetupFnComponent<MenuProps, {}, SlotsType<{
|
|
137
|
+
default?: () => VNode[];
|
|
138
|
+
}>, MenuProps & {}, import("vue").PublicProps>;
|
|
139
|
+
interface MenuItemProps {
|
|
140
|
+
/** Makes it this command's row: its icon, label and state, and picking it runs it. */
|
|
141
|
+
command?: string;
|
|
142
|
+
/** An icon by name, the viewer's or yours. */
|
|
143
|
+
icon?: string;
|
|
144
|
+
}
|
|
145
|
+
/** A row in a `Menu`, with its text in its slot. `@select` when the row is picked. */
|
|
146
|
+
declare const MenuItem: import("vue").DefineSetupFnComponent<MenuItemProps, {
|
|
147
|
+
select: () => true;
|
|
148
|
+
}, SlotsType<{
|
|
149
|
+
default?: () => VNode[];
|
|
150
|
+
}>, MenuItemProps & {
|
|
151
|
+
onSelect?: (() => any) | undefined;
|
|
152
|
+
}, import("vue").PublicProps>;
|
|
153
|
+
//#endregion
|
|
154
|
+
export { PDF_VIEWER_OPTIONS as C, PDFViewerSlots as S, PDFViewerComponent as _, MenuItemProps as a, PDFViewerImplProps as b, PanelProps as c, RegionProps as d, ToolbarItem as f, usePDFViewer as g, useCommand as h, MenuItem as i, Region as l, useToolbarItem as m, ButtonProps as n, MenuProps as o, ToolbarItemProps as p, Menu as r, Panel as s, Button as t, RegionName as u, PDFViewerEmits as v, setupPDFViewer as w, PDFViewerPropsOf as x, PDFViewerExposed as y };
|
|
155
|
+
//# sourceMappingURL=parts-BD781tPE.d.cts.map
|
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
let vue = require("vue");
|
|
2
|
+
let _embedpdf_vue_runtime = require("@embedpdf/vue/runtime");
|
|
3
|
+
require("@embedpdf/vue/commands");
|
|
4
|
+
//#region src/composables.ts
|
|
5
|
+
/** The `viewer` the components inside a <PDFViewer> belong to. */
|
|
6
|
+
const ViewerKey = Symbol("embedpdf full viewer");
|
|
7
|
+
/**
|
|
8
|
+
* The `viewer`, in a component inside <PDFViewer>: `get(name)`, `documents`, `commands`,
|
|
9
|
+
* `watch` and `forDocument`. Your components mount once the viewer is live, so it is always
|
|
10
|
+
* there. Outside the viewer, keep the one `@ready` gives you; called there, this throws.
|
|
11
|
+
*/
|
|
12
|
+
function usePDFViewer() {
|
|
13
|
+
const viewer = (0, vue.inject)(ViewerKey, null);
|
|
14
|
+
if (!viewer) throw new Error("[embedpdf] usePDFViewer() works in a component inside <PDFViewer>. Outside the viewer, keep the viewer its @ready event gives you.");
|
|
15
|
+
return viewer;
|
|
16
|
+
}
|
|
17
|
+
/** The options each entry defines <PDFViewer> with, next to {@link setupPDFViewer}. */
|
|
18
|
+
const PDF_VIEWER_OPTIONS = {
|
|
19
|
+
name: "PDFViewer",
|
|
20
|
+
props: {
|
|
21
|
+
src: null,
|
|
22
|
+
documents: null,
|
|
23
|
+
engine: null,
|
|
24
|
+
commands: null,
|
|
25
|
+
icons: null,
|
|
26
|
+
strings: null,
|
|
27
|
+
locale: null,
|
|
28
|
+
disable: null,
|
|
29
|
+
readOnly: {
|
|
30
|
+
type: [Boolean, Object],
|
|
31
|
+
default: void 0
|
|
32
|
+
},
|
|
33
|
+
scope: null,
|
|
34
|
+
identity: null,
|
|
35
|
+
notAllowed: null,
|
|
36
|
+
layout: null,
|
|
37
|
+
plugins: null,
|
|
38
|
+
theme: null
|
|
39
|
+
},
|
|
40
|
+
emits: [
|
|
41
|
+
"ready",
|
|
42
|
+
"document-change",
|
|
43
|
+
"panel-resize"
|
|
44
|
+
]
|
|
45
|
+
};
|
|
46
|
+
/** Where the viewer keeps its kernel (`createViewer` in `@embedpdf/viewer-chrome`). */
|
|
47
|
+
const VIEWER_KERNEL = Symbol.for("@embedpdf/viewer/kernel");
|
|
48
|
+
const kernelOf = (viewer) => viewer[VIEWER_KERNEL] ?? null;
|
|
49
|
+
/** A key for each viewer, so the children mount again inside a new one. */
|
|
50
|
+
const viewerKeys = /* @__PURE__ */ new WeakMap();
|
|
51
|
+
let nextViewerKey = 0;
|
|
52
|
+
const keyOf = (viewer) => {
|
|
53
|
+
let key = viewerKeys.get(viewer);
|
|
54
|
+
if (key === void 0) viewerKeys.set(viewer, key = nextViewerKey++);
|
|
55
|
+
return key;
|
|
56
|
+
};
|
|
57
|
+
/** The children inside the viewer: its kernel for the headless composables, and the `viewer`. */
|
|
58
|
+
const InViewer = (0, vue.defineComponent)((props, { slots }) => {
|
|
59
|
+
(0, vue.provide)(ViewerKey, props.viewer);
|
|
60
|
+
const kernel = kernelOf(props.viewer);
|
|
61
|
+
return () => kernel ? (0, vue.h)(_embedpdf_vue_runtime.KernelProvider, { kernel }, slots) : slots.default?.();
|
|
62
|
+
}, {
|
|
63
|
+
name: "InViewer",
|
|
64
|
+
props: ["viewer"]
|
|
65
|
+
});
|
|
66
|
+
/** The props the element follows while it runs; the component hands their changes on. */
|
|
67
|
+
const LIVE_PROPS = {
|
|
68
|
+
src: true,
|
|
69
|
+
theme: true,
|
|
70
|
+
locale: true,
|
|
71
|
+
disable: true,
|
|
72
|
+
readOnly: true
|
|
73
|
+
};
|
|
74
|
+
/** The config as the props give it, each value raw: a reactive copy is another object. */
|
|
75
|
+
function rawConfigOf(props) {
|
|
76
|
+
const config = { ...props };
|
|
77
|
+
for (const key in config) config[key] = (0, vue.toRaw)(config[key]);
|
|
78
|
+
return config;
|
|
79
|
+
}
|
|
80
|
+
/** Every other prop is read once: a changed one is ignored, and development warns once. */
|
|
81
|
+
function warnReadOnceChanges(props) {
|
|
82
|
+
const initial = { ...props };
|
|
83
|
+
const keys = Object.keys(initial);
|
|
84
|
+
const stop = (0, vue.watch)(() => keys.find((key) => !(key in LIVE_PROPS) && !Object.is(props[key], initial[key])), (key) => {
|
|
85
|
+
if (key === void 0) return;
|
|
86
|
+
console.warn(`[embedpdf] <PDFViewer>: \`${key}\` is read once, when the viewer starts, so the change is ignored. Pass a stable value (module scope, a const in <script setup>, a shallowRef), or give the viewer a new \`key\` to mount a new one with it.`);
|
|
87
|
+
stop();
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* The shared setup. Each entry defines <PDFViewer> from it, typed with its door's config: see
|
|
92
|
+
* `PDFViewer` in ./index.ts (engine optional) and ./core.ts (engine required).
|
|
93
|
+
*/
|
|
94
|
+
function setupPDFViewer(props, { emit, slots, expose }) {
|
|
95
|
+
const element = (0, vue.shallowRef)(null);
|
|
96
|
+
const viewer = (0, vue.shallowRef)(null);
|
|
97
|
+
expose({ elementRef: element });
|
|
98
|
+
if (process.env.NODE_ENV !== "production") warnReadOnceChanges(props);
|
|
99
|
+
const callbacks = {
|
|
100
|
+
onReady: (ready) => emit("ready", ready),
|
|
101
|
+
onDocumentChange: (documentId) => emit("document-change", documentId),
|
|
102
|
+
onPanelResize: (event) => emit("panel-resize", event)
|
|
103
|
+
};
|
|
104
|
+
let stopListening = null;
|
|
105
|
+
(0, vue.onMounted)(() => {
|
|
106
|
+
const target = element.value;
|
|
107
|
+
const onReady = () => viewer.value = target.viewer;
|
|
108
|
+
target.addEventListener("epdf:ready", onReady);
|
|
109
|
+
stopListening = () => target.removeEventListener("epdf:ready", onReady);
|
|
110
|
+
target.config = {
|
|
111
|
+
...rawConfigOf(props),
|
|
112
|
+
...callbacks
|
|
113
|
+
};
|
|
114
|
+
if (target.viewer) onReady();
|
|
115
|
+
});
|
|
116
|
+
(0, vue.onBeforeUnmount)(() => stopListening?.());
|
|
117
|
+
(0, vue.watch)(() => [
|
|
118
|
+
props.src,
|
|
119
|
+
props.theme,
|
|
120
|
+
props.locale,
|
|
121
|
+
props.disable,
|
|
122
|
+
props.readOnly
|
|
123
|
+
], () => {
|
|
124
|
+
const target = element.value;
|
|
125
|
+
if (!target) return;
|
|
126
|
+
target.src = (0, vue.toRaw)(props.src);
|
|
127
|
+
target.theme = (0, vue.toRaw)(props.theme);
|
|
128
|
+
target.locale = props.locale;
|
|
129
|
+
target.disable = (0, vue.toRaw)(props.disable);
|
|
130
|
+
target.readOnly = (0, vue.toRaw)(props.readOnly);
|
|
131
|
+
});
|
|
132
|
+
return () => (0, vue.h)("embedpdf-viewer", {
|
|
133
|
+
ref: element,
|
|
134
|
+
"data-epdf-wrapped": ""
|
|
135
|
+
}, viewer.value ? [(0, vue.h)(InViewer, {
|
|
136
|
+
key: keyOf(viewer.value),
|
|
137
|
+
viewer: viewer.value
|
|
138
|
+
}, slots)] : []);
|
|
139
|
+
}
|
|
140
|
+
//#endregion
|
|
141
|
+
//#region src/slots.ts
|
|
142
|
+
/** The element around what you put in a place adds no box: your component lays out there. */
|
|
143
|
+
const CONTENTS = { display: "contents" };
|
|
144
|
+
const EDGES = [
|
|
145
|
+
"top",
|
|
146
|
+
"bottom",
|
|
147
|
+
"start",
|
|
148
|
+
"end",
|
|
149
|
+
"float",
|
|
150
|
+
"selection"
|
|
151
|
+
];
|
|
152
|
+
const SIZES = [
|
|
153
|
+
"compact",
|
|
154
|
+
"medium",
|
|
155
|
+
"expanded"
|
|
156
|
+
];
|
|
157
|
+
/** Before the viewer says where the item is: the main bar's place. */
|
|
158
|
+
const AT_THE_TOP = {
|
|
159
|
+
orientation: "horizontal",
|
|
160
|
+
edge: "top",
|
|
161
|
+
variant: null,
|
|
162
|
+
size: "expanded"
|
|
163
|
+
};
|
|
164
|
+
const ATTRIBUTES = [
|
|
165
|
+
"data-orientation",
|
|
166
|
+
"data-edge",
|
|
167
|
+
"data-variant",
|
|
168
|
+
"data-size"
|
|
169
|
+
];
|
|
170
|
+
/** Where the item whose element is `element` sits, as the viewer wrote it there. */
|
|
171
|
+
function toolbarItemContextOf(element) {
|
|
172
|
+
const edge = element.getAttribute("data-edge");
|
|
173
|
+
const size = element.getAttribute("data-size");
|
|
174
|
+
return {
|
|
175
|
+
orientation: element.getAttribute("data-orientation") === "vertical" ? "vertical" : "horizontal",
|
|
176
|
+
edge: edge && EDGES.includes(edge) ? edge : AT_THE_TOP.edge,
|
|
177
|
+
variant: element.getAttribute("data-variant"),
|
|
178
|
+
size: size && SIZES.includes(size) ? size : AT_THE_TOP.size
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
const ToolbarItemKey = Symbol("embedpdf toolbar item");
|
|
182
|
+
/** Your component in the toolbar, where the layout's `{ custom: id }` makes room for it. */
|
|
183
|
+
const ToolbarItem = (0, vue.defineComponent)((props, { slots }) => {
|
|
184
|
+
const element = (0, vue.shallowRef)(null);
|
|
185
|
+
const context = (0, vue.shallowReactive)({ ...AT_THE_TOP });
|
|
186
|
+
(0, vue.provide)(ToolbarItemKey, (0, vue.shallowReadonly)(context));
|
|
187
|
+
let observer = null;
|
|
188
|
+
(0, vue.onMounted)(() => {
|
|
189
|
+
const target = element.value;
|
|
190
|
+
const read = () => Object.assign(context, toolbarItemContextOf(target));
|
|
191
|
+
read();
|
|
192
|
+
observer = new MutationObserver(read);
|
|
193
|
+
observer.observe(target, {
|
|
194
|
+
attributes: true,
|
|
195
|
+
attributeFilter: ATTRIBUTES
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
(0, vue.onBeforeUnmount)(() => observer?.disconnect());
|
|
199
|
+
return () => (0, vue.h)("div", {
|
|
200
|
+
ref: element,
|
|
201
|
+
slot: `item:${props.id}`,
|
|
202
|
+
style: CONTENTS
|
|
203
|
+
}, slots.default?.());
|
|
204
|
+
}, {
|
|
205
|
+
name: "ToolbarItem",
|
|
206
|
+
props: ["id"],
|
|
207
|
+
slots: Object
|
|
208
|
+
});
|
|
209
|
+
/**
|
|
210
|
+
* Where the toolbar item this component is in sits, as a reactive object: which way its bar
|
|
211
|
+
* runs (`orientation`), the bar's place (`edge`), which of the item's `variants` the toolbar
|
|
212
|
+
* picked (`variant`), and the viewer's size (`size`). Works inside a `ToolbarItem`.
|
|
213
|
+
*/
|
|
214
|
+
function useToolbarItem() {
|
|
215
|
+
const context = (0, vue.inject)(ToolbarItemKey, null);
|
|
216
|
+
if (!context) throw new Error("[embedpdf] useToolbarItem() works inside a <ToolbarItem>: it says where that item sits.");
|
|
217
|
+
return context;
|
|
218
|
+
}
|
|
219
|
+
/** What goes inside a panel: the viewer draws its frame, header and the way it opens. */
|
|
220
|
+
const Panel = (0, vue.defineComponent)((props, { slots }) => () => (0, vue.h)("div", {
|
|
221
|
+
slot: `panel:${props.id}`,
|
|
222
|
+
style: CONTENTS
|
|
223
|
+
}, slots.default?.()), {
|
|
224
|
+
name: "Panel",
|
|
225
|
+
props: ["id"],
|
|
226
|
+
slots: Object
|
|
227
|
+
});
|
|
228
|
+
/** Your component in one of the viewer's regions. */
|
|
229
|
+
const Region = (0, vue.defineComponent)((props, { slots }) => () => (0, vue.h)("div", {
|
|
230
|
+
slot: props.name,
|
|
231
|
+
style: CONTENTS
|
|
232
|
+
}, slots.default?.()), {
|
|
233
|
+
name: "Region",
|
|
234
|
+
props: ["name"],
|
|
235
|
+
slots: Object
|
|
236
|
+
});
|
|
237
|
+
//#endregion
|
|
238
|
+
//#region src/viewer-components.ts
|
|
239
|
+
/**
|
|
240
|
+
* The viewer's own components, for yours: `Button`, `Menu` and `MenuItem`
|
|
241
|
+
* render the viewer's `<epdf-button>`, `<epdf-menu>` and `<epdf-menu-item>`
|
|
242
|
+
* elements, which the viewer draws like its own toolbar buttons and menus.
|
|
243
|
+
* Use them inside the viewer: in a `ToolbarItem`, a `Panel` or a `Region`.
|
|
244
|
+
* The elements come with the viewer, so this module imports nothing from it.
|
|
245
|
+
*/
|
|
246
|
+
/**
|
|
247
|
+
* The attributes that have a value. Vue sets an element's property where it has one, and the
|
|
248
|
+
* elements' properties write `undefined` as the text "undefined".
|
|
249
|
+
*/
|
|
250
|
+
const given = (attributes) => Object.fromEntries(Object.entries(attributes).filter((entry) => entry[1] !== void 0));
|
|
251
|
+
/** A toolbar button, the viewer's own. `@click` for a button of your own. */
|
|
252
|
+
const Button = (0, vue.defineComponent)((props, { emit }) => () => (0, vue.h)("epdf-button", {
|
|
253
|
+
...given({
|
|
254
|
+
command: props.command,
|
|
255
|
+
icon: props.icon,
|
|
256
|
+
label: props.label
|
|
257
|
+
}),
|
|
258
|
+
onClick: (event) => emit("click", event)
|
|
259
|
+
}), {
|
|
260
|
+
name: "Button",
|
|
261
|
+
props: [
|
|
262
|
+
"command",
|
|
263
|
+
"icon",
|
|
264
|
+
"label"
|
|
265
|
+
],
|
|
266
|
+
emits: ["click"]
|
|
267
|
+
});
|
|
268
|
+
/**
|
|
269
|
+
* A button that opens a menu of `MenuItem`s, the way the viewer's menus open: away from its bar,
|
|
270
|
+
* flipped when there's no room, and up from the bottom on a phone. Its rows go in its slot.
|
|
271
|
+
*/
|
|
272
|
+
const Menu = (0, vue.defineComponent)((props, { slots }) => () => (0, vue.h)("epdf-menu", given({
|
|
273
|
+
icon: props.icon,
|
|
274
|
+
label: props.label
|
|
275
|
+
}), slots.default?.()), {
|
|
276
|
+
name: "Menu",
|
|
277
|
+
props: ["icon", "label"],
|
|
278
|
+
slots: Object
|
|
279
|
+
});
|
|
280
|
+
/** A row in a `Menu`, with its text in its slot. `@select` when the row is picked. */
|
|
281
|
+
const MenuItem = (0, vue.defineComponent)((props, { emit, slots }) => () => (0, vue.h)("epdf-menu-item", {
|
|
282
|
+
...given({
|
|
283
|
+
command: props.command,
|
|
284
|
+
icon: props.icon
|
|
285
|
+
}),
|
|
286
|
+
onSelect: () => emit("select")
|
|
287
|
+
}, slots.default?.()), {
|
|
288
|
+
name: "MenuItem",
|
|
289
|
+
props: ["command", "icon"],
|
|
290
|
+
emits: ["select"]
|
|
291
|
+
});
|
|
292
|
+
//#endregion
|
|
293
|
+
Object.defineProperty(exports, "Button", {
|
|
294
|
+
enumerable: true,
|
|
295
|
+
get: function() {
|
|
296
|
+
return Button;
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
Object.defineProperty(exports, "Menu", {
|
|
300
|
+
enumerable: true,
|
|
301
|
+
get: function() {
|
|
302
|
+
return Menu;
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
Object.defineProperty(exports, "MenuItem", {
|
|
306
|
+
enumerable: true,
|
|
307
|
+
get: function() {
|
|
308
|
+
return MenuItem;
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
Object.defineProperty(exports, "PDF_VIEWER_OPTIONS", {
|
|
312
|
+
enumerable: true,
|
|
313
|
+
get: function() {
|
|
314
|
+
return PDF_VIEWER_OPTIONS;
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
Object.defineProperty(exports, "Panel", {
|
|
318
|
+
enumerable: true,
|
|
319
|
+
get: function() {
|
|
320
|
+
return Panel;
|
|
321
|
+
}
|
|
322
|
+
});
|
|
323
|
+
Object.defineProperty(exports, "Region", {
|
|
324
|
+
enumerable: true,
|
|
325
|
+
get: function() {
|
|
326
|
+
return Region;
|
|
327
|
+
}
|
|
328
|
+
});
|
|
329
|
+
Object.defineProperty(exports, "ToolbarItem", {
|
|
330
|
+
enumerable: true,
|
|
331
|
+
get: function() {
|
|
332
|
+
return ToolbarItem;
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
Object.defineProperty(exports, "setupPDFViewer", {
|
|
336
|
+
enumerable: true,
|
|
337
|
+
get: function() {
|
|
338
|
+
return setupPDFViewer;
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
Object.defineProperty(exports, "usePDFViewer", {
|
|
342
|
+
enumerable: true,
|
|
343
|
+
get: function() {
|
|
344
|
+
return usePDFViewer;
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
Object.defineProperty(exports, "useToolbarItem", {
|
|
348
|
+
enumerable: true,
|
|
349
|
+
get: function() {
|
|
350
|
+
return useToolbarItem;
|
|
351
|
+
}
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
//# sourceMappingURL=parts-BLlgtdE3.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parts-BLlgtdE3.cjs","names":["KernelProvider"],"sources":["../src/composables.ts","../src/component.ts","../src/slots.ts","../src/viewer-components.ts"],"sourcesContent":["/**\n * The composables for components inside <PDFViewer>: the `viewer`, and a command as a button\n * needs it. They work in the components you give the viewer, which mount once it's live, inside\n * it. The headless composables of `@embedpdf/vue` work there too, for any plugin's API and state.\n */\n// Types only, so this module holds no runtime edge to any engine (see ./component).\nimport type { Viewer } from '@embedpdf/viewer/core';\nimport { inject, type InjectionKey } from 'vue';\n\n/**\n * A command as a button needs it, for the active document: its `label`, `icon` and `shortcut`,\n * whether it's `enabled`, `active` and `visible`, and `run()`, as a ref. The headless composable,\n * which reads the kernel <PDFViewer> gives its children: an id the viewer doesn't have is neither\n * visible nor enabled.\n */\nexport { useCommand } from '@embedpdf/vue/commands';\n\n/** The `viewer` the components inside a <PDFViewer> belong to. */\nexport const ViewerKey: InjectionKey<Viewer> = Symbol('embedpdf full viewer');\n\n/**\n * The `viewer`, in a component inside <PDFViewer>: `get(name)`, `documents`, `commands`,\n * `watch` and `forDocument`. Your components mount once the viewer is live, so it is always\n * there. Outside the viewer, keep the one `@ready` gives you; called there, this throws.\n */\nexport function usePDFViewer(): Viewer {\n const viewer = inject(ViewerKey, null);\n if (!viewer) {\n throw new Error(\n '[embedpdf] usePDFViewer() works in a component inside <PDFViewer>. Outside the viewer, ' +\n 'keep the viewer its @ready event gives you.',\n );\n }\n return viewer;\n}\n","/**\n * <PDFViewer>: the Vue face of the <embedpdf-viewer> custom element, and\n * engine-blind on purpose: this module imports the viewer for types only, so it\n * holds no runtime edge to any engine. Which engine ships is decided by the\n * entry that defines the component:\n *\n * ./index.ts → `@embedpdf/viewer` — the local PDFium engine, registered as\n * the default (the zero-config door)\n * ./core.ts → `@embedpdf/viewer/core` — no default engine; you pass one,\n * and PDFium is not in the module graph\n *\n * ```vue\n * <PDFViewer src=\"/report.pdf\" style=\"height: 100vh\">\n * <ToolbarItem id=\"doc-picker\"><DocPicker /></ToolbarItem> <!-- slot=\"item:doc-picker\" -->\n * </PDFViewer>\n * ```\n *\n * It renders the custom element, hands it the config before its deferred first\n * mount, and renders its slot as the element's light-DOM children: the browser\n * shows a child with `slot=\"item:<id>\"` in the viewer's matching place while\n * the child stays in the app's component tree, so what it injects, its state and\n * the page's CSS keep working. The children mount once the viewer is ready,\n * inside its kernel, so the headless composables of `@embedpdf/vue` in them\n * read this viewer, and `usePDFViewer()` gives them its `viewer`. When the\n * viewer goes they unmount with it, and mount again inside the next one.\n *\n * On the server it renders the empty element, and the viewer starts in the\n * browser: nothing here, or in the viewer it imports, touches the DOM when\n * imported.\n *\n * Every config key is a prop, and `v-bind=\"config\"` passes a whole config.\n * `src`, `theme`, `locale`, `disable` and `readOnly` follow their props: the\n * element changes them in place. The callbacks are events (`@ready`,\n * `@document-change`, `@panel-resize`), so they reach the handler the app gives\n * now. Every other prop is read once, when the viewer starts; a later change is\n * ignored (development warns), and a new `key` mounts a new viewer with it.\n * `class`, `style` and other attributes go on the element.\n */\n// `ElementConfig` is the kernel's config, the widest of all, with the engine seam left `unknown`:\n// the setup below takes it, so each entry defines the component with its own, narrower config and\n// passes the setup as it is (parameter types are contravariant, so this direction needs no cast).\n// Every import from the viewer is type-only, which keeps this module engine-blind.\nimport type {\n ElementConfig,\n EmbedPdfViewerElement,\n LiveConfigKey,\n PanelResizeEvent,\n Viewer,\n} from '@embedpdf/viewer/core';\n// The headless runtime carries no engine: it gives the children the viewer's kernel.\nimport { KernelProvider, type Kernel } from '@embedpdf/vue/runtime';\nimport {\n defineComponent,\n h,\n onBeforeUnmount,\n onMounted,\n provide,\n shallowRef,\n toRaw,\n watch,\n type ComponentOptionsMixin,\n type CreateComponentPublicInstanceWithMixins,\n type EmitsToProps,\n type PublicProps,\n type SetupContext,\n type SlotsType,\n type VNode,\n} from 'vue';\n\nimport { ViewerKey } from './composables';\n\n/** The config keys the viewer calls back with: events here. */\ntype CallbackKey = 'onReady' | 'onDocumentChange' | 'onPanelResize';\n\n/** A door's config as props: every key but the callbacks, which are events. */\nexport type PDFViewerPropsOf<Config extends object> = Omit<Config, CallbackKey>;\n\n/** The props of the shared setup: the kernel's config, the widest. */\nexport type PDFViewerImplProps = PDFViewerPropsOf<ElementConfig>;\n\n/** The events: the config's callbacks, by their Vue names. */\nexport type PDFViewerEmits = {\n /** The viewer is live, before any document has opened: its `viewer`, for code outside it. */\n ready: (viewer: Viewer) => true;\n /**\n * The document that's showing: the first one, each one the user switches to, and `null` once\n * the last one closes.\n */\n 'document-change': (documentId: string | null) => true;\n /** The user resized a panel: its id and new width in px. */\n 'panel-resize': (event: PanelResizeEvent) => true;\n};\n\n/** Your components, shown where their slot says: `<ToolbarItem>`, `<Panel>`, `<Region>`. */\nexport type PDFViewerSlots = SlotsType<{ default?: () => VNode[] }>;\n\n/** What a template ref on <PDFViewer> reads. */\nexport interface PDFViewerExposed {\n /** The `<embedpdf-viewer>` element, for its imperative surface; null before it mounts. */\n readonly elementRef: EmbedPdfViewerElement | null;\n}\n\n/**\n * <PDFViewer> typed with a door's props. Vue's own type for a component made from a setup\n * function says nothing of what it exposes, so this one adds what a template ref reads.\n */\nexport type PDFViewerComponent<Props> = new (\n props: Props & EmitsToProps<PDFViewerEmits> & PublicProps,\n) => CreateComponentPublicInstanceWithMixins<\n Props & EmitsToProps<PDFViewerEmits>,\n PDFViewerExposed,\n {},\n {},\n {},\n ComponentOptionsMixin,\n ComponentOptionsMixin,\n PDFViewerEmits,\n PublicProps,\n {},\n false,\n {},\n PDFViewerSlots\n>;\n\n/**\n * Every config key, as a prop (TypeScript keeps the list complete). `null` takes any value, which\n * the viewer checks itself; `readOnly` written without a value is `true`, as for any boolean prop\n * (`<PDFViewer read-only />`).\n */\nconst CONFIG_PROPS = {\n src: null,\n documents: null,\n engine: null,\n commands: null,\n icons: null,\n strings: null,\n locale: null,\n disable: null,\n readOnly: { type: [Boolean, Object], default: undefined },\n scope: null,\n identity: null,\n notAllowed: null,\n layout: null,\n plugins: null,\n theme: null,\n} satisfies Record<keyof PDFViewerImplProps, unknown>;\n\n/** The options each entry defines <PDFViewer> with, next to {@link setupPDFViewer}. */\nexport const PDF_VIEWER_OPTIONS = {\n name: 'PDFViewer',\n props: CONFIG_PROPS,\n emits: ['ready', 'document-change', 'panel-resize'],\n};\n\n/** Where the viewer keeps its kernel (`createViewer` in `@embedpdf/viewer-chrome`). */\nconst VIEWER_KERNEL = Symbol.for('@embedpdf/viewer/kernel');\nconst kernelOf = (viewer: Viewer): Kernel | null =>\n (viewer as unknown as Partial<Record<symbol, Kernel>>)[VIEWER_KERNEL] ?? null;\n\n/** A key for each viewer, so the children mount again inside a new one. */\nconst viewerKeys = new WeakMap<Viewer, number>();\nlet nextViewerKey = 0;\nconst keyOf = (viewer: Viewer): number => {\n let key = viewerKeys.get(viewer);\n if (key === undefined) viewerKeys.set(viewer, (key = nextViewerKey++));\n return key;\n};\n\n/** The children inside the viewer: its kernel for the headless composables, and the `viewer`. */\nconst InViewer = defineComponent(\n (props: { viewer: Viewer }, { slots }) => {\n provide(ViewerKey, props.viewer);\n const kernel = kernelOf(props.viewer);\n return () => (kernel ? h(KernelProvider, { kernel }, slots) : slots.default?.());\n },\n { name: 'InViewer', props: ['viewer'] },\n);\n\n/** The props the element follows while it runs; the component hands their changes on. */\nconst LIVE_PROPS: Readonly<Record<LiveConfigKey, true>> = {\n src: true,\n theme: true,\n locale: true,\n disable: true,\n readOnly: true,\n};\n\n/** The config as the props give it, each value raw: a reactive copy is another object. */\nfunction rawConfigOf<Config extends object>(props: Config): Config {\n const config = { ...props };\n for (const key in config) config[key] = toRaw(config[key]);\n return config;\n}\n\n/** Every other prop is read once: a changed one is ignored, and development warns once. */\nfunction warnReadOnceChanges(props: PDFViewerImplProps): void {\n const initial = { ...props };\n const keys = Object.keys(initial) as (keyof PDFViewerImplProps)[];\n const stop = watch(\n () => keys.find((key) => !(key in LIVE_PROPS) && !Object.is(props[key], initial[key])),\n (key) => {\n if (key === undefined) return;\n console.warn(\n `[embedpdf] <PDFViewer>: \\`${key}\\` is read once, when the viewer starts, so the change is ` +\n 'ignored. Pass a stable value (module scope, a const in <script setup>, a shallowRef), ' +\n 'or give the viewer a new `key` to mount a new one with it.',\n );\n stop();\n },\n );\n}\n\n/**\n * The shared setup. Each entry defines <PDFViewer> from it, typed with its door's config: see\n * `PDFViewer` in ./index.ts (engine optional) and ./core.ts (engine required).\n */\nexport function setupPDFViewer(\n props: PDFViewerImplProps,\n { emit, slots, expose }: SetupContext<PDFViewerEmits, PDFViewerSlots>,\n): () => VNode {\n const element = shallowRef<EmbedPdfViewerElement | null>(null);\n // The viewer once it's ready: the children render inside its kernel, so the headless\n // composables in them read this viewer. Before that the viewer has no places to show them in.\n const viewer = shallowRef<Viewer | null>(null);\n expose({ elementRef: element });\n\n // Read once, like <Viewer engine plugins>: the element boots once with the first config. A\n // later change to anything but the live props can't mean \"rebuild\" without dropping every\n // open document, so it is ignored, with a warning in development.\n if (process.env.NODE_ENV !== 'production') warnReadOnceChanges(props);\n\n // The callbacks reach the element once, as functions that emit: Vue calls the handler the app\n // gives at the time, so a new one each render changes nothing.\n const callbacks: Pick<ElementConfig, CallbackKey> = {\n onReady: (ready) => emit('ready', ready),\n onDocumentChange: (documentId) => emit('document-change', documentId),\n onPanelResize: (event) => emit('panel-resize', event),\n };\n\n let stopListening: (() => void) | null = null;\n // Mounted hooks run in the task the element was inserted in, before its deferred (microtask)\n // mount, so the viewer boots exactly once, with this config, and the ready listener is in place\n // before it can fire.\n onMounted(() => {\n const target = element.value!;\n // Each mount of the element brings a new viewer: the element taken out and put back.\n const onReady = () => (viewer.value = target.viewer);\n target.addEventListener('epdf:ready', onReady);\n stopListening = () => target.removeEventListener('epdf:ready', onReady);\n target.config = { ...rawConfigOf(props), ...callbacks };\n if (target.viewer) onReady();\n });\n onBeforeUnmount(() => stopListening?.());\n\n // The live props, on every change of one: the element compares them by value, so an unchanged\n // one (an inline `:disable=\"['forms']\"` too) changes nothing.\n watch(\n () => [props.src, props.theme, props.locale, props.disable, props.readOnly],\n () => {\n const target = element.value;\n if (!target) return;\n target.src = toRaw(props.src);\n target.theme = toRaw(props.theme);\n target.locale = props.locale;\n target.disable = toRaw(props.disable);\n target.readOnly = toRaw(props.readOnly);\n },\n );\n\n return () =>\n h(\n 'embedpdf-viewer',\n // The element waits for the config this sets, also over the server's HTML before hydration.\n { ref: element, 'data-epdf-wrapped': '' },\n viewer.value ? [h(InViewer, { key: keyOf(viewer.value), viewer: viewer.value }, slots)] : [],\n );\n}\n","/**\n * Your own components in the viewer: `ToolbarItem`, `Panel` and `Region` put\n * your component in the place the viewer makes for it (`item:<id>`,\n * `panel:<id>`, or a region's name). It renders as a child of the\n * `<embedpdf-viewer>` element, so it stays in your Vue app, with what it\n * provides and injects, your state and your CSS; the browser shows it in that\n * place.\n *\n * `useToolbarItem()` tells a component inside a `ToolbarItem` where it sits.\n * The viewer keeps that on the item's element as `data-orientation`,\n * `data-edge`, `data-variant` and `data-size`; `ToolbarItem` reads them, live,\n * into a reactive object, and Vue draws the change in the same task, before the\n * browser lays the bar out, so the toolbar measures your component in the\n * variant it picked. Types only from the viewer, as in `./component`: this\n * module is shared by both doors.\n */\nimport type { ToolbarItemContext, ToolbarItemEdge, ViewerSize } from '@embedpdf/viewer/core';\nimport {\n defineComponent,\n h,\n inject,\n onBeforeUnmount,\n onMounted,\n provide,\n shallowReactive,\n shallowReadonly,\n shallowRef,\n type InjectionKey,\n type SlotsType,\n type VNode,\n} from 'vue';\n\n/** The element around what you put in a place adds no box: your component lays out there. */\nconst CONTENTS = { display: 'contents' } as const;\n\n/** What a place holds: your components. */\ntype DefaultSlot = SlotsType<{ default?: () => VNode[] }>;\n\n// ── a toolbar item ───────────────────────────────────────────────────────────\n\nconst EDGES: readonly ToolbarItemEdge[] = ['top', 'bottom', 'start', 'end', 'float', 'selection'];\nconst SIZES: readonly ViewerSize[] = ['compact', 'medium', 'expanded'];\n\n/** Before the viewer says where the item is: the main bar's place. */\nconst AT_THE_TOP: ToolbarItemContext = {\n orientation: 'horizontal',\n edge: 'top',\n variant: null,\n size: 'expanded',\n};\n\nconst ATTRIBUTES = ['data-orientation', 'data-edge', 'data-variant', 'data-size'];\n\n/** Where the item whose element is `element` sits, as the viewer wrote it there. */\nfunction toolbarItemContextOf(element: Element): ToolbarItemContext {\n const edge = element.getAttribute('data-edge') as ToolbarItemEdge | null;\n const size = element.getAttribute('data-size') as ViewerSize | null;\n return {\n orientation:\n element.getAttribute('data-orientation') === 'vertical' ? 'vertical' : 'horizontal',\n edge: edge && EDGES.includes(edge) ? edge : AT_THE_TOP.edge,\n variant: element.getAttribute('data-variant'),\n size: size && SIZES.includes(size) ? size : AT_THE_TOP.size,\n };\n}\n\nconst ToolbarItemKey: InjectionKey<Readonly<ToolbarItemContext>> = Symbol('embedpdf toolbar item');\n\nexport interface ToolbarItemProps {\n /** The item's id: `{ custom: id }` in the layout. */\n id: string;\n}\n\n/** Your component in the toolbar, where the layout's `{ custom: id }` makes room for it. */\nexport const ToolbarItem = defineComponent(\n (props: ToolbarItemProps, { slots }) => {\n const element = shallowRef<HTMLDivElement | null>(null);\n // One field each, so a component reading only `orientation` draws again only when it changes.\n const context = shallowReactive<ToolbarItemContext>({ ...AT_THE_TOP });\n provide(ToolbarItemKey, shallowReadonly(context));\n\n let observer: MutationObserver | null = null;\n onMounted(() => {\n const target = element.value!;\n // A field set to the value it has changes nothing, so only what the viewer changed redraws.\n const read = () => Object.assign(context, toolbarItemContextOf(target));\n read();\n observer = new MutationObserver(read);\n observer.observe(target, { attributes: true, attributeFilter: ATTRIBUTES });\n });\n onBeforeUnmount(() => observer?.disconnect());\n\n return () =>\n h('div', { ref: element, slot: `item:${props.id}`, style: CONTENTS }, slots.default?.());\n },\n { name: 'ToolbarItem', props: ['id'], slots: Object as DefaultSlot },\n);\n\n/**\n * Where the toolbar item this component is in sits, as a reactive object: which way its bar\n * runs (`orientation`), the bar's place (`edge`), which of the item's `variants` the toolbar\n * picked (`variant`), and the viewer's size (`size`). Works inside a `ToolbarItem`.\n */\nexport function useToolbarItem(): Readonly<ToolbarItemContext> {\n const context = inject(ToolbarItemKey, null);\n if (!context) {\n throw new Error(\n '[embedpdf] useToolbarItem() works inside a <ToolbarItem>: it says where that item sits.',\n );\n }\n return context;\n}\n\n// ── a panel, a region ────────────────────────────────────────────────────────\n\nexport interface PanelProps {\n /** The panel's id, as `addPanel(id, …)` names it in the layout. */\n id: string;\n}\n\n/** What goes inside a panel: the viewer draws its frame, header and the way it opens. */\nexport const Panel = defineComponent(\n (props: PanelProps, { slots }) =>\n () =>\n h('div', { slot: `panel:${props.id}`, style: CONTENTS }, slots.default?.()),\n { name: 'Panel', props: ['id'], slots: Object as DefaultSlot },\n);\n\n/**\n * A place around the viewer for your own components: `header` above everything, `footer` below\n * everything, `tabs` in place of the document tabs, `empty` over the pages while no document is\n * open.\n */\nexport type RegionName = 'header' | 'footer' | 'tabs' | 'empty';\n\nexport interface RegionProps {\n name: RegionName;\n}\n\n/** Your component in one of the viewer's regions. */\nexport const Region = defineComponent(\n (props: RegionProps, { slots }) =>\n () =>\n h('div', { slot: props.name, style: CONTENTS }, slots.default?.()),\n { name: 'Region', props: ['name'], slots: Object as DefaultSlot },\n);\n","/**\n * The viewer's own components, for yours: `Button`, `Menu` and `MenuItem`\n * render the viewer's `<epdf-button>`, `<epdf-menu>` and `<epdf-menu-item>`\n * elements, which the viewer draws like its own toolbar buttons and menus.\n * Use them inside the viewer: in a `ToolbarItem`, a `Panel` or a `Region`.\n * The elements come with the viewer, so this module imports nothing from it.\n */\nimport { defineComponent, h, type SlotsType, type VNode } from 'vue';\n\n/**\n * The attributes that have a value. Vue sets an element's property where it has one, and the\n * elements' properties write `undefined` as the text \"undefined\".\n */\nconst given = (attributes: Readonly<Record<string, string | undefined>>): Record<string, string> =>\n Object.fromEntries(\n Object.entries(attributes).filter((entry): entry is [string, string] => entry[1] !== undefined),\n );\n\nexport interface ButtonProps {\n /** Makes it this command's button: its icon, tooltip and state, and it runs it. */\n command?: string;\n /** An icon by name, the viewer's or yours, for a button of your own. */\n icon?: string;\n /** The name of a button of your own, for its tooltip and screen readers. */\n label?: string;\n}\n\n/** A toolbar button, the viewer's own. `@click` for a button of your own. */\nexport const Button = defineComponent<ButtonProps, { click: (event: MouseEvent) => true }>(\n (props, { emit }) =>\n () =>\n h('epdf-button', {\n ...given({ command: props.command, icon: props.icon, label: props.label }),\n onClick: (event: MouseEvent) => emit('click', event),\n }),\n { name: 'Button', props: ['command', 'icon', 'label'], emits: ['click'] },\n);\n\nexport interface MenuProps {\n /** The icon of the button that opens it, by name. */\n icon?: string;\n /** Its name, for the button's tooltip and screen readers. */\n label: string;\n}\n\n/**\n * A button that opens a menu of `MenuItem`s, the way the viewer's menus open: away from its bar,\n * flipped when there's no room, and up from the bottom on a phone. Its rows go in its slot.\n */\nexport const Menu = defineComponent(\n (props: MenuProps, { slots }) =>\n () =>\n h('epdf-menu', given({ icon: props.icon, label: props.label }), slots.default?.()),\n {\n name: 'Menu',\n props: ['icon', 'label'],\n slots: Object as SlotsType<{ default?: () => VNode[] }>,\n },\n);\n\nexport interface MenuItemProps {\n /** Makes it this command's row: its icon, label and state, and picking it runs it. */\n command?: string;\n /** An icon by name, the viewer's or yours. */\n icon?: string;\n}\n\n/** A row in a `Menu`, with its text in its slot. `@select` when the row is picked. */\nexport const MenuItem = defineComponent<\n MenuItemProps,\n { select: () => true },\n string,\n SlotsType<{ default?: () => VNode[] }>\n>(\n (props, { emit, slots }) =>\n () =>\n h(\n 'epdf-menu-item',\n // The element's own `select` event, which Vue listens to as it would a native one.\n { ...given({ command: props.command, icon: props.icon }), onSelect: () => emit('select') },\n slots.default?.(),\n ),\n { name: 'MenuItem', props: ['command', 'icon'], emits: ['select'] },\n);\n"],"mappings":";;;;;AAkBA,MAAa,YAAkC,OAAO,sBAAsB;;;;;;AAO5E,SAAgB,eAAuB;CACrC,MAAM,UAAA,GAAA,IAAA,OAAA,CAAgB,WAAW,IAAI;CACrC,IAAI,CAAC,QACH,MAAM,IAAI,MACR,oIAEF;CAEF,OAAO;AACT;;ACkHA,MAAa,qBAAqB;CAChC,MAAM;CACN,OAAO;EApBP,KAAK;EACL,WAAW;EACX,QAAQ;EACR,UAAU;EACV,OAAO;EACP,SAAS;EACT,QAAQ;EACR,SAAS;EACT,UAAU;GAAE,MAAM,CAAC,SAAS,MAAM;GAAG,SAAS,KAAA;EAAU;EACxD,OAAO;EACP,UAAU;EACV,YAAY;EACZ,QAAQ;EACR,SAAS;EACT,OAAO;CAMA;CACP,OAAO;EAAC;EAAS;EAAmB;CAAc;AACpD;;AAGA,MAAM,gBAAgB,OAAO,IAAI,yBAAyB;AAC1D,MAAM,YAAY,WACf,OAAsD,kBAAkB;;AAG3E,MAAM,6BAAa,IAAI,QAAwB;AAC/C,IAAI,gBAAgB;AACpB,MAAM,SAAS,WAA2B;CACxC,IAAI,MAAM,WAAW,IAAI,MAAM;CAC/B,IAAI,QAAQ,KAAA,GAAW,WAAW,IAAI,QAAS,MAAM,eAAgB;CACrE,OAAO;AACT;;AAGA,MAAM,YAAA,GAAA,IAAA,gBAAA,EACH,OAA2B,EAAE,YAAY;CACxC,CAAA,GAAA,IAAA,QAAA,CAAQ,WAAW,MAAM,MAAM;CAC/B,MAAM,SAAS,SAAS,MAAM,MAAM;CACpC,aAAc,UAAA,GAAA,IAAA,EAAA,CAAWA,sBAAAA,gBAAgB,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,UAAU;AAChF,GACA;CAAE,MAAM;CAAY,OAAO,CAAC,QAAQ;AAAE,CACxC;;AAGA,MAAM,aAAoD;CACxD,KAAK;CACL,OAAO;CACP,QAAQ;CACR,SAAS;CACT,UAAU;AACZ;;AAGA,SAAS,YAAmC,OAAuB;CACjE,MAAM,SAAS,EAAE,GAAG,MAAM;CAC1B,KAAK,MAAM,OAAO,QAAQ,OAAO,QAAA,GAAA,IAAA,MAAA,CAAa,OAAO,IAAI;CACzD,OAAO;AACT;;AAGA,SAAS,oBAAoB,OAAiC;CAC5D,MAAM,UAAU,EAAE,GAAG,MAAM;CAC3B,MAAM,OAAO,OAAO,KAAK,OAAO;CAChC,MAAM,QAAA,GAAA,IAAA,MAAA,OACE,KAAK,MAAM,QAAQ,EAAE,OAAO,eAAe,CAAC,OAAO,GAAG,MAAM,MAAM,QAAQ,IAAI,CAAC,IACpF,QAAQ;EACP,IAAI,QAAQ,KAAA,GAAW;EACvB,QAAQ,KACN,6BAA6B,IAAI,6MAGnC;EACA,KAAK;CACP,CACF;AACF;;;;;AAMA,SAAgB,eACd,OACA,EAAE,MAAM,OAAO,UACF;CACb,MAAM,WAAA,GAAA,IAAA,WAAA,CAAmD,IAAI;CAG7D,MAAM,UAAA,GAAA,IAAA,WAAA,CAAmC,IAAI;CAC7C,OAAO,EAAE,YAAY,QAAQ,CAAC;CAK9B,IAAI,QAAQ,IAAI,aAAa,cAAc,oBAAoB,KAAK;CAIpE,MAAM,YAA8C;EAClD,UAAU,UAAU,KAAK,SAAS,KAAK;EACvC,mBAAmB,eAAe,KAAK,mBAAmB,UAAU;EACpE,gBAAgB,UAAU,KAAK,gBAAgB,KAAK;CACtD;CAEA,IAAI,gBAAqC;CAIzC,CAAA,GAAA,IAAA,UAAA,OAAgB;EACd,MAAM,SAAS,QAAQ;EAEvB,MAAM,gBAAiB,OAAO,QAAQ,OAAO;EAC7C,OAAO,iBAAiB,cAAc,OAAO;EAC7C,sBAAsB,OAAO,oBAAoB,cAAc,OAAO;EACtE,OAAO,SAAS;GAAE,GAAG,YAAY,KAAK;GAAG,GAAG;EAAU;EACtD,IAAI,OAAO,QAAQ,QAAQ;CAC7B,CAAC;CACD,CAAA,GAAA,IAAA,gBAAA,OAAsB,gBAAgB,CAAC;CAIvC,CAAA,GAAA,IAAA,MAAA,OACQ;EAAC,MAAM;EAAK,MAAM;EAAO,MAAM;EAAQ,MAAM;EAAS,MAAM;CAAQ,SACpE;EACJ,MAAM,SAAS,QAAQ;EACvB,IAAI,CAAC,QAAQ;EACb,OAAO,OAAA,GAAA,IAAA,MAAA,CAAY,MAAM,GAAG;EAC5B,OAAO,SAAA,GAAA,IAAA,MAAA,CAAc,MAAM,KAAK;EAChC,OAAO,SAAS,MAAM;EACtB,OAAO,WAAA,GAAA,IAAA,MAAA,CAAgB,MAAM,OAAO;EACpC,OAAO,YAAA,GAAA,IAAA,MAAA,CAAiB,MAAM,QAAQ;CACxC,CACF;CAEA,cAAA,GAAA,IAAA,EAAA,CAEI,mBAEA;EAAE,KAAK;EAAS,qBAAqB;CAAG,GACxC,OAAO,QAAQ,EAAA,GAAA,IAAA,EAAA,CAAG,UAAU;EAAE,KAAK,MAAM,OAAO,KAAK;EAAG,QAAQ,OAAO;CAAM,GAAG,KAAK,CAAC,IAAI,CAAC,CAC7F;AACJ;;;;ACnPA,MAAM,WAAW,EAAE,SAAS,WAAW;AAOvC,MAAM,QAAoC;CAAC;CAAO;CAAU;CAAS;CAAO;CAAS;AAAW;AAChG,MAAM,QAA+B;CAAC;CAAW;CAAU;AAAU;;AAGrE,MAAM,aAAiC;CACrC,aAAa;CACb,MAAM;CACN,SAAS;CACT,MAAM;AACR;AAEA,MAAM,aAAa;CAAC;CAAoB;CAAa;CAAgB;AAAW;;AAGhF,SAAS,qBAAqB,SAAsC;CAClE,MAAM,OAAO,QAAQ,aAAa,WAAW;CAC7C,MAAM,OAAO,QAAQ,aAAa,WAAW;CAC7C,OAAO;EACL,aACE,QAAQ,aAAa,kBAAkB,MAAM,aAAa,aAAa;EACzE,MAAM,QAAQ,MAAM,SAAS,IAAI,IAAI,OAAO,WAAW;EACvD,SAAS,QAAQ,aAAa,cAAc;EAC5C,MAAM,QAAQ,MAAM,SAAS,IAAI,IAAI,OAAO,WAAW;CACzD;AACF;AAEA,MAAM,iBAA6D,OAAO,uBAAuB;;AAQjG,MAAa,eAAA,GAAA,IAAA,gBAAA,EACV,OAAyB,EAAE,YAAY;CACtC,MAAM,WAAA,GAAA,IAAA,WAAA,CAA4C,IAAI;CAEtD,MAAM,WAAA,GAAA,IAAA,gBAAA,CAA8C,EAAE,GAAG,WAAW,CAAC;CACrE,CAAA,GAAA,IAAA,QAAA,CAAQ,iBAAA,GAAA,IAAA,gBAAA,CAAgC,OAAO,CAAC;CAEhD,IAAI,WAAoC;CACxC,CAAA,GAAA,IAAA,UAAA,OAAgB;EACd,MAAM,SAAS,QAAQ;EAEvB,MAAM,aAAa,OAAO,OAAO,SAAS,qBAAqB,MAAM,CAAC;EACtE,KAAK;EACL,WAAW,IAAI,iBAAiB,IAAI;EACpC,SAAS,QAAQ,QAAQ;GAAE,YAAY;GAAM,iBAAiB;EAAW,CAAC;CAC5E,CAAC;CACD,CAAA,GAAA,IAAA,gBAAA,OAAsB,UAAU,WAAW,CAAC;CAE5C,cAAA,GAAA,IAAA,EAAA,CACI,OAAO;EAAE,KAAK;EAAS,MAAM,QAAQ,MAAM;EAAM,OAAO;CAAS,GAAG,MAAM,UAAU,CAAC;AAC3F,GACA;CAAE,MAAM;CAAe,OAAO,CAAC,IAAI;CAAG,OAAO;AAAsB,CACrE;;;;;;AAOA,SAAgB,iBAA+C;CAC7D,MAAM,WAAA,GAAA,IAAA,OAAA,CAAiB,gBAAgB,IAAI;CAC3C,IAAI,CAAC,SACH,MAAM,IAAI,MACR,yFACF;CAEF,OAAO;AACT;;AAUA,MAAa,SAAA,GAAA,IAAA,gBAAA,EACV,OAAmB,EAAE,mBAAA,GAAA,IAAA,EAAA,CAEhB,OAAO;CAAE,MAAM,SAAS,MAAM;CAAM,OAAO;AAAS,GAAG,MAAM,UAAU,CAAC,GAC9E;CAAE,MAAM;CAAS,OAAO,CAAC,IAAI;CAAG,OAAO;AAAsB,CAC/D;;AAcA,MAAa,UAAA,GAAA,IAAA,gBAAA,EACV,OAAoB,EAAE,mBAAA,GAAA,IAAA,EAAA,CAEjB,OAAO;CAAE,MAAM,MAAM;CAAM,OAAO;AAAS,GAAG,MAAM,UAAU,CAAC,GACrE;CAAE,MAAM;CAAU,OAAO,CAAC,MAAM;CAAG,OAAO;AAAsB,CAClE;;;;;;;;;;;;;;ACpIA,MAAM,SAAS,eACb,OAAO,YACL,OAAO,QAAQ,UAAU,CAAC,CAAC,QAAQ,UAAqC,MAAM,OAAO,KAAA,CAAS,CAChG;;AAYF,MAAa,UAAA,GAAA,IAAA,gBAAA,EACV,OAAO,EAAE,kBAAA,GAAA,IAAA,EAAA,CAEJ,eAAe;CACf,GAAG,MAAM;EAAE,SAAS,MAAM;EAAS,MAAM,MAAM;EAAM,OAAO,MAAM;CAAM,CAAC;CACzE,UAAU,UAAsB,KAAK,SAAS,KAAK;AACrD,CAAC,GACL;CAAE,MAAM;CAAU,OAAO;EAAC;EAAW;EAAQ;CAAO;CAAG,OAAO,CAAC,OAAO;AAAE,CAC1E;;;;;AAaA,MAAa,QAAA,GAAA,IAAA,gBAAA,EACV,OAAkB,EAAE,mBAAA,GAAA,IAAA,EAAA,CAEf,aAAa,MAAM;CAAE,MAAM,MAAM;CAAM,OAAO,MAAM;AAAM,CAAC,GAAG,MAAM,UAAU,CAAC,GACrF;CACE,MAAM;CACN,OAAO,CAAC,QAAQ,OAAO;CACvB,OAAO;AACT,CACF;;AAUA,MAAa,YAAA,GAAA,IAAA,gBAAA,EAMV,OAAO,EAAE,MAAM,mBAAA,GAAA,IAAA,EAAA,CAGV,kBAEA;CAAE,GAAG,MAAM;EAAE,SAAS,MAAM;EAAS,MAAM,MAAM;CAAK,CAAC;CAAG,gBAAgB,KAAK,QAAQ;AAAE,GACzF,MAAM,UAAU,CAClB,GACJ;CAAE,MAAM;CAAY,OAAO,CAAC,WAAW,MAAM;CAAG,OAAO,CAAC,QAAQ;AAAE,CACpE"}
|