@embedpdf/viewer-chrome 3.0.0-next.13 → 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/README.md +175 -132
- package/dist/annotation-fonts-BqoLZ4Mp.js +80 -0
- package/dist/annotation-fonts-BqoLZ4Mp.js.map +1 -0
- package/dist/annotation-fonts-Dt0IQXhz.cjs +91 -0
- package/dist/annotation-fonts-Dt0IQXhz.cjs.map +1 -0
- package/dist/annotation-style--rPIZsuP.js +879 -0
- package/dist/annotation-style--rPIZsuP.js.map +1 -0
- package/dist/annotation-style-Bzvvp8-N.cjs +879 -0
- package/dist/annotation-style-Bzvvp8-N.cjs.map +1 -0
- package/dist/ar-D9XKAmDx.js +567 -0
- package/dist/ar-D9XKAmDx.js.map +1 -0
- package/dist/ar-DnEj5vbP.cjs +567 -0
- package/dist/ar-DnEj5vbP.cjs.map +1 -0
- package/dist/chrome.cjs +378 -221
- package/dist/chrome.cjs.map +1 -1
- package/dist/chrome.d.cts +5 -34
- package/dist/chrome.d.ts +5 -34
- package/dist/chrome.js +377 -218
- package/dist/chrome.js.map +1 -1
- package/dist/commands-BmgxhJ8B.js +953 -0
- package/dist/commands-BmgxhJ8B.js.map +1 -0
- package/dist/commands-CYt4SFUX.cjs +1060 -0
- package/dist/commands-CYt4SFUX.cjs.map +1 -0
- package/dist/commands.cjs +12 -595
- package/dist/commands.d.cts +29 -4
- package/dist/commands.d.ts +29 -4
- package/dist/commands.js +2 -593
- package/dist/comments-panel-MUVgLCBI.js +514 -0
- package/dist/comments-panel-MUVgLCBI.js.map +1 -0
- package/dist/comments-panel-pEcQg4Vs.cjs +514 -0
- package/dist/comments-panel-pEcQg4Vs.cjs.map +1 -0
- package/dist/de-Bdr4aWzm.js +566 -0
- package/dist/de-Bdr4aWzm.js.map +1 -0
- package/dist/de-Dv6zvbnd.cjs +566 -0
- package/dist/de-Dv6zvbnd.cjs.map +1 -0
- package/dist/dialog-B5GBisKv.js +55 -0
- package/dist/dialog-B5GBisKv.js.map +1 -0
- package/dist/dialog-t8F13BL_.cjs +60 -0
- package/dist/dialog-t8F13BL_.cjs.map +1 -0
- package/dist/es-BP09DR9w.cjs +566 -0
- package/dist/es-BP09DR9w.cjs.map +1 -0
- package/dist/es-BSXz5tBv.js +566 -0
- package/dist/es-BSXz5tBv.js.map +1 -0
- package/dist/form-design-panel-B5MXTZ96.cjs +418 -0
- package/dist/form-design-panel-B5MXTZ96.cjs.map +1 -0
- package/dist/form-design-panel-vWWU9uB-.js +418 -0
- package/dist/form-design-panel-vWWU9uB-.js.map +1 -0
- package/dist/fr-BBQQn7tJ.cjs +566 -0
- package/dist/fr-BBQQn7tJ.cjs.map +1 -0
- package/dist/fr-Ckn3K9v1.js +566 -0
- package/dist/fr-Ckn3K9v1.js.map +1 -0
- package/dist/he-DRsG7bH7.cjs +567 -0
- package/dist/he-DRsG7bH7.cjs.map +1 -0
- package/dist/he-wdGU5PkU.js +567 -0
- package/dist/he-wdGU5PkU.js.map +1 -0
- package/dist/icons-BrK5iVL8.js +856 -0
- package/dist/icons-BrK5iVL8.js.map +1 -0
- package/dist/icons-x0Tc05bs.cjs +1010 -0
- package/dist/icons-x0Tc05bs.cjs.map +1 -0
- package/dist/index.cjs +3162 -5106
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +636 -143
- package/dist/index.d.ts +636 -143
- package/dist/index.js +3083 -4975
- package/dist/index.js.map +1 -1
- package/dist/it-BuP4o0xQ.cjs +566 -0
- package/dist/it-BuP4o0xQ.cjs.map +1 -0
- package/dist/it-Us-VmvIu.js +566 -0
- package/dist/it-Us-VmvIu.js.map +1 -0
- package/dist/ja-Cizj0-5O.js +566 -0
- package/dist/ja-Cizj0-5O.js.map +1 -0
- package/dist/ja-DovEd6ts.cjs +566 -0
- package/dist/ja-DovEd6ts.cjs.map +1 -0
- package/dist/ko-B-qJEol2.cjs +566 -0
- package/dist/ko-B-qJEol2.cjs.map +1 -0
- package/dist/ko-DlrXliE1.js +566 -0
- package/dist/ko-DlrXliE1.js.map +1 -0
- package/dist/labels-BiM9wp9K.cjs +21 -0
- package/dist/labels-BiM9wp9K.cjs.map +1 -0
- package/dist/labels-C6_i87Oj.js +16 -0
- package/dist/labels-C6_i87Oj.js.map +1 -0
- package/dist/link-editor-CSjqPnj1.cjs +125 -0
- package/dist/link-editor-CSjqPnj1.cjs.map +1 -0
- package/dist/link-editor-SxM1nnJU.js +125 -0
- package/dist/link-editor-SxM1nnJU.js.map +1 -0
- package/dist/measurement-Bs61XWbJ.js +325 -0
- package/dist/measurement-Bs61XWbJ.js.map +1 -0
- package/dist/measurement-CcCsHPOX.cjs +326 -0
- package/dist/measurement-CcCsHPOX.cjs.map +1 -0
- package/dist/nl-0aF7M_0h.js +566 -0
- package/dist/nl-0aF7M_0h.js.map +1 -0
- package/dist/nl-D3KZDDiJ.cjs +566 -0
- package/dist/nl-D3KZDDiJ.cjs.map +1 -0
- package/dist/pl-BW--AaCI.js +566 -0
- package/dist/pl-BW--AaCI.js.map +1 -0
- package/dist/pl-DSFhAUqx.cjs +566 -0
- package/dist/pl-DSFhAUqx.cjs.map +1 -0
- package/dist/pt-C5S-8MC5.cjs +566 -0
- package/dist/pt-C5S-8MC5.cjs.map +1 -0
- package/dist/pt-DIhpU5pT.js +566 -0
- package/dist/pt-DIhpU5pT.js.map +1 -0
- package/dist/redact-confirm-B6j36TPw.js +83 -0
- package/dist/redact-confirm-B6j36TPw.js.map +1 -0
- package/dist/redact-confirm-CX_SY2ZN.cjs +83 -0
- package/dist/redact-confirm-CX_SY2ZN.cjs.map +1 -0
- package/dist/redaction-panel-BmoIl-Ll.cjs +96 -0
- package/dist/redaction-panel-BmoIl-Ll.cjs.map +1 -0
- package/dist/redaction-panel-IJDshSJI.js +96 -0
- package/dist/redaction-panel-IJDshSJI.js.map +1 -0
- package/dist/search-panel-HfIhJm1M.js +249 -0
- package/dist/search-panel-HfIhJm1M.js.map +1 -0
- package/dist/search-panel-s9IoiOtv.cjs +249 -0
- package/dist/search-panel-s9IoiOtv.cjs.map +1 -0
- package/dist/sheet-BDsa_Sup.cjs +442 -0
- package/dist/sheet-BDsa_Sup.cjs.map +1 -0
- package/dist/sheet-R6XDgyEf.js +365 -0
- package/dist/sheet-R6XDgyEf.js.map +1 -0
- package/dist/sign-dialog-CgnR7akj.cjs +155 -0
- package/dist/sign-dialog-CgnR7akj.cjs.map +1 -0
- package/dist/sign-dialog-GDqCoQhA.js +155 -0
- package/dist/sign-dialog-GDqCoQhA.js.map +1 -0
- package/dist/signature-inspector-DyO313Qf.cjs +166 -0
- package/dist/signature-inspector-DyO313Qf.cjs.map +1 -0
- package/dist/signature-inspector-okFz8do6.js +166 -0
- package/dist/signature-inspector-okFz8do6.js.map +1 -0
- package/dist/signature-maker-BhCmYyHD.js +393 -0
- package/dist/signature-maker-BhCmYyHD.js.map +1 -0
- package/dist/signature-maker-BoYa8vgA.cjs +393 -0
- package/dist/signature-maker-BoYa8vgA.cjs.map +1 -0
- package/dist/signatures-panel-B56PC6d9.cjs +300 -0
- package/dist/signatures-panel-B56PC6d9.cjs.map +1 -0
- package/dist/signatures-panel-CgnFfhFm.js +300 -0
- package/dist/signatures-panel-CgnFfhFm.js.map +1 -0
- package/dist/stamp-store-BHvRs-Do.cjs +147 -0
- package/dist/stamp-store-BHvRs-Do.cjs.map +1 -0
- package/dist/stamp-store-WuF-L3Jj.js +112 -0
- package/dist/stamp-store-WuF-L3Jj.js.map +1 -0
- package/dist/stamps-panel-B9NYGayn.cjs +231 -0
- package/dist/stamps-panel-B9NYGayn.cjs.map +1 -0
- package/dist/stamps-panel-CDO0FPyK.js +231 -0
- package/dist/stamps-panel-CDO0FPyK.js.map +1 -0
- package/dist/toolbar-CJu2wKTU.cjs +1659 -0
- package/dist/toolbar-CJu2wKTU.cjs.map +1 -0
- package/dist/toolbar-z9od3tKl.js +1564 -0
- package/dist/toolbar-z9od3tKl.js.map +1 -0
- package/dist/zh-cn-3tmMeHqv.cjs +566 -0
- package/dist/zh-cn-3tmMeHqv.cjs.map +1 -0
- package/dist/zh-cn-CxkUUBct.js +566 -0
- package/dist/zh-cn-CxkUUBct.js.map +1 -0
- package/package.json +6 -4
- package/src/styles.css +153 -89
- package/dist/commands.cjs.map +0 -1
- package/dist/commands.js.map +0 -1
- package/dist/es-DYwzfxyt.cjs +0 -293
- package/dist/es-DYwzfxyt.cjs.map +0 -1
- package/dist/es-sN6uqBgD.js +0 -293
- package/dist/es-sN6uqBgD.js.map +0 -1
|
@@ -0,0 +1,442 @@
|
|
|
1
|
+
let react = require("react");
|
|
2
|
+
let _embedpdf_web = require("@embedpdf/web");
|
|
3
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
4
|
+
//#region src/ui/screen-edges.ts
|
|
5
|
+
const NO_SCREEN_EDGES = {
|
|
6
|
+
top: false,
|
|
7
|
+
right: false,
|
|
8
|
+
bottom: false,
|
|
9
|
+
left: false
|
|
10
|
+
};
|
|
11
|
+
/** How close to the window's edge a box counts as reaching it, for rounding. */
|
|
12
|
+
const EDGE_TOLERANCE_PX = 1;
|
|
13
|
+
/** The edges of a `width` × `height` window that `box` reaches while some of it is on screen. */
|
|
14
|
+
function screenEdgesOf(box, view) {
|
|
15
|
+
const across = box.right > 0 && box.left < view.width;
|
|
16
|
+
const down = box.bottom > 0 && box.top < view.height;
|
|
17
|
+
return {
|
|
18
|
+
top: across && box.top <= EDGE_TOLERANCE_PX && box.bottom > 0,
|
|
19
|
+
right: down && box.right >= view.width - EDGE_TOLERANCE_PX && box.left < view.width,
|
|
20
|
+
bottom: across && box.bottom >= view.height - EDGE_TOLERANCE_PX && box.top < view.height,
|
|
21
|
+
left: down && box.left <= EDGE_TOLERANCE_PX && box.right > 0
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
const sameScreenEdges = (left, right) => left.top === right.top && left.right === right.right && left.bottom === right.bottom && left.left === right.left;
|
|
25
|
+
const PADDING = {
|
|
26
|
+
top: "paddingTop",
|
|
27
|
+
right: "paddingRight",
|
|
28
|
+
bottom: "paddingBottom",
|
|
29
|
+
left: "paddingLeft"
|
|
30
|
+
};
|
|
31
|
+
/** The safe-area padding for the reached edges among `sides` (default all four), as style properties. */
|
|
32
|
+
function safeAreaPaddingOf(edges, sides = [
|
|
33
|
+
"top",
|
|
34
|
+
"right",
|
|
35
|
+
"bottom",
|
|
36
|
+
"left"
|
|
37
|
+
]) {
|
|
38
|
+
const padding = {};
|
|
39
|
+
for (const side of sides) if (edges[side]) padding[PADDING[side]] = `env(safe-area-inset-${side}, 0px)`;
|
|
40
|
+
return padding;
|
|
41
|
+
}
|
|
42
|
+
/** The window's size, without its scrollbars. */
|
|
43
|
+
function windowSizeOf(element) {
|
|
44
|
+
const { clientWidth, clientHeight } = element.ownerDocument.documentElement;
|
|
45
|
+
return {
|
|
46
|
+
width: clientWidth,
|
|
47
|
+
height: clientHeight
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
//#endregion
|
|
51
|
+
//#region src/ui/viewer-layer.ts
|
|
52
|
+
/**
|
|
53
|
+
* What opens over the whole viewer: a layer the size of the viewer's box on
|
|
54
|
+
* screen, in the browser's top layer, where sheets and dialogs open. In the
|
|
55
|
+
* top layer nothing the viewer draws covers it, and what opens later (a menu
|
|
56
|
+
* from a sheet, a dialog from a panel) sits above what opened before. And
|
|
57
|
+
* what holds the keyboard while it's open (a sheet, a dialog): it takes
|
|
58
|
+
* focus, keeps Tab inside it, closes on Escape, and gives focus back to what
|
|
59
|
+
* had it before, the button that opened it. An overlay panel takes focus the
|
|
60
|
+
* same way but lets Tab move on, so the rest of the viewer stays in reach.
|
|
61
|
+
*/
|
|
62
|
+
/** The `popover` attribute, which React's types don't list yet. */
|
|
63
|
+
const POPOVER = { popover: "manual" };
|
|
64
|
+
/** The custom element's root: the viewer's box. */
|
|
65
|
+
const VIEWER_ROOT_SELECTOR = "[data-embedpdf-root]";
|
|
66
|
+
/**
|
|
67
|
+
* What the viewer's root is marked with: it takes focus on a press that lands on nothing that
|
|
68
|
+
* takes focus itself (the pages), so the viewer's keys reach it from there.
|
|
69
|
+
*/
|
|
70
|
+
const FOCUS_ROOT_ATTRIBUTE = "data-epdf-focus-root";
|
|
71
|
+
/** Place `element` (`position: fixed`) at a box in window px. */
|
|
72
|
+
function placeFixed(element, box) {
|
|
73
|
+
element.style.left = `${box.left}px`;
|
|
74
|
+
element.style.top = `${box.top}px`;
|
|
75
|
+
element.style.width = `${box.width}px`;
|
|
76
|
+
element.style.height = `${box.height}px`;
|
|
77
|
+
const landed = element.getBoundingClientRect();
|
|
78
|
+
if (Math.abs(landed.left - box.left) > .5 || Math.abs(landed.top - box.top) > .5) {
|
|
79
|
+
element.style.left = `${2 * box.left - landed.left}px`;
|
|
80
|
+
element.style.top = `${2 * box.top - landed.top}px`;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Show `layer` in the top layer over the part of the viewer on screen, and keep it there as the
|
|
85
|
+
* viewer or the window resizes or scrolls. `onPlace` hears which edges of the window the viewer
|
|
86
|
+
* reaches, each time the layer is placed. Returns the stop, which hides the layer.
|
|
87
|
+
*/
|
|
88
|
+
function attachViewerLayer(layer, onPlace) {
|
|
89
|
+
const root = layer.parentElement?.closest(VIEWER_ROOT_SELECTOR) ?? null;
|
|
90
|
+
if (typeof layer.showPopover === "function") layer.showPopover();
|
|
91
|
+
let placed = "";
|
|
92
|
+
const place = () => {
|
|
93
|
+
const view = windowSizeOf(layer);
|
|
94
|
+
const rect = root?.getBoundingClientRect() ?? {
|
|
95
|
+
left: 0,
|
|
96
|
+
top: 0,
|
|
97
|
+
right: view.width,
|
|
98
|
+
bottom: view.height
|
|
99
|
+
};
|
|
100
|
+
const left = Math.max(0, rect.left);
|
|
101
|
+
const top = Math.max(0, rect.top);
|
|
102
|
+
const box = {
|
|
103
|
+
left,
|
|
104
|
+
top,
|
|
105
|
+
width: Math.max(0, Math.min(view.width, rect.right) - left),
|
|
106
|
+
height: Math.max(0, Math.min(view.height, rect.bottom) - top)
|
|
107
|
+
};
|
|
108
|
+
const key = `${box.left},${box.top},${box.width},${box.height},${view.width},${view.height}`;
|
|
109
|
+
if (key === placed) return;
|
|
110
|
+
placed = key;
|
|
111
|
+
placeFixed(layer, box);
|
|
112
|
+
onPlace?.(screenEdgesOf(rect, view));
|
|
113
|
+
};
|
|
114
|
+
place();
|
|
115
|
+
const resizes = new ResizeObserver(place);
|
|
116
|
+
if (root) resizes.observe(root);
|
|
117
|
+
const stopGeometry = (0, _embedpdf_web.observeClientGeometry)(place);
|
|
118
|
+
return () => {
|
|
119
|
+
stopGeometry();
|
|
120
|
+
resizes.disconnect();
|
|
121
|
+
if (typeof layer.hidePopover === "function" && layer.matches(":popover-open")) layer.hidePopover();
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Hold the keyboard in `container` until released: focus moves into it unless it's there
|
|
126
|
+
* already (to `initialFocus`, else its first control), so a field that took the cursor as it
|
|
127
|
+
* appeared keeps it; Tab and Shift+Tab stay inside it, and Escape calls `onEscape`. With
|
|
128
|
+
* `trap: false` Tab moves on past it, as it does past anything else in the viewer. Releasing
|
|
129
|
+
* gives focus back to what had it before, unless the user has moved it elsewhere: a press on
|
|
130
|
+
* the pages, which puts focus on the viewer's root, doesn't count.
|
|
131
|
+
*/
|
|
132
|
+
function holdFocus(container, options) {
|
|
133
|
+
const doc = container.ownerDocument;
|
|
134
|
+
const before = (0, _embedpdf_web.deepActiveElementOf)(doc);
|
|
135
|
+
const onKeyDown = (event) => {
|
|
136
|
+
if (event.key !== "Escape" || event.defaultPrevented) return;
|
|
137
|
+
event.preventDefault();
|
|
138
|
+
event.stopPropagation();
|
|
139
|
+
options.onEscape();
|
|
140
|
+
};
|
|
141
|
+
container.addEventListener("keydown", onKeyDown);
|
|
142
|
+
let releaseTrap = null;
|
|
143
|
+
if (options.trap === false) (0, _embedpdf_web.moveFocusInto)(container, options.initialFocus);
|
|
144
|
+
else releaseTrap = (0, _embedpdf_web.attachFocusTrap)(container, {
|
|
145
|
+
initialFocus: options.initialFocus,
|
|
146
|
+
returnFocus: false
|
|
147
|
+
});
|
|
148
|
+
const standDown = () => {
|
|
149
|
+
releaseTrap?.();
|
|
150
|
+
releaseTrap = null;
|
|
151
|
+
container.removeEventListener("keydown", onKeyDown);
|
|
152
|
+
};
|
|
153
|
+
return {
|
|
154
|
+
standDown,
|
|
155
|
+
release: () => {
|
|
156
|
+
standDown();
|
|
157
|
+
const active = (0, _embedpdf_web.deepActiveElementOf)(doc);
|
|
158
|
+
const nowhere = active === null || container.contains(active) || active.hasAttribute("data-epdf-focus-root");
|
|
159
|
+
if (before?.isConnected && nowhere) before.focus();
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
/** How much of the viewer's height a panel's sheet opens at. */
|
|
164
|
+
const PANEL_SHEET_OPEN_FRACTION = .5;
|
|
165
|
+
/**
|
|
166
|
+
* The height a sheet dragged to `height` comes to rest at, one of `heights` (ascending), or null
|
|
167
|
+
* when it closes. `velocity` is the release speed in px per second, downward positive.
|
|
168
|
+
*/
|
|
169
|
+
function sheetRestOf(heights, height, velocity) {
|
|
170
|
+
if (heights.length === 0) return null;
|
|
171
|
+
if (velocity >= 500) {
|
|
172
|
+
const lower = heights.filter((rest) => rest < height - 1);
|
|
173
|
+
return lower.length > 0 ? lower[lower.length - 1] : null;
|
|
174
|
+
}
|
|
175
|
+
if (velocity <= -500) return heights.find((rest) => rest > height + 1) ?? heights[heights.length - 1];
|
|
176
|
+
if (height < heights[0] / 2) return null;
|
|
177
|
+
return heights.reduce((nearest, rest) => Math.abs(rest - height) < Math.abs(nearest - height) ? rest : nearest);
|
|
178
|
+
}
|
|
179
|
+
/** The heights a panel's sheet rests at in a viewer `viewerHeight` px tall: half of it, and nearly all. */
|
|
180
|
+
function panelSheetHeightsOf(viewerHeight) {
|
|
181
|
+
const tallest = Math.max(0, Math.round(viewerHeight - 40));
|
|
182
|
+
const open = Math.min(tallest, Math.round(viewerHeight * PANEL_SHEET_OPEN_FRACTION));
|
|
183
|
+
return open < tallest ? [open, tallest] : [tallest];
|
|
184
|
+
}
|
|
185
|
+
//#endregion
|
|
186
|
+
//#region src/ui/sheet.tsx
|
|
187
|
+
/**
|
|
188
|
+
* A sheet: what a panel or a menu is on a phone. It slides up from the bottom
|
|
189
|
+
* of the viewer, over the pages, in a layer over the whole viewer
|
|
190
|
+
* (`viewer-layer.ts`); the viewer above it dims, and a tap there closes it.
|
|
191
|
+
* Its handle drags it taller or shorter, or down to close it, and a flick
|
|
192
|
+
* moves it a whole step (`sheet-rest.ts`). It keeps clear of the home bar and
|
|
193
|
+
* the screen's rounded corners when the viewer reaches the screen's edge.
|
|
194
|
+
* A sheet takes focus when it opens, keeps Tab inside it, closes on Escape
|
|
195
|
+
* and gives focus back to the button that opened it; a menu's sheet leaves
|
|
196
|
+
* the keyboard to its menu. A sheet that holds a list closes when one of its
|
|
197
|
+
* items is picked ({@link useCloseOnPick}).
|
|
198
|
+
*/
|
|
199
|
+
/** A press that starts on one of these in the handle's row is the control's, not a drag. */
|
|
200
|
+
const CONTROL_SELECTOR = "button, a[href], input, select, textarea, [role=\"tab\"], [contenteditable]:not([contenteditable=\"false\"])";
|
|
201
|
+
/** The dimmed viewer behind a sheet or a dialog. */
|
|
202
|
+
const SCRIM_CLASS = "bg-black/30 transition-opacity duration-200 starting:opacity-0";
|
|
203
|
+
const NO_PICK = () => {};
|
|
204
|
+
const CloseOnPickContext = (0, react.createContext)(NO_PICK);
|
|
205
|
+
/** Gives what's inside a sheet or an overlay the close it runs when one of its items is picked. */
|
|
206
|
+
const CloseOnPickProvider = CloseOnPickContext.Provider;
|
|
207
|
+
/**
|
|
208
|
+
* What a list's item runs when it's picked: it closes the sheet or the overlay the list is in,
|
|
209
|
+
* so you see where it took you. It does nothing in a docked panel, or in one that isn't a list.
|
|
210
|
+
*/
|
|
211
|
+
function useCloseOnPick() {
|
|
212
|
+
return (0, react.useContext)(CloseOnPickContext);
|
|
213
|
+
}
|
|
214
|
+
/** Whether a press landed in another surface that holds focus, like a dialog opened over this one. */
|
|
215
|
+
const pressedInOtherModal = (event, own) => event.composedPath().some((node) => node instanceof Element && node !== own && node.matches("[aria-modal=\"true\"]"));
|
|
216
|
+
/** `data` as the `data-*` attributes it names. */
|
|
217
|
+
const dataAttributesOf = (data) => Object.fromEntries(Object.entries(data ?? {}).map(([name, value]) => [`data-${name}`, value]));
|
|
218
|
+
/** How many pointer samples a drag keeps for its release speed. */
|
|
219
|
+
const DRAG_SAMPLES = 8;
|
|
220
|
+
function Sheet({ label, onClose, size = "content", list = false, trapFocus = true, header, part, data, children }) {
|
|
221
|
+
const layer = (0, react.useRef)(null);
|
|
222
|
+
const sheet = (0, react.useRef)(null);
|
|
223
|
+
const close = (0, react.useRef)(onClose);
|
|
224
|
+
close.current = onClose;
|
|
225
|
+
/** Which of its heights a panel's sheet rests at: the first (open) or a taller one. */
|
|
226
|
+
const restIndex = (0, react.useRef)(0);
|
|
227
|
+
const drag = (0, react.useRef)(null);
|
|
228
|
+
/** The heights it rests at now: a panel's from the viewer's height, a menu's as tall as it is. */
|
|
229
|
+
const heightsNow = () => size === "panel" ? panelSheetHeightsOf(layer.current?.offsetHeight ?? 0) : [sheet.current?.offsetHeight ?? 0];
|
|
230
|
+
/** Show the sheet dragged to `height` (its top that far above the viewer's bottom). */
|
|
231
|
+
const show = (height, heights) => {
|
|
232
|
+
const element = sheet.current;
|
|
233
|
+
if (!element || heights.length === 0) return;
|
|
234
|
+
const lowest = heights[0];
|
|
235
|
+
const tallest = heights[heights.length - 1];
|
|
236
|
+
if (size === "panel") element.style.height = `${Math.min(tallest, Math.max(lowest, height))}px`;
|
|
237
|
+
const below = Math.max(0, lowest - height);
|
|
238
|
+
element.style.translate = below > 0 ? `0 ${below}px` : "";
|
|
239
|
+
};
|
|
240
|
+
(0, react.useLayoutEffect)(() => {
|
|
241
|
+
const layerElement = layer.current;
|
|
242
|
+
const sheetElement = sheet.current;
|
|
243
|
+
if (!layerElement || !sheetElement) return;
|
|
244
|
+
const stopLayer = attachViewerLayer(layerElement, (edges) => {
|
|
245
|
+
const padding = safeAreaPaddingOf(edges, [
|
|
246
|
+
"right",
|
|
247
|
+
"bottom",
|
|
248
|
+
"left"
|
|
249
|
+
]);
|
|
250
|
+
sheetElement.style.paddingLeft = padding.paddingLeft ?? "";
|
|
251
|
+
sheetElement.style.paddingRight = padding.paddingRight ?? "";
|
|
252
|
+
sheetElement.style.paddingBottom = padding.paddingBottom ?? "";
|
|
253
|
+
sheetElement.style.maxHeight = `${Math.max(0, layerElement.offsetHeight - 40)}px`;
|
|
254
|
+
if (size === "panel" && !drag.current) {
|
|
255
|
+
const heights = panelSheetHeightsOf(layerElement.offsetHeight);
|
|
256
|
+
show(heights[Math.min(restIndex.current, heights.length - 1)], heights);
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
const held = trapFocus ? holdFocus(sheetElement, { onEscape: () => close.current() }) : null;
|
|
260
|
+
const stopOutside = (0, _embedpdf_web.observeOutsidePress)(layerElement, (event) => {
|
|
261
|
+
if (!pressedInOtherModal(event, sheetElement)) close.current();
|
|
262
|
+
});
|
|
263
|
+
return () => {
|
|
264
|
+
stopOutside();
|
|
265
|
+
held?.release();
|
|
266
|
+
stopLayer();
|
|
267
|
+
};
|
|
268
|
+
}, []);
|
|
269
|
+
const onGripDown = (event) => {
|
|
270
|
+
if (event.pointerType === "mouse" && event.button !== 0) return;
|
|
271
|
+
if (event.target.closest(CONTROL_SELECTOR)) return;
|
|
272
|
+
const element = sheet.current;
|
|
273
|
+
if (!element) return;
|
|
274
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
275
|
+
const startHeight = element.offsetHeight;
|
|
276
|
+
drag.current = {
|
|
277
|
+
pointerId: event.pointerId,
|
|
278
|
+
startY: event.clientY,
|
|
279
|
+
startHeight,
|
|
280
|
+
heights: heightsNow(),
|
|
281
|
+
samples: [{
|
|
282
|
+
t: event.timeStamp,
|
|
283
|
+
x: event.clientX,
|
|
284
|
+
y: event.clientY
|
|
285
|
+
}],
|
|
286
|
+
height: startHeight
|
|
287
|
+
};
|
|
288
|
+
element.setAttribute("data-dragging", "");
|
|
289
|
+
};
|
|
290
|
+
const onGripMove = (event) => {
|
|
291
|
+
const current = drag.current;
|
|
292
|
+
if (!current || current.pointerId !== event.pointerId) return;
|
|
293
|
+
current.height = current.startHeight - (event.clientY - current.startY);
|
|
294
|
+
current.samples.push({
|
|
295
|
+
t: event.timeStamp,
|
|
296
|
+
x: event.clientX,
|
|
297
|
+
y: event.clientY
|
|
298
|
+
});
|
|
299
|
+
if (current.samples.length > DRAG_SAMPLES) current.samples.shift();
|
|
300
|
+
show(current.height, current.heights);
|
|
301
|
+
};
|
|
302
|
+
const onGripUp = (event) => {
|
|
303
|
+
const current = drag.current;
|
|
304
|
+
if (!current || current.pointerId !== event.pointerId) return;
|
|
305
|
+
drag.current = null;
|
|
306
|
+
sheet.current?.removeAttribute("data-dragging");
|
|
307
|
+
const cancelled = event.type === "pointercancel";
|
|
308
|
+
const velocity = cancelled ? 0 : (0, _embedpdf_web.computeReleaseVelocity)(current.samples, event.timeStamp)?.vy ?? 0;
|
|
309
|
+
const rest = cancelled ? current.heights[restIndex.current] : sheetRestOf(current.heights, current.height, velocity);
|
|
310
|
+
if (rest === null) {
|
|
311
|
+
close.current();
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
restIndex.current = Math.max(0, current.heights.indexOf(rest));
|
|
315
|
+
show(rest, current.heights);
|
|
316
|
+
};
|
|
317
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
318
|
+
ref: layer,
|
|
319
|
+
...POPOVER,
|
|
320
|
+
"data-epdf-layer": "",
|
|
321
|
+
className: "text-fg m-0 overflow-hidden border-0 bg-transparent p-0 open:flex open:flex-col",
|
|
322
|
+
style: {
|
|
323
|
+
position: "fixed",
|
|
324
|
+
inset: "auto",
|
|
325
|
+
maxWidth: "none",
|
|
326
|
+
maxHeight: "none"
|
|
327
|
+
},
|
|
328
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
329
|
+
"aria-hidden": "true",
|
|
330
|
+
className: `min-h-0 flex-1 ${SCRIM_CLASS}`,
|
|
331
|
+
onClick: () => close.current()
|
|
332
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
333
|
+
ref: sheet,
|
|
334
|
+
role: trapFocus ? "dialog" : void 0,
|
|
335
|
+
"aria-modal": trapFocus ? true : void 0,
|
|
336
|
+
"aria-label": trapFocus ? label : void 0,
|
|
337
|
+
part,
|
|
338
|
+
...dataAttributesOf(data),
|
|
339
|
+
"data-epdf-sheet": "",
|
|
340
|
+
className: "border-border-subtle bg-elevated starting:translate-y-full data-dragging:transition-none relative flex w-full shrink-0 flex-col rounded-t-2xl border-t shadow-2xl transition-[translate,height] duration-200 ease-out motion-reduce:transition-none",
|
|
341
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
342
|
+
className: "shrink-0 touch-pan-x select-none",
|
|
343
|
+
onPointerDown: onGripDown,
|
|
344
|
+
onPointerMove: onGripMove,
|
|
345
|
+
onPointerUp: onGripUp,
|
|
346
|
+
onPointerCancel: onGripUp,
|
|
347
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
348
|
+
"data-epdf-sheet-handle": "",
|
|
349
|
+
className: "flex h-6 cursor-grab items-center justify-center active:cursor-grabbing",
|
|
350
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "bg-border-strong h-1 w-10 rounded-full" })
|
|
351
|
+
}), header]
|
|
352
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
353
|
+
className: "flex min-h-0 flex-1 flex-col overflow-y-auto overflow-x-hidden overscroll-contain",
|
|
354
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CloseOnPickProvider, {
|
|
355
|
+
value: list ? () => close.current() : NO_PICK,
|
|
356
|
+
children
|
|
357
|
+
})
|
|
358
|
+
})]
|
|
359
|
+
})]
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
//#endregion
|
|
363
|
+
Object.defineProperty(exports, "CloseOnPickProvider", {
|
|
364
|
+
enumerable: true,
|
|
365
|
+
get: function() {
|
|
366
|
+
return CloseOnPickProvider;
|
|
367
|
+
}
|
|
368
|
+
});
|
|
369
|
+
Object.defineProperty(exports, "FOCUS_ROOT_ATTRIBUTE", {
|
|
370
|
+
enumerable: true,
|
|
371
|
+
get: function() {
|
|
372
|
+
return FOCUS_ROOT_ATTRIBUTE;
|
|
373
|
+
}
|
|
374
|
+
});
|
|
375
|
+
Object.defineProperty(exports, "NO_SCREEN_EDGES", {
|
|
376
|
+
enumerable: true,
|
|
377
|
+
get: function() {
|
|
378
|
+
return NO_SCREEN_EDGES;
|
|
379
|
+
}
|
|
380
|
+
});
|
|
381
|
+
Object.defineProperty(exports, "POPOVER", {
|
|
382
|
+
enumerable: true,
|
|
383
|
+
get: function() {
|
|
384
|
+
return POPOVER;
|
|
385
|
+
}
|
|
386
|
+
});
|
|
387
|
+
Object.defineProperty(exports, "SCRIM_CLASS", {
|
|
388
|
+
enumerable: true,
|
|
389
|
+
get: function() {
|
|
390
|
+
return SCRIM_CLASS;
|
|
391
|
+
}
|
|
392
|
+
});
|
|
393
|
+
Object.defineProperty(exports, "Sheet", {
|
|
394
|
+
enumerable: true,
|
|
395
|
+
get: function() {
|
|
396
|
+
return Sheet;
|
|
397
|
+
}
|
|
398
|
+
});
|
|
399
|
+
Object.defineProperty(exports, "attachViewerLayer", {
|
|
400
|
+
enumerable: true,
|
|
401
|
+
get: function() {
|
|
402
|
+
return attachViewerLayer;
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
Object.defineProperty(exports, "holdFocus", {
|
|
406
|
+
enumerable: true,
|
|
407
|
+
get: function() {
|
|
408
|
+
return holdFocus;
|
|
409
|
+
}
|
|
410
|
+
});
|
|
411
|
+
Object.defineProperty(exports, "safeAreaPaddingOf", {
|
|
412
|
+
enumerable: true,
|
|
413
|
+
get: function() {
|
|
414
|
+
return safeAreaPaddingOf;
|
|
415
|
+
}
|
|
416
|
+
});
|
|
417
|
+
Object.defineProperty(exports, "sameScreenEdges", {
|
|
418
|
+
enumerable: true,
|
|
419
|
+
get: function() {
|
|
420
|
+
return sameScreenEdges;
|
|
421
|
+
}
|
|
422
|
+
});
|
|
423
|
+
Object.defineProperty(exports, "screenEdgesOf", {
|
|
424
|
+
enumerable: true,
|
|
425
|
+
get: function() {
|
|
426
|
+
return screenEdgesOf;
|
|
427
|
+
}
|
|
428
|
+
});
|
|
429
|
+
Object.defineProperty(exports, "useCloseOnPick", {
|
|
430
|
+
enumerable: true,
|
|
431
|
+
get: function() {
|
|
432
|
+
return useCloseOnPick;
|
|
433
|
+
}
|
|
434
|
+
});
|
|
435
|
+
Object.defineProperty(exports, "windowSizeOf", {
|
|
436
|
+
enumerable: true,
|
|
437
|
+
get: function() {
|
|
438
|
+
return windowSizeOf;
|
|
439
|
+
}
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
//# sourceMappingURL=sheet-BDsa_Sup.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sheet-BDsa_Sup.cjs","names":[],"sources":["../src/ui/screen-edges.ts","../src/ui/viewer-layer.ts","../src/ui/sheet-rest.ts","../src/ui/sheet.tsx"],"sourcesContent":["/**\n * Which edges of the window the viewer reaches, and the padding that keeps\n * what sits at those edges clear of the notch, the rounded corners and the\n * home bar. The padding is the browser's `env(safe-area-inset-*)`, which is\n * zero unless the page lets content under those areas (`viewport-fit=cover`),\n * so it changes nothing on an ordinary page. The viewer reaches an edge when\n * its box is at that edge of the window or past it, as in full screen or as\n * the whole page of a phone app.\n */\n/** For each edge of the window, whether the viewer reaches it. */\nexport interface ScreenEdges {\n readonly top: boolean;\n readonly right: boolean;\n readonly bottom: boolean;\n readonly left: boolean;\n}\n\nexport const NO_SCREEN_EDGES: ScreenEdges = {\n top: false,\n right: false,\n bottom: false,\n left: false,\n};\n\n/** A box in window px. */\nexport interface ScreenBox {\n readonly left: number;\n readonly top: number;\n readonly right: number;\n readonly bottom: number;\n}\n\n/** How close to the window's edge a box counts as reaching it, for rounding. */\nconst EDGE_TOLERANCE_PX = 1;\n\n/** The edges of a `width` × `height` window that `box` reaches while some of it is on screen. */\nexport function screenEdgesOf(\n box: ScreenBox,\n view: { readonly width: number; readonly height: number },\n): ScreenEdges {\n const across = box.right > 0 && box.left < view.width;\n const down = box.bottom > 0 && box.top < view.height;\n return {\n top: across && box.top <= EDGE_TOLERANCE_PX && box.bottom > 0,\n right: down && box.right >= view.width - EDGE_TOLERANCE_PX && box.left < view.width,\n bottom: across && box.bottom >= view.height - EDGE_TOLERANCE_PX && box.top < view.height,\n left: down && box.left <= EDGE_TOLERANCE_PX && box.right > 0,\n };\n}\n\nexport const sameScreenEdges = (left: ScreenEdges, right: ScreenEdges): boolean =>\n left.top === right.top &&\n left.right === right.right &&\n left.bottom === right.bottom &&\n left.left === right.left;\n\n/** The padding of each side in `sides` whose edge the viewer reaches. */\nexport interface SafeAreaPadding {\n paddingTop?: string;\n paddingRight?: string;\n paddingBottom?: string;\n paddingLeft?: string;\n}\n\nconst PADDING: Readonly<Record<keyof ScreenEdges, keyof SafeAreaPadding>> = {\n top: 'paddingTop',\n right: 'paddingRight',\n bottom: 'paddingBottom',\n left: 'paddingLeft',\n};\n\n/** The safe-area padding for the reached edges among `sides` (default all four), as style properties. */\nexport function safeAreaPaddingOf(\n edges: ScreenEdges,\n sides: readonly (keyof ScreenEdges)[] = ['top', 'right', 'bottom', 'left'],\n): SafeAreaPadding {\n const padding: SafeAreaPadding = {};\n for (const side of sides) {\n if (edges[side]) padding[PADDING[side]] = `env(safe-area-inset-${side}, 0px)`;\n }\n return padding;\n}\n\n/** The window's size, without its scrollbars. */\nexport function windowSizeOf(element: Element): { width: number; height: number } {\n const { clientWidth, clientHeight } = element.ownerDocument.documentElement;\n return { width: clientWidth, height: clientHeight };\n}\n","/**\n * What opens over the whole viewer: a layer the size of the viewer's box on\n * screen, in the browser's top layer, where sheets and dialogs open. In the\n * top layer nothing the viewer draws covers it, and what opens later (a menu\n * from a sheet, a dialog from a panel) sits above what opened before. And\n * what holds the keyboard while it's open (a sheet, a dialog): it takes\n * focus, keeps Tab inside it, closes on Escape, and gives focus back to what\n * had it before, the button that opened it. An overlay panel takes focus the\n * same way but lets Tab move on, so the rest of the viewer stays in reach.\n */\nimport {\n attachFocusTrap,\n deepActiveElementOf,\n moveFocusInto,\n observeClientGeometry,\n} from '@embedpdf/web';\n\nimport { screenEdgesOf, windowSizeOf, type ScreenEdges } from './screen-edges';\n\n/** The `popover` attribute, which React's types don't list yet. */\nexport const POPOVER = { popover: 'manual' } as Record<string, string>;\n\n/** The custom element's root: the viewer's box. */\nconst VIEWER_ROOT_SELECTOR = '[data-embedpdf-root]';\n\n/** What another surface that holds focus is marked with: a press in it is not a press outside. */\nexport const MODAL_SELECTOR = '[aria-modal=\"true\"]';\n\n/**\n * What the viewer's root is marked with: it takes focus on a press that lands on nothing that\n * takes focus itself (the pages), so the viewer's keys reach it from there.\n */\nexport const FOCUS_ROOT_ATTRIBUTE = 'data-epdf-focus-root';\n\n/** Place `element` (`position: fixed`) at a box in window px. */\nfunction placeFixed(\n element: HTMLElement,\n box: { left: number; top: number; width: number; height: number },\n): void {\n element.style.left = `${box.left}px`;\n element.style.top = `${box.top}px`;\n element.style.width = `${box.width}px`;\n element.style.height = `${box.height}px`;\n // Without the top layer, `position: fixed` starts at the viewer's box (its `contain`): move by\n // however far from the window's origin the layer landed.\n const landed = element.getBoundingClientRect();\n if (Math.abs(landed.left - box.left) > 0.5 || Math.abs(landed.top - box.top) > 0.5) {\n element.style.left = `${2 * box.left - landed.left}px`;\n element.style.top = `${2 * box.top - landed.top}px`;\n }\n}\n\n/**\n * Show `layer` in the top layer over the part of the viewer on screen, and keep it there as the\n * viewer or the window resizes or scrolls. `onPlace` hears which edges of the window the viewer\n * reaches, each time the layer is placed. Returns the stop, which hides the layer.\n */\nexport function attachViewerLayer(\n layer: HTMLElement,\n onPlace?: (edges: ScreenEdges) => void,\n): () => void {\n const root = layer.parentElement?.closest(VIEWER_ROOT_SELECTOR) ?? null;\n if (typeof layer.showPopover === 'function') layer.showPopover();\n let placed = '';\n const place = () => {\n const view = windowSizeOf(layer);\n const rect = root?.getBoundingClientRect() ?? {\n left: 0,\n top: 0,\n right: view.width,\n bottom: view.height,\n };\n const left = Math.max(0, rect.left);\n const top = Math.max(0, rect.top);\n const box = {\n left,\n top,\n width: Math.max(0, Math.min(view.width, rect.right) - left),\n height: Math.max(0, Math.min(view.height, rect.bottom) - top),\n };\n // Scrolling inside the layer reaches here too: only a move of the viewer changes anything.\n const key = `${box.left},${box.top},${box.width},${box.height},${view.width},${view.height}`;\n if (key === placed) return;\n placed = key;\n placeFixed(layer, box);\n onPlace?.(screenEdgesOf(rect, view));\n };\n place();\n const resizes = new ResizeObserver(place);\n if (root) resizes.observe(root);\n const stopGeometry = observeClientGeometry(place);\n return () => {\n stopGeometry();\n resizes.disconnect();\n if (typeof layer.hidePopover === 'function' && layer.matches(':popover-open')) {\n layer.hidePopover();\n }\n };\n}\n\nexport interface HeldFocus {\n /** Stop holding focus, leaving it where it is. */\n standDown(): void;\n /** Stop holding focus, and give it back to what had it before when it's still in `container`. */\n release(): void;\n}\n\n/**\n * Hold the keyboard in `container` until released: focus moves into it unless it's there\n * already (to `initialFocus`, else its first control), so a field that took the cursor as it\n * appeared keeps it; Tab and Shift+Tab stay inside it, and Escape calls `onEscape`. With\n * `trap: false` Tab moves on past it, as it does past anything else in the viewer. Releasing\n * gives focus back to what had it before, unless the user has moved it elsewhere: a press on\n * the pages, which puts focus on the viewer's root, doesn't count.\n */\nexport function holdFocus(\n container: HTMLElement,\n options: {\n readonly onEscape: () => void;\n readonly initialFocus?: HTMLElement | null;\n readonly trap?: boolean;\n },\n): HeldFocus {\n const doc = container.ownerDocument;\n const before = deepActiveElementOf(doc) as HTMLElement | null;\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key !== 'Escape' || event.defaultPrevented) return;\n event.preventDefault();\n // Escape closes this, not what it opened over.\n event.stopPropagation();\n options.onEscape();\n };\n container.addEventListener('keydown', onKeyDown);\n let releaseTrap: (() => void) | null = null;\n if (options.trap === false) {\n moveFocusInto(container, options.initialFocus);\n } else {\n releaseTrap = attachFocusTrap(container, {\n initialFocus: options.initialFocus,\n returnFocus: false,\n });\n }\n const standDown = () => {\n releaseTrap?.();\n releaseTrap = null;\n container.removeEventListener('keydown', onKeyDown);\n };\n return {\n standDown,\n release: () => {\n standDown();\n const active = deepActiveElementOf(doc);\n const nowhere =\n active === null || container.contains(active) || active.hasAttribute(FOCUS_ROOT_ATTRIBUTE);\n if (before?.isConnected && nowhere) before.focus();\n },\n };\n}\n","/**\n * Where a sheet comes to rest after its handle is let go: at one of the\n * heights it rests at, or closed. A flick moves it a whole step, down to the\n * next lower height (closing from the lowest) or up to the next higher one;\n * a slow drag settles at the nearest height, and closes when the sheet was\n * dragged below half of the lowest.\n */\n\n/** A release faster than this, in px per second, is a flick. */\nexport const SHEET_FLICK_PX_PER_S = 500;\n\n/** How much of the viewer's height a panel's sheet opens at. */\nexport const PANEL_SHEET_OPEN_FRACTION = 0.5;\n\n/** Px a sheet leaves above itself at its tallest, so the pages show it's a sheet. */\nexport const SHEET_TOP_CLEARANCE_PX = 40;\n\n/**\n * The height a sheet dragged to `height` comes to rest at, one of `heights` (ascending), or null\n * when it closes. `velocity` is the release speed in px per second, downward positive.\n */\nexport function sheetRestOf(\n heights: readonly number[],\n height: number,\n velocity: number,\n): number | null {\n if (heights.length === 0) return null;\n if (velocity >= SHEET_FLICK_PX_PER_S) {\n const lower = heights.filter((rest) => rest < height - 1);\n return lower.length > 0 ? lower[lower.length - 1]! : null;\n }\n if (velocity <= -SHEET_FLICK_PX_PER_S) {\n return heights.find((rest) => rest > height + 1) ?? heights[heights.length - 1]!;\n }\n if (height < heights[0]! / 2) return null;\n return heights.reduce((nearest, rest) =>\n Math.abs(rest - height) < Math.abs(nearest - height) ? rest : nearest,\n );\n}\n\n/** The heights a panel's sheet rests at in a viewer `viewerHeight` px tall: half of it, and nearly all. */\nexport function panelSheetHeightsOf(viewerHeight: number): readonly number[] {\n const tallest = Math.max(0, Math.round(viewerHeight - SHEET_TOP_CLEARANCE_PX));\n const open = Math.min(tallest, Math.round(viewerHeight * PANEL_SHEET_OPEN_FRACTION));\n return open < tallest ? [open, tallest] : [tallest];\n}\n","/**\n * A sheet: what a panel or a menu is on a phone. It slides up from the bottom\n * of the viewer, over the pages, in a layer over the whole viewer\n * (`viewer-layer.ts`); the viewer above it dims, and a tap there closes it.\n * Its handle drags it taller or shorter, or down to close it, and a flick\n * moves it a whole step (`sheet-rest.ts`). It keeps clear of the home bar and\n * the screen's rounded corners when the viewer reaches the screen's edge.\n * A sheet takes focus when it opens, keeps Tab inside it, closes on Escape\n * and gives focus back to the button that opened it; a menu's sheet leaves\n * the keyboard to its menu. A sheet that holds a list closes when one of its\n * items is picked ({@link useCloseOnPick}).\n */\nimport { computeReleaseVelocity, observeOutsidePress } from '@embedpdf/web';\nimport {\n createContext,\n useContext,\n useLayoutEffect,\n useRef,\n type PointerEvent as ReactPointerEvent,\n type ReactNode,\n} from 'react';\n\nimport { safeAreaPaddingOf } from './screen-edges';\nimport { SHEET_TOP_CLEARANCE_PX, panelSheetHeightsOf, sheetRestOf } from './sheet-rest';\nimport { MODAL_SELECTOR, POPOVER, attachViewerLayer, holdFocus } from './viewer-layer';\n\n/** A press that starts on one of these in the handle's row is the control's, not a drag. */\nconst CONTROL_SELECTOR =\n 'button, a[href], input, select, textarea, [role=\"tab\"], [contenteditable]:not([contenteditable=\"false\"])';\n\n/** The dimmed viewer behind a sheet or a dialog. */\nexport const SCRIM_CLASS = 'bg-black/30 transition-opacity duration-200 starting:opacity-0';\n\nconst NO_PICK = () => {};\n\nconst CloseOnPickContext = createContext<() => void>(NO_PICK);\n\n/** Gives what's inside a sheet or an overlay the close it runs when one of its items is picked. */\nexport const CloseOnPickProvider = CloseOnPickContext.Provider;\n\n/**\n * What a list's item runs when it's picked: it closes the sheet or the overlay the list is in,\n * so you see where it took you. It does nothing in a docked panel, or in one that isn't a list.\n */\nexport function useCloseOnPick(): () => void {\n return useContext(CloseOnPickContext);\n}\n\n/** Whether a press landed in another surface that holds focus, like a dialog opened over this one. */\nconst pressedInOtherModal = (event: PointerEvent, own: Element): boolean =>\n event\n .composedPath()\n .some((node) => node instanceof Element && node !== own && node.matches(MODAL_SELECTOR));\n\nexport interface SheetProps {\n /** Names the sheet for assistive technology. */\n readonly label: string;\n readonly onClose: () => void;\n /**\n * `'content'`: as tall as what's in it, like a menu. `'panel'`: opens at half the viewer's\n * height, and drags up to nearly all of it. Default `'content'`.\n */\n readonly size?: 'content' | 'panel';\n /** It holds a list: picking an item ({@link useCloseOnPick}) closes it. */\n readonly list?: boolean;\n /**\n * Whether it holds the keyboard (default true). A menu's sheet doesn't: its menu takes focus\n * and gives it back.\n */\n readonly trapFocus?: boolean;\n /** Drawn under the handle, above the part that scrolls; dragging it moves the sheet too. */\n readonly header?: ReactNode;\n /** The sheet's part name, for page CSS through `::part()`, when it is one: a panel's `panel`. */\n readonly part?: string;\n /** `data-*` attributes for the sheet, by their names without `data-`. */\n readonly data?: Readonly<Record<string, string>>;\n readonly children: ReactNode;\n}\n\ninterface Drag {\n readonly pointerId: number;\n readonly startY: number;\n readonly startHeight: number;\n /** The heights it can rest at, ascending. */\n readonly heights: readonly number[];\n readonly samples: { t: number; x: number; y: number }[];\n height: number;\n}\n\n/** `data` as the `data-*` attributes it names. */\nconst dataAttributesOf = (data: Readonly<Record<string, string>> | undefined) =>\n Object.fromEntries(Object.entries(data ?? {}).map(([name, value]) => [`data-${name}`, value]));\n\n/** How many pointer samples a drag keeps for its release speed. */\nconst DRAG_SAMPLES = 8;\n\nexport function Sheet({\n label,\n onClose,\n size = 'content',\n list = false,\n trapFocus = true,\n header,\n part,\n data,\n children,\n}: SheetProps) {\n const layer = useRef<HTMLDivElement>(null);\n const sheet = useRef<HTMLDivElement>(null);\n const close = useRef(onClose);\n close.current = onClose;\n /** Which of its heights a panel's sheet rests at: the first (open) or a taller one. */\n const restIndex = useRef(0);\n const drag = useRef<Drag | null>(null);\n\n /** The heights it rests at now: a panel's from the viewer's height, a menu's as tall as it is. */\n const heightsNow = (): readonly number[] =>\n size === 'panel'\n ? panelSheetHeightsOf(layer.current?.offsetHeight ?? 0)\n : [sheet.current?.offsetHeight ?? 0];\n\n /** Show the sheet dragged to `height` (its top that far above the viewer's bottom). */\n const show = (height: number, heights: readonly number[]) => {\n const element = sheet.current;\n if (!element || heights.length === 0) return;\n const lowest = heights[0]!;\n const tallest = heights[heights.length - 1]!;\n if (size === 'panel') element.style.height = `${Math.min(tallest, Math.max(lowest, height))}px`;\n const below = Math.max(0, lowest - height);\n element.style.translate = below > 0 ? `0 ${below}px` : '';\n };\n\n useLayoutEffect(() => {\n const layerElement = layer.current;\n const sheetElement = sheet.current;\n if (!layerElement || !sheetElement) return;\n const stopLayer = attachViewerLayer(layerElement, (edges) => {\n const padding = safeAreaPaddingOf(edges, ['right', 'bottom', 'left']);\n sheetElement.style.paddingLeft = padding.paddingLeft ?? '';\n sheetElement.style.paddingRight = padding.paddingRight ?? '';\n sheetElement.style.paddingBottom = padding.paddingBottom ?? '';\n sheetElement.style.maxHeight = `${Math.max(0, layerElement.offsetHeight - SHEET_TOP_CLEARANCE_PX)}px`;\n if (size === 'panel' && !drag.current) {\n const heights = panelSheetHeightsOf(layerElement.offsetHeight);\n show(heights[Math.min(restIndex.current, heights.length - 1)]!, heights);\n }\n });\n const held = trapFocus ? holdFocus(sheetElement, { onEscape: () => close.current() }) : null;\n // A press on the viewer above the sheet is the scrim's click; one outside the viewer closes it too.\n const stopOutside = observeOutsidePress(layerElement, (event) => {\n if (!pressedInOtherModal(event, sheetElement)) close.current();\n });\n return () => {\n stopOutside();\n held?.release();\n stopLayer();\n };\n // The sheet opens once; it closes by unmounting.\n }, []);\n\n const onGripDown = (event: ReactPointerEvent<HTMLDivElement>) => {\n if (event.pointerType === 'mouse' && event.button !== 0) return;\n if ((event.target as Element).closest(CONTROL_SELECTOR)) return;\n const element = sheet.current;\n if (!element) return;\n event.currentTarget.setPointerCapture(event.pointerId);\n const startHeight = element.offsetHeight;\n drag.current = {\n pointerId: event.pointerId,\n startY: event.clientY,\n startHeight,\n heights: heightsNow(),\n samples: [{ t: event.timeStamp, x: event.clientX, y: event.clientY }],\n height: startHeight,\n };\n element.setAttribute('data-dragging', '');\n };\n\n const onGripMove = (event: ReactPointerEvent<HTMLDivElement>) => {\n const current = drag.current;\n if (!current || current.pointerId !== event.pointerId) return;\n current.height = current.startHeight - (event.clientY - current.startY);\n current.samples.push({ t: event.timeStamp, x: event.clientX, y: event.clientY });\n if (current.samples.length > DRAG_SAMPLES) current.samples.shift();\n show(current.height, current.heights);\n };\n\n const onGripUp = (event: ReactPointerEvent<HTMLDivElement>) => {\n const current = drag.current;\n if (!current || current.pointerId !== event.pointerId) return;\n drag.current = null;\n sheet.current?.removeAttribute('data-dragging');\n const cancelled = event.type === 'pointercancel';\n const velocity = cancelled\n ? 0\n : (computeReleaseVelocity(current.samples, event.timeStamp)?.vy ?? 0);\n const rest = cancelled\n ? current.heights[restIndex.current]!\n : sheetRestOf(current.heights, current.height, velocity);\n if (rest === null) {\n close.current();\n return;\n }\n restIndex.current = Math.max(0, current.heights.indexOf(rest));\n show(rest, current.heights);\n };\n\n return (\n <div\n ref={layer}\n {...POPOVER}\n data-epdf-layer=\"\"\n className=\"text-fg m-0 overflow-hidden border-0 bg-transparent p-0 open:flex open:flex-col\"\n style={{ position: 'fixed', inset: 'auto', maxWidth: 'none', maxHeight: 'none' }}\n >\n <div\n aria-hidden=\"true\"\n className={`min-h-0 flex-1 ${SCRIM_CLASS}`}\n onClick={() => close.current()}\n />\n <div\n ref={sheet}\n role={trapFocus ? 'dialog' : undefined}\n aria-modal={trapFocus ? true : undefined}\n aria-label={trapFocus ? label : undefined}\n part={part}\n {...dataAttributesOf(data)}\n data-epdf-sheet=\"\"\n className=\"border-border-subtle bg-elevated starting:translate-y-full data-dragging:transition-none relative flex w-full shrink-0 flex-col rounded-t-2xl border-t shadow-2xl transition-[translate,height] duration-200 ease-out motion-reduce:transition-none\"\n >\n <div\n className=\"shrink-0 touch-pan-x select-none\"\n onPointerDown={onGripDown}\n onPointerMove={onGripMove}\n onPointerUp={onGripUp}\n onPointerCancel={onGripUp}\n >\n <div\n data-epdf-sheet-handle=\"\"\n className=\"flex h-6 cursor-grab items-center justify-center active:cursor-grabbing\"\n >\n <span className=\"bg-border-strong h-1 w-10 rounded-full\" />\n </div>\n {header}\n </div>\n <div className=\"flex min-h-0 flex-1 flex-col overflow-y-auto overflow-x-hidden overscroll-contain\">\n <CloseOnPickProvider value={list ? () => close.current() : NO_PICK}>\n {children}\n </CloseOnPickProvider>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|