kviewer 0.0.4 → 0.0.6
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 +3 -0
- package/dist/module.json +2 -2
- package/dist/runtime/annotation/engine/painter.d.ts +7 -0
- package/dist/runtime/annotation/engine/painter.js +14 -0
- package/dist/runtime/annotation/engine/store.d.ts +5 -0
- package/dist/runtime/annotation/engine/store.js +17 -0
- package/dist/runtime/annotation/engine/tools/free-text.js +3 -1
- package/dist/runtime/annotation/engine/types.d.ts +20 -0
- package/dist/runtime/annotation/pdf-export/export.d.ts +4 -1
- package/dist/runtime/annotation/pdf-export/export.js +101 -4
- package/dist/runtime/annotation/pdf-export/parse_freetext.js +106 -18
- package/dist/runtime/annotation/pdf-export/parse_highlight.js +22 -6
- package/dist/runtime/annotation/pdf-export/parse_ink.js +32 -3
- package/dist/runtime/annotation/pdf-export/parse_line.js +133 -13
- package/dist/runtime/annotation/pdf-import/decode.d.ts +21 -0
- package/dist/runtime/annotation/pdf-import/decode.js +134 -0
- package/dist/runtime/annotation/pdf-import/decode_circle.d.ts +3 -0
- package/dist/runtime/annotation/pdf-import/decode_circle.js +36 -0
- package/dist/runtime/annotation/pdf-import/decode_freetext.d.ts +3 -0
- package/dist/runtime/annotation/pdf-import/decode_freetext.js +87 -0
- package/dist/runtime/annotation/pdf-import/decode_highlight.d.ts +3 -0
- package/dist/runtime/annotation/pdf-import/decode_highlight.js +96 -0
- package/dist/runtime/annotation/pdf-import/decode_ink.d.ts +3 -0
- package/dist/runtime/annotation/pdf-import/decode_ink.js +48 -0
- package/dist/runtime/annotation/pdf-import/decode_line.d.ts +3 -0
- package/dist/runtime/annotation/pdf-import/decode_line.js +48 -0
- package/dist/runtime/annotation/pdf-import/decode_square.d.ts +3 -0
- package/dist/runtime/annotation/pdf-import/decode_square.js +39 -0
- package/dist/runtime/annotation/pdf-import/decode_stamp.d.ts +3 -0
- package/dist/runtime/annotation/pdf-import/decode_stamp.js +38 -0
- package/dist/runtime/annotation/pdf-import/decode_text.d.ts +3 -0
- package/dist/runtime/annotation/pdf-import/decode_text.js +33 -0
- package/dist/runtime/annotation/pdf-import/extract_stamp_appearance.d.ts +23 -0
- package/dist/runtime/annotation/pdf-import/extract_stamp_appearance.js +168 -0
- package/dist/runtime/annotation/pdf-import/types.d.ts +57 -0
- package/dist/runtime/annotation/pdf-import/types.js +25 -0
- package/dist/runtime/annotation/pdf-import/utils.d.ts +48 -0
- package/dist/runtime/annotation/pdf-import/utils.js +250 -0
- package/dist/runtime/assets/kviewer.css +1 -1
- package/dist/runtime/components/AnnotationToolbar.vue +1 -0
- package/dist/runtime/components/FloatingPageIndicator.vue +4 -1
- package/dist/runtime/components/PdfPage.vue +27 -1
- package/dist/runtime/components/Viewer.d.vue.ts +12 -1
- package/dist/runtime/components/Viewer.vue +114 -35
- package/dist/runtime/components/Viewer.vue.d.ts +12 -1
- package/dist/runtime/components/ViewerBar.vue +3 -14
- package/dist/runtime/components/ViewerTabs.d.vue.ts +16 -1
- package/dist/runtime/components/ViewerTabs.vue +42 -12
- package/dist/runtime/components/ViewerTabs.vue.d.ts +16 -1
- package/dist/runtime/components/form-fields/FormCheckbox.vue +37 -1
- package/dist/runtime/components/tools/ActionTools.vue +3 -0
- package/dist/runtime/components/tools/PageInfo.vue +1 -1
- package/dist/runtime/components/tools/SearchTool.vue +3 -1
- package/dist/runtime/components/tools/ZoomControls.vue +3 -0
- package/dist/runtime/composables/shape-detection-utils.d.ts +38 -0
- package/dist/runtime/composables/shape-detection-utils.js +50 -0
- package/dist/runtime/composables/useFormFields.d.ts +3 -1
- package/dist/runtime/composables/useFormFields.js +47 -0
- package/dist/runtime/composables/useShapeDetection.d.ts +24 -0
- package/dist/runtime/composables/useShapeDetection.js +235 -0
- package/dist/runtime/composables/useViewerState.d.ts +4 -0
- package/dist/runtime/composables/useViewerState.js +13 -1
- package/package.json +28 -5
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import { provide, inject } from "vue";
|
|
2
|
+
import {
|
|
3
|
+
pdfRectToViewport,
|
|
4
|
+
isCheckboxLikePdf,
|
|
5
|
+
isCheckboxLikeWidget,
|
|
6
|
+
makeShape,
|
|
7
|
+
SYMBOL_CHARS
|
|
8
|
+
} from "./shape-detection-utils.js";
|
|
9
|
+
const SHAPE_DETECTION_KEY = Symbol("kviewer-shape-detection");
|
|
10
|
+
let opsPromise = null;
|
|
11
|
+
function getOPS() {
|
|
12
|
+
if (!opsPromise) {
|
|
13
|
+
opsPromise = import("pdfjs-dist/legacy/build/pdf.mjs").then(
|
|
14
|
+
(pdfjs) => pdfjs.OPS
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
return opsPromise;
|
|
18
|
+
}
|
|
19
|
+
async function detectAnnotationShapes(pageNumber, pdfPage, viewport) {
|
|
20
|
+
const shapes = [];
|
|
21
|
+
const annotations = await pdfPage.getAnnotations({ intent: "display" });
|
|
22
|
+
for (const annot of annotations) {
|
|
23
|
+
if (!annot.rect) continue;
|
|
24
|
+
const isWidget = annot.fieldType === "Btn" || annot.subtype === "Widget" || annot.subtype === "Square" || annot.subtype === "Circle";
|
|
25
|
+
if (!isWidget) continue;
|
|
26
|
+
const [x1, y1, x2, y2] = annot.rect;
|
|
27
|
+
const { left, top, w, h } = pdfRectToViewport(viewport, x1, y1, x2, y2);
|
|
28
|
+
if (!isCheckboxLikeWidget(w, h)) continue;
|
|
29
|
+
shapes.push(
|
|
30
|
+
makeShape(
|
|
31
|
+
annot.id || `annot_p${pageNumber}_${shapes.length}`,
|
|
32
|
+
left,
|
|
33
|
+
top,
|
|
34
|
+
w,
|
|
35
|
+
h
|
|
36
|
+
)
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
return shapes;
|
|
40
|
+
}
|
|
41
|
+
async function detectGraphicalShapes(pageNumber, pdfPage, viewport) {
|
|
42
|
+
const shapes = [];
|
|
43
|
+
try {
|
|
44
|
+
const opList = await pdfPage.getOperatorList();
|
|
45
|
+
const OPS = await getOPS();
|
|
46
|
+
let pathStarted = false;
|
|
47
|
+
let currentPath = [];
|
|
48
|
+
let pathBBox = null;
|
|
49
|
+
const addShape = (x, y, w, h, type) => {
|
|
50
|
+
const aw = Math.abs(w);
|
|
51
|
+
const ah = Math.abs(h);
|
|
52
|
+
if (!isCheckboxLikePdf(aw, ah)) return;
|
|
53
|
+
const { left, top, w: vw, h: vh } = pdfRectToViewport(viewport, x, y, x + w, y + h);
|
|
54
|
+
shapes.push(makeShape(`gfx_p${pageNumber}_${shapes.length}`, left, top, vw, vh, type));
|
|
55
|
+
};
|
|
56
|
+
const checkPathBBox = (type) => {
|
|
57
|
+
if (!pathBBox) return;
|
|
58
|
+
const w = pathBBox.maxX - pathBBox.minX;
|
|
59
|
+
const h = pathBBox.maxY - pathBBox.minY;
|
|
60
|
+
if (!isCheckboxLikePdf(w, h)) return;
|
|
61
|
+
const { left, top, w: vw, h: vh } = pdfRectToViewport(
|
|
62
|
+
viewport,
|
|
63
|
+
pathBBox.minX,
|
|
64
|
+
pathBBox.minY,
|
|
65
|
+
pathBBox.maxX,
|
|
66
|
+
pathBBox.maxY
|
|
67
|
+
);
|
|
68
|
+
shapes.push(makeShape(`gfx_p${pageNumber}_${shapes.length}`, left, top, vw, vh, type));
|
|
69
|
+
};
|
|
70
|
+
const expandBBox = (x, y) => {
|
|
71
|
+
if (!pathBBox) {
|
|
72
|
+
pathBBox = { minX: x, maxX: x, minY: y, maxY: y };
|
|
73
|
+
} else {
|
|
74
|
+
pathBBox.minX = Math.min(pathBBox.minX, x);
|
|
75
|
+
pathBBox.maxX = Math.max(pathBBox.maxX, x);
|
|
76
|
+
pathBBox.minY = Math.min(pathBBox.minY, y);
|
|
77
|
+
pathBBox.maxY = Math.max(pathBBox.maxY, y);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
for (let i = 0; i < opList.fnArray.length; i++) {
|
|
81
|
+
const fn = opList.fnArray[i];
|
|
82
|
+
const args = opList.argsArray[i];
|
|
83
|
+
if (fn === OPS.rectangle) {
|
|
84
|
+
const [x, y, w, h] = args;
|
|
85
|
+
addShape(x, y, w, h, "rectangle");
|
|
86
|
+
} else if (fn === OPS.constructPath) {
|
|
87
|
+
if (args[2] && args[2].length === 4) {
|
|
88
|
+
const bbox = args[2];
|
|
89
|
+
const bw = bbox[2] - bbox[0];
|
|
90
|
+
const bh = bbox[3] - bbox[1];
|
|
91
|
+
addShape(bbox[0], bbox[1], bw, bh, "rectangle");
|
|
92
|
+
} else if (Array.isArray(args[0])) {
|
|
93
|
+
const ops = args[0];
|
|
94
|
+
const coords = args[1];
|
|
95
|
+
if (!ops || !coords) continue;
|
|
96
|
+
currentPath = [];
|
|
97
|
+
pathBBox = null;
|
|
98
|
+
let ci = 0;
|
|
99
|
+
for (let oi = 0; oi < ops.length; oi++) {
|
|
100
|
+
const op = ops[oi];
|
|
101
|
+
if (op === OPS.moveTo) {
|
|
102
|
+
const x = coords[ci++];
|
|
103
|
+
const y = coords[ci++];
|
|
104
|
+
currentPath.push([x, y]);
|
|
105
|
+
expandBBox(x, y);
|
|
106
|
+
} else if (op === OPS.lineTo) {
|
|
107
|
+
const x = coords[ci++];
|
|
108
|
+
const y = coords[ci++];
|
|
109
|
+
currentPath.push([x, y]);
|
|
110
|
+
expandBBox(x, y);
|
|
111
|
+
} else if (op === OPS.rectangle) {
|
|
112
|
+
const x = coords[ci++];
|
|
113
|
+
const y = coords[ci++];
|
|
114
|
+
const w = coords[ci++];
|
|
115
|
+
const h = coords[ci++];
|
|
116
|
+
addShape(x, y, w, h, "rectangle");
|
|
117
|
+
} else if (op === OPS.curveTo) {
|
|
118
|
+
ci += 6;
|
|
119
|
+
} else if (op === OPS.curveTo2) {
|
|
120
|
+
ci += 4;
|
|
121
|
+
} else if (op === OPS.curveTo3) {
|
|
122
|
+
ci += 4;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (pathBBox && currentPath.length >= 4) {
|
|
126
|
+
checkPathBBox(currentPath.length > 8 ? "circle" : "rectangle");
|
|
127
|
+
}
|
|
128
|
+
pathStarted = true;
|
|
129
|
+
}
|
|
130
|
+
} else if (fn === OPS.moveTo) {
|
|
131
|
+
pathStarted = true;
|
|
132
|
+
currentPath = [[args[0], args[1]]];
|
|
133
|
+
pathBBox = null;
|
|
134
|
+
expandBBox(args[0], args[1]);
|
|
135
|
+
} else if (fn === OPS.lineTo && pathStarted) {
|
|
136
|
+
currentPath.push([args[0], args[1]]);
|
|
137
|
+
expandBBox(args[0], args[1]);
|
|
138
|
+
} else if (pathStarted && (fn === OPS.stroke || fn === OPS.fill || fn === OPS.eoFill || fn === OPS.fillStroke)) {
|
|
139
|
+
if ((currentPath.length === 5 || currentPath.length > 8) && pathBBox) {
|
|
140
|
+
checkPathBBox(currentPath.length > 8 ? "circle" : "rectangle");
|
|
141
|
+
}
|
|
142
|
+
pathStarted = false;
|
|
143
|
+
currentPath = [];
|
|
144
|
+
pathBBox = null;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
} catch (err) {
|
|
148
|
+
console.error("[ShapeDetection] Graphical detection error:", err);
|
|
149
|
+
}
|
|
150
|
+
return shapes;
|
|
151
|
+
}
|
|
152
|
+
async function detectIconFontShapes(pageNumber, pdfPage, viewport) {
|
|
153
|
+
const shapes = [];
|
|
154
|
+
try {
|
|
155
|
+
const textContent = await pdfPage.getTextContent();
|
|
156
|
+
for (const item of textContent.items) {
|
|
157
|
+
if (!("str" in item) || !item.str || !("transform" in item) || !item.transform) continue;
|
|
158
|
+
const char = item.str;
|
|
159
|
+
const code = char.charCodeAt(0);
|
|
160
|
+
const isSymbol = SYMBOL_CHARS.has(char);
|
|
161
|
+
const isBox = code >= 9472 && code <= 9599;
|
|
162
|
+
const isGeo = code >= 9632 && code <= 9727;
|
|
163
|
+
const isPUA = code >= 57344 && code <= 63743;
|
|
164
|
+
if (!isSymbol && !isBox && !isGeo && !isPUA) continue;
|
|
165
|
+
const t = item.transform;
|
|
166
|
+
const w = item.width || Math.abs(t[0]);
|
|
167
|
+
const h = item.height || Math.abs(t[3]);
|
|
168
|
+
const x = t[4];
|
|
169
|
+
const y = t[5];
|
|
170
|
+
const minSize = isPUA ? 12 : 5;
|
|
171
|
+
if (w < minSize || w > 40 || h < minSize || h > 40) continue;
|
|
172
|
+
if (isPUA) {
|
|
173
|
+
const ratio = w / h;
|
|
174
|
+
if (ratio < 0.8 || ratio > 1.25) continue;
|
|
175
|
+
}
|
|
176
|
+
const { left, top, w: vw, h: vh } = pdfRectToViewport(viewport, x, y, x + w, y + h);
|
|
177
|
+
const type = isPUA ? "circle" : void 0;
|
|
178
|
+
shapes.push(makeShape(`icon_p${pageNumber}_${shapes.length}`, left, top, vw, vh, type));
|
|
179
|
+
}
|
|
180
|
+
} catch (err) {
|
|
181
|
+
console.error("[ShapeDetection] Icon-font detection error:", err);
|
|
182
|
+
}
|
|
183
|
+
return shapes;
|
|
184
|
+
}
|
|
185
|
+
export function createShapeDetection() {
|
|
186
|
+
const shapeCache = /* @__PURE__ */ new Map();
|
|
187
|
+
async function preprocessShapesForPage(pageNumber, pdfPage, viewport) {
|
|
188
|
+
try {
|
|
189
|
+
const [annotShapes, gfxShapes, iconShapes] = await Promise.all([
|
|
190
|
+
detectAnnotationShapes(pageNumber, pdfPage, viewport),
|
|
191
|
+
detectGraphicalShapes(pageNumber, pdfPage, viewport),
|
|
192
|
+
detectIconFontShapes(pageNumber, pdfPage, viewport)
|
|
193
|
+
]);
|
|
194
|
+
const shapes = [...annotShapes, ...gfxShapes, ...iconShapes];
|
|
195
|
+
shapeCache.set(pageNumber, shapes);
|
|
196
|
+
if (import.meta.dev) {
|
|
197
|
+
console.debug(
|
|
198
|
+
`[ShapeDetection] Page ${pageNumber}: ${shapes.length} shapes (${annotShapes.length} annot, ${gfxShapes.length} gfx, ${iconShapes.length} icon)`
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
return shapes;
|
|
202
|
+
} catch (err) {
|
|
203
|
+
console.error("[ShapeDetection] preprocessShapesForPage error:", err);
|
|
204
|
+
shapeCache.set(pageNumber, []);
|
|
205
|
+
return [];
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
function findShapeAtPoint(pageNumber, x, y) {
|
|
209
|
+
const shapes = shapeCache.get(pageNumber) || [];
|
|
210
|
+
return shapes.find(
|
|
211
|
+
(s) => x >= s.rect.x && x <= s.rect.x + s.rect.w && y >= s.rect.y && y <= s.rect.y + s.rect.h
|
|
212
|
+
) || null;
|
|
213
|
+
}
|
|
214
|
+
function clearShapeCache(pageNumber) {
|
|
215
|
+
shapeCache.delete(pageNumber);
|
|
216
|
+
}
|
|
217
|
+
function clearAllShapeCache() {
|
|
218
|
+
shapeCache.clear();
|
|
219
|
+
}
|
|
220
|
+
const detection = {
|
|
221
|
+
preprocessShapesForPage,
|
|
222
|
+
findShapeAtPoint,
|
|
223
|
+
clearShapeCache,
|
|
224
|
+
clearAllShapeCache
|
|
225
|
+
};
|
|
226
|
+
provide(SHAPE_DETECTION_KEY, detection);
|
|
227
|
+
return detection;
|
|
228
|
+
}
|
|
229
|
+
export function useShapeDetection() {
|
|
230
|
+
const detection = inject(SHAPE_DETECTION_KEY);
|
|
231
|
+
if (!detection) {
|
|
232
|
+
throw new Error("useShapeDetection() must be used inside a <KViewer> component");
|
|
233
|
+
}
|
|
234
|
+
return detection;
|
|
235
|
+
}
|
|
@@ -26,6 +26,7 @@ export interface ViewerState {
|
|
|
26
26
|
currentPage: Ref<number>;
|
|
27
27
|
totalPages: Ref<number>;
|
|
28
28
|
isLoading: Ref<boolean>;
|
|
29
|
+
error: Ref<string | null>;
|
|
29
30
|
activeTool: Ref<ActiveTool>;
|
|
30
31
|
doc: ShallowRef<PDFDocumentProxy | null>;
|
|
31
32
|
annotations: ShallowRef<Map<string, IAnnotationStore>>;
|
|
@@ -52,12 +53,15 @@ export interface ViewerState {
|
|
|
52
53
|
stylusMode: Ref<boolean>;
|
|
53
54
|
setStylusMode: (enabled: boolean) => void;
|
|
54
55
|
scrollToPage: (pageNumber: number) => void;
|
|
56
|
+
downloadPdf: () => Promise<void>;
|
|
55
57
|
history: AnnotationHistory;
|
|
56
58
|
readonly: Ref<boolean>;
|
|
59
|
+
shapeDetection: Ref<boolean>;
|
|
57
60
|
}
|
|
58
61
|
export interface ViewerStateProvider {
|
|
59
62
|
state: ViewerState;
|
|
60
63
|
setScrollToPageFn: (fn: (pageNumber: number) => void) => void;
|
|
64
|
+
setDownloadPdfFn: (fn: () => Promise<void>) => void;
|
|
61
65
|
}
|
|
62
66
|
export declare function provideViewerState(): ViewerStateProvider;
|
|
63
67
|
export declare function useViewerState(): ViewerState;
|
|
@@ -20,6 +20,7 @@ export function provideViewerState() {
|
|
|
20
20
|
const currentPage = ref(1);
|
|
21
21
|
const totalPages = ref(0);
|
|
22
22
|
const isLoading = ref(false);
|
|
23
|
+
const error = ref(null);
|
|
23
24
|
const activeTool = ref("hand");
|
|
24
25
|
const doc = shallowRef(null);
|
|
25
26
|
const annotations = shallowRef(/* @__PURE__ */ new Map());
|
|
@@ -63,6 +64,7 @@ export function provideViewerState() {
|
|
|
63
64
|
}
|
|
64
65
|
}
|
|
65
66
|
const readonly = ref(false);
|
|
67
|
+
const shapeDetectionEnabled = ref(false);
|
|
66
68
|
const stylusMode = ref(false);
|
|
67
69
|
function setStylusMode(enabled) {
|
|
68
70
|
stylusMode.value = enabled;
|
|
@@ -128,9 +130,13 @@ export function provideViewerState() {
|
|
|
128
130
|
return painter.value?.getData() ?? [];
|
|
129
131
|
}
|
|
130
132
|
let _scrollToPageFn = null;
|
|
133
|
+
let _downloadPdfFn = null;
|
|
131
134
|
function scrollToPage(pageNumber) {
|
|
132
135
|
_scrollToPageFn?.(pageNumber);
|
|
133
136
|
}
|
|
137
|
+
async function downloadPdf() {
|
|
138
|
+
await _downloadPdfFn?.();
|
|
139
|
+
}
|
|
134
140
|
const history = createAnnotationHistory(annotations, painter);
|
|
135
141
|
const state = {
|
|
136
142
|
scale,
|
|
@@ -145,6 +151,7 @@ export function provideViewerState() {
|
|
|
145
151
|
currentPage,
|
|
146
152
|
totalPages,
|
|
147
153
|
isLoading,
|
|
154
|
+
error,
|
|
148
155
|
activeTool,
|
|
149
156
|
doc,
|
|
150
157
|
annotations,
|
|
@@ -171,14 +178,19 @@ export function provideViewerState() {
|
|
|
171
178
|
stylusMode,
|
|
172
179
|
setStylusMode,
|
|
173
180
|
scrollToPage,
|
|
181
|
+
downloadPdf,
|
|
174
182
|
history,
|
|
175
|
-
readonly
|
|
183
|
+
readonly,
|
|
184
|
+
shapeDetection: shapeDetectionEnabled
|
|
176
185
|
};
|
|
177
186
|
provide(VIEWER_STATE_KEY, state);
|
|
178
187
|
return {
|
|
179
188
|
state,
|
|
180
189
|
setScrollToPageFn(fn) {
|
|
181
190
|
_scrollToPageFn = fn;
|
|
191
|
+
},
|
|
192
|
+
setDownloadPdfFn(fn) {
|
|
193
|
+
_downloadPdfFn = fn;
|
|
182
194
|
}
|
|
183
195
|
};
|
|
184
196
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kviewer",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"description": "Kabema PDF Editor",
|
|
5
5
|
"repository": "kabema/kviewer",
|
|
6
6
|
"license": "MIT",
|
|
@@ -23,7 +23,8 @@
|
|
|
23
23
|
"dist"
|
|
24
24
|
],
|
|
25
25
|
"workspaces": [
|
|
26
|
-
"playground"
|
|
26
|
+
"playground",
|
|
27
|
+
"docs"
|
|
27
28
|
],
|
|
28
29
|
"scripts": {
|
|
29
30
|
"prepack": "nuxt-module-build build",
|
|
@@ -32,9 +33,11 @@
|
|
|
32
33
|
"dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxt prepare playground",
|
|
33
34
|
"release": "npm run lint && npm run test && npm run prepack && changelogen --release && npm publish && git push --follow-tags",
|
|
34
35
|
"lint": "eslint .",
|
|
35
|
-
"test": "vitest run",
|
|
36
|
+
"test": "vitest run --exclude '**/e2e/**'",
|
|
36
37
|
"test:watch": "vitest watch",
|
|
37
|
-
"test:types": "vue-tsc --noEmit && cd playground && vue-tsc --noEmit"
|
|
38
|
+
"test:types": "vue-tsc --noEmit && cd playground && vue-tsc --noEmit",
|
|
39
|
+
"test:e2e": "playwright test",
|
|
40
|
+
"test:e2e:ui": "playwright test --ui"
|
|
38
41
|
},
|
|
39
42
|
"dependencies": {
|
|
40
43
|
"@nuxt/kit": "^4.4.2",
|
|
@@ -52,13 +55,33 @@
|
|
|
52
55
|
"@nuxt/schema": "^4.4.2",
|
|
53
56
|
"@nuxt/test-utils": "^4.0.0",
|
|
54
57
|
"@nuxt/ui": "4.6.0",
|
|
58
|
+
"@playwright/test": "^1.59.1",
|
|
55
59
|
"@types/node": "latest",
|
|
60
|
+
"canvas": "^3.2.3",
|
|
56
61
|
"changelogen": "^0.6.2",
|
|
57
62
|
"eslint": "^10.1.0",
|
|
58
63
|
"nuxt": "^4.4.2",
|
|
64
|
+
"path2d": "^0.3.1",
|
|
65
|
+
"pixelmatch": "^7.1.0",
|
|
66
|
+
"pngjs": "^7.0.0",
|
|
59
67
|
"typescript": "~6.0.2",
|
|
60
68
|
"vitest": "^4.1.1",
|
|
61
69
|
"vue-tsc": "^3.2.6"
|
|
62
70
|
},
|
|
63
|
-
"packageManager": "pnpm@10.33.0"
|
|
71
|
+
"packageManager": "pnpm@10.33.0",
|
|
72
|
+
"pnpm": {
|
|
73
|
+
"onlyBuiltDependencies": [
|
|
74
|
+
"canvas",
|
|
75
|
+
"@parcel/watcher",
|
|
76
|
+
"better-sqlite3",
|
|
77
|
+
"esbuild",
|
|
78
|
+
"sharp",
|
|
79
|
+
"vue-demi",
|
|
80
|
+
"unrs-resolver"
|
|
81
|
+
],
|
|
82
|
+
"overrides": {
|
|
83
|
+
"vue": "^3.5.32",
|
|
84
|
+
"vue-router": "^5.0.4"
|
|
85
|
+
}
|
|
86
|
+
}
|
|
64
87
|
}
|