@casualoffice/sheets 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +200 -0
- package/dist/embed/embed-runtime.js +537 -0
- package/dist/embed/embed.html +29 -0
- package/dist/embed/parser.worker.js +48474 -0
- package/dist/embed.cjs +225 -0
- package/dist/embed.cjs.map +1 -0
- package/dist/embed.d.cts +100 -0
- package/dist/embed.d.ts +100 -0
- package/dist/embed.js +204 -0
- package/dist/embed.js.map +1 -0
- package/dist/index.cjs +1549 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +9 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +1530 -0
- package/dist/index.js.map +1 -0
- package/dist/parser.worker.cjs +48469 -0
- package/dist/parser.worker.cjs.map +1 -0
- package/dist/parser.worker.js +48474 -0
- package/dist/parser.worker.js.map +1 -0
- package/dist/protocol--KyBQUjU.d.cts +171 -0
- package/dist/protocol-cEzy7S0i.d.ts +171 -0
- package/dist/sheets.cjs +677 -0
- package/dist/sheets.cjs.map +1 -0
- package/dist/sheets.d.cts +177 -0
- package/dist/sheets.d.ts +177 -0
- package/dist/sheets.js +658 -0
- package/dist/sheets.js.map +1 -0
- package/dist/signing.cjs +706 -0
- package/dist/signing.cjs.map +1 -0
- package/dist/signing.d.cts +141 -0
- package/dist/signing.d.ts +141 -0
- package/dist/signing.js +683 -0
- package/dist/signing.js.map +1 -0
- package/dist/styles.cjs +10 -0
- package/dist/styles.cjs.map +1 -0
- package/dist/styles.d.cts +2 -0
- package/dist/styles.d.ts +2 -0
- package/dist/styles.js +8 -0
- package/dist/styles.js.map +1 -0
- package/dist/types-s_O0u6Cg.d.cts +90 -0
- package/dist/types-s_O0u6Cg.d.ts +90 -0
- package/dist/univer.cjs +220 -0
- package/dist/univer.cjs.map +1 -0
- package/dist/univer.d.cts +60 -0
- package/dist/univer.d.ts +60 -0
- package/dist/univer.js +187 -0
- package/dist/univer.js.map +1 -0
- package/dist/xlsx.cjs +3388 -0
- package/dist/xlsx.cjs.map +1 -0
- package/dist/xlsx.d.cts +383 -0
- package/dist/xlsx.d.ts +383 -0
- package/dist/xlsx.js +3383 -0
- package/dist/xlsx.js.map +1 -0
- package/package.json +293 -0
- package/src/embed/EmbedHostTransport.ts +226 -0
- package/src/embed/EmbedTransport.ts +323 -0
- package/src/embed/EmbedTransport.unit.test.ts +161 -0
- package/src/embed/index.ts +40 -0
- package/src/embed/protocol.ts +258 -0
- package/src/embed-runtime/embed.html +29 -0
- package/src/embed-runtime/index.tsx +440 -0
- package/src/index.ts +16 -0
- package/src/sheets/CasualSheets.tsx +319 -0
- package/src/sheets/CasualSheetsIframe.tsx +220 -0
- package/src/sheets/api.ts +108 -0
- package/src/sheets/index.ts +11 -0
- package/src/signing/SigningPane.tsx +374 -0
- package/src/signing/SigningProvider.tsx +126 -0
- package/src/signing/captures.tsx +316 -0
- package/src/signing/controller.ts +151 -0
- package/src/signing/controller.unit.test.ts +133 -0
- package/src/signing/index.ts +44 -0
- package/src/signing/types.ts +89 -0
- package/src/styles.ts +16 -0
- package/src/univer/index.ts +17 -0
- package/src/univer/lazy-plugins.ts +280 -0
- package/src/xlsx/_perf.ts +14 -0
- package/src/xlsx/_snapshot-constants.ts +15 -0
- package/src/xlsx/comments-resource.ts +209 -0
- package/src/xlsx/constants.ts +9 -0
- package/src/xlsx/data-validation-resource.ts +219 -0
- package/src/xlsx/import.ts +35 -0
- package/src/xlsx/index.ts +40 -0
- package/src/xlsx/page-setup-resource.ts +205 -0
- package/src/xlsx/parse-impl.ts +418 -0
- package/src/xlsx/parse-in-worker.ts +82 -0
- package/src/xlsx/parser.worker.ts +39 -0
- package/src/xlsx/passthrough-resource.ts +175 -0
- package/src/xlsx/pivot-passthrough.ts +359 -0
- package/src/xlsx/style-mapping.ts +171 -0
- package/src/xlsx/tables-resource.ts +211 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,1549 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
29
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
31
|
+
|
|
32
|
+
// src/index.ts
|
|
33
|
+
var src_exports = {};
|
|
34
|
+
__export(src_exports, {
|
|
35
|
+
CasualSheets: () => CasualSheets,
|
|
36
|
+
CasualSheetsIframe: () => CasualSheetsIframe,
|
|
37
|
+
DrawnSignaturePad: () => DrawnSignaturePad,
|
|
38
|
+
EmbedTransport: () => EmbedTransport,
|
|
39
|
+
SigningPane: () => SigningPane,
|
|
40
|
+
SigningProvider: () => SigningProvider,
|
|
41
|
+
TypedSignatureField: () => TypedSignatureField,
|
|
42
|
+
UploadedSignatureField: () => UploadedSignatureField,
|
|
43
|
+
createCasualSheetsAPI: () => createCasualSheetsAPI,
|
|
44
|
+
createSigningController: () => createSigningController,
|
|
45
|
+
isCasualEnvelope: () => isCasualEnvelope,
|
|
46
|
+
useSigning: () => useSigning
|
|
47
|
+
});
|
|
48
|
+
module.exports = __toCommonJS(src_exports);
|
|
49
|
+
|
|
50
|
+
// src/signing/SigningProvider.tsx
|
|
51
|
+
var import_react = require("react");
|
|
52
|
+
|
|
53
|
+
// src/signing/controller.ts
|
|
54
|
+
function createSigningController(fields, mode) {
|
|
55
|
+
if (fields.length === 0) {
|
|
56
|
+
throw new Error("createSigningController: at least one field required");
|
|
57
|
+
}
|
|
58
|
+
const fieldIds = new Set(fields.map((f) => f.fieldId));
|
|
59
|
+
if (fieldIds.size !== fields.length) {
|
|
60
|
+
throw new Error("createSigningController: duplicate fieldId");
|
|
61
|
+
}
|
|
62
|
+
const signed = {};
|
|
63
|
+
let activeFieldIndex = nextRequiredIndex(fields, signed);
|
|
64
|
+
let isComplete = false;
|
|
65
|
+
let isCancelled = false;
|
|
66
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
67
|
+
function emit() {
|
|
68
|
+
const snap = snapshotInternal();
|
|
69
|
+
for (const l of listeners) l(snap);
|
|
70
|
+
}
|
|
71
|
+
function snapshotInternal() {
|
|
72
|
+
return {
|
|
73
|
+
fields,
|
|
74
|
+
mode,
|
|
75
|
+
signed: { ...signed },
|
|
76
|
+
activeFieldIndex,
|
|
77
|
+
canComplete: allRequiredSigned(fields, signed),
|
|
78
|
+
isComplete,
|
|
79
|
+
isCancelled
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
snapshot: snapshotInternal,
|
|
84
|
+
subscribe(listener) {
|
|
85
|
+
listeners.add(listener);
|
|
86
|
+
return () => {
|
|
87
|
+
listeners.delete(listener);
|
|
88
|
+
};
|
|
89
|
+
},
|
|
90
|
+
signField(payload) {
|
|
91
|
+
if (isComplete || isCancelled) return;
|
|
92
|
+
if (!fieldIds.has(payload.fieldId)) {
|
|
93
|
+
throw new Error(`signField: unknown fieldId ${payload.fieldId}`);
|
|
94
|
+
}
|
|
95
|
+
signed[payload.fieldId] = payload;
|
|
96
|
+
activeFieldIndex = nextRequiredIndex(fields, signed);
|
|
97
|
+
emit();
|
|
98
|
+
},
|
|
99
|
+
focusField(fieldId) {
|
|
100
|
+
if (isComplete || isCancelled) return;
|
|
101
|
+
const idx = fields.findIndex((f) => f.fieldId === fieldId);
|
|
102
|
+
if (idx < 0) return;
|
|
103
|
+
if (mode === "sequential") {
|
|
104
|
+
const next = nextRequiredIndex(fields, signed);
|
|
105
|
+
if (idx !== next) return;
|
|
106
|
+
}
|
|
107
|
+
activeFieldIndex = idx;
|
|
108
|
+
emit();
|
|
109
|
+
},
|
|
110
|
+
complete() {
|
|
111
|
+
if (!allRequiredSigned(fields, signed)) {
|
|
112
|
+
throw new Error("complete: required fields are still unsigned");
|
|
113
|
+
}
|
|
114
|
+
isComplete = true;
|
|
115
|
+
activeFieldIndex = -1;
|
|
116
|
+
emit();
|
|
117
|
+
return snapshotInternal();
|
|
118
|
+
},
|
|
119
|
+
cancel() {
|
|
120
|
+
if (isComplete || isCancelled) return;
|
|
121
|
+
isCancelled = true;
|
|
122
|
+
activeFieldIndex = -1;
|
|
123
|
+
emit();
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
function allRequiredSigned(fields, signed) {
|
|
128
|
+
return fields.every((f) => !f.required || signed[f.fieldId] !== void 0);
|
|
129
|
+
}
|
|
130
|
+
function nextRequiredIndex(fields, signed) {
|
|
131
|
+
for (let i = 0; i < fields.length; i++) {
|
|
132
|
+
if (fields[i].required && !signed[fields[i].fieldId]) return i;
|
|
133
|
+
}
|
|
134
|
+
for (let i = 0; i < fields.length; i++) {
|
|
135
|
+
if (!signed[fields[i].fieldId]) return i;
|
|
136
|
+
}
|
|
137
|
+
return -1;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// src/signing/SigningProvider.tsx
|
|
141
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
142
|
+
var SigningContext = (0, import_react.createContext)(null);
|
|
143
|
+
function SigningProvider({ session, documentBytes, children }) {
|
|
144
|
+
if (!session) {
|
|
145
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children });
|
|
146
|
+
}
|
|
147
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SigningProviderInner, { session, documentBytes, children });
|
|
148
|
+
}
|
|
149
|
+
function SigningProviderInner({
|
|
150
|
+
session,
|
|
151
|
+
documentBytes,
|
|
152
|
+
children
|
|
153
|
+
}) {
|
|
154
|
+
const controller = (0, import_react.useMemo)(
|
|
155
|
+
() => createSigningController(session.fields, session.mode),
|
|
156
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
157
|
+
[session.fields, session.mode]
|
|
158
|
+
);
|
|
159
|
+
const [snapshot, setSnapshot] = (0, import_react.useState)(() => controller.snapshot());
|
|
160
|
+
(0, import_react.useEffect)(() => {
|
|
161
|
+
const unsub = controller.subscribe(setSnapshot);
|
|
162
|
+
return unsub;
|
|
163
|
+
}, [controller]);
|
|
164
|
+
const value = (0, import_react.useMemo)(
|
|
165
|
+
() => ({
|
|
166
|
+
controller,
|
|
167
|
+
snapshot,
|
|
168
|
+
signField: async (payload) => {
|
|
169
|
+
controller.signField(payload);
|
|
170
|
+
await session.onFieldSigned?.(payload);
|
|
171
|
+
},
|
|
172
|
+
completeIfReady: async () => {
|
|
173
|
+
if (!controller.snapshot().canComplete) return;
|
|
174
|
+
const final = controller.complete();
|
|
175
|
+
const completePayload = {
|
|
176
|
+
fieldIds: final.fields.map((f) => f.fieldId).filter((id) => final.signed[id] !== void 0),
|
|
177
|
+
bytes: documentBytes ?? new ArrayBuffer(0),
|
|
178
|
+
fields: final.signed
|
|
179
|
+
};
|
|
180
|
+
await session.onComplete?.(completePayload);
|
|
181
|
+
},
|
|
182
|
+
cancel: (reason) => {
|
|
183
|
+
controller.cancel();
|
|
184
|
+
session.onCancel?.({ reason });
|
|
185
|
+
},
|
|
186
|
+
baseDocumentBytes: documentBytes
|
|
187
|
+
}),
|
|
188
|
+
[controller, snapshot, session, documentBytes]
|
|
189
|
+
);
|
|
190
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SigningContext.Provider, { value, children });
|
|
191
|
+
}
|
|
192
|
+
function useSigning() {
|
|
193
|
+
return (0, import_react.useContext)(SigningContext);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// src/signing/SigningPane.tsx
|
|
197
|
+
var import_react3 = require("react");
|
|
198
|
+
|
|
199
|
+
// src/signing/captures.tsx
|
|
200
|
+
var import_react2 = require("react");
|
|
201
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
202
|
+
function DrawnSignaturePad({
|
|
203
|
+
onCapture,
|
|
204
|
+
clearLabel = "Clear",
|
|
205
|
+
saveLabel = "Use this signature",
|
|
206
|
+
width = 480,
|
|
207
|
+
height = 160
|
|
208
|
+
}) {
|
|
209
|
+
const canvasRef = (0, import_react2.useRef)(null);
|
|
210
|
+
const drawingRef = (0, import_react2.useRef)(false);
|
|
211
|
+
const [hasInk, setHasInk] = (0, import_react2.useState)(false);
|
|
212
|
+
(0, import_react2.useEffect)(() => {
|
|
213
|
+
const canvas = canvasRef.current;
|
|
214
|
+
if (!canvas) return;
|
|
215
|
+
const ctx = canvas.getContext("2d");
|
|
216
|
+
if (!ctx) return;
|
|
217
|
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
218
|
+
ctx.strokeStyle = "#0f172a";
|
|
219
|
+
ctx.lineWidth = 2;
|
|
220
|
+
ctx.lineCap = "round";
|
|
221
|
+
ctx.lineJoin = "round";
|
|
222
|
+
}, []);
|
|
223
|
+
const start = (e) => {
|
|
224
|
+
const canvas = canvasRef.current;
|
|
225
|
+
if (!canvas) return;
|
|
226
|
+
const ctx = canvas.getContext("2d");
|
|
227
|
+
if (!ctx) return;
|
|
228
|
+
const { x, y } = pointerPos(e, canvas);
|
|
229
|
+
ctx.beginPath();
|
|
230
|
+
ctx.moveTo(x, y);
|
|
231
|
+
drawingRef.current = true;
|
|
232
|
+
canvas.setPointerCapture(e.pointerId);
|
|
233
|
+
};
|
|
234
|
+
const move = (e) => {
|
|
235
|
+
if (!drawingRef.current) return;
|
|
236
|
+
const canvas = canvasRef.current;
|
|
237
|
+
if (!canvas) return;
|
|
238
|
+
const ctx = canvas.getContext("2d");
|
|
239
|
+
if (!ctx) return;
|
|
240
|
+
const { x, y } = pointerPos(e, canvas);
|
|
241
|
+
ctx.lineTo(x, y);
|
|
242
|
+
ctx.stroke();
|
|
243
|
+
if (!hasInk) setHasInk(true);
|
|
244
|
+
};
|
|
245
|
+
const end = (e) => {
|
|
246
|
+
drawingRef.current = false;
|
|
247
|
+
canvasRef.current?.releasePointerCapture(e.pointerId);
|
|
248
|
+
};
|
|
249
|
+
const clear = () => {
|
|
250
|
+
const canvas = canvasRef.current;
|
|
251
|
+
if (!canvas) return;
|
|
252
|
+
const ctx = canvas.getContext("2d");
|
|
253
|
+
if (!ctx) return;
|
|
254
|
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
255
|
+
setHasInk(false);
|
|
256
|
+
};
|
|
257
|
+
const save = async () => {
|
|
258
|
+
const canvas = canvasRef.current;
|
|
259
|
+
if (!canvas || !hasInk) return;
|
|
260
|
+
const blob = await new Promise((resolve) => {
|
|
261
|
+
canvas.toBlob((b) => resolve(b), "image/png");
|
|
262
|
+
});
|
|
263
|
+
if (!blob) return;
|
|
264
|
+
const bytes = await blob.arrayBuffer();
|
|
265
|
+
onCapture({ bytes, mime: "image/png" });
|
|
266
|
+
clear();
|
|
267
|
+
};
|
|
268
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: padWrapStyle, "data-testid": "drawn-signature-pad", children: [
|
|
269
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
270
|
+
"canvas",
|
|
271
|
+
{
|
|
272
|
+
ref: canvasRef,
|
|
273
|
+
width,
|
|
274
|
+
height,
|
|
275
|
+
style: padCanvasStyle(width, height),
|
|
276
|
+
onPointerDown: start,
|
|
277
|
+
onPointerMove: move,
|
|
278
|
+
onPointerUp: end,
|
|
279
|
+
onPointerLeave: end,
|
|
280
|
+
"data-testid": "drawn-signature-canvas"
|
|
281
|
+
}
|
|
282
|
+
),
|
|
283
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: padActionsStyle, children: [
|
|
284
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", onClick: clear, style: secondaryBtnStyle(false), children: clearLabel }),
|
|
285
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
286
|
+
"button",
|
|
287
|
+
{
|
|
288
|
+
type: "button",
|
|
289
|
+
onClick: save,
|
|
290
|
+
disabled: !hasInk,
|
|
291
|
+
style: primaryBtnStyle(!hasInk),
|
|
292
|
+
"data-testid": "drawn-signature-save",
|
|
293
|
+
children: saveLabel
|
|
294
|
+
}
|
|
295
|
+
)
|
|
296
|
+
] })
|
|
297
|
+
] });
|
|
298
|
+
}
|
|
299
|
+
function pointerPos(e, canvas) {
|
|
300
|
+
const rect = canvas.getBoundingClientRect();
|
|
301
|
+
const scaleX = canvas.width / rect.width;
|
|
302
|
+
const scaleY = canvas.height / rect.height;
|
|
303
|
+
return {
|
|
304
|
+
x: (e.clientX - rect.left) * scaleX,
|
|
305
|
+
y: (e.clientY - rect.top) * scaleY
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
function TypedSignatureField({
|
|
309
|
+
onCapture,
|
|
310
|
+
defaultText = "",
|
|
311
|
+
saveLabel = "Use this signature"
|
|
312
|
+
}) {
|
|
313
|
+
const [value, setValue] = (0, import_react2.useState)(defaultText);
|
|
314
|
+
const save = () => {
|
|
315
|
+
const trimmed = value.trim();
|
|
316
|
+
if (!trimmed) return;
|
|
317
|
+
const bytes = new TextEncoder().encode(trimmed).buffer;
|
|
318
|
+
onCapture({ bytes, mime: "text/plain" });
|
|
319
|
+
setValue("");
|
|
320
|
+
};
|
|
321
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: padWrapStyle, "data-testid": "typed-signature-field", children: [
|
|
322
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
323
|
+
"input",
|
|
324
|
+
{
|
|
325
|
+
type: "text",
|
|
326
|
+
value,
|
|
327
|
+
onChange: (e) => setValue(e.target.value),
|
|
328
|
+
placeholder: "Type your full name",
|
|
329
|
+
style: typedInputStyle,
|
|
330
|
+
"data-testid": "typed-signature-input",
|
|
331
|
+
autoFocus: true
|
|
332
|
+
}
|
|
333
|
+
),
|
|
334
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: padActionsStyle, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
335
|
+
"button",
|
|
336
|
+
{
|
|
337
|
+
type: "button",
|
|
338
|
+
onClick: save,
|
|
339
|
+
disabled: !value.trim(),
|
|
340
|
+
style: primaryBtnStyle(!value.trim()),
|
|
341
|
+
"data-testid": "typed-signature-save",
|
|
342
|
+
children: saveLabel
|
|
343
|
+
}
|
|
344
|
+
) })
|
|
345
|
+
] });
|
|
346
|
+
}
|
|
347
|
+
function UploadedSignatureField({
|
|
348
|
+
onCapture,
|
|
349
|
+
accept = "image/png,image/jpeg,image/svg+xml"
|
|
350
|
+
}) {
|
|
351
|
+
const inputRef = (0, import_react2.useRef)(null);
|
|
352
|
+
const [fileName, setFileName] = (0, import_react2.useState)(null);
|
|
353
|
+
const onChange = async (e) => {
|
|
354
|
+
const file = e.target.files?.[0];
|
|
355
|
+
if (!file) return;
|
|
356
|
+
const bytes = await file.arrayBuffer();
|
|
357
|
+
onCapture({ bytes, mime: file.type || "application/octet-stream" });
|
|
358
|
+
setFileName(file.name);
|
|
359
|
+
if (inputRef.current) inputRef.current.value = "";
|
|
360
|
+
};
|
|
361
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: padWrapStyle, "data-testid": "uploaded-signature-field", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { style: uploadLabelStyle, children: [
|
|
362
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
363
|
+
"input",
|
|
364
|
+
{
|
|
365
|
+
ref: inputRef,
|
|
366
|
+
type: "file",
|
|
367
|
+
accept,
|
|
368
|
+
onChange,
|
|
369
|
+
style: { display: "none" },
|
|
370
|
+
"data-testid": "uploaded-signature-input"
|
|
371
|
+
}
|
|
372
|
+
),
|
|
373
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: fileName ?? "Choose image\u2026" })
|
|
374
|
+
] }) });
|
|
375
|
+
}
|
|
376
|
+
var padWrapStyle = {
|
|
377
|
+
display: "flex",
|
|
378
|
+
flexDirection: "column",
|
|
379
|
+
gap: 10
|
|
380
|
+
};
|
|
381
|
+
var padCanvasStyle = (w, h) => ({
|
|
382
|
+
width: w,
|
|
383
|
+
height: h,
|
|
384
|
+
maxWidth: "100%",
|
|
385
|
+
border: "1px dashed var(--doc-border, #cbd5e1)",
|
|
386
|
+
borderRadius: 8,
|
|
387
|
+
background: "var(--doc-surface, #fff)",
|
|
388
|
+
cursor: "crosshair",
|
|
389
|
+
touchAction: "none"
|
|
390
|
+
});
|
|
391
|
+
var padActionsStyle = {
|
|
392
|
+
display: "flex",
|
|
393
|
+
justifyContent: "flex-end",
|
|
394
|
+
gap: 8
|
|
395
|
+
};
|
|
396
|
+
var typedInputStyle = {
|
|
397
|
+
width: "100%",
|
|
398
|
+
padding: "10px 12px",
|
|
399
|
+
border: "1px solid var(--doc-border, #cbd5e1)",
|
|
400
|
+
borderRadius: 6,
|
|
401
|
+
fontSize: 18,
|
|
402
|
+
fontFamily: '"Caveat", "Dancing Script", "Brush Script MT", cursive',
|
|
403
|
+
background: "var(--doc-surface, #fff)",
|
|
404
|
+
color: "var(--doc-text, #0f172a)"
|
|
405
|
+
};
|
|
406
|
+
var uploadLabelStyle = {
|
|
407
|
+
display: "inline-flex",
|
|
408
|
+
padding: "8px 14px",
|
|
409
|
+
border: "1px dashed var(--doc-border, #cbd5e1)",
|
|
410
|
+
borderRadius: 6,
|
|
411
|
+
background: "var(--doc-surface, #fff)",
|
|
412
|
+
color: "var(--doc-text, #0f172a)",
|
|
413
|
+
fontSize: 13,
|
|
414
|
+
cursor: "pointer",
|
|
415
|
+
alignSelf: "flex-start"
|
|
416
|
+
};
|
|
417
|
+
function primaryBtnStyle(disabled) {
|
|
418
|
+
return {
|
|
419
|
+
padding: "8px 16px",
|
|
420
|
+
borderRadius: 6,
|
|
421
|
+
border: "1px solid transparent",
|
|
422
|
+
background: disabled ? "var(--doc-border, #cbd5e1)" : "var(--doc-accent, #2563eb)",
|
|
423
|
+
color: disabled ? "var(--doc-text-muted, #64748b)" : "#fff",
|
|
424
|
+
fontSize: 13,
|
|
425
|
+
fontWeight: 600,
|
|
426
|
+
cursor: disabled ? "not-allowed" : "pointer",
|
|
427
|
+
fontFamily: "inherit"
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
function secondaryBtnStyle(disabled) {
|
|
431
|
+
return {
|
|
432
|
+
padding: "8px 16px",
|
|
433
|
+
borderRadius: 6,
|
|
434
|
+
border: "1px solid var(--doc-border, #cbd5e1)",
|
|
435
|
+
background: "transparent",
|
|
436
|
+
color: "var(--doc-text, #0f172a)",
|
|
437
|
+
fontSize: 13,
|
|
438
|
+
fontWeight: 500,
|
|
439
|
+
cursor: disabled ? "not-allowed" : "pointer",
|
|
440
|
+
fontFamily: "inherit"
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// src/signing/SigningPane.tsx
|
|
445
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
446
|
+
function SigningPane({ banner, testId = "signing-pane" }) {
|
|
447
|
+
const ctx = useSigning();
|
|
448
|
+
if (!ctx) return null;
|
|
449
|
+
const { snapshot, signField, completeIfReady, cancel } = ctx;
|
|
450
|
+
if (snapshot.isComplete || snapshot.isCancelled) return null;
|
|
451
|
+
const active = snapshot.activeFieldIndex >= 0 ? snapshot.fields[snapshot.activeFieldIndex] : null;
|
|
452
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("aside", { style: paneStyle, role: "region", "aria-label": "Signing pane", "data-testid": testId, children: [
|
|
453
|
+
banner && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: bannerStyle, "data-testid": `${testId}-banner`, children: banner }),
|
|
454
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: listStyle, "data-testid": `${testId}-fields`, children: snapshot.fields.map((f, i) => {
|
|
455
|
+
const isSigned = !!snapshot.signed[f.fieldId];
|
|
456
|
+
const isActive = i === snapshot.activeFieldIndex;
|
|
457
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
458
|
+
"div",
|
|
459
|
+
{
|
|
460
|
+
style: listItemStyle(isActive, isSigned),
|
|
461
|
+
"data-testid": `${testId}-field-${f.fieldId}`,
|
|
462
|
+
"data-state": isSigned ? "signed" : isActive ? "active" : "pending",
|
|
463
|
+
children: [
|
|
464
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: listIconStyle(isSigned), "aria-hidden": "true", children: isSigned ? "\u2713" : i + 1 }),
|
|
465
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: listLabelStyle, children: f.label }),
|
|
466
|
+
!f.required && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: optionalChipStyle, "aria-label": "Optional", children: "optional" })
|
|
467
|
+
]
|
|
468
|
+
},
|
|
469
|
+
f.fieldId
|
|
470
|
+
);
|
|
471
|
+
}) }),
|
|
472
|
+
active && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
473
|
+
ActiveFieldEditor,
|
|
474
|
+
{
|
|
475
|
+
field: active,
|
|
476
|
+
testId,
|
|
477
|
+
onCapture: async (cap, method) => {
|
|
478
|
+
const payload = {
|
|
479
|
+
fieldId: active.fieldId,
|
|
480
|
+
method,
|
|
481
|
+
bytes: cap.bytes,
|
|
482
|
+
mime: cap.mime,
|
|
483
|
+
signedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
484
|
+
};
|
|
485
|
+
await signField(payload);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
),
|
|
489
|
+
!active && snapshot.canComplete && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: completeBlockStyle, "data-testid": `${testId}-complete-block`, children: "All required signatures collected. Ready to finalise." }),
|
|
490
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("footer", { style: footerStyle, children: [
|
|
491
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
492
|
+
"button",
|
|
493
|
+
{
|
|
494
|
+
type: "button",
|
|
495
|
+
onClick: () => cancel("signer_cancelled"),
|
|
496
|
+
style: secondaryBtnStyle2(),
|
|
497
|
+
"data-testid": `${testId}-cancel`,
|
|
498
|
+
children: "Cancel"
|
|
499
|
+
}
|
|
500
|
+
),
|
|
501
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
502
|
+
"button",
|
|
503
|
+
{
|
|
504
|
+
type: "button",
|
|
505
|
+
onClick: () => void completeIfReady(),
|
|
506
|
+
disabled: !snapshot.canComplete,
|
|
507
|
+
style: primaryBtnStyle2(!snapshot.canComplete),
|
|
508
|
+
"data-testid": `${testId}-complete`,
|
|
509
|
+
children: "Complete"
|
|
510
|
+
}
|
|
511
|
+
)
|
|
512
|
+
] })
|
|
513
|
+
] });
|
|
514
|
+
}
|
|
515
|
+
function ActiveFieldEditor({
|
|
516
|
+
field,
|
|
517
|
+
testId,
|
|
518
|
+
onCapture
|
|
519
|
+
}) {
|
|
520
|
+
const [method, setMethod] = (0, import_react3.useState)(field.methods[0]);
|
|
521
|
+
(0, import_react3.useEffect)(() => {
|
|
522
|
+
setMethod(field.methods[0]);
|
|
523
|
+
}, [field]);
|
|
524
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: editorStyle, "data-testid": `${testId}-editor`, children: [
|
|
525
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: editorHeaderStyle, children: [
|
|
526
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: editorLabelStyle, children: field.label }),
|
|
527
|
+
field.signer?.name && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: editorSignerStyle, children: field.signer.name })
|
|
528
|
+
] }),
|
|
529
|
+
field.methods.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: methodTabsStyle, role: "tablist", "data-testid": `${testId}-methods`, children: field.methods.map((m) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
530
|
+
"button",
|
|
531
|
+
{
|
|
532
|
+
type: "button",
|
|
533
|
+
role: "tab",
|
|
534
|
+
"aria-selected": method === m,
|
|
535
|
+
onClick: () => setMethod(m),
|
|
536
|
+
style: methodTabStyle(method === m),
|
|
537
|
+
"data-testid": `${testId}-method-${m}`,
|
|
538
|
+
children: methodLabel(m)
|
|
539
|
+
},
|
|
540
|
+
m
|
|
541
|
+
)) }),
|
|
542
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: captureWrapStyle, children: [
|
|
543
|
+
method === "drawn" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(DrawnSignaturePad, { onCapture: (c) => onCapture(c, "drawn") }),
|
|
544
|
+
method === "typed" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
545
|
+
TypedSignatureField,
|
|
546
|
+
{
|
|
547
|
+
defaultText: field.signer?.name ?? "",
|
|
548
|
+
onCapture: (c) => onCapture(c, "typed")
|
|
549
|
+
}
|
|
550
|
+
),
|
|
551
|
+
method === "uploaded" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(UploadedSignatureField, { onCapture: (c) => onCapture(c, "uploaded") })
|
|
552
|
+
] })
|
|
553
|
+
] });
|
|
554
|
+
}
|
|
555
|
+
function methodLabel(m) {
|
|
556
|
+
switch (m) {
|
|
557
|
+
case "drawn":
|
|
558
|
+
return "Draw";
|
|
559
|
+
case "typed":
|
|
560
|
+
return "Type";
|
|
561
|
+
case "uploaded":
|
|
562
|
+
return "Upload";
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
var paneStyle = {
|
|
566
|
+
position: "fixed",
|
|
567
|
+
top: 16,
|
|
568
|
+
right: 16,
|
|
569
|
+
bottom: 16,
|
|
570
|
+
width: 360,
|
|
571
|
+
maxWidth: "100vw",
|
|
572
|
+
display: "flex",
|
|
573
|
+
flexDirection: "column",
|
|
574
|
+
gap: 14,
|
|
575
|
+
padding: 16,
|
|
576
|
+
background: "var(--doc-surface, #fff)",
|
|
577
|
+
border: "1px solid var(--doc-border, #cbd5e1)",
|
|
578
|
+
borderRadius: 12,
|
|
579
|
+
boxShadow: "0 1px 1px rgba(0, 0, 0, 0.04), 0 6px 24px rgba(15, 23, 42, 0.12)",
|
|
580
|
+
fontFamily: "inherit",
|
|
581
|
+
zIndex: 9e3
|
|
582
|
+
};
|
|
583
|
+
var bannerStyle = {
|
|
584
|
+
padding: "8px 10px",
|
|
585
|
+
background: "var(--doc-surface-2, #f1f5f9)",
|
|
586
|
+
border: "1px solid var(--doc-border-light, #e2e8f0)",
|
|
587
|
+
borderRadius: 6,
|
|
588
|
+
fontSize: 12,
|
|
589
|
+
color: "var(--doc-text-muted, #475569)"
|
|
590
|
+
};
|
|
591
|
+
var listStyle = {
|
|
592
|
+
display: "flex",
|
|
593
|
+
flexDirection: "column",
|
|
594
|
+
gap: 4
|
|
595
|
+
};
|
|
596
|
+
function listItemStyle(active, signed) {
|
|
597
|
+
return {
|
|
598
|
+
display: "flex",
|
|
599
|
+
alignItems: "center",
|
|
600
|
+
gap: 10,
|
|
601
|
+
padding: "8px 10px",
|
|
602
|
+
borderRadius: 6,
|
|
603
|
+
background: active ? "var(--doc-surface-2, #f1f5f9)" : signed ? "transparent" : "transparent",
|
|
604
|
+
border: active ? "1px solid var(--doc-border, #cbd5e1)" : "1px solid transparent",
|
|
605
|
+
opacity: signed && !active ? 0.7 : 1
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
function listIconStyle(signed) {
|
|
609
|
+
return {
|
|
610
|
+
display: "inline-flex",
|
|
611
|
+
alignItems: "center",
|
|
612
|
+
justifyContent: "center",
|
|
613
|
+
width: 22,
|
|
614
|
+
height: 22,
|
|
615
|
+
borderRadius: "50%",
|
|
616
|
+
background: signed ? "var(--doc-accent, #2563eb)" : "var(--doc-surface-2, #f1f5f9)",
|
|
617
|
+
color: signed ? "#fff" : "var(--doc-text-muted, #475569)",
|
|
618
|
+
fontSize: 12,
|
|
619
|
+
fontWeight: 600,
|
|
620
|
+
flexShrink: 0
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
var listLabelStyle = {
|
|
624
|
+
flex: 1,
|
|
625
|
+
fontSize: 13,
|
|
626
|
+
color: "var(--doc-text, #0f172a)",
|
|
627
|
+
fontWeight: 500
|
|
628
|
+
};
|
|
629
|
+
var optionalChipStyle = {
|
|
630
|
+
fontSize: 11,
|
|
631
|
+
color: "var(--doc-text-muted, #64748b)",
|
|
632
|
+
padding: "2px 6px",
|
|
633
|
+
background: "var(--doc-surface-2, #f1f5f9)",
|
|
634
|
+
borderRadius: 4
|
|
635
|
+
};
|
|
636
|
+
var editorStyle = {
|
|
637
|
+
display: "flex",
|
|
638
|
+
flexDirection: "column",
|
|
639
|
+
gap: 12
|
|
640
|
+
};
|
|
641
|
+
var editorHeaderStyle = {
|
|
642
|
+
display: "flex",
|
|
643
|
+
flexDirection: "column",
|
|
644
|
+
gap: 2
|
|
645
|
+
};
|
|
646
|
+
var editorLabelStyle = {
|
|
647
|
+
fontSize: 13,
|
|
648
|
+
fontWeight: 600,
|
|
649
|
+
color: "var(--doc-text, #0f172a)"
|
|
650
|
+
};
|
|
651
|
+
var editorSignerStyle = {
|
|
652
|
+
fontSize: 12,
|
|
653
|
+
color: "var(--doc-text-muted, #64748b)"
|
|
654
|
+
};
|
|
655
|
+
var methodTabsStyle = {
|
|
656
|
+
display: "flex",
|
|
657
|
+
gap: 4,
|
|
658
|
+
padding: 2,
|
|
659
|
+
background: "var(--doc-surface-2, #f1f5f9)",
|
|
660
|
+
borderRadius: 6
|
|
661
|
+
};
|
|
662
|
+
function methodTabStyle(selected) {
|
|
663
|
+
return {
|
|
664
|
+
flex: 1,
|
|
665
|
+
padding: "6px 10px",
|
|
666
|
+
background: selected ? "var(--doc-surface, #fff)" : "transparent",
|
|
667
|
+
border: "none",
|
|
668
|
+
borderRadius: 4,
|
|
669
|
+
fontSize: 12,
|
|
670
|
+
fontWeight: 500,
|
|
671
|
+
color: selected ? "var(--doc-text, #0f172a)" : "var(--doc-text-muted, #475569)",
|
|
672
|
+
cursor: "pointer",
|
|
673
|
+
fontFamily: "inherit"
|
|
674
|
+
};
|
|
675
|
+
}
|
|
676
|
+
var captureWrapStyle = {
|
|
677
|
+
display: "flex",
|
|
678
|
+
flexDirection: "column",
|
|
679
|
+
gap: 8
|
|
680
|
+
};
|
|
681
|
+
var completeBlockStyle = {
|
|
682
|
+
padding: "10px 12px",
|
|
683
|
+
background: "rgba(34, 197, 94, 0.08)",
|
|
684
|
+
border: "1px solid rgba(34, 197, 94, 0.28)",
|
|
685
|
+
borderRadius: 6,
|
|
686
|
+
fontSize: 12,
|
|
687
|
+
color: "rgb(20, 83, 45)"
|
|
688
|
+
};
|
|
689
|
+
var footerStyle = {
|
|
690
|
+
display: "flex",
|
|
691
|
+
justifyContent: "flex-end",
|
|
692
|
+
gap: 8,
|
|
693
|
+
marginTop: "auto",
|
|
694
|
+
paddingTop: 12,
|
|
695
|
+
borderTop: "1px solid var(--doc-border-light, #e2e8f0)"
|
|
696
|
+
};
|
|
697
|
+
function primaryBtnStyle2(disabled) {
|
|
698
|
+
return {
|
|
699
|
+
padding: "8px 16px",
|
|
700
|
+
borderRadius: 6,
|
|
701
|
+
border: "1px solid transparent",
|
|
702
|
+
background: disabled ? "var(--doc-border, #cbd5e1)" : "var(--doc-accent, #2563eb)",
|
|
703
|
+
color: disabled ? "var(--doc-text-muted, #64748b)" : "#fff",
|
|
704
|
+
fontSize: 13,
|
|
705
|
+
fontWeight: 600,
|
|
706
|
+
cursor: disabled ? "not-allowed" : "pointer",
|
|
707
|
+
fontFamily: "inherit"
|
|
708
|
+
};
|
|
709
|
+
}
|
|
710
|
+
function secondaryBtnStyle2() {
|
|
711
|
+
return {
|
|
712
|
+
padding: "8px 16px",
|
|
713
|
+
borderRadius: 6,
|
|
714
|
+
border: "1px solid var(--doc-border, #cbd5e1)",
|
|
715
|
+
background: "transparent",
|
|
716
|
+
color: "var(--doc-text, #0f172a)",
|
|
717
|
+
fontSize: 13,
|
|
718
|
+
fontWeight: 500,
|
|
719
|
+
cursor: "pointer",
|
|
720
|
+
fontFamily: "inherit"
|
|
721
|
+
};
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
// src/embed/protocol.ts
|
|
725
|
+
function isCasualEnvelope(value) {
|
|
726
|
+
if (!value || typeof value !== "object") return false;
|
|
727
|
+
const v = value;
|
|
728
|
+
return typeof v.type === "string" && v.type.startsWith("casual.") && (v.app === "docs" || v.app === "sheet") && v.v === 1 && "data" in v;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
// src/embed/EmbedTransport.ts
|
|
732
|
+
var EmbedTransport = class {
|
|
733
|
+
constructor(opts) {
|
|
734
|
+
__publicField(this, "opts");
|
|
735
|
+
__publicField(this, "handlers", {});
|
|
736
|
+
__publicField(this, "destroyed", false);
|
|
737
|
+
__publicField(this, "pendingRequests", /* @__PURE__ */ new Map());
|
|
738
|
+
this.opts = {
|
|
739
|
+
...opts,
|
|
740
|
+
parentWindow: opts.parentWindow ?? (typeof window !== "undefined" ? window.parent : { postMessage: () => void 0 }),
|
|
741
|
+
hostWindow: opts.hostWindow ?? (typeof window !== "undefined" ? window : {
|
|
742
|
+
addEventListener: () => void 0,
|
|
743
|
+
removeEventListener: () => void 0
|
|
744
|
+
})
|
|
745
|
+
};
|
|
746
|
+
this.boundMessage = this.boundMessage.bind(this);
|
|
747
|
+
this.opts.hostWindow.addEventListener("message", this.boundMessage);
|
|
748
|
+
}
|
|
749
|
+
/** Replaces the handler set. Idempotent — call multiple times. */
|
|
750
|
+
on(handlers) {
|
|
751
|
+
this.handlers = { ...this.handlers, ...handlers };
|
|
752
|
+
}
|
|
753
|
+
/** Editor → Host: announce ourselves. Call once after handlers are wired. */
|
|
754
|
+
sendHello() {
|
|
755
|
+
const data = {
|
|
756
|
+
capabilities: this.opts.capabilities,
|
|
757
|
+
version: this.opts.version,
|
|
758
|
+
commit: this.opts.commit
|
|
759
|
+
};
|
|
760
|
+
this.post("casual.hello", data);
|
|
761
|
+
}
|
|
762
|
+
/** Editor → Host: editor is ready to receive commands. */
|
|
763
|
+
sendReady() {
|
|
764
|
+
this.post("casual.ready", {});
|
|
765
|
+
}
|
|
766
|
+
/** Editor → Host: ask the host to supply document bytes for `docId`. */
|
|
767
|
+
async requestLoad(docId, timeoutMs = 3e4) {
|
|
768
|
+
return this.request(
|
|
769
|
+
"casual.load.request",
|
|
770
|
+
{ docId },
|
|
771
|
+
timeoutMs
|
|
772
|
+
);
|
|
773
|
+
}
|
|
774
|
+
/** Editor → Host: ask the host to persist `bytes`. */
|
|
775
|
+
async requestSave(req, timeoutMs = 3e4) {
|
|
776
|
+
return this.request("casual.save.request", req, timeoutMs, [req.bytes]);
|
|
777
|
+
}
|
|
778
|
+
/** Editor → Host: selection moved. Fire-and-forget. */
|
|
779
|
+
sendSelectionChanged(data) {
|
|
780
|
+
this.post("casual.selection.changed", data);
|
|
781
|
+
}
|
|
782
|
+
/** Editor → Host: format flags on the active cell changed (bold,
|
|
783
|
+
* italic, …). Drive's custom toolbar mirrors this state in its
|
|
784
|
+
* "pressed" indicators. v0.6+. */
|
|
785
|
+
sendSelectionFormatState(data) {
|
|
786
|
+
this.post("casual.selection.format-state", data);
|
|
787
|
+
}
|
|
788
|
+
/** Editor → Host: a noteworthy event. */
|
|
789
|
+
sendTelemetry(data) {
|
|
790
|
+
this.post("casual.telemetry.event", data);
|
|
791
|
+
}
|
|
792
|
+
/** Editor → Host: per-field progress during a signing session. */
|
|
793
|
+
sendSignatureFieldSigned(data) {
|
|
794
|
+
this.post("casual.signature.field.signed", data, [data.bytes]);
|
|
795
|
+
}
|
|
796
|
+
/** Editor → Host: signing session is finished. */
|
|
797
|
+
sendSignatureComplete(data) {
|
|
798
|
+
this.post("casual.signature.complete", data, [data.bytes]);
|
|
799
|
+
}
|
|
800
|
+
/** Editor → Host: editor-side cancel of a signing session. */
|
|
801
|
+
sendSignatureCancel(reason) {
|
|
802
|
+
this.post("casual.signature.cancel", { reason });
|
|
803
|
+
}
|
|
804
|
+
/** Editor → Host: fatal boot / load error. Host surfaces via wrapper
|
|
805
|
+
* `onError` callback. Fire-and-forget. */
|
|
806
|
+
sendError(data) {
|
|
807
|
+
this.post("casual.error", data);
|
|
808
|
+
}
|
|
809
|
+
/** Tear down listeners. Idempotent. */
|
|
810
|
+
destroy() {
|
|
811
|
+
if (this.destroyed) return;
|
|
812
|
+
this.opts.hostWindow.removeEventListener("message", this.boundMessage);
|
|
813
|
+
this.pendingRequests.clear();
|
|
814
|
+
this.destroyed = true;
|
|
815
|
+
}
|
|
816
|
+
// ---------------------------------------------------------------
|
|
817
|
+
// Internals
|
|
818
|
+
// ---------------------------------------------------------------
|
|
819
|
+
boundMessage(ev) {
|
|
820
|
+
const msg = ev;
|
|
821
|
+
if (msg.origin && msg.origin !== this.opts.hostOrigin) return;
|
|
822
|
+
if (!isCasualEnvelope(msg.data)) return;
|
|
823
|
+
void this.dispatch(msg.data);
|
|
824
|
+
}
|
|
825
|
+
async dispatch(env) {
|
|
826
|
+
if (env.id && this.pendingRequests.has(env.id)) {
|
|
827
|
+
const resolve = this.pendingRequests.get(env.id);
|
|
828
|
+
this.pendingRequests.delete(env.id);
|
|
829
|
+
resolve(env);
|
|
830
|
+
return;
|
|
831
|
+
}
|
|
832
|
+
switch (env.type) {
|
|
833
|
+
case "casual.hello":
|
|
834
|
+
await this.handlers.onHostHello?.(env.data);
|
|
835
|
+
this.sendReady();
|
|
836
|
+
return;
|
|
837
|
+
case "casual.command.setReadOnly":
|
|
838
|
+
await this.handlers.onCommandSetReadOnly?.(env.data);
|
|
839
|
+
return;
|
|
840
|
+
case "casual.command.setTheme":
|
|
841
|
+
await this.handlers.onCommandSetTheme?.(env.data);
|
|
842
|
+
return;
|
|
843
|
+
case "casual.command.setLocale":
|
|
844
|
+
await this.handlers.onCommandSetLocale?.(env.data);
|
|
845
|
+
return;
|
|
846
|
+
case "casual.command.set.viewmode":
|
|
847
|
+
await this.handlers.onCommandSetViewMode?.(env.data);
|
|
848
|
+
return;
|
|
849
|
+
case "casual.command.execute":
|
|
850
|
+
await this.handlers.onCommandExecute?.(env.data);
|
|
851
|
+
return;
|
|
852
|
+
case "casual.command.focus":
|
|
853
|
+
await this.handlers.onCommandFocus?.();
|
|
854
|
+
return;
|
|
855
|
+
case "casual.command.save":
|
|
856
|
+
await this.handlers.onCommandSave?.();
|
|
857
|
+
return;
|
|
858
|
+
case "casual.command.load":
|
|
859
|
+
await this.handlers.onCommandLoad?.();
|
|
860
|
+
return;
|
|
861
|
+
case "casual.signature.request": {
|
|
862
|
+
const ack = await this.handlers.onSignatureRequest?.(
|
|
863
|
+
env.data
|
|
864
|
+
) ?? {
|
|
865
|
+
ok: false,
|
|
866
|
+
code: "unhandled"
|
|
867
|
+
};
|
|
868
|
+
if (env.id) {
|
|
869
|
+
this.postReply(env.id, "casual.signature.request.ack", ack);
|
|
870
|
+
}
|
|
871
|
+
return;
|
|
872
|
+
}
|
|
873
|
+
case "casual.signature.cancel":
|
|
874
|
+
await this.handlers.onSignatureCancel?.(env.data);
|
|
875
|
+
return;
|
|
876
|
+
default:
|
|
877
|
+
return;
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
post(type, data, transfer) {
|
|
881
|
+
const env = { type, app: this.opts.app, v: 1, data };
|
|
882
|
+
try {
|
|
883
|
+
this.opts.parentWindow.postMessage(env, this.opts.hostOrigin, transfer);
|
|
884
|
+
} catch {
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
postReply(id, type, data) {
|
|
888
|
+
const env = { type, app: this.opts.app, id, v: 1, data };
|
|
889
|
+
try {
|
|
890
|
+
this.opts.parentWindow.postMessage(env, this.opts.hostOrigin);
|
|
891
|
+
} catch {
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
async request(type, data, timeoutMs, transfer) {
|
|
895
|
+
const id = newRequestId();
|
|
896
|
+
return new Promise((resolve, reject) => {
|
|
897
|
+
const timer = timeoutMs > 0 ? setTimeout(() => {
|
|
898
|
+
this.pendingRequests.delete(id);
|
|
899
|
+
reject(new Error(`Embed request ${type} timed out after ${timeoutMs}ms`));
|
|
900
|
+
}, timeoutMs) : null;
|
|
901
|
+
this.pendingRequests.set(id, (env2) => {
|
|
902
|
+
if (timer) clearTimeout(timer);
|
|
903
|
+
resolve(env2.data);
|
|
904
|
+
});
|
|
905
|
+
const env = { type, app: this.opts.app, id, v: 1, data };
|
|
906
|
+
try {
|
|
907
|
+
this.opts.parentWindow.postMessage(env, this.opts.hostOrigin, transfer);
|
|
908
|
+
} catch (err) {
|
|
909
|
+
if (timer) clearTimeout(timer);
|
|
910
|
+
this.pendingRequests.delete(id);
|
|
911
|
+
reject(err);
|
|
912
|
+
}
|
|
913
|
+
});
|
|
914
|
+
}
|
|
915
|
+
};
|
|
916
|
+
function newRequestId() {
|
|
917
|
+
return Math.random().toString(16).slice(2, 10);
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
// src/sheets/CasualSheets.tsx
|
|
921
|
+
var import_react4 = require("react");
|
|
922
|
+
var import_core2 = require("@univerjs/core");
|
|
923
|
+
var import_facade2 = require("@univerjs/core/facade");
|
|
924
|
+
var import_themes = require("@univerjs/themes");
|
|
925
|
+
var import_engine_render = require("@univerjs/engine-render");
|
|
926
|
+
var import_engine_formula = require("@univerjs/engine-formula");
|
|
927
|
+
var import_ui = require("@univerjs/ui");
|
|
928
|
+
var import_docs = require("@univerjs/docs");
|
|
929
|
+
var import_docs_ui = require("@univerjs/docs-ui");
|
|
930
|
+
var import_sheets = require("@univerjs/sheets");
|
|
931
|
+
var import_sheets_ui = require("@univerjs/sheets-ui");
|
|
932
|
+
var import_sheets_formula = require("@univerjs/sheets-formula");
|
|
933
|
+
var import_sheets_formula_ui = require("@univerjs/sheets-formula-ui");
|
|
934
|
+
var import_sheets_numfmt = require("@univerjs/sheets-numfmt");
|
|
935
|
+
var import_sheets_numfmt_ui = require("@univerjs/sheets-numfmt-ui");
|
|
936
|
+
|
|
937
|
+
// src/sheets/api.ts
|
|
938
|
+
var import_facade = require("@univerjs/sheets/facade");
|
|
939
|
+
var import_core = require("@univerjs/core");
|
|
940
|
+
function createCasualSheetsAPI(univerAPI) {
|
|
941
|
+
return {
|
|
942
|
+
univer: univerAPI,
|
|
943
|
+
getSnapshot() {
|
|
944
|
+
return univerAPI.getActiveWorkbook()?.save() ?? null;
|
|
945
|
+
},
|
|
946
|
+
loadSnapshot(data) {
|
|
947
|
+
const current = univerAPI.getActiveWorkbook();
|
|
948
|
+
if (current) univerAPI.disposeUnit(current.getId());
|
|
949
|
+
univerAPI.createWorkbook(data);
|
|
950
|
+
},
|
|
951
|
+
getSelection() {
|
|
952
|
+
const wb = univerAPI.getActiveWorkbook();
|
|
953
|
+
const range = wb?.getActiveRange();
|
|
954
|
+
if (!wb || !range) return null;
|
|
955
|
+
return {
|
|
956
|
+
unitId: wb.getId(),
|
|
957
|
+
sheetId: wb.getActiveSheet().getSheetId(),
|
|
958
|
+
range: range.getRange()
|
|
959
|
+
};
|
|
960
|
+
},
|
|
961
|
+
executeCommand(id, params) {
|
|
962
|
+
return univerAPI.executeCommand(id, params);
|
|
963
|
+
},
|
|
964
|
+
setTheme(appearance) {
|
|
965
|
+
const dark = appearance === "dark";
|
|
966
|
+
const injector = univerAPI._injector;
|
|
967
|
+
const themeService = injector?.get(import_core.ThemeService);
|
|
968
|
+
if (themeService && themeService.darkMode !== dark) themeService.setDarkMode(dark);
|
|
969
|
+
}
|
|
970
|
+
};
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
// src/univer/lazy-plugins.ts
|
|
974
|
+
var LOADERS = {
|
|
975
|
+
cf: async () => {
|
|
976
|
+
const [base, ui] = await Promise.all([
|
|
977
|
+
import("@univerjs/sheets-conditional-formatting"),
|
|
978
|
+
import("@univerjs/sheets-conditional-formatting-ui")
|
|
979
|
+
]);
|
|
980
|
+
return [
|
|
981
|
+
[base.UniverSheetsConditionalFormattingPlugin],
|
|
982
|
+
[ui.UniverSheetsConditionalFormattingUIPlugin]
|
|
983
|
+
];
|
|
984
|
+
},
|
|
985
|
+
dv: async () => {
|
|
986
|
+
const [base, ui] = await Promise.all([
|
|
987
|
+
import("@univerjs/sheets-data-validation"),
|
|
988
|
+
import("@univerjs/sheets-data-validation-ui")
|
|
989
|
+
]);
|
|
990
|
+
return [
|
|
991
|
+
[base.UniverSheetsDataValidationPlugin],
|
|
992
|
+
[ui.UniverSheetsDataValidationUIPlugin]
|
|
993
|
+
];
|
|
994
|
+
},
|
|
995
|
+
hyperlink: async () => {
|
|
996
|
+
const [base, ui] = await Promise.all([
|
|
997
|
+
import("@univerjs/sheets-hyper-link"),
|
|
998
|
+
import("@univerjs/sheets-hyper-link-ui")
|
|
999
|
+
]);
|
|
1000
|
+
return [
|
|
1001
|
+
[base.UniverSheetsHyperLinkPlugin],
|
|
1002
|
+
[ui.UniverSheetsHyperLinkUIPlugin]
|
|
1003
|
+
];
|
|
1004
|
+
},
|
|
1005
|
+
note: async () => {
|
|
1006
|
+
const [base, ui] = await Promise.all([
|
|
1007
|
+
import("@univerjs/sheets-note"),
|
|
1008
|
+
import("@univerjs/sheets-note-ui")
|
|
1009
|
+
]);
|
|
1010
|
+
return [[base.UniverSheetsNotePlugin], [ui.UniverSheetsNoteUIPlugin]];
|
|
1011
|
+
},
|
|
1012
|
+
table: async () => {
|
|
1013
|
+
const [base, ui] = await Promise.all([
|
|
1014
|
+
import("@univerjs/sheets-table"),
|
|
1015
|
+
import("@univerjs/sheets-table-ui")
|
|
1016
|
+
]);
|
|
1017
|
+
return [[base.UniverSheetsTablePlugin], [ui.UniverSheetsTableUIPlugin]];
|
|
1018
|
+
},
|
|
1019
|
+
threadComment: async () => {
|
|
1020
|
+
const [tc, tcUi, sheetsTc, sheetsTcUi] = await Promise.all([
|
|
1021
|
+
import("@univerjs/thread-comment"),
|
|
1022
|
+
import("@univerjs/thread-comment-ui"),
|
|
1023
|
+
import("@univerjs/sheets-thread-comment"),
|
|
1024
|
+
import("@univerjs/sheets-thread-comment-ui")
|
|
1025
|
+
]);
|
|
1026
|
+
return [
|
|
1027
|
+
[tc.UniverThreadCommentPlugin],
|
|
1028
|
+
[tcUi.UniverThreadCommentUIPlugin],
|
|
1029
|
+
[sheetsTc.UniverSheetsThreadCommentPlugin],
|
|
1030
|
+
[sheetsTcUi.UniverSheetsThreadCommentUIPlugin]
|
|
1031
|
+
];
|
|
1032
|
+
},
|
|
1033
|
+
drawing: async () => {
|
|
1034
|
+
const [d, dUi, sd, sdUi] = await Promise.all([
|
|
1035
|
+
import("@univerjs/drawing"),
|
|
1036
|
+
import("@univerjs/drawing-ui"),
|
|
1037
|
+
import("@univerjs/sheets-drawing"),
|
|
1038
|
+
import("@univerjs/sheets-drawing-ui"),
|
|
1039
|
+
// Side-effect imports: install FWorksheet.insertImage / getImages /
|
|
1040
|
+
// updateImages on the facade prototype. Without these, code that
|
|
1041
|
+
// reaches in via the FUniver facade (e2e specs, future shell glue)
|
|
1042
|
+
// sees an undefined method even though the plugin is registered.
|
|
1043
|
+
import("@univerjs/sheets-drawing/facade"),
|
|
1044
|
+
import("@univerjs/sheets-drawing-ui/facade")
|
|
1045
|
+
]);
|
|
1046
|
+
return [
|
|
1047
|
+
[d.UniverDrawingPlugin],
|
|
1048
|
+
[dUi.UniverDrawingUIPlugin],
|
|
1049
|
+
[sd.UniverSheetsDrawingPlugin],
|
|
1050
|
+
[sdUi.UniverSheetsDrawingUIPlugin]
|
|
1051
|
+
];
|
|
1052
|
+
},
|
|
1053
|
+
sort: async () => {
|
|
1054
|
+
const [base, ui] = await Promise.all([
|
|
1055
|
+
import("@univerjs/sheets-sort"),
|
|
1056
|
+
import("@univerjs/sheets-sort-ui")
|
|
1057
|
+
]);
|
|
1058
|
+
return [[base.UniverSheetsSortPlugin], [ui.UniverSheetsSortUIPlugin]];
|
|
1059
|
+
},
|
|
1060
|
+
filter: async () => {
|
|
1061
|
+
const [base, ui] = await Promise.all([
|
|
1062
|
+
import("@univerjs/sheets-filter"),
|
|
1063
|
+
import("@univerjs/sheets-filter-ui")
|
|
1064
|
+
]);
|
|
1065
|
+
return [[base.UniverSheetsFilterPlugin], [ui.UniverSheetsFilterUIPlugin]];
|
|
1066
|
+
},
|
|
1067
|
+
findReplace: async () => {
|
|
1068
|
+
const [base, sheets] = await Promise.all([
|
|
1069
|
+
import("@univerjs/find-replace"),
|
|
1070
|
+
import("@univerjs/sheets-find-replace")
|
|
1071
|
+
]);
|
|
1072
|
+
return [[base.UniverFindReplacePlugin], [sheets.UniverSheetsFindReplacePlugin]];
|
|
1073
|
+
}
|
|
1074
|
+
};
|
|
1075
|
+
var RESOURCE_NAME_TO_GROUP = {
|
|
1076
|
+
SHEET_CONDITIONAL_FORMATTING_PLUGIN: "cf",
|
|
1077
|
+
SHEET_DATA_VALIDATION_PLUGIN: "dv",
|
|
1078
|
+
SHEET_HYPER_LINK_PLUGIN: "hyperlink",
|
|
1079
|
+
SHEET_NOTE_PLUGIN: "note",
|
|
1080
|
+
SHEET_TABLE_PLUGIN: "table",
|
|
1081
|
+
SHEET_THREAD_COMMENT_BASE_PLUGIN: "threadComment",
|
|
1082
|
+
SHEET_DRAWING_PLUGIN: "drawing",
|
|
1083
|
+
SHEET_SORT_PLUGIN: "sort",
|
|
1084
|
+
SHEET_FILTER_PLUGIN: "filter"
|
|
1085
|
+
};
|
|
1086
|
+
var loaded = /* @__PURE__ */ new Set();
|
|
1087
|
+
var inflight = /* @__PURE__ */ new Map();
|
|
1088
|
+
var currentUniver = null;
|
|
1089
|
+
function setUniverForLazyLoad(univer) {
|
|
1090
|
+
currentUniver = univer;
|
|
1091
|
+
}
|
|
1092
|
+
function ensurePlugin(univer, group) {
|
|
1093
|
+
if (loaded.has(group)) return Promise.resolve();
|
|
1094
|
+
const existing = inflight.get(group);
|
|
1095
|
+
if (existing) return existing;
|
|
1096
|
+
const loader = LOADERS[group];
|
|
1097
|
+
if (!loader) return Promise.resolve();
|
|
1098
|
+
const p = loader().then((plugins) => {
|
|
1099
|
+
for (const [PluginCtor, config] of plugins) {
|
|
1100
|
+
univer.registerPlugin(PluginCtor, config);
|
|
1101
|
+
}
|
|
1102
|
+
loaded.add(group);
|
|
1103
|
+
inflight.delete(group);
|
|
1104
|
+
});
|
|
1105
|
+
inflight.set(group, p);
|
|
1106
|
+
return p;
|
|
1107
|
+
}
|
|
1108
|
+
async function eagerLoadForSnapshot(univer, snapshot) {
|
|
1109
|
+
const groups = /* @__PURE__ */ new Set();
|
|
1110
|
+
const resources = snapshot.resources ?? [];
|
|
1111
|
+
for (const r of resources) {
|
|
1112
|
+
const g = RESOURCE_NAME_TO_GROUP[r.name];
|
|
1113
|
+
if (g) groups.add(g);
|
|
1114
|
+
}
|
|
1115
|
+
if (snapshotHasHyperlinks(snapshot)) groups.add("hyperlink");
|
|
1116
|
+
await Promise.all(Array.from(groups).map((g) => ensurePlugin(univer, g)));
|
|
1117
|
+
}
|
|
1118
|
+
function idleLoadAll(univer) {
|
|
1119
|
+
const groups = Object.keys(LOADERS);
|
|
1120
|
+
schedule(() => {
|
|
1121
|
+
for (const g of groups) {
|
|
1122
|
+
void ensurePlugin(univer, g);
|
|
1123
|
+
}
|
|
1124
|
+
});
|
|
1125
|
+
}
|
|
1126
|
+
function schedule(fn) {
|
|
1127
|
+
const ric = globalThis.requestIdleCallback;
|
|
1128
|
+
if (ric) ric(fn, { timeout: 500 });
|
|
1129
|
+
else setTimeout(fn, 0);
|
|
1130
|
+
}
|
|
1131
|
+
function snapshotHasHyperlinks(snapshot) {
|
|
1132
|
+
const sheetOrder = snapshot.sheetOrder ?? [];
|
|
1133
|
+
for (const sid of sheetOrder) {
|
|
1134
|
+
const sheet = snapshot.sheets?.[sid];
|
|
1135
|
+
if (!sheet?.cellData) continue;
|
|
1136
|
+
const cellData = sheet.cellData;
|
|
1137
|
+
for (const r of Object.keys(cellData)) {
|
|
1138
|
+
const row = cellData[r];
|
|
1139
|
+
for (const c of Object.keys(row)) {
|
|
1140
|
+
const ranges = row[c]?.p?.body?.customRanges ?? [];
|
|
1141
|
+
if (ranges.some((cr) => cr.rangeType === 0)) return true;
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
return false;
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
// src/sheets/CasualSheets.tsx
|
|
1149
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
1150
|
+
var DEFAULT_STYLE = {
|
|
1151
|
+
width: "100%",
|
|
1152
|
+
height: "100%",
|
|
1153
|
+
position: "relative"
|
|
1154
|
+
};
|
|
1155
|
+
var DEFAULT_UI = {
|
|
1156
|
+
header: false,
|
|
1157
|
+
toolbar: false,
|
|
1158
|
+
footer: false,
|
|
1159
|
+
contextMenu: true
|
|
1160
|
+
};
|
|
1161
|
+
function CasualSheets({
|
|
1162
|
+
initialData,
|
|
1163
|
+
onReady,
|
|
1164
|
+
onChange,
|
|
1165
|
+
onChangeDebounceMs = 400,
|
|
1166
|
+
lazyPlugins = true,
|
|
1167
|
+
locale = import_core2.LocaleType.EN_US,
|
|
1168
|
+
locales,
|
|
1169
|
+
logLevel = import_core2.LogLevel.WARN,
|
|
1170
|
+
ui,
|
|
1171
|
+
theme = import_themes.defaultTheme,
|
|
1172
|
+
appearance = "light",
|
|
1173
|
+
style,
|
|
1174
|
+
className,
|
|
1175
|
+
testId = "casual-sheets"
|
|
1176
|
+
}) {
|
|
1177
|
+
const hostRef = (0, import_react4.useRef)(null);
|
|
1178
|
+
const onChangeRef = (0, import_react4.useRef)(onChange);
|
|
1179
|
+
onChangeRef.current = onChange;
|
|
1180
|
+
const hasOnChange = (0, import_react4.useRef)(!!onChange).current;
|
|
1181
|
+
const apiRef = (0, import_react4.useRef)(null);
|
|
1182
|
+
(0, import_react4.useEffect)(() => {
|
|
1183
|
+
const container = hostRef.current;
|
|
1184
|
+
if (!container) return;
|
|
1185
|
+
const univer = new import_core2.Univer({
|
|
1186
|
+
theme,
|
|
1187
|
+
locale,
|
|
1188
|
+
locales,
|
|
1189
|
+
logLevel
|
|
1190
|
+
});
|
|
1191
|
+
const uiOpts = { ...DEFAULT_UI, ...ui, container };
|
|
1192
|
+
univer.registerPlugin(import_engine_render.UniverRenderEnginePlugin);
|
|
1193
|
+
univer.registerPlugin(import_engine_formula.UniverFormulaEnginePlugin);
|
|
1194
|
+
univer.registerPlugin(import_ui.UniverUIPlugin, uiOpts);
|
|
1195
|
+
univer.registerPlugin(import_docs.UniverDocsPlugin);
|
|
1196
|
+
univer.registerPlugin(import_docs_ui.UniverDocsUIPlugin);
|
|
1197
|
+
univer.registerPlugin(import_sheets.UniverSheetsPlugin);
|
|
1198
|
+
univer.registerPlugin(import_sheets_ui.UniverSheetsUIPlugin);
|
|
1199
|
+
univer.registerPlugin(import_sheets_formula.UniverSheetsFormulaPlugin);
|
|
1200
|
+
univer.registerPlugin(import_sheets_formula_ui.UniverSheetsFormulaUIPlugin);
|
|
1201
|
+
univer.registerPlugin(import_sheets_numfmt.UniverSheetsNumfmtPlugin);
|
|
1202
|
+
univer.registerPlugin(import_sheets_numfmt_ui.UniverSheetsNumfmtUIPlugin);
|
|
1203
|
+
if (lazyPlugins) setUniverForLazyLoad(univer);
|
|
1204
|
+
let cancelled = false;
|
|
1205
|
+
let changeTimer = null;
|
|
1206
|
+
let changeSub;
|
|
1207
|
+
void (async () => {
|
|
1208
|
+
if (lazyPlugins) {
|
|
1209
|
+
await eagerLoadForSnapshot(univer, initialData);
|
|
1210
|
+
if (cancelled) return;
|
|
1211
|
+
}
|
|
1212
|
+
univer.createUnit(import_core2.UniverInstanceType.UNIVER_SHEET, initialData);
|
|
1213
|
+
const api = createCasualSheetsAPI(import_facade2.FUniver.newAPI(univer));
|
|
1214
|
+
apiRef.current = api;
|
|
1215
|
+
applyAppearance(api, container, appearance);
|
|
1216
|
+
onReady?.(api);
|
|
1217
|
+
if (hasOnChange) {
|
|
1218
|
+
const injector = api.univer._injector;
|
|
1219
|
+
const cmdSvc = injector?.get(import_core2.ICommandService);
|
|
1220
|
+
changeSub = cmdSvc?.onMutationExecutedForCollab(() => {
|
|
1221
|
+
if (changeTimer) clearTimeout(changeTimer);
|
|
1222
|
+
changeTimer = setTimeout(() => {
|
|
1223
|
+
const snap = api.getSnapshot();
|
|
1224
|
+
if (snap) onChangeRef.current?.(snap);
|
|
1225
|
+
}, onChangeDebounceMs);
|
|
1226
|
+
});
|
|
1227
|
+
if (cancelled) changeSub?.dispose();
|
|
1228
|
+
}
|
|
1229
|
+
if (lazyPlugins) idleLoadAll(univer);
|
|
1230
|
+
})();
|
|
1231
|
+
return () => {
|
|
1232
|
+
cancelled = true;
|
|
1233
|
+
if (changeTimer) clearTimeout(changeTimer);
|
|
1234
|
+
changeSub?.dispose();
|
|
1235
|
+
apiRef.current = null;
|
|
1236
|
+
if (lazyPlugins) setUniverForLazyLoad(null);
|
|
1237
|
+
const toDispose = univer;
|
|
1238
|
+
queueMicrotask(() => toDispose.dispose());
|
|
1239
|
+
};
|
|
1240
|
+
}, []);
|
|
1241
|
+
(0, import_react4.useEffect)(() => {
|
|
1242
|
+
const api = apiRef.current;
|
|
1243
|
+
const container = hostRef.current;
|
|
1244
|
+
if (!api || !container) return;
|
|
1245
|
+
applyAppearance(api, container, appearance);
|
|
1246
|
+
}, [appearance]);
|
|
1247
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1248
|
+
"div",
|
|
1249
|
+
{
|
|
1250
|
+
ref: hostRef,
|
|
1251
|
+
style: { ...DEFAULT_STYLE, ...style },
|
|
1252
|
+
className,
|
|
1253
|
+
"data-testid": testId
|
|
1254
|
+
}
|
|
1255
|
+
);
|
|
1256
|
+
}
|
|
1257
|
+
function applyAppearance(api, container, appearance) {
|
|
1258
|
+
const dark = appearance === "dark";
|
|
1259
|
+
container.classList.toggle("univer-dark", dark);
|
|
1260
|
+
try {
|
|
1261
|
+
const injector = api.univer._injector;
|
|
1262
|
+
const themeService = injector?.get(import_core2.ThemeService);
|
|
1263
|
+
if (themeService && themeService.darkMode !== dark) themeService.setDarkMode(dark);
|
|
1264
|
+
} catch {
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
// src/sheets/CasualSheetsIframe.tsx
|
|
1269
|
+
var import_react5 = require("react");
|
|
1270
|
+
|
|
1271
|
+
// src/embed/EmbedHostTransport.ts
|
|
1272
|
+
var EmbedHostTransport = class {
|
|
1273
|
+
constructor(opts) {
|
|
1274
|
+
__publicField(this, "opts");
|
|
1275
|
+
__publicField(this, "handlers", {});
|
|
1276
|
+
__publicField(this, "boundOnMessage");
|
|
1277
|
+
__publicField(this, "destroyed", false);
|
|
1278
|
+
this.opts = opts;
|
|
1279
|
+
this.boundOnMessage = this.onMessage.bind(this);
|
|
1280
|
+
const target = opts.hostWindow ?? window;
|
|
1281
|
+
target.addEventListener("message", this.boundOnMessage);
|
|
1282
|
+
}
|
|
1283
|
+
on(handlers) {
|
|
1284
|
+
this.handlers = { ...this.handlers, ...handlers };
|
|
1285
|
+
}
|
|
1286
|
+
destroy() {
|
|
1287
|
+
if (this.destroyed) return;
|
|
1288
|
+
this.destroyed = true;
|
|
1289
|
+
const target = this.opts.hostWindow ?? window;
|
|
1290
|
+
target.removeEventListener("message", this.boundOnMessage);
|
|
1291
|
+
}
|
|
1292
|
+
sendHostHello(data) {
|
|
1293
|
+
this.post("casual.hello", data);
|
|
1294
|
+
}
|
|
1295
|
+
sendSetViewMode(data) {
|
|
1296
|
+
this.post("casual.command.set.viewmode", data);
|
|
1297
|
+
}
|
|
1298
|
+
sendSetReadOnly(data) {
|
|
1299
|
+
this.post("casual.command.set.readonly", data);
|
|
1300
|
+
}
|
|
1301
|
+
sendSetTheme(data) {
|
|
1302
|
+
this.post("casual.command.set.theme", data);
|
|
1303
|
+
}
|
|
1304
|
+
sendSetLocale(data) {
|
|
1305
|
+
this.post("casual.command.set.locale", data);
|
|
1306
|
+
}
|
|
1307
|
+
sendCommandSave() {
|
|
1308
|
+
this.post("casual.command.save", null);
|
|
1309
|
+
}
|
|
1310
|
+
sendCommandFocus() {
|
|
1311
|
+
this.post("casual.command.focus", null);
|
|
1312
|
+
}
|
|
1313
|
+
/** Host → Editor: run a formatting / navigation command (bold,
|
|
1314
|
+
* italic, undo, …) against the active selection. v0.6+. */
|
|
1315
|
+
sendCommandExecute(data) {
|
|
1316
|
+
this.post("casual.command.execute", data);
|
|
1317
|
+
}
|
|
1318
|
+
sendSignatureRequest(id, data) {
|
|
1319
|
+
this.post("casual.signature.request", data, id);
|
|
1320
|
+
}
|
|
1321
|
+
sendSignatureCancel(data) {
|
|
1322
|
+
this.post("casual.signature.cancel", data);
|
|
1323
|
+
}
|
|
1324
|
+
onMessage(ev) {
|
|
1325
|
+
if (this.destroyed) return;
|
|
1326
|
+
if (ev.origin !== this.opts.embedOrigin) return;
|
|
1327
|
+
if (ev.source !== this.opts.iframeWindow) return;
|
|
1328
|
+
if (!isCasualEnvelope(ev.data)) return;
|
|
1329
|
+
if (ev.data.app !== this.opts.app) return;
|
|
1330
|
+
void this.dispatch(ev.data);
|
|
1331
|
+
}
|
|
1332
|
+
async dispatch(env) {
|
|
1333
|
+
switch (env.type) {
|
|
1334
|
+
case "casual.ready":
|
|
1335
|
+
this.handlers.onEditorReady?.(env.data);
|
|
1336
|
+
return;
|
|
1337
|
+
case "casual.load.request": {
|
|
1338
|
+
if (!this.handlers.onLoadRequest) return;
|
|
1339
|
+
const id = env.id ?? "";
|
|
1340
|
+
try {
|
|
1341
|
+
const resp = await this.handlers.onLoadRequest(env.data);
|
|
1342
|
+
const transfer = resp.ok ? [resp.bytes] : [];
|
|
1343
|
+
this.post("casual.load.response", resp, id, transfer);
|
|
1344
|
+
} catch (err) {
|
|
1345
|
+
this.post(
|
|
1346
|
+
"casual.load.response",
|
|
1347
|
+
{
|
|
1348
|
+
ok: false,
|
|
1349
|
+
code: "host_error",
|
|
1350
|
+
message: err instanceof Error ? err.message : String(err)
|
|
1351
|
+
},
|
|
1352
|
+
id
|
|
1353
|
+
);
|
|
1354
|
+
}
|
|
1355
|
+
return;
|
|
1356
|
+
}
|
|
1357
|
+
case "casual.save.request": {
|
|
1358
|
+
if (!this.handlers.onSaveRequest) return;
|
|
1359
|
+
const id = env.id ?? "";
|
|
1360
|
+
try {
|
|
1361
|
+
const resp = await this.handlers.onSaveRequest(env.data);
|
|
1362
|
+
this.post("casual.save.response", resp, id);
|
|
1363
|
+
} catch (err) {
|
|
1364
|
+
this.post(
|
|
1365
|
+
"casual.save.response",
|
|
1366
|
+
{
|
|
1367
|
+
ok: false,
|
|
1368
|
+
code: "host_error",
|
|
1369
|
+
message: err instanceof Error ? err.message : String(err)
|
|
1370
|
+
},
|
|
1371
|
+
id
|
|
1372
|
+
);
|
|
1373
|
+
}
|
|
1374
|
+
return;
|
|
1375
|
+
}
|
|
1376
|
+
case "casual.selection.changed":
|
|
1377
|
+
this.handlers.onSelectionChanged?.(env.data);
|
|
1378
|
+
return;
|
|
1379
|
+
case "casual.selection.format-state":
|
|
1380
|
+
this.handlers.onSelectionFormatState?.(env.data);
|
|
1381
|
+
return;
|
|
1382
|
+
case "casual.telemetry.event":
|
|
1383
|
+
this.handlers.onTelemetry?.(env.data);
|
|
1384
|
+
return;
|
|
1385
|
+
case "casual.signature.field.signed":
|
|
1386
|
+
this.handlers.onSignatureFieldSigned?.(env.data);
|
|
1387
|
+
return;
|
|
1388
|
+
case "casual.signature.complete":
|
|
1389
|
+
this.handlers.onSignatureComplete?.(env.data);
|
|
1390
|
+
return;
|
|
1391
|
+
case "casual.signature.cancel":
|
|
1392
|
+
this.handlers.onSignatureCancel?.(env.data);
|
|
1393
|
+
return;
|
|
1394
|
+
case "casual.signature.request.ack":
|
|
1395
|
+
return;
|
|
1396
|
+
case "casual.error":
|
|
1397
|
+
this.handlers.onError?.(env.data);
|
|
1398
|
+
return;
|
|
1399
|
+
default:
|
|
1400
|
+
return;
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1403
|
+
post(type, data, id, transfer) {
|
|
1404
|
+
const env = {
|
|
1405
|
+
type,
|
|
1406
|
+
app: this.opts.app,
|
|
1407
|
+
v: 1,
|
|
1408
|
+
data,
|
|
1409
|
+
...id ? { id } : {}
|
|
1410
|
+
};
|
|
1411
|
+
const send = this.opts.iframeWindow.postMessage.bind(
|
|
1412
|
+
this.opts.iframeWindow
|
|
1413
|
+
);
|
|
1414
|
+
send(env, this.opts.embedOrigin, transfer);
|
|
1415
|
+
}
|
|
1416
|
+
};
|
|
1417
|
+
|
|
1418
|
+
// src/sheets/CasualSheetsIframe.tsx
|
|
1419
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
1420
|
+
var DEFAULT_STYLE2 = {
|
|
1421
|
+
width: "100%",
|
|
1422
|
+
height: "100%",
|
|
1423
|
+
border: "none",
|
|
1424
|
+
display: "block"
|
|
1425
|
+
};
|
|
1426
|
+
var CasualSheetsIframe = (0, import_react5.forwardRef)(
|
|
1427
|
+
function CasualSheetsIframe2(props, ref) {
|
|
1428
|
+
const {
|
|
1429
|
+
fileSource,
|
|
1430
|
+
docId,
|
|
1431
|
+
viewMode = "editor",
|
|
1432
|
+
embedBasePath = "/embed/sheets",
|
|
1433
|
+
onSelectionChanged,
|
|
1434
|
+
onSelectionFormatState,
|
|
1435
|
+
onTelemetry,
|
|
1436
|
+
onError,
|
|
1437
|
+
style,
|
|
1438
|
+
className,
|
|
1439
|
+
testId = "casual-sheets-iframe"
|
|
1440
|
+
} = props;
|
|
1441
|
+
const iframeRef = (0, import_react5.useRef)(null);
|
|
1442
|
+
const transportRef = (0, import_react5.useRef)(null);
|
|
1443
|
+
const fileSourceRef = (0, import_react5.useRef)(fileSource);
|
|
1444
|
+
fileSourceRef.current = fileSource;
|
|
1445
|
+
const onLoad = (0, import_react5.useCallback)(async (req) => {
|
|
1446
|
+
try {
|
|
1447
|
+
const { bytes, name, etag } = await fileSourceRef.current.open(req.docId);
|
|
1448
|
+
return {
|
|
1449
|
+
ok: true,
|
|
1450
|
+
bytes,
|
|
1451
|
+
fileName: name,
|
|
1452
|
+
...etag !== void 0 ? { etag } : {}
|
|
1453
|
+
};
|
|
1454
|
+
} catch (err) {
|
|
1455
|
+
return {
|
|
1456
|
+
ok: false,
|
|
1457
|
+
code: "open_failed",
|
|
1458
|
+
message: err instanceof Error ? err.message : String(err)
|
|
1459
|
+
};
|
|
1460
|
+
}
|
|
1461
|
+
}, []);
|
|
1462
|
+
const onSave = (0, import_react5.useCallback)(
|
|
1463
|
+
async (req) => {
|
|
1464
|
+
try {
|
|
1465
|
+
if (!fileSourceRef.current.save) {
|
|
1466
|
+
return {
|
|
1467
|
+
ok: false,
|
|
1468
|
+
code: "save_unsupported",
|
|
1469
|
+
message: "host fileSource does not implement save"
|
|
1470
|
+
};
|
|
1471
|
+
}
|
|
1472
|
+
const opts = req.baseEtag !== void 0 ? { etag: req.baseEtag } : void 0;
|
|
1473
|
+
const { etag } = await fileSourceRef.current.save(req.docId, req.bytes, opts);
|
|
1474
|
+
return { ok: true, etag };
|
|
1475
|
+
} catch (err) {
|
|
1476
|
+
return {
|
|
1477
|
+
ok: false,
|
|
1478
|
+
code: "save_failed",
|
|
1479
|
+
message: err instanceof Error ? err.message : String(err)
|
|
1480
|
+
};
|
|
1481
|
+
}
|
|
1482
|
+
},
|
|
1483
|
+
[]
|
|
1484
|
+
);
|
|
1485
|
+
const onIframeLoad = (0, import_react5.useCallback)(() => {
|
|
1486
|
+
const iframe = iframeRef.current;
|
|
1487
|
+
if (!iframe?.contentWindow) return;
|
|
1488
|
+
transportRef.current?.destroy();
|
|
1489
|
+
const transport = new EmbedHostTransport({
|
|
1490
|
+
app: "sheet",
|
|
1491
|
+
iframeWindow: iframe.contentWindow,
|
|
1492
|
+
embedOrigin: window.location.origin
|
|
1493
|
+
});
|
|
1494
|
+
transport.on({
|
|
1495
|
+
onLoadRequest: onLoad,
|
|
1496
|
+
onSaveRequest: onSave,
|
|
1497
|
+
...onSelectionChanged ? { onSelectionChanged } : {},
|
|
1498
|
+
...onSelectionFormatState ? { onSelectionFormatState } : {},
|
|
1499
|
+
...onTelemetry ? { onTelemetry } : {},
|
|
1500
|
+
...onError ? { onError } : {},
|
|
1501
|
+
onEditorReady: () => {
|
|
1502
|
+
transport.sendHostHello({ capabilities: ["load", "save"] });
|
|
1503
|
+
transport.sendSetViewMode({ viewMode });
|
|
1504
|
+
}
|
|
1505
|
+
});
|
|
1506
|
+
transportRef.current = transport;
|
|
1507
|
+
}, [
|
|
1508
|
+
onLoad,
|
|
1509
|
+
onSave,
|
|
1510
|
+
onSelectionChanged,
|
|
1511
|
+
onSelectionFormatState,
|
|
1512
|
+
onTelemetry,
|
|
1513
|
+
onError,
|
|
1514
|
+
viewMode
|
|
1515
|
+
]);
|
|
1516
|
+
(0, import_react5.useEffect)(() => {
|
|
1517
|
+
transportRef.current?.sendSetViewMode({ viewMode });
|
|
1518
|
+
}, [viewMode]);
|
|
1519
|
+
(0, import_react5.useEffect)(() => {
|
|
1520
|
+
return () => {
|
|
1521
|
+
transportRef.current?.destroy();
|
|
1522
|
+
transportRef.current = null;
|
|
1523
|
+
};
|
|
1524
|
+
}, []);
|
|
1525
|
+
if (ref) {
|
|
1526
|
+
const apiRef = ref;
|
|
1527
|
+
apiRef.current = {
|
|
1528
|
+
setViewMode: (mode) => transportRef.current?.sendSetViewMode({ viewMode: mode }),
|
|
1529
|
+
iframe: () => iframeRef.current,
|
|
1530
|
+
executeCommand: (command) => transportRef.current?.sendCommandExecute({ command })
|
|
1531
|
+
};
|
|
1532
|
+
}
|
|
1533
|
+
const url = `${embedBasePath}/embed.html?app=sheet&docId=${encodeURIComponent(docId)}&viewMode=${viewMode}`;
|
|
1534
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1535
|
+
"iframe",
|
|
1536
|
+
{
|
|
1537
|
+
ref: iframeRef,
|
|
1538
|
+
src: url,
|
|
1539
|
+
onLoad: onIframeLoad,
|
|
1540
|
+
title: "Casual Sheets",
|
|
1541
|
+
sandbox: "allow-scripts allow-same-origin allow-downloads allow-modals",
|
|
1542
|
+
style: { ...DEFAULT_STYLE2, ...style },
|
|
1543
|
+
className,
|
|
1544
|
+
"data-testid": testId
|
|
1545
|
+
}
|
|
1546
|
+
);
|
|
1547
|
+
}
|
|
1548
|
+
);
|
|
1549
|
+
//# sourceMappingURL=index.cjs.map
|