@june-ai/june-ui 0.2.7 → 0.2.9
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/CHANGELOG.md +49 -2
- package/README.md +633 -400
- package/dist/{chunk-VFZI3SEL.js → chunk-27XM6EVX.js} +8 -8
- package/dist/chunk-G6YPSE6J.cjs +520 -0
- package/dist/chunk-GFCROSGQ.cjs +4399 -0
- package/dist/chunk-JSRO5CRO.js +4399 -0
- package/dist/{document-engine-RKD5SLXR.js → document-engine-BUTK73DW.js} +1 -1
- package/dist/document-engine-GXZH2LNW.cjs +12 -0
- package/dist/entry-core.cjs +148 -0
- package/dist/entry-core.d.cts +1005 -0
- package/dist/entry-core.d.ts +1005 -0
- package/dist/entry-core.js +149 -0
- package/dist/index.cjs +182 -4238
- package/dist/index.d.cts +80 -525
- package/dist/index.d.ts +80 -525
- package/dist/index.js +168 -3599
- package/dist/june.css +94 -0
- package/docs/architecture.md +95 -0
- package/docs/component-registration.md +115 -0
- package/docs/custom-features.md +68 -0
- package/docs/streaming.md +76 -0
- package/docs/theming.md +65 -0
- package/docs/troubleshooting.md +59 -0
- package/package.json +19 -5
package/dist/index.cjs
CHANGED
|
@@ -1,4296 +1,240 @@
|
|
|
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 __esm = (fn, res) => function __init() {
|
|
9
|
-
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
10
|
-
};
|
|
11
|
-
var __export = (target, all) => {
|
|
12
|
-
for (var name in all)
|
|
13
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
14
|
-
};
|
|
15
|
-
var __copyProps = (to, from, except, desc) => {
|
|
16
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
17
|
-
for (let key of __getOwnPropNames(from))
|
|
18
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
19
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
20
|
-
}
|
|
21
|
-
return to;
|
|
22
|
-
};
|
|
23
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
24
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
25
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
26
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
27
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
28
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
29
|
-
mod
|
|
30
|
-
));
|
|
31
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
32
|
-
|
|
33
|
-
// src/errors/errors.ts
|
|
34
|
-
function isJuneError(value) {
|
|
35
|
-
return value instanceof JuneError;
|
|
36
|
-
}
|
|
37
|
-
function toJuneError(error, fallbackCode, message) {
|
|
38
|
-
if (error instanceof JuneError) return error;
|
|
39
|
-
const text = message ?? (error instanceof Error ? error.message : String(error));
|
|
40
|
-
return new JuneError(fallbackCode, text, { cause: error });
|
|
41
|
-
}
|
|
42
|
-
var JuneError;
|
|
43
|
-
var init_errors = __esm({
|
|
44
|
-
"src/errors/errors.ts"() {
|
|
45
|
-
"use strict";
|
|
46
|
-
JuneError = class _JuneError extends Error {
|
|
47
|
-
constructor(code2, message, options = {}) {
|
|
48
|
-
super(message);
|
|
49
|
-
Object.setPrototypeOf(this, _JuneError.prototype);
|
|
50
|
-
this.name = "JuneError";
|
|
51
|
-
this.code = code2;
|
|
52
|
-
this.details = options.details;
|
|
53
|
-
if (options.cause !== void 0) {
|
|
54
|
-
this.cause = options.cause;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
});
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
|
|
60
2
|
|
|
61
|
-
// src/components/document-editor/document-utils.ts
|
|
62
|
-
function isDocJSON(value) {
|
|
63
|
-
if (!value || typeof value !== "object") return false;
|
|
64
|
-
const v = value;
|
|
65
|
-
return v.type === "doc" && (v.content === void 0 || Array.isArray(v.content));
|
|
66
|
-
}
|
|
67
|
-
function looksLikeDocJSON(text) {
|
|
68
|
-
return /^\s*\{\s*"type"\s*:\s*"doc"/.test(text);
|
|
69
|
-
}
|
|
70
|
-
function tryParseDocJSON(text) {
|
|
71
|
-
try {
|
|
72
|
-
const value = JSON.parse(text);
|
|
73
|
-
return isDocJSON(value) ? value : null;
|
|
74
|
-
} catch {
|
|
75
|
-
return null;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
function docKey(doc) {
|
|
79
|
-
let key = keyCache.get(doc);
|
|
80
|
-
if (key === void 0) {
|
|
81
|
-
key = JSON.stringify(doc);
|
|
82
|
-
keyCache.set(doc, key);
|
|
83
|
-
}
|
|
84
|
-
return key;
|
|
85
|
-
}
|
|
86
|
-
function plainText(node) {
|
|
87
|
-
const n = node;
|
|
88
|
-
if (typeof n.text === "string") return n.text;
|
|
89
|
-
return (n.content ?? []).map(plainText).join(" ");
|
|
90
|
-
}
|
|
91
|
-
function countWords(text) {
|
|
92
|
-
const trimmed = text.trim();
|
|
93
|
-
return trimmed ? trimmed.split(/\s+/).length : 0;
|
|
94
|
-
}
|
|
95
|
-
function wordCountOf(doc) {
|
|
96
|
-
let count = wordCache.get(doc);
|
|
97
|
-
if (count === void 0) {
|
|
98
|
-
count = countWords(plainText(doc));
|
|
99
|
-
wordCache.set(doc, count);
|
|
100
|
-
}
|
|
101
|
-
return count;
|
|
102
|
-
}
|
|
103
|
-
function slugify(value) {
|
|
104
|
-
return value.toLowerCase().normalize("NFKD").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 60);
|
|
105
|
-
}
|
|
106
|
-
function debounce(fn, wait) {
|
|
107
|
-
let timer = null;
|
|
108
|
-
const run = () => {
|
|
109
|
-
timer = null;
|
|
110
|
-
fn();
|
|
111
|
-
};
|
|
112
|
-
const debounced = (() => {
|
|
113
|
-
if (timer !== null) clearTimeout(timer);
|
|
114
|
-
timer = setTimeout(run, wait);
|
|
115
|
-
});
|
|
116
|
-
debounced.cancel = () => {
|
|
117
|
-
if (timer !== null) {
|
|
118
|
-
clearTimeout(timer);
|
|
119
|
-
timer = null;
|
|
120
|
-
}
|
|
121
|
-
};
|
|
122
|
-
debounced.flush = () => {
|
|
123
|
-
if (timer !== null) {
|
|
124
|
-
clearTimeout(timer);
|
|
125
|
-
run();
|
|
126
|
-
}
|
|
127
|
-
};
|
|
128
|
-
return debounced;
|
|
129
|
-
}
|
|
130
|
-
function sanitizeHref(input) {
|
|
131
|
-
const value = input.trim();
|
|
132
|
-
if (!value) return null;
|
|
133
|
-
if (/^(https?:|mailto:|tel:)/i.test(value)) return value;
|
|
134
|
-
if (/^[a-z][a-z0-9+.-]*:/i.test(value)) return null;
|
|
135
|
-
if (value.startsWith("/") || value.startsWith("#")) return value;
|
|
136
|
-
return `https://${value}`;
|
|
137
|
-
}
|
|
138
|
-
var emptyDoc, keyCache, wordCache;
|
|
139
|
-
var init_document_utils = __esm({
|
|
140
|
-
"src/components/document-editor/document-utils.ts"() {
|
|
141
|
-
"use strict";
|
|
142
|
-
emptyDoc = () => ({ type: "doc", content: [{ type: "paragraph" }] });
|
|
143
|
-
keyCache = /* @__PURE__ */ new WeakMap();
|
|
144
|
-
wordCache = /* @__PURE__ */ new WeakMap();
|
|
145
|
-
}
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
// src/components/document-editor/document-pagination.ts
|
|
149
|
-
function gapWidget(height) {
|
|
150
|
-
return () => {
|
|
151
|
-
const el = document.createElement("div");
|
|
152
|
-
el.className = "june-doc__page-gap";
|
|
153
|
-
el.contentEditable = "false";
|
|
154
|
-
el.setAttribute("aria-hidden", "true");
|
|
155
|
-
el.style.height = `${height}px`;
|
|
156
|
-
return el;
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
function build(doc, breaks) {
|
|
160
|
-
return import_view.DecorationSet.create(
|
|
161
|
-
doc,
|
|
162
|
-
breaks.map(
|
|
163
|
-
(b) => import_view.Decoration.widget(b.pos, gapWidget(b.height), {
|
|
164
|
-
side: -1,
|
|
165
|
-
ignoreSelection: true,
|
|
166
|
-
key: `jd-gap-${b.pos}-${Math.round(b.height)}`
|
|
167
|
-
})
|
|
168
|
-
)
|
|
169
|
-
);
|
|
170
|
-
}
|
|
171
|
-
function collectUnits(doc) {
|
|
172
|
-
const units = [];
|
|
173
|
-
const walk = (parent, start, inheritedBreak) => {
|
|
174
|
-
parent.forEach((child, offset, index) => {
|
|
175
|
-
const pos = start + offset;
|
|
176
|
-
const breakPos = index === 0 && inheritedBreak !== null ? inheritedBreak : pos;
|
|
177
|
-
if (SPLITTABLE.has(child.type.name) && child.childCount > 0) {
|
|
178
|
-
walk(child, pos + 1, breakPos);
|
|
179
|
-
} else {
|
|
180
|
-
units.push({ pos, breakPos, node: child });
|
|
181
|
-
}
|
|
182
|
-
});
|
|
183
|
-
};
|
|
184
|
-
walk(doc, 0, null);
|
|
185
|
-
return units;
|
|
186
|
-
}
|
|
187
|
-
function measure(view, cfg) {
|
|
188
|
-
const prose = view.dom;
|
|
189
|
-
const proseRect = prose.getBoundingClientRect();
|
|
190
|
-
const scale = prose.offsetWidth ? proseRect.width / prose.offsetWidth : 1;
|
|
191
|
-
if (!scale || !proseRect.width) return { breaks: [], pages: 1 };
|
|
192
|
-
const gaps = [...prose.querySelectorAll(".june-doc__page-gap")].map((g) => {
|
|
193
|
-
const r = g.getBoundingClientRect();
|
|
194
|
-
return { top: (r.top - proseRect.top) / scale, height: r.height / scale };
|
|
195
|
-
});
|
|
196
|
-
const gapsAbove = (y) => gaps.reduce((sum, g) => g.top <= y + 0.5 ? sum + g.height : sum, 0);
|
|
197
|
-
const contentH = Math.max(80, cfg.pageHeight - cfg.padTop - cfg.padBottom);
|
|
198
|
-
const stride = cfg.pageHeight + cfg.gap;
|
|
199
|
-
const breaks = /* @__PURE__ */ new Map();
|
|
200
|
-
let pageStart = 0;
|
|
201
|
-
let added = 0;
|
|
202
|
-
let force = false;
|
|
203
|
-
for (const unit of collectUnits(view.state.doc)) {
|
|
204
|
-
const el = view.nodeDOM(unit.pos);
|
|
205
|
-
if (!(el instanceof HTMLElement)) continue;
|
|
206
|
-
const r = el.getBoundingClientRect();
|
|
207
|
-
const rawTop = (r.top - proseRect.top) / scale;
|
|
208
|
-
const natural = rawTop - gapsAbove(rawTop);
|
|
209
|
-
const h = r.height / scale;
|
|
210
|
-
let top = natural + added;
|
|
211
|
-
let bottom = top + h;
|
|
212
|
-
const overflows = bottom > pageStart + contentH + 0.5 && top > pageStart + 1;
|
|
213
|
-
if (force || overflows) {
|
|
214
|
-
const target = pageStart + stride;
|
|
215
|
-
if (top < target) {
|
|
216
|
-
const spacer = target - top;
|
|
217
|
-
breaks.set(unit.breakPos, (breaks.get(unit.breakPos) ?? 0) + spacer);
|
|
218
|
-
added += spacer;
|
|
219
|
-
top = target;
|
|
220
|
-
bottom = top + h;
|
|
221
|
-
}
|
|
222
|
-
pageStart = target;
|
|
223
|
-
while (top >= pageStart + stride) pageStart += stride;
|
|
224
|
-
force = false;
|
|
225
|
-
}
|
|
226
|
-
while (bottom > pageStart + contentH + 0.5) pageStart += stride;
|
|
227
|
-
if (unit.node.type.name === "pageBreak") force = true;
|
|
228
|
-
}
|
|
229
|
-
const pages = Math.max(1, Math.round(pageStart / stride) + 1 + (force ? 1 : 0));
|
|
230
|
-
return {
|
|
231
|
-
breaks: [...breaks].map(([pos, height]) => ({ pos, height: Math.round(height * 10) / 10 })).sort((a, b) => a.pos - b.pos),
|
|
232
|
-
pages
|
|
233
|
-
};
|
|
234
|
-
}
|
|
235
|
-
function setPaginationConfig(editor, cfg) {
|
|
236
|
-
if (editor.isDestroyed) return;
|
|
237
|
-
const prev = configs.get(editor.view);
|
|
238
|
-
configs.set(editor.view, cfg);
|
|
239
|
-
if (!prev || prev.enabled !== cfg.enabled || prev.pageHeight !== cfg.pageHeight || prev.gap !== cfg.gap || prev.padTop !== cfg.padTop || prev.padBottom !== cfg.padBottom) {
|
|
240
|
-
remeasurePagination(editor);
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
function remeasurePagination(editor) {
|
|
244
|
-
if (editor.isDestroyed) return;
|
|
245
|
-
const s = paginationKey.getState(editor.state);
|
|
246
|
-
if (!s) return;
|
|
247
|
-
editor.view.dispatch(editor.state.tr.setMeta(paginationKey, { remeasure: true }).setMeta("addToHistory", false));
|
|
248
|
-
}
|
|
249
|
-
function getPageCount(editor) {
|
|
250
|
-
return editor && paginationKey.getState(editor.state)?.pages || 1;
|
|
251
|
-
}
|
|
252
|
-
var import_core, import_state, import_view, paginationKey, configs, SPLITTABLE, same2, DocumentPagination;
|
|
253
|
-
var init_document_pagination = __esm({
|
|
254
|
-
"src/components/document-editor/document-pagination.ts"() {
|
|
255
|
-
"use strict";
|
|
256
|
-
import_core = require("@tiptap/core");
|
|
257
|
-
import_state = require("@tiptap/pm/state");
|
|
258
|
-
import_view = require("@tiptap/pm/view");
|
|
259
|
-
paginationKey = new import_state.PluginKey("juneDocPagination");
|
|
260
|
-
configs = /* @__PURE__ */ new WeakMap();
|
|
261
|
-
SPLITTABLE = /* @__PURE__ */ new Set(["bulletList", "orderedList", "listItem", "blockquote"]);
|
|
262
|
-
same2 = (a, b) => a.length === b.length && a.every((x, i) => x.pos === b[i].pos && Math.abs(x.height - b[i].height) < 1);
|
|
263
|
-
DocumentPagination = import_core.Extension.create({
|
|
264
|
-
name: "juneDocPagination",
|
|
265
|
-
addProseMirrorPlugins() {
|
|
266
|
-
return [
|
|
267
|
-
new import_state.Plugin({
|
|
268
|
-
key: paginationKey,
|
|
269
|
-
state: {
|
|
270
|
-
init: () => ({ breaks: [], pages: 1, decorations: import_view.DecorationSet.empty, epoch: 0 }),
|
|
271
|
-
apply(tr, prev, _old, state) {
|
|
272
|
-
const meta = tr.getMeta(paginationKey);
|
|
273
|
-
if (meta?.remeasure) return { ...prev, epoch: prev.epoch + 1 };
|
|
274
|
-
if (meta?.breaks) {
|
|
275
|
-
return { ...prev, breaks: meta.breaks, pages: meta.pages ?? prev.pages, decorations: build(state.doc, meta.breaks) };
|
|
276
|
-
}
|
|
277
|
-
if (tr.docChanged) {
|
|
278
|
-
const breaks = prev.breaks.map((b) => ({ ...b, pos: tr.mapping.map(b.pos, -1) })).filter((b) => b.pos >= 0 && b.pos <= state.doc.content.size);
|
|
279
|
-
return { ...prev, breaks, decorations: prev.decorations.map(tr.mapping, tr.doc) };
|
|
280
|
-
}
|
|
281
|
-
return prev;
|
|
282
|
-
}
|
|
283
|
-
},
|
|
284
|
-
props: {
|
|
285
|
-
decorations: (state) => paginationKey.getState(state)?.decorations
|
|
286
|
-
},
|
|
287
|
-
view(view) {
|
|
288
|
-
let frame = null;
|
|
289
|
-
let rounds = 0;
|
|
290
|
-
const schedule = (reset) => {
|
|
291
|
-
if (reset) rounds = 0;
|
|
292
|
-
if (frame !== null || typeof window === "undefined") return;
|
|
293
|
-
const raf = window.requestAnimationFrame ?? ((cb) => window.setTimeout(() => cb(0), 16));
|
|
294
|
-
frame = raf(() => {
|
|
295
|
-
frame = null;
|
|
296
|
-
if (view.isDestroyed) return;
|
|
297
|
-
const cfg = configs.get(view);
|
|
298
|
-
const current = paginationKey.getState(view.state);
|
|
299
|
-
if (!current) return;
|
|
300
|
-
const next = cfg?.enabled ? measure(view, cfg) : { breaks: [], pages: 1 };
|
|
301
|
-
if (same2(next.breaks, current.breaks) && next.pages === current.pages) return;
|
|
302
|
-
if (++rounds > 4) return;
|
|
303
|
-
view.dispatch(view.state.tr.setMeta(paginationKey, next).setMeta("addToHistory", false));
|
|
304
|
-
});
|
|
305
|
-
};
|
|
306
|
-
schedule(true);
|
|
307
|
-
return {
|
|
308
|
-
update(v, prevState) {
|
|
309
|
-
const pg = paginationKey.getState(v.state);
|
|
310
|
-
const prevPg = paginationKey.getState(prevState);
|
|
311
|
-
if (v.state.doc !== prevState.doc || pg?.epoch !== prevPg?.epoch) schedule(true);
|
|
312
|
-
else if (pg !== prevPg) schedule(false);
|
|
313
|
-
},
|
|
314
|
-
destroy() {
|
|
315
|
-
frame = null;
|
|
316
|
-
}
|
|
317
|
-
};
|
|
318
|
-
}
|
|
319
|
-
})
|
|
320
|
-
];
|
|
321
|
-
}
|
|
322
|
-
});
|
|
323
|
-
}
|
|
324
|
-
});
|
|
325
|
-
|
|
326
|
-
// src/components/document-editor/document-search.ts
|
|
327
|
-
function findMatches(doc, term, caseSensitive) {
|
|
328
|
-
if (!term) return [];
|
|
329
|
-
const needle = caseSensitive ? term : term.toLowerCase();
|
|
330
|
-
const out = [];
|
|
331
|
-
doc.descendants((node, pos) => {
|
|
332
|
-
if (!node.isTextblock) return true;
|
|
333
|
-
let text = "";
|
|
334
|
-
const map = [];
|
|
335
|
-
node.forEach((child, offset) => {
|
|
336
|
-
const start = pos + 1 + offset;
|
|
337
|
-
if (child.isText && child.text) {
|
|
338
|
-
for (let i = 0; i < child.text.length; i++) map.push(start + i);
|
|
339
|
-
text += child.text;
|
|
340
|
-
} else {
|
|
341
|
-
map.push(start);
|
|
342
|
-
text += "\uFFFC";
|
|
343
|
-
}
|
|
344
|
-
});
|
|
345
|
-
const hay = caseSensitive ? text : text.toLowerCase();
|
|
346
|
-
let idx = hay.indexOf(needle);
|
|
347
|
-
while (idx !== -1) {
|
|
348
|
-
out.push({ from: map[idx], to: map[idx + needle.length - 1] + 1 });
|
|
349
|
-
idx = hay.indexOf(needle, idx + needle.length);
|
|
350
|
-
}
|
|
351
|
-
return false;
|
|
352
|
-
});
|
|
353
|
-
return out;
|
|
354
|
-
}
|
|
355
|
-
function build2(doc, term, caseSensitive, current) {
|
|
356
|
-
const matches = findMatches(doc, term, caseSensitive);
|
|
357
|
-
const active = matches.length ? Math.min(Math.max(current, 0), matches.length - 1) : -1;
|
|
358
|
-
const decorations = import_view2.DecorationSet.create(
|
|
359
|
-
doc,
|
|
360
|
-
matches.map(
|
|
361
|
-
(m, i) => import_view2.Decoration.inline(m.from, m.to, {
|
|
362
|
-
class: i === active ? "june-doc__match june-doc__match--active" : "june-doc__match"
|
|
363
|
-
})
|
|
364
|
-
)
|
|
365
|
-
);
|
|
366
|
-
return { term, caseSensitive, current: active, matches, decorations };
|
|
367
|
-
}
|
|
368
|
-
function getSearchState(editor) {
|
|
369
|
-
return editor ? searchKey.getState(editor.state) : void 0;
|
|
370
|
-
}
|
|
371
|
-
function setSearch(editor, meta) {
|
|
372
|
-
editor.view.dispatch(editor.state.tr.setMeta(searchKey, meta));
|
|
373
|
-
}
|
|
374
|
-
function gotoMatch(editor, step) {
|
|
375
|
-
const s = getSearchState(editor);
|
|
376
|
-
if (!s || !s.matches.length) return;
|
|
377
|
-
const n = s.matches.length;
|
|
378
|
-
const current = s.current < 0 ? 0 : (s.current + step + n) % n;
|
|
379
|
-
setSearch(editor, { current });
|
|
380
|
-
const m = s.matches[current];
|
|
381
|
-
editor.chain().setTextSelection(m).scrollIntoView().run();
|
|
382
|
-
}
|
|
383
|
-
function replaceCurrent(editor, replacement) {
|
|
384
|
-
const s = getSearchState(editor);
|
|
385
|
-
if (!s || s.current < 0) return;
|
|
386
|
-
const m = s.matches[s.current];
|
|
387
|
-
editor.chain().command(({ tr }) => {
|
|
388
|
-
if (replacement) tr.insertText(replacement, m.from, m.to);
|
|
389
|
-
else tr.delete(m.from, m.to);
|
|
390
|
-
return true;
|
|
391
|
-
}).run();
|
|
392
|
-
gotoMatch(editor, 0);
|
|
393
|
-
}
|
|
394
|
-
function replaceAll(editor, replacement) {
|
|
395
|
-
const s = getSearchState(editor);
|
|
396
|
-
if (!s || !s.matches.length) return 0;
|
|
397
|
-
const matches = [...s.matches].reverse();
|
|
398
|
-
editor.chain().command(({ tr }) => {
|
|
399
|
-
for (const m of matches) {
|
|
400
|
-
if (replacement) tr.insertText(replacement, m.from, m.to);
|
|
401
|
-
else tr.delete(m.from, m.to);
|
|
402
|
-
}
|
|
403
|
-
return true;
|
|
404
|
-
}).run();
|
|
405
|
-
return matches.length;
|
|
406
|
-
}
|
|
407
|
-
var import_core2, import_state2, import_view2, searchKey, DocumentSearch;
|
|
408
|
-
var init_document_search = __esm({
|
|
409
|
-
"src/components/document-editor/document-search.ts"() {
|
|
410
|
-
"use strict";
|
|
411
|
-
import_core2 = require("@tiptap/core");
|
|
412
|
-
import_state2 = require("@tiptap/pm/state");
|
|
413
|
-
import_view2 = require("@tiptap/pm/view");
|
|
414
|
-
searchKey = new import_state2.PluginKey("juneDocSearch");
|
|
415
|
-
DocumentSearch = import_core2.Extension.create({
|
|
416
|
-
name: "juneDocSearch",
|
|
417
|
-
addProseMirrorPlugins() {
|
|
418
|
-
return [
|
|
419
|
-
new import_state2.Plugin({
|
|
420
|
-
key: searchKey,
|
|
421
|
-
state: {
|
|
422
|
-
init: () => ({ term: "", caseSensitive: false, current: -1, matches: [], decorations: import_view2.DecorationSet.empty }),
|
|
423
|
-
apply(tr, prev, _old, state) {
|
|
424
|
-
const meta = tr.getMeta(searchKey);
|
|
425
|
-
if (!meta && !tr.docChanged) return prev;
|
|
426
|
-
if (!meta && !prev.term) return prev;
|
|
427
|
-
return build2(
|
|
428
|
-
state.doc,
|
|
429
|
-
meta?.term ?? prev.term,
|
|
430
|
-
meta?.caseSensitive ?? prev.caseSensitive,
|
|
431
|
-
meta?.current ?? prev.current
|
|
432
|
-
);
|
|
433
|
-
}
|
|
434
|
-
},
|
|
435
|
-
props: {
|
|
436
|
-
decorations: (state) => searchKey.getState(state)?.decorations
|
|
437
|
-
}
|
|
438
|
-
})
|
|
439
|
-
];
|
|
440
|
-
}
|
|
441
|
-
});
|
|
442
|
-
}
|
|
443
|
-
});
|
|
444
|
-
|
|
445
|
-
// src/components/document-editor/document-extensions.ts
|
|
446
|
-
function createDocumentExtensions() {
|
|
447
|
-
return [
|
|
448
|
-
import_starter_kit.default.configure({
|
|
449
|
-
heading: { levels: [1, 2, 3] },
|
|
450
|
-
// Tiptap v3 StarterKit already includes Link and Underline
|
|
451
|
-
link: { openOnClick: false, autolink: true, defaultProtocol: "https" }
|
|
452
|
-
}),
|
|
453
|
-
import_extension_text_align.default.configure({ types: ["heading", "paragraph"] }),
|
|
454
|
-
import_extension_table.TableKit,
|
|
455
|
-
import_extension_text_style.TextStyle,
|
|
456
|
-
import_extension_text_style.Color,
|
|
457
|
-
import_extension_text_style.FontFamily,
|
|
458
|
-
import_extension_text_style.FontSize,
|
|
459
|
-
import_extension_highlight.default.configure({ multicolor: true }),
|
|
460
|
-
import_extension_subscript.default,
|
|
461
|
-
import_extension_superscript.default,
|
|
462
|
-
import_extension_image.default.configure({
|
|
463
|
-
inline: false,
|
|
464
|
-
allowBase64: true,
|
|
465
|
-
resize: { enabled: true, minWidth: 48, minHeight: 32, alwaysPreserveAspectRatio: true }
|
|
466
|
-
}),
|
|
467
|
-
PageBreak,
|
|
468
|
-
DocumentSearch,
|
|
469
|
-
DocumentPagination,
|
|
470
|
-
// inactive until the live editor sets a page geometry
|
|
471
|
-
import_markdown.Markdown
|
|
472
|
-
];
|
|
473
|
-
}
|
|
474
|
-
var import_core3, import_extension_highlight, import_extension_image, import_extension_subscript, import_extension_superscript, import_extension_table, import_extension_text_align, import_extension_text_style, import_markdown, import_starter_kit, PageBreak;
|
|
475
|
-
var init_document_extensions = __esm({
|
|
476
|
-
"src/components/document-editor/document-extensions.ts"() {
|
|
477
|
-
"use strict";
|
|
478
|
-
import_core3 = require("@tiptap/core");
|
|
479
|
-
import_extension_highlight = __toESM(require("@tiptap/extension-highlight"), 1);
|
|
480
|
-
import_extension_image = __toESM(require("@tiptap/extension-image"), 1);
|
|
481
|
-
import_extension_subscript = __toESM(require("@tiptap/extension-subscript"), 1);
|
|
482
|
-
import_extension_superscript = __toESM(require("@tiptap/extension-superscript"), 1);
|
|
483
|
-
import_extension_table = require("@tiptap/extension-table");
|
|
484
|
-
import_extension_text_align = __toESM(require("@tiptap/extension-text-align"), 1);
|
|
485
|
-
import_extension_text_style = require("@tiptap/extension-text-style");
|
|
486
|
-
import_markdown = require("@tiptap/markdown");
|
|
487
|
-
import_starter_kit = __toESM(require("@tiptap/starter-kit"), 1);
|
|
488
|
-
init_document_pagination();
|
|
489
|
-
init_document_search();
|
|
490
|
-
PageBreak = import_core3.Node.create({
|
|
491
|
-
name: "pageBreak",
|
|
492
|
-
group: "block",
|
|
493
|
-
atom: true,
|
|
494
|
-
selectable: true,
|
|
495
|
-
parseHTML() {
|
|
496
|
-
return [{ tag: "div[data-page-break]" }];
|
|
497
|
-
},
|
|
498
|
-
renderHTML({ HTMLAttributes }) {
|
|
499
|
-
return [
|
|
500
|
-
"div",
|
|
501
|
-
(0, import_core3.mergeAttributes)(HTMLAttributes, {
|
|
502
|
-
"data-page-break": "true",
|
|
503
|
-
class: "june-doc__page-break",
|
|
504
|
-
style: "break-after: page; page-break-after: always;"
|
|
505
|
-
})
|
|
506
|
-
];
|
|
507
|
-
},
|
|
508
|
-
// Markdown has no page break; a thematic break is the closest stable equivalent.
|
|
509
|
-
renderMarkdown: () => "---",
|
|
510
|
-
addCommands() {
|
|
511
|
-
return {
|
|
512
|
-
setPageBreak: () => ({ chain }) => chain().insertContent([{ type: this.name }, { type: "paragraph" }]).run()
|
|
513
|
-
};
|
|
514
|
-
},
|
|
515
|
-
addKeyboardShortcuts() {
|
|
516
|
-
return { "Mod-Enter": () => this.editor.commands.setPageBreak() };
|
|
517
|
-
}
|
|
518
|
-
});
|
|
519
|
-
}
|
|
520
|
-
});
|
|
521
|
-
|
|
522
|
-
// src/components/document-editor/document-engine.ts
|
|
523
|
-
var document_engine_exports = {};
|
|
524
|
-
__export(document_engine_exports, {
|
|
525
|
-
docToHtml: () => docToHtml,
|
|
526
|
-
docToMarkdown: () => docToMarkdown,
|
|
527
|
-
docToText: () => docToText,
|
|
528
|
-
parseDocumentContent: () => parseDocumentContent
|
|
529
|
-
});
|
|
530
|
-
function scratchEditor() {
|
|
531
|
-
if (!scratch || scratch.isDestroyed) {
|
|
532
|
-
scratch = new import_core4.Editor({ extensions: createDocumentExtensions(), content: "" });
|
|
533
|
-
}
|
|
534
|
-
return scratch;
|
|
535
|
-
}
|
|
536
|
-
function parseDocumentContent(text) {
|
|
537
|
-
const editor = scratchEditor();
|
|
538
|
-
const trimmed = text.trim();
|
|
539
|
-
try {
|
|
540
|
-
if (looksLikeDocJSON(trimmed)) {
|
|
541
|
-
const json = tryParseDocJSON(trimmed);
|
|
542
|
-
if (!json) throw new Error("The document JSON could not be parsed");
|
|
543
|
-
editor.schema.nodeFromJSON(json).check();
|
|
544
|
-
editor.commands.setContent(json, { emitUpdate: false });
|
|
545
|
-
} else {
|
|
546
|
-
editor.commands.setContent(trimmed, { contentType: "markdown", emitUpdate: false });
|
|
547
|
-
}
|
|
548
|
-
return editor.getJSON();
|
|
549
|
-
} catch (error) {
|
|
550
|
-
throw toJuneError(error, "DOCUMENT_ERROR", "The document content is invalid");
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
function load(doc) {
|
|
554
|
-
const editor = scratchEditor();
|
|
555
|
-
editor.commands.setContent(doc, { emitUpdate: false });
|
|
556
|
-
return editor;
|
|
557
|
-
}
|
|
558
|
-
var import_core4, scratch, docToHtml, docToMarkdown, docToText;
|
|
559
|
-
var init_document_engine = __esm({
|
|
560
|
-
"src/components/document-editor/document-engine.ts"() {
|
|
561
|
-
"use strict";
|
|
562
|
-
import_core4 = require("@tiptap/core");
|
|
563
|
-
init_errors();
|
|
564
|
-
init_document_extensions();
|
|
565
|
-
init_document_utils();
|
|
566
|
-
scratch = null;
|
|
567
|
-
docToHtml = (doc) => load(doc).getHTML();
|
|
568
|
-
docToMarkdown = (doc) => load(doc).getMarkdown();
|
|
569
|
-
docToText = (doc) => load(doc).getText({ blockSeparator: "\n\n" });
|
|
570
|
-
}
|
|
571
|
-
});
|
|
572
|
-
|
|
573
|
-
// src/index.ts
|
|
574
|
-
var index_exports = {};
|
|
575
|
-
__export(index_exports, {
|
|
576
|
-
ALL_EXPORT_FORMATS: () => ALL_EXPORT_FORMATS,
|
|
577
|
-
DocumentEditor: () => DocumentEditor,
|
|
578
|
-
JuneDocumentContext: () => JuneDocumentContext,
|
|
579
|
-
JuneDocumentEditorComponent: () => JuneDocumentEditorComponent,
|
|
580
|
-
JuneError: () => JuneError,
|
|
581
|
-
JuneErrorBoundary: () => JuneErrorBoundary,
|
|
582
|
-
JuneRenderer: () => JuneRenderer,
|
|
583
|
-
JuneRuntimeContext: () => JuneRuntimeContext,
|
|
584
|
-
JuneThemeProvider: () => JuneThemeProvider,
|
|
585
|
-
JuneUI: () => JuneUI,
|
|
586
|
-
consumeStream: () => consumeStream,
|
|
587
|
-
copyDocumentToClipboard: () => copyDocumentToClipboard,
|
|
588
|
-
createActionHandler: () => createActionHandler,
|
|
589
|
-
createDocumentStore: () => createDocumentStore,
|
|
590
|
-
createJuneLibrary: () => createJuneLibrary,
|
|
591
|
-
darkTheme: () => darkTheme,
|
|
592
|
-
defaultParseActionEvent: () => defaultParseActionEvent,
|
|
593
|
-
defineJuneAction: () => defineJuneAction,
|
|
594
|
-
defineJuneComponent: () => defineJuneComponent,
|
|
595
|
-
documentPromptOptions: () => documentPromptOptions,
|
|
596
|
-
downloadResult: () => downloadResult,
|
|
597
|
-
exportDocument: () => exportDocument,
|
|
598
|
-
fetchStream: () => fetchStream,
|
|
599
|
-
getDefaultDocumentStore: () => getDefaultDocumentStore,
|
|
600
|
-
getDocumentEditorInstructions: () => getDocumentEditorInstructions,
|
|
601
|
-
getDocumentEditorRules: () => getDocumentEditorRules,
|
|
602
|
-
isDocumentEcho: () => isDocumentEcho,
|
|
603
|
-
isJuneError: () => isJuneError,
|
|
604
|
-
jsonFieldExtractor: () => jsonFieldExtractor,
|
|
605
|
-
juneLibrary: () => juneLibrary,
|
|
606
|
-
lightTheme: () => lightTheme,
|
|
607
|
-
listDocumentExporters: () => listDocumentExporters,
|
|
608
|
-
mergeDocuments: () => mergeDocuments,
|
|
609
|
-
readDocumentFromProgram: () => readDocumentFromProgram,
|
|
610
|
-
registerDocumentExporter: () => registerDocumentExporter,
|
|
611
|
-
rememberDocumentEcho: () => rememberDocumentEcho,
|
|
612
|
-
runAction: () => runAction,
|
|
613
|
-
serializeDocumentsForAgent: () => serializeDocumentsForAgent,
|
|
614
|
-
sseToText: () => sseToText,
|
|
615
|
-
toJuneError: () => toJuneError,
|
|
616
|
-
updateDocumentInProgram: () => updateDocumentInProgram,
|
|
617
|
-
useDocumentOptions: () => useDocumentOptions,
|
|
618
|
-
useJuneRuntime: () => useJuneRuntime,
|
|
619
|
-
useJuneStream: () => useJuneStream,
|
|
620
|
-
useJuneTheme: () => useJuneTheme,
|
|
621
|
-
useResolvedTheme: () => useResolvedTheme,
|
|
622
|
-
withDocumentEditor: () => withDocumentEditor
|
|
623
|
-
});
|
|
624
|
-
module.exports = __toCommonJS(index_exports);
|
|
625
|
-
|
|
626
|
-
// src/openui/disable-devtools.tsx
|
|
627
|
-
var import_devtools = require("@openuidev/devtools");
|
|
628
|
-
var import_jsx_runtime = require("react/jsx-runtime");
|
|
629
|
-
var AUTO_MOUNT_FLAG = /* @__PURE__ */ Symbol.for("openui.devtools.autoMount");
|
|
630
|
-
var BLOCKED_BY_JUNE = /* @__PURE__ */ Symbol.for("openui.devtools.blockedByJune");
|
|
631
|
-
var flags = globalThis;
|
|
632
|
-
var scheduledByOpenUI = flags[AUTO_MOUNT_FLAG] === true && flags[BLOCKED_BY_JUNE] !== true;
|
|
633
|
-
flags[AUTO_MOUNT_FLAG] = true;
|
|
634
|
-
flags[BLOCKED_BY_JUNE] = true;
|
|
635
|
-
var DEVTOOLS_BUNDLE = "https://cdn.jsdelivr.net/npm/@openuidev/devtools@0/dist/devtools.browser.js";
|
|
636
|
-
var ALIAS_CACHE_MS = 5 * 60 * 1e3;
|
|
637
|
-
function claimDisabledDevtools() {
|
|
638
|
-
if (typeof document === "undefined") return () => {
|
|
639
|
-
};
|
|
640
|
-
const url = `${DEVTOOLS_BUNDLE}?t=${Math.floor(Date.now() / ALIAS_CACHE_MS)}`;
|
|
641
|
-
let cancelled = false;
|
|
642
|
-
let unmount = () => {
|
|
643
|
-
cancelled = true;
|
|
644
|
-
};
|
|
645
|
-
void Promise.all([
|
|
646
|
-
import(
|
|
647
|
-
/* @vite-ignore */
|
|
648
|
-
url
|
|
649
|
-
),
|
|
650
|
-
import("react"),
|
|
651
|
-
import("react-dom"),
|
|
652
|
-
import("react-dom/client")
|
|
653
|
-
]).then(([devtools, react, reactDom, reactDomClient]) => {
|
|
654
|
-
if (cancelled) return;
|
|
655
|
-
unmount = devtools.mountOpenUIDevtools({
|
|
656
|
-
React: react,
|
|
657
|
-
ReactDOM: reactDom,
|
|
658
|
-
ReactDOMClient: reactDomClient,
|
|
659
|
-
loadReactLang: () => import("@openuidev/react-lang"),
|
|
660
|
-
props: { enabled: false }
|
|
661
|
-
});
|
|
662
|
-
}).catch(() => {
|
|
663
|
-
});
|
|
664
|
-
return () => unmount();
|
|
665
|
-
}
|
|
666
|
-
if (scheduledByOpenUI && process.env.NODE_ENV === "development" && process.env.VITEST !== "true" && typeof document !== "undefined") {
|
|
667
|
-
claimDisabledDevtools();
|
|
668
|
-
}
|
|
669
|
-
function OpenUIDevtoolsGate() {
|
|
670
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_devtools.OpenUIDevtools, { enabled: false });
|
|
671
|
-
}
|
|
672
3
|
|
|
673
|
-
// src/renderer/renderer.tsx
|
|
674
|
-
var import_react_lang = require("@openuidev/react-lang");
|
|
675
|
-
var import_react5 = require("react");
|
|
676
4
|
|
|
677
|
-
// src/actions/action-handler.ts
|
|
678
|
-
init_errors();
|
|
679
|
-
function firstString(...values) {
|
|
680
|
-
for (const v of values) if (typeof v === "string" && v.length > 0) return v;
|
|
681
|
-
return null;
|
|
682
|
-
}
|
|
683
|
-
var defaultParseActionEvent = (event) => {
|
|
684
|
-
if (!event || typeof event !== "object") return null;
|
|
685
|
-
const e = event;
|
|
686
|
-
const name = firstString(e.type, e.name, e.action);
|
|
687
|
-
if (!name) return null;
|
|
688
|
-
return { name, payload: e.params ?? e.payload ?? e.data };
|
|
689
|
-
};
|
|
690
|
-
async function runAction(event, options) {
|
|
691
|
-
const { actions, parseEvent = defaultParseActionEvent, confirm, onError, onUnhandled } = options;
|
|
692
|
-
const parsed = parseEvent(event);
|
|
693
|
-
const action = parsed && Object.prototype.hasOwnProperty.call(actions, parsed.name) ? actions[parsed.name] : void 0;
|
|
694
|
-
if (!parsed || !action) {
|
|
695
|
-
onUnhandled?.(event);
|
|
696
|
-
return "unhandled";
|
|
697
|
-
}
|
|
698
|
-
const { name } = parsed;
|
|
699
|
-
let payload = parsed.payload;
|
|
700
|
-
if (action.schema) {
|
|
701
|
-
const result = action.schema.safeParse(payload);
|
|
702
|
-
if (!result.success) {
|
|
703
|
-
onError?.(
|
|
704
|
-
new JuneError("ACTION_VALIDATION_ERROR", `Invalid payload for action "${name}"`, {
|
|
705
|
-
details: result.error
|
|
706
|
-
})
|
|
707
|
-
);
|
|
708
|
-
return "failed";
|
|
709
|
-
}
|
|
710
|
-
payload = result.data;
|
|
711
|
-
}
|
|
712
|
-
try {
|
|
713
|
-
if (action.sensitive || action.confirm) {
|
|
714
|
-
const ask = action.confirm ?? confirm;
|
|
715
|
-
if (!ask) {
|
|
716
|
-
onError?.(
|
|
717
|
-
new JuneError(
|
|
718
|
-
"ACTION_REJECTED",
|
|
719
|
-
`Action "${name}" requires confirmation but no confirm handler was provided`
|
|
720
|
-
)
|
|
721
|
-
);
|
|
722
|
-
return "rejected";
|
|
723
|
-
}
|
|
724
|
-
const approved = await ask({ name, payload, description: action.description });
|
|
725
|
-
if (!approved) return "rejected";
|
|
726
|
-
}
|
|
727
|
-
await action.handler(payload, { name, event });
|
|
728
|
-
return "handled";
|
|
729
|
-
} catch (error) {
|
|
730
|
-
onError?.(toJuneError(error, "ACTION_ERROR"));
|
|
731
|
-
return "failed";
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
function createActionHandler(options) {
|
|
735
|
-
return (event) => {
|
|
736
|
-
void runAction(event, options);
|
|
737
|
-
};
|
|
738
|
-
}
|
|
739
5
|
|
|
740
|
-
// src/components/document-editor/document-context.ts
|
|
741
|
-
var import_react = require("react");
|
|
742
|
-
var JuneDocumentContext = (0, import_react.createContext)({});
|
|
743
|
-
function useDocumentOptions() {
|
|
744
|
-
return (0, import_react.useContext)(JuneDocumentContext);
|
|
745
|
-
}
|
|
746
|
-
function useDocumentValue(store, id, selector) {
|
|
747
|
-
const read = () => selector(store.get(id));
|
|
748
|
-
return (0, import_react.useSyncExternalStore)(store.subscribe, read, read);
|
|
749
|
-
}
|
|
750
6
|
|
|
751
|
-
// src/components/document-editor/document-merge.ts
|
|
752
|
-
init_document_utils();
|
|
753
|
-
var MAX_CELLS = 4e6;
|
|
754
|
-
function matchIndices(a, b) {
|
|
755
|
-
const n = a.length;
|
|
756
|
-
const m = b.length;
|
|
757
|
-
if (n * m > MAX_CELLS) return null;
|
|
758
|
-
const dp = Array.from({ length: n + 1 }, () => new Uint32Array(m + 1));
|
|
759
|
-
for (let i2 = n - 1; i2 >= 0; i2--) {
|
|
760
|
-
for (let j2 = m - 1; j2 >= 0; j2--) {
|
|
761
|
-
dp[i2][j2] = a[i2] === b[j2] ? dp[i2 + 1][j2 + 1] + 1 : Math.max(dp[i2 + 1][j2], dp[i2][j2 + 1]);
|
|
762
|
-
}
|
|
763
|
-
}
|
|
764
|
-
const matches = /* @__PURE__ */ new Map();
|
|
765
|
-
let i = 0;
|
|
766
|
-
let j = 0;
|
|
767
|
-
while (i < n && j < m) {
|
|
768
|
-
if (a[i] === b[j]) {
|
|
769
|
-
matches.set(i, j);
|
|
770
|
-
i++;
|
|
771
|
-
j++;
|
|
772
|
-
} else if (dp[i + 1][j] >= dp[i][j + 1]) i++;
|
|
773
|
-
else j++;
|
|
774
|
-
}
|
|
775
|
-
return matches;
|
|
776
|
-
}
|
|
777
|
-
var same = (x, y) => x.length === y.length && x.every((v, i) => v === y[i]);
|
|
778
|
-
function mergeBlocks(base, local, incoming) {
|
|
779
|
-
if (same(local, base)) return { blocks: incoming, conflicts: 0 };
|
|
780
|
-
if (same(incoming, base) || same(local, incoming)) return { blocks: local, conflicts: 0 };
|
|
781
|
-
const ml = matchIndices(base, local);
|
|
782
|
-
const mn = matchIndices(base, incoming);
|
|
783
|
-
if (!ml || !mn) return { blocks: null, conflicts: 1 };
|
|
784
|
-
const anchors = [...ml.keys()].filter((i) => mn.has(i)).sort((x, y) => x - y);
|
|
785
|
-
const out = [];
|
|
786
|
-
let conflicts = 0;
|
|
787
|
-
let pb = -1;
|
|
788
|
-
let pl = -1;
|
|
789
|
-
let pn = -1;
|
|
790
|
-
const region = (bEnd, lEnd, nEnd) => {
|
|
791
|
-
const B = base.slice(pb + 1, bEnd);
|
|
792
|
-
const L = local.slice(pl + 1, lEnd);
|
|
793
|
-
const N = incoming.slice(pn + 1, nEnd);
|
|
794
|
-
if (B.length === L.length && L.length === N.length) {
|
|
795
|
-
for (let k = 0; k < B.length; k++) {
|
|
796
|
-
if (L[k] === B[k]) out.push(N[k]);
|
|
797
|
-
else if (N[k] === B[k] || N[k] === L[k]) out.push(L[k]);
|
|
798
|
-
else {
|
|
799
|
-
conflicts++;
|
|
800
|
-
out.push(L[k]);
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
return;
|
|
804
|
-
}
|
|
805
|
-
if (same(L, B)) out.push(...N);
|
|
806
|
-
else if (same(N, B) || same(L, N)) out.push(...L);
|
|
807
|
-
else {
|
|
808
|
-
conflicts++;
|
|
809
|
-
out.push(...L);
|
|
810
|
-
}
|
|
811
|
-
};
|
|
812
|
-
for (const a of anchors) {
|
|
813
|
-
const la = ml.get(a);
|
|
814
|
-
const na = mn.get(a);
|
|
815
|
-
region(a, la, na);
|
|
816
|
-
out.push(local[la]);
|
|
817
|
-
pb = a;
|
|
818
|
-
pl = la;
|
|
819
|
-
pn = na;
|
|
820
|
-
}
|
|
821
|
-
region(base.length, local.length, incoming.length);
|
|
822
|
-
return { blocks: out, conflicts };
|
|
823
|
-
}
|
|
824
|
-
function mergeDocuments(base, local, incoming) {
|
|
825
|
-
const toBlocks = (d) => (d.content ?? []).map((node) => JSON.stringify(node));
|
|
826
|
-
const { blocks: blocks2, conflicts } = mergeBlocks(toBlocks(base), toBlocks(local), toBlocks(incoming));
|
|
827
|
-
if (!blocks2) return { doc: local, conflicts: Math.max(1, conflicts) };
|
|
828
|
-
if (blocks2.length === 0) return { doc: emptyDoc(), conflicts };
|
|
829
|
-
return { doc: { type: "doc", content: blocks2.map((b) => JSON.parse(b)) }, conflicts };
|
|
830
|
-
}
|
|
831
7
|
|
|
832
|
-
// src/components/document-editor/document-store.ts
|
|
833
|
-
init_document_utils();
|
|
834
|
-
var incomingKey = (doc) => JSON.stringify([doc.title, docKey(doc.json)]);
|
|
835
|
-
function createDocumentStore() {
|
|
836
|
-
const records = /* @__PURE__ */ new Map();
|
|
837
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
838
|
-
const emit = () => listeners.forEach((listener) => listener());
|
|
839
|
-
const put = (record) => {
|
|
840
|
-
records.set(record.id, record);
|
|
841
|
-
emit();
|
|
842
|
-
};
|
|
843
|
-
const fresh2 = (doc) => ({
|
|
844
|
-
id: doc.id,
|
|
845
|
-
title: doc.title,
|
|
846
|
-
documentType: doc.documentType,
|
|
847
|
-
status: doc.status,
|
|
848
|
-
json: doc.json,
|
|
849
|
-
baseJson: doc.json,
|
|
850
|
-
baseTitle: doc.title,
|
|
851
|
-
lastIncomingKey: incomingKey(doc),
|
|
852
|
-
revision: 0,
|
|
853
|
-
origin: "external",
|
|
854
|
-
pending: null,
|
|
855
|
-
updatedAt: Date.now()
|
|
856
|
-
});
|
|
857
|
-
return {
|
|
858
|
-
get: (id) => records.get(id),
|
|
859
|
-
list: () => [...records.values()],
|
|
860
|
-
subscribe: (listener) => {
|
|
861
|
-
listeners.add(listener);
|
|
862
|
-
return () => {
|
|
863
|
-
listeners.delete(listener);
|
|
864
|
-
};
|
|
865
|
-
},
|
|
866
|
-
receive(incoming) {
|
|
867
|
-
const current = records.get(incoming.id);
|
|
868
|
-
if (!current) {
|
|
869
|
-
put(fresh2(incoming));
|
|
870
|
-
return "created";
|
|
871
|
-
}
|
|
872
|
-
const key = incomingKey(incoming);
|
|
873
|
-
if (current.lastIncomingKey === key) return "unchanged";
|
|
874
|
-
const userEditedBody = docKey(current.json) !== docKey(current.baseJson);
|
|
875
|
-
const userEditedTitle = current.title !== current.baseTitle;
|
|
876
|
-
const title = userEditedTitle ? current.title : incoming.title;
|
|
877
|
-
const meta = {
|
|
878
|
-
documentType: incoming.documentType ?? current.documentType,
|
|
879
|
-
status: incoming.status ?? current.status
|
|
880
|
-
};
|
|
881
|
-
if (!userEditedBody) {
|
|
882
|
-
put({
|
|
883
|
-
...current,
|
|
884
|
-
...meta,
|
|
885
|
-
title,
|
|
886
|
-
baseTitle: incoming.title,
|
|
887
|
-
json: incoming.json,
|
|
888
|
-
baseJson: incoming.json,
|
|
889
|
-
lastIncomingKey: key,
|
|
890
|
-
revision: current.revision + 1,
|
|
891
|
-
origin: "external",
|
|
892
|
-
pending: null,
|
|
893
|
-
updatedAt: Date.now()
|
|
894
|
-
});
|
|
895
|
-
return "applied";
|
|
896
|
-
}
|
|
897
|
-
const { doc, conflicts } = mergeDocuments(current.baseJson, current.json, incoming.json);
|
|
898
|
-
if (conflicts === 0) {
|
|
899
|
-
put({
|
|
900
|
-
...current,
|
|
901
|
-
...meta,
|
|
902
|
-
title,
|
|
903
|
-
baseTitle: incoming.title,
|
|
904
|
-
json: doc,
|
|
905
|
-
baseJson: incoming.json,
|
|
906
|
-
lastIncomingKey: key,
|
|
907
|
-
revision: current.revision + 1,
|
|
908
|
-
origin: "external",
|
|
909
|
-
pending: null,
|
|
910
|
-
updatedAt: Date.now()
|
|
911
|
-
});
|
|
912
|
-
return "merged";
|
|
913
|
-
}
|
|
914
|
-
put({
|
|
915
|
-
...current,
|
|
916
|
-
...meta,
|
|
917
|
-
lastIncomingKey: key,
|
|
918
|
-
pending: { json: incoming.json, title: incoming.title, merged: doc, conflicts }
|
|
919
|
-
});
|
|
920
|
-
return "conflict";
|
|
921
|
-
},
|
|
922
|
-
hydrate(doc) {
|
|
923
|
-
put(fresh2(doc));
|
|
924
|
-
},
|
|
925
|
-
edit(id, json, origin) {
|
|
926
|
-
const current = records.get(id);
|
|
927
|
-
if (!current || docKey(current.json) === docKey(json)) return;
|
|
928
|
-
put({ ...current, json, origin, revision: current.revision + 1, updatedAt: Date.now() });
|
|
929
|
-
},
|
|
930
|
-
setTitle(id, title) {
|
|
931
|
-
const current = records.get(id);
|
|
932
|
-
if (!current || current.title === title) return;
|
|
933
|
-
put({ ...current, title, updatedAt: Date.now() });
|
|
934
|
-
},
|
|
935
|
-
resolve(id, choice) {
|
|
936
|
-
const current = records.get(id);
|
|
937
|
-
const pending = current?.pending;
|
|
938
|
-
if (!current || !pending) return;
|
|
939
|
-
if (choice === "keep") {
|
|
940
|
-
put({ ...current, baseJson: pending.json, baseTitle: pending.title, pending: null });
|
|
941
|
-
return;
|
|
942
|
-
}
|
|
943
|
-
const json = choice === "merge" ? pending.merged : pending.json;
|
|
944
|
-
const title = choice === "merge" ? current.title : pending.title;
|
|
945
|
-
put({
|
|
946
|
-
...current,
|
|
947
|
-
title,
|
|
948
|
-
json,
|
|
949
|
-
baseJson: pending.json,
|
|
950
|
-
baseTitle: pending.title,
|
|
951
|
-
revision: current.revision + 1,
|
|
952
|
-
origin: "external",
|
|
953
|
-
pending: null,
|
|
954
|
-
updatedAt: Date.now()
|
|
955
|
-
});
|
|
956
|
-
},
|
|
957
|
-
remove(id) {
|
|
958
|
-
if (records.delete(id)) emit();
|
|
959
|
-
}
|
|
960
|
-
};
|
|
961
|
-
}
|
|
962
|
-
var echoes = /* @__PURE__ */ new WeakMap();
|
|
963
|
-
var ECHO_MEMORY = 8;
|
|
964
|
-
function rememberDocumentEcho(store, id, content) {
|
|
965
|
-
let byId = echoes.get(store);
|
|
966
|
-
if (!byId) echoes.set(store, byId = /* @__PURE__ */ new Map());
|
|
967
|
-
const list2 = byId.get(id) ?? [];
|
|
968
|
-
list2.push(content);
|
|
969
|
-
if (list2.length > ECHO_MEMORY) list2.shift();
|
|
970
|
-
byId.set(id, list2);
|
|
971
|
-
}
|
|
972
|
-
function isDocumentEcho(store, id, content) {
|
|
973
|
-
return !!content && !!echoes.get(store)?.get(id)?.includes(content);
|
|
974
|
-
}
|
|
975
|
-
var defaultStore = null;
|
|
976
|
-
function getDefaultDocumentStore() {
|
|
977
|
-
if (!defaultStore) defaultStore = createDocumentStore();
|
|
978
|
-
return defaultStore;
|
|
979
|
-
}
|
|
980
8
|
|
|
981
|
-
// src/utils/update-document-program.ts
|
|
982
|
-
function readString(src, i) {
|
|
983
|
-
if (src[i] !== '"') return null;
|
|
984
|
-
let j = i + 1;
|
|
985
|
-
let value = "";
|
|
986
|
-
while (j < src.length) {
|
|
987
|
-
const ch = src[j];
|
|
988
|
-
if (ch === '"') return { start: i, end: j + 1, value };
|
|
989
|
-
if (ch === "\\") {
|
|
990
|
-
const next = src[j + 1];
|
|
991
|
-
if (next === void 0) return null;
|
|
992
|
-
if (next === "u" && /^[0-9a-fA-F]{4}$/.test(src.slice(j + 2, j + 6))) {
|
|
993
|
-
value += String.fromCharCode(parseInt(src.slice(j + 2, j + 6), 16));
|
|
994
|
-
j += 6;
|
|
995
|
-
continue;
|
|
996
|
-
}
|
|
997
|
-
value += next === "n" ? "\n" : next === "t" ? " " : next === "r" ? "\r" : next === "b" ? "\b" : next === "f" ? "\f" : next;
|
|
998
|
-
j += 2;
|
|
999
|
-
continue;
|
|
1000
|
-
}
|
|
1001
|
-
value += ch;
|
|
1002
|
-
j++;
|
|
1003
|
-
}
|
|
1004
|
-
return null;
|
|
1005
|
-
}
|
|
1006
|
-
var skipSpace = (src, i) => {
|
|
1007
|
-
while (i < src.length && /\s/.test(src[i])) i++;
|
|
1008
|
-
return i;
|
|
1009
|
-
};
|
|
1010
|
-
var toLangString = (value) => JSON.stringify(value);
|
|
1011
|
-
function updateDocumentInProgram(program, documentId, update, componentName = "DocumentEditor") {
|
|
1012
|
-
const re = new RegExp(`\\b${componentName}\\s*\\(`, "g");
|
|
1013
|
-
let match;
|
|
1014
|
-
while (match = re.exec(program)) {
|
|
1015
|
-
const args = [];
|
|
1016
|
-
let i = match.index + match[0].length;
|
|
1017
|
-
for (let n = 0; n < 3; n++) {
|
|
1018
|
-
i = skipSpace(program, i);
|
|
1019
|
-
const tok = readString(program, i);
|
|
1020
|
-
if (!tok) break;
|
|
1021
|
-
args.push(tok);
|
|
1022
|
-
i = skipSpace(program, tok.end);
|
|
1023
|
-
if (program[i] === ",") i++;
|
|
1024
|
-
else break;
|
|
1025
|
-
}
|
|
1026
|
-
if (args[0]?.value !== documentId) continue;
|
|
1027
|
-
const edits = [];
|
|
1028
|
-
if (update.title !== void 0 && args[1] && args[1].value !== update.title) {
|
|
1029
|
-
edits.push({ start: args[1].start, end: args[1].end, text: toLangString(update.title) });
|
|
1030
|
-
}
|
|
1031
|
-
if (update.content !== void 0 && args[2] && args[2].value !== update.content) {
|
|
1032
|
-
edits.push({ start: args[2].start, end: args[2].end, text: toLangString(update.content) });
|
|
1033
|
-
}
|
|
1034
|
-
if (!args[2] && update.content !== void 0) return null;
|
|
1035
|
-
let out = program;
|
|
1036
|
-
for (const e of edits.sort((a, b) => b.start - a.start)) {
|
|
1037
|
-
out = out.slice(0, e.start) + e.text + out.slice(e.end);
|
|
1038
|
-
}
|
|
1039
|
-
return out;
|
|
1040
|
-
}
|
|
1041
|
-
return null;
|
|
1042
|
-
}
|
|
1043
|
-
function readDocumentFromProgram(program, documentId, componentName = "DocumentEditor") {
|
|
1044
|
-
const re = new RegExp(`\\b${componentName}\\s*\\(`, "g");
|
|
1045
|
-
let match;
|
|
1046
|
-
while (match = re.exec(program)) {
|
|
1047
|
-
const args = [];
|
|
1048
|
-
let i = match.index + match[0].length;
|
|
1049
|
-
for (let n = 0; n < 3; n++) {
|
|
1050
|
-
i = skipSpace(program, i);
|
|
1051
|
-
const tok = readString(program, i);
|
|
1052
|
-
if (!tok) break;
|
|
1053
|
-
args.push(tok);
|
|
1054
|
-
i = skipSpace(program, tok.end);
|
|
1055
|
-
if (program[i] === ",") i++;
|
|
1056
|
-
else break;
|
|
1057
|
-
}
|
|
1058
|
-
if (args[0]?.value === documentId && args[1] && args[2]) return { title: args[1].value, content: args[2].value };
|
|
1059
|
-
}
|
|
1060
|
-
return null;
|
|
1061
|
-
}
|
|
1062
9
|
|
|
1063
|
-
// src/core/context.ts
|
|
1064
|
-
var import_react2 = require("react");
|
|
1065
|
-
var JuneContext = (0, import_react2.createContext)({
|
|
1066
|
-
mode: "light",
|
|
1067
|
-
theme: "light"
|
|
1068
|
-
});
|
|
1069
|
-
function useJuneTheme() {
|
|
1070
|
-
return (0, import_react2.useContext)(JuneContext);
|
|
1071
|
-
}
|
|
1072
|
-
var JuneRuntimeContext = (0, import_react2.createContext)({ isStreaming: false });
|
|
1073
|
-
function useJuneRuntime() {
|
|
1074
|
-
return (0, import_react2.useContext)(JuneRuntimeContext);
|
|
1075
|
-
}
|
|
1076
10
|
|
|
1077
|
-
// src/renderer/renderer.tsx
|
|
1078
|
-
init_errors();
|
|
1079
|
-
|
|
1080
|
-
// src/themes/theme-provider.tsx
|
|
1081
|
-
var import_react3 = require("react");
|
|
1082
|
-
|
|
1083
|
-
// src/themes/dark.ts
|
|
1084
|
-
var darkTheme = {
|
|
1085
|
-
"--june-foreground": "#f3f4f6",
|
|
1086
|
-
"--june-muted": "#9ca3af",
|
|
1087
|
-
"--june-border": "#1f2937",
|
|
1088
|
-
"--june-accent": "#818cf8",
|
|
1089
|
-
"--june-danger": "#f87171"
|
|
1090
|
-
};
|
|
1091
|
-
|
|
1092
|
-
// src/themes/light.ts
|
|
1093
|
-
var lightTheme = {
|
|
1094
|
-
"--june-foreground": "#111827",
|
|
1095
|
-
"--june-muted": "#6b7280",
|
|
1096
|
-
"--june-border": "#e5e7eb",
|
|
1097
|
-
"--june-accent": "#4f46e5",
|
|
1098
|
-
"--june-danger": "#b91c1c"
|
|
1099
|
-
};
|
|
1100
|
-
|
|
1101
|
-
// src/themes/theme-provider.tsx
|
|
1102
|
-
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
1103
|
-
var QUERY = "(prefers-color-scheme: dark)";
|
|
1104
|
-
function subscribe(onChange) {
|
|
1105
|
-
if (typeof window === "undefined" || !window.matchMedia) return () => {
|
|
1106
|
-
};
|
|
1107
|
-
const mq = window.matchMedia(QUERY);
|
|
1108
|
-
mq.addEventListener("change", onChange);
|
|
1109
|
-
return () => mq.removeEventListener("change", onChange);
|
|
1110
|
-
}
|
|
1111
|
-
function getSnapshot() {
|
|
1112
|
-
if (typeof window === "undefined") return "light";
|
|
1113
|
-
return window.matchMedia?.(QUERY)?.matches ? "dark" : "light";
|
|
1114
|
-
}
|
|
1115
|
-
function getServerSnapshot() {
|
|
1116
|
-
return "light";
|
|
1117
|
-
}
|
|
1118
|
-
function useResolvedTheme(mode) {
|
|
1119
|
-
const system = (0, import_react3.useSyncExternalStore)(subscribe, getSnapshot, getServerSnapshot);
|
|
1120
|
-
return mode === "system" ? system : mode;
|
|
1121
|
-
}
|
|
1122
|
-
function JuneThemeProvider({
|
|
1123
|
-
mode,
|
|
1124
|
-
vars,
|
|
1125
|
-
className,
|
|
1126
|
-
style,
|
|
1127
|
-
children
|
|
1128
|
-
}) {
|
|
1129
|
-
const explicit = mode !== void 0;
|
|
1130
|
-
const resolved = useResolvedTheme(mode ?? "system");
|
|
1131
|
-
const mergedStyle = (0, import_react3.useMemo)(() => {
|
|
1132
|
-
if (!explicit && !vars && !style) return void 0;
|
|
1133
|
-
const base = explicit ? resolved === "dark" ? darkTheme : lightTheme : void 0;
|
|
1134
|
-
return {
|
|
1135
|
-
...base,
|
|
1136
|
-
...vars,
|
|
1137
|
-
...explicit ? { colorScheme: resolved } : {},
|
|
1138
|
-
...style
|
|
1139
|
-
};
|
|
1140
|
-
}, [explicit, resolved, vars, style]);
|
|
1141
|
-
const context = (0, import_react3.useMemo)(
|
|
1142
|
-
() => ({ mode: mode ?? "system", theme: resolved }),
|
|
1143
|
-
[mode, resolved]
|
|
1144
|
-
);
|
|
1145
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(JuneContext.Provider, { value: context, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1146
|
-
"div",
|
|
1147
|
-
{
|
|
1148
|
-
className: className ? `june-ui-root ${className}` : "june-ui-root",
|
|
1149
|
-
"data-june-theme": explicit ? resolved : void 0,
|
|
1150
|
-
style: mergedStyle,
|
|
1151
|
-
children
|
|
1152
|
-
}
|
|
1153
|
-
) });
|
|
1154
|
-
}
|
|
1155
11
|
|
|
1156
|
-
// src/utils/normalize-program.ts
|
|
1157
|
-
var ATTACHABLE = /* @__PURE__ */ new Set([
|
|
1158
|
-
"Accordion",
|
|
1159
|
-
"AreaChart",
|
|
1160
|
-
"BarChart",
|
|
1161
|
-
"Buttons",
|
|
1162
|
-
"Button",
|
|
1163
|
-
"Callout",
|
|
1164
|
-
"Card",
|
|
1165
|
-
"CardHeader",
|
|
1166
|
-
"Carousel",
|
|
1167
|
-
"CodeBlock",
|
|
1168
|
-
"CompositeCardBlock",
|
|
1169
|
-
"ContextCardBlock",
|
|
1170
|
-
"DocumentEditor",
|
|
1171
|
-
"EditableTable",
|
|
1172
|
-
"EntityList",
|
|
1173
|
-
"Form",
|
|
1174
|
-
"HorizontalBarChart",
|
|
1175
|
-
"IconButton",
|
|
1176
|
-
"Image",
|
|
1177
|
-
"ImageBlock",
|
|
1178
|
-
"ImageGallery",
|
|
1179
|
-
"InlineHeader",
|
|
1180
|
-
"LineChart",
|
|
1181
|
-
"ListBlock",
|
|
1182
|
-
"MarkDownRenderer",
|
|
1183
|
-
"Modal",
|
|
1184
|
-
"OverviewCardBlock",
|
|
1185
|
-
"PieChart",
|
|
1186
|
-
"RadarChart",
|
|
1187
|
-
"RadialChart",
|
|
1188
|
-
"ScatterChart",
|
|
1189
|
-
"Separator",
|
|
1190
|
-
"SingleStackedBarChart",
|
|
1191
|
-
"SnippetCardBlock",
|
|
1192
|
-
"Stack",
|
|
1193
|
-
"Steps",
|
|
1194
|
-
"Table",
|
|
1195
|
-
"Tabs",
|
|
1196
|
-
"TagBlock",
|
|
1197
|
-
"TextCallout",
|
|
1198
|
-
"TextContent",
|
|
1199
|
-
"VisualCardBlock"
|
|
1200
|
-
]);
|
|
1201
|
-
function normalizeProgram(source) {
|
|
1202
|
-
const rewritten = rewriteCalls(source);
|
|
1203
|
-
return attachOrphans(rewritten);
|
|
1204
|
-
}
|
|
1205
|
-
function rewriteCalls(source) {
|
|
1206
|
-
let out = "";
|
|
1207
|
-
let i = 0;
|
|
1208
|
-
let quote = false;
|
|
1209
|
-
while (i < source.length) {
|
|
1210
|
-
const ch = source[i];
|
|
1211
|
-
if (quote) {
|
|
1212
|
-
out += ch;
|
|
1213
|
-
if (ch === "\\") {
|
|
1214
|
-
i += 1;
|
|
1215
|
-
if (i < source.length) out += source[i];
|
|
1216
|
-
} else if (ch === '"') {
|
|
1217
|
-
quote = false;
|
|
1218
|
-
}
|
|
1219
|
-
i += 1;
|
|
1220
|
-
continue;
|
|
1221
|
-
}
|
|
1222
|
-
if (ch === '"') {
|
|
1223
|
-
quote = true;
|
|
1224
|
-
out += ch;
|
|
1225
|
-
i += 1;
|
|
1226
|
-
continue;
|
|
1227
|
-
}
|
|
1228
|
-
const call = readCall(source, i);
|
|
1229
|
-
if (call) {
|
|
1230
|
-
const next = rewriteKnownCall(call);
|
|
1231
|
-
if (next !== null) {
|
|
1232
|
-
out += next;
|
|
1233
|
-
i = call.end;
|
|
1234
|
-
continue;
|
|
1235
|
-
}
|
|
1236
|
-
}
|
|
1237
|
-
out += ch;
|
|
1238
|
-
i += 1;
|
|
1239
|
-
}
|
|
1240
|
-
return out === source ? source : out;
|
|
1241
|
-
}
|
|
1242
|
-
function rewriteKnownCall(call) {
|
|
1243
|
-
if (call.callee === "Grid") {
|
|
1244
|
-
const args = call.args.map((arg) => rewriteCalls(arg));
|
|
1245
|
-
const children = args.length === 0 ? "[]" : args.length === 1 ? args[0] : null;
|
|
1246
|
-
if (children !== null) {
|
|
1247
|
-
return `Stack(${children}, "row", "m", "stretch", "start", true)`;
|
|
1248
|
-
}
|
|
1249
|
-
return `Stack(${args.join(", ")})`;
|
|
1250
|
-
}
|
|
1251
|
-
if (call.callee === "Card") {
|
|
1252
|
-
const args = call.args.map((arg) => rewriteCalls(arg));
|
|
1253
|
-
if (args.length >= 2 && isStringLiteral(args[0]) && isStringLiteral(args[1])) {
|
|
1254
|
-
const children = `[TextContent(${args[0]}, "small"), TextContent(${args[1]}, "large-heavy")]`;
|
|
1255
|
-
return `Card(${[children, ...args.slice(2)].join(", ")})`;
|
|
1256
|
-
}
|
|
1257
|
-
if (args.some((arg, index) => arg !== call.args[index])) {
|
|
1258
|
-
return `Card(${args.join(", ")})`;
|
|
1259
|
-
}
|
|
1260
|
-
}
|
|
1261
|
-
return null;
|
|
1262
|
-
}
|
|
1263
|
-
function readCall(source, index) {
|
|
1264
|
-
if (index > 0 && /[A-Za-z0-9_$]/.test(source[index - 1])) return null;
|
|
1265
|
-
const match = /^(Grid|Card)\s*\(/.exec(source.slice(index));
|
|
1266
|
-
if (!match) return null;
|
|
1267
|
-
const open = index + match[0].length - 1;
|
|
1268
|
-
const close = findMatchingParen(source, open);
|
|
1269
|
-
if (close < 0) return null;
|
|
1270
|
-
const args = splitArgs(source.slice(open + 1, close));
|
|
1271
|
-
if (!args) return null;
|
|
1272
|
-
return { callee: match[1], args, end: close + 1 };
|
|
1273
|
-
}
|
|
1274
|
-
function findMatchingParen(source, open) {
|
|
1275
|
-
let depth = 0;
|
|
1276
|
-
let quote = false;
|
|
1277
|
-
for (let i = open; i < source.length; i += 1) {
|
|
1278
|
-
const ch = source[i];
|
|
1279
|
-
if (quote) {
|
|
1280
|
-
if (ch === "\\") i += 1;
|
|
1281
|
-
else if (ch === '"') quote = false;
|
|
1282
|
-
continue;
|
|
1283
|
-
}
|
|
1284
|
-
if (ch === '"') quote = true;
|
|
1285
|
-
else if (ch === "(") depth += 1;
|
|
1286
|
-
else if (ch === ")") {
|
|
1287
|
-
depth -= 1;
|
|
1288
|
-
if (depth === 0) return i;
|
|
1289
|
-
}
|
|
1290
|
-
}
|
|
1291
|
-
return -1;
|
|
1292
|
-
}
|
|
1293
|
-
function splitArgs(inner) {
|
|
1294
|
-
const args = [];
|
|
1295
|
-
let start = 0;
|
|
1296
|
-
let depth = 0;
|
|
1297
|
-
let quote = false;
|
|
1298
|
-
for (let i = 0; i < inner.length; i += 1) {
|
|
1299
|
-
const ch = inner[i];
|
|
1300
|
-
if (quote) {
|
|
1301
|
-
if (ch === "\\") i += 1;
|
|
1302
|
-
else if (ch === '"') quote = false;
|
|
1303
|
-
continue;
|
|
1304
|
-
}
|
|
1305
|
-
if (ch === '"') quote = true;
|
|
1306
|
-
else if (ch === "(" || ch === "[" || ch === "{") depth += 1;
|
|
1307
|
-
else if (ch === ")" || ch === "]" || ch === "}") depth -= 1;
|
|
1308
|
-
else if (ch === "," && depth === 0) {
|
|
1309
|
-
args.push(inner.slice(start, i).trim());
|
|
1310
|
-
start = i + 1;
|
|
1311
|
-
}
|
|
1312
|
-
}
|
|
1313
|
-
if (quote || depth !== 0) return null;
|
|
1314
|
-
const last = inner.slice(start).trim();
|
|
1315
|
-
if (last) args.push(last);
|
|
1316
|
-
return args;
|
|
1317
|
-
}
|
|
1318
|
-
function isStringLiteral(value) {
|
|
1319
|
-
return /^"(?:\\.|[^"\\])*"$/.test(value.trim());
|
|
1320
|
-
}
|
|
1321
|
-
function attachOrphans(source) {
|
|
1322
|
-
let text = source;
|
|
1323
|
-
let stmts = parseStatements(text);
|
|
1324
|
-
if (!stmts) return source;
|
|
1325
|
-
const taken = new Set(stmts.map((stmt) => stmt.name));
|
|
1326
|
-
const extraRoots = stmts.filter((stmt) => stmt.name === "root").slice(1);
|
|
1327
|
-
if (extraRoots.length > 0) {
|
|
1328
|
-
const edits = extraRoots.map((stmt) => {
|
|
1329
|
-
const body2 = fresh(taken, "rootBlock");
|
|
1330
|
-
const stmtText = text.slice(stmt.start, stmt.end);
|
|
1331
|
-
return {
|
|
1332
|
-
start: stmt.start,
|
|
1333
|
-
end: stmt.end,
|
|
1334
|
-
text: stmtText.replace(/^(\s*)root\b/, `$1${body2}`)
|
|
1335
|
-
};
|
|
1336
|
-
});
|
|
1337
|
-
text = applyEdits(text, edits);
|
|
1338
|
-
stmts = parseStatements(text);
|
|
1339
|
-
if (!stmts) return source;
|
|
1340
|
-
}
|
|
1341
|
-
const orphans = stmts.filter(
|
|
1342
|
-
(stmt) => stmt.name !== "root" && ATTACHABLE.has(calleeOf(stmt.rhs) ?? "") && !referencedByOther(stmt.name, stmts)
|
|
1343
|
-
);
|
|
1344
|
-
if (orphans.length === 0) return source;
|
|
1345
|
-
const names = orphans.map((stmt) => stmt.name);
|
|
1346
|
-
const root = stmts.find((stmt) => stmt.name === "root");
|
|
1347
|
-
if (!root) return `root = Stack([${names.join(", ")}])
|
|
1348
|
-
${text}`;
|
|
1349
|
-
const rawRhs = text.slice(root.rhsStart, root.end);
|
|
1350
|
-
const lead = /^\s*/.exec(rawRhs)?.[0] ?? "";
|
|
1351
|
-
const spliced = spliceFirstArray(rawRhs.trim(), names);
|
|
1352
|
-
if (spliced !== null) {
|
|
1353
|
-
return text.slice(0, root.rhsStart) + lead + spliced + text.slice(root.end);
|
|
1354
|
-
}
|
|
1355
|
-
const body = fresh(new Set(stmts.map((stmt) => stmt.name)), "rootBody");
|
|
1356
|
-
const wrapped = `root = Stack([${body}, ${names.join(", ")}])
|
|
1357
|
-
${body} = ${rawRhs.trim()}`;
|
|
1358
|
-
return text.slice(0, root.start) + wrapped + text.slice(root.end);
|
|
1359
|
-
}
|
|
1360
|
-
function spliceFirstArray(rhs, names) {
|
|
1361
|
-
const match = /^([A-Za-z_]\w*)\s*\(/.exec(rhs);
|
|
1362
|
-
if (!match || match[1] !== "Stack" && match[1] !== "Card") return null;
|
|
1363
|
-
const openParen = match[0].length - 1;
|
|
1364
|
-
let paren = 0;
|
|
1365
|
-
let quote = false;
|
|
1366
|
-
let arrayStart = -1;
|
|
1367
|
-
let arrayDepth = 0;
|
|
1368
|
-
let arrayEnd = -1;
|
|
1369
|
-
for (let i = openParen; i < rhs.length; i += 1) {
|
|
1370
|
-
const ch = rhs[i];
|
|
1371
|
-
if (quote) {
|
|
1372
|
-
if (ch === "\\") i += 1;
|
|
1373
|
-
else if (ch === '"') quote = false;
|
|
1374
|
-
continue;
|
|
1375
|
-
}
|
|
1376
|
-
if (ch === '"') quote = true;
|
|
1377
|
-
else if (ch === "(") paren += 1;
|
|
1378
|
-
else if (ch === ")") {
|
|
1379
|
-
paren -= 1;
|
|
1380
|
-
if (paren === 0) break;
|
|
1381
|
-
} else if (ch === "[") {
|
|
1382
|
-
if (paren === 1 && arrayStart < 0) {
|
|
1383
|
-
arrayStart = i;
|
|
1384
|
-
arrayDepth = 1;
|
|
1385
|
-
} else if (arrayStart >= 0 && arrayEnd < 0) {
|
|
1386
|
-
arrayDepth += 1;
|
|
1387
|
-
}
|
|
1388
|
-
} else if (ch === "]" && arrayStart >= 0 && arrayEnd < 0) {
|
|
1389
|
-
arrayDepth -= 1;
|
|
1390
|
-
if (arrayDepth === 0) arrayEnd = i;
|
|
1391
|
-
}
|
|
1392
|
-
}
|
|
1393
|
-
if (arrayStart < 0 || arrayEnd < 0) return null;
|
|
1394
|
-
const inner = rhs.slice(arrayStart + 1, arrayEnd).trim();
|
|
1395
|
-
const merged = inner === "" ? names.join(", ") : `${inner.replace(/,\s*$/, "")}, ${names.join(", ")}`;
|
|
1396
|
-
return rhs.slice(0, arrayStart + 1) + merged + rhs.slice(arrayEnd);
|
|
1397
|
-
}
|
|
1398
|
-
function referencedByOther(name, stmts) {
|
|
1399
|
-
const pattern = new RegExp(
|
|
1400
|
-
`(?<![A-Za-z0-9_$.])${name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?![A-Za-z0-9_])`
|
|
1401
|
-
);
|
|
1402
|
-
return stmts.some((stmt) => stmt.name !== name && pattern.test(stripStrings(stmt.rhs)));
|
|
1403
|
-
}
|
|
1404
|
-
function calleeOf(rhs) {
|
|
1405
|
-
const match = /^([A-Za-z_]\w*)\s*\(/.exec(rhs.trim());
|
|
1406
|
-
return match ? match[1] : null;
|
|
1407
|
-
}
|
|
1408
|
-
function stripStrings(text) {
|
|
1409
|
-
return text.replace(/"(?:\\.|[^"\\])*"/g, '""');
|
|
1410
|
-
}
|
|
1411
|
-
function fresh(taken, base) {
|
|
1412
|
-
let name = base;
|
|
1413
|
-
let n = 2;
|
|
1414
|
-
while (taken.has(name)) {
|
|
1415
|
-
name = `${base}${n}`;
|
|
1416
|
-
n += 1;
|
|
1417
|
-
}
|
|
1418
|
-
taken.add(name);
|
|
1419
|
-
return name;
|
|
1420
|
-
}
|
|
1421
|
-
function applyEdits(source, edits) {
|
|
1422
|
-
const ordered = [...edits].sort((a, b) => b.start - a.start);
|
|
1423
|
-
let text = source;
|
|
1424
|
-
for (const edit of ordered) {
|
|
1425
|
-
text = text.slice(0, edit.start) + edit.text + text.slice(edit.end);
|
|
1426
|
-
}
|
|
1427
|
-
return text;
|
|
1428
|
-
}
|
|
1429
|
-
function parseStatements(source) {
|
|
1430
|
-
const lines = source.split("\n");
|
|
1431
|
-
const stmts = [];
|
|
1432
|
-
let offset = 0;
|
|
1433
|
-
let depth = 0;
|
|
1434
|
-
let quote = false;
|
|
1435
|
-
let current = null;
|
|
1436
|
-
const scan2 = (line) => {
|
|
1437
|
-
for (let i = 0; i < line.length; i += 1) {
|
|
1438
|
-
const ch = line[i];
|
|
1439
|
-
if (quote) {
|
|
1440
|
-
if (ch === "\\") i += 1;
|
|
1441
|
-
else if (ch === '"') quote = false;
|
|
1442
|
-
} else if (ch === '"') {
|
|
1443
|
-
quote = true;
|
|
1444
|
-
} else if (ch === "(" || ch === "[" || ch === "{") {
|
|
1445
|
-
depth += 1;
|
|
1446
|
-
} else if (ch === ")" || ch === "]" || ch === "}") {
|
|
1447
|
-
depth = Math.max(0, depth - 1);
|
|
1448
|
-
}
|
|
1449
|
-
}
|
|
1450
|
-
};
|
|
1451
|
-
for (let li = 0; li < lines.length; li += 1) {
|
|
1452
|
-
const line = lines[li];
|
|
1453
|
-
const lineStart = offset;
|
|
1454
|
-
const lineEnd = offset + line.length;
|
|
1455
|
-
offset = lineEnd + (li < lines.length - 1 ? 1 : 0);
|
|
1456
|
-
if (current && depth > 0) {
|
|
1457
|
-
scan2(line);
|
|
1458
|
-
if (depth === 0) {
|
|
1459
|
-
stmts.push({
|
|
1460
|
-
name: current.name,
|
|
1461
|
-
rhs: source.slice(current.rhsStart, lineEnd).trim(),
|
|
1462
|
-
start: current.start,
|
|
1463
|
-
end: lineEnd,
|
|
1464
|
-
rhsStart: current.rhsStart
|
|
1465
|
-
});
|
|
1466
|
-
current = null;
|
|
1467
|
-
}
|
|
1468
|
-
continue;
|
|
1469
|
-
}
|
|
1470
|
-
const trimmed = line.trim();
|
|
1471
|
-
if (trimmed === "" || trimmed.startsWith("```")) continue;
|
|
1472
|
-
const match = /^(\s*)(\$?[A-Za-z_]\w*)\s*=/.exec(line);
|
|
1473
|
-
if (!match) return null;
|
|
1474
|
-
const eq = line.indexOf("=");
|
|
1475
|
-
const rhsStart = lineStart + eq + 1;
|
|
1476
|
-
depth = 0;
|
|
1477
|
-
quote = false;
|
|
1478
|
-
scan2(line);
|
|
1479
|
-
if (depth === 0) {
|
|
1480
|
-
stmts.push({
|
|
1481
|
-
name: match[2],
|
|
1482
|
-
rhs: line.slice(eq + 1).trim(),
|
|
1483
|
-
start: lineStart,
|
|
1484
|
-
end: lineEnd,
|
|
1485
|
-
rhsStart
|
|
1486
|
-
});
|
|
1487
|
-
} else {
|
|
1488
|
-
current = { name: match[2], start: lineStart, rhsStart };
|
|
1489
|
-
}
|
|
1490
|
-
}
|
|
1491
|
-
if (current || depth !== 0) return null;
|
|
1492
|
-
return stmts;
|
|
1493
|
-
}
|
|
1494
12
|
|
|
1495
|
-
// src/utils/split-response.ts
|
|
1496
|
-
var STATEMENT_START = /^\$?[A-Za-z_]\w*\s*=/;
|
|
1497
|
-
var PENDING_IDENTIFIER = /^\s*\$?[A-Za-z_]\w*\s*$/;
|
|
1498
|
-
function scan(line, state) {
|
|
1499
|
-
for (let i = 0; i < line.length; i++) {
|
|
1500
|
-
const ch = line[i];
|
|
1501
|
-
if (state.quote) {
|
|
1502
|
-
if (ch === "\\") i++;
|
|
1503
|
-
else if (ch === state.quote) state.quote = null;
|
|
1504
|
-
} else if (ch === '"') {
|
|
1505
|
-
state.quote = ch;
|
|
1506
|
-
} else if (ch === "(" || ch === "[" || ch === "{") {
|
|
1507
|
-
state.depth++;
|
|
1508
|
-
} else if (ch === ")" || ch === "]" || ch === "}") {
|
|
1509
|
-
state.depth = Math.max(0, state.depth - 1);
|
|
1510
|
-
}
|
|
1511
|
-
}
|
|
1512
|
-
state.quote = null;
|
|
1513
|
-
}
|
|
1514
|
-
function splitResponse(source, options = {}) {
|
|
1515
|
-
let input = source;
|
|
1516
|
-
if (options.streaming && !input.endsWith("\n")) {
|
|
1517
|
-
const cut = input.lastIndexOf("\n");
|
|
1518
|
-
if (PENDING_IDENTIFIER.test(input.slice(cut + 1))) input = input.slice(0, cut + 1);
|
|
1519
|
-
}
|
|
1520
|
-
const before = [];
|
|
1521
|
-
const after = [];
|
|
1522
|
-
const ui = [];
|
|
1523
|
-
const state = { depth: 0, quote: null };
|
|
1524
|
-
let text = [];
|
|
1525
|
-
let seenUi = false;
|
|
1526
|
-
let sawFence = false;
|
|
1527
|
-
const flushText = () => {
|
|
1528
|
-
const joined = text.join(" ").trim();
|
|
1529
|
-
text = [];
|
|
1530
|
-
if (joined) (seenUi ? after : before).push(joined);
|
|
1531
|
-
};
|
|
1532
|
-
for (const line of input.split(/\r?\n/)) {
|
|
1533
|
-
const trimmed = line.trim();
|
|
1534
|
-
if (trimmed.startsWith("```")) {
|
|
1535
|
-
sawFence = true;
|
|
1536
|
-
continue;
|
|
1537
|
-
}
|
|
1538
|
-
if (state.depth > 0) {
|
|
1539
|
-
ui.push(line);
|
|
1540
|
-
scan(line, state);
|
|
1541
|
-
continue;
|
|
1542
|
-
}
|
|
1543
|
-
if (STATEMENT_START.test(trimmed)) {
|
|
1544
|
-
flushText();
|
|
1545
|
-
seenUi = true;
|
|
1546
|
-
ui.push(line);
|
|
1547
|
-
scan(line, state);
|
|
1548
|
-
continue;
|
|
1549
|
-
}
|
|
1550
|
-
if (trimmed === "") {
|
|
1551
|
-
flushText();
|
|
1552
|
-
continue;
|
|
1553
|
-
}
|
|
1554
|
-
text.push(trimmed);
|
|
1555
|
-
}
|
|
1556
|
-
flushText();
|
|
1557
|
-
return {
|
|
1558
|
-
before,
|
|
1559
|
-
ui: ui.join("\n"),
|
|
1560
|
-
after,
|
|
1561
|
-
pure: !sawFence && before.length === 0 && after.length === 0
|
|
1562
|
-
};
|
|
1563
|
-
}
|
|
1564
13
|
|
|
1565
|
-
// src/renderer/error-boundary.tsx
|
|
1566
|
-
var import_react4 = require("react");
|
|
1567
|
-
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
1568
|
-
function keysChanged(a = [], b = []) {
|
|
1569
|
-
return a.length !== b.length || a.some((v, i) => !Object.is(v, b[i]));
|
|
1570
|
-
}
|
|
1571
|
-
var JuneErrorBoundary = class extends import_react4.Component {
|
|
1572
|
-
constructor() {
|
|
1573
|
-
super(...arguments);
|
|
1574
|
-
this.state = { error: null };
|
|
1575
|
-
this.reset = () => {
|
|
1576
|
-
this.setState({ error: null });
|
|
1577
|
-
};
|
|
1578
|
-
}
|
|
1579
|
-
static getDerivedStateFromError(error) {
|
|
1580
|
-
return { error };
|
|
1581
|
-
}
|
|
1582
|
-
componentDidCatch(error, info) {
|
|
1583
|
-
this.props.onError?.(error, info);
|
|
1584
|
-
}
|
|
1585
|
-
componentDidUpdate(prev) {
|
|
1586
|
-
if (this.state.error && keysChanged(prev.resetKeys, this.props.resetKeys)) {
|
|
1587
|
-
this.reset();
|
|
1588
|
-
}
|
|
1589
|
-
}
|
|
1590
|
-
render() {
|
|
1591
|
-
const { error } = this.state;
|
|
1592
|
-
if (!error) return this.props.children;
|
|
1593
|
-
const { fallback } = this.props;
|
|
1594
|
-
if (typeof fallback === "function") return fallback({ error, reset: this.reset });
|
|
1595
|
-
if (fallback !== void 0) return fallback;
|
|
1596
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { role: "alert", "data-june-error": "", children: "Something went wrong while rendering this UI." });
|
|
1597
|
-
}
|
|
1598
|
-
};
|
|
1599
|
-
|
|
1600
|
-
// src/renderer/renderer.tsx
|
|
1601
|
-
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
1602
|
-
function JuneRenderer(props) {
|
|
1603
|
-
const {
|
|
1604
|
-
library,
|
|
1605
|
-
response,
|
|
1606
|
-
isStreaming = false,
|
|
1607
|
-
mixedContent = true,
|
|
1608
|
-
renderText,
|
|
1609
|
-
repair = true,
|
|
1610
|
-
theme,
|
|
1611
|
-
themeVars,
|
|
1612
|
-
className,
|
|
1613
|
-
style,
|
|
1614
|
-
actions,
|
|
1615
|
-
confirmAction,
|
|
1616
|
-
parseActionEvent,
|
|
1617
|
-
onAction,
|
|
1618
|
-
onError,
|
|
1619
|
-
onJuneError,
|
|
1620
|
-
documents,
|
|
1621
|
-
onResponseChange,
|
|
1622
|
-
responseChangeDelay = 300,
|
|
1623
|
-
loadingFallback = null,
|
|
1624
|
-
emptyFallback = null,
|
|
1625
|
-
errorFallback,
|
|
1626
|
-
resetKeys,
|
|
1627
|
-
...rendererProps
|
|
1628
|
-
} = props;
|
|
1629
|
-
const latest = (0, import_react5.useRef)({ actions, confirmAction, parseActionEvent, onAction, onError, onJuneError, onResponseChange, responseChangeDelay, response });
|
|
1630
|
-
latest.current = { actions, confirmAction, parseActionEvent, onAction, onError, onJuneError, onResponseChange, responseChangeDelay, response };
|
|
1631
|
-
const syncTimers = (0, import_react5.useRef)(/* @__PURE__ */ new Map());
|
|
1632
|
-
(0, import_react5.useEffect)(() => {
|
|
1633
|
-
const timers = syncTimers.current;
|
|
1634
|
-
return () => {
|
|
1635
|
-
timers.forEach(clearTimeout);
|
|
1636
|
-
timers.clear();
|
|
1637
|
-
};
|
|
1638
|
-
}, []);
|
|
1639
|
-
const syncProgram = (0, import_react5.useCallback)(async (change, store) => {
|
|
1640
|
-
const l = latest.current;
|
|
1641
|
-
if (!l.onResponseChange || typeof l.response !== "string") return;
|
|
1642
|
-
const record = store.get(change.documentId);
|
|
1643
|
-
const title = record?.title ?? change.title;
|
|
1644
|
-
const json = record?.json ?? change.json;
|
|
1645
|
-
try {
|
|
1646
|
-
const { docToMarkdown: docToMarkdown2 } = await Promise.resolve().then(() => (init_document_engine(), document_engine_exports));
|
|
1647
|
-
const markdown = docToMarkdown2(json);
|
|
1648
|
-
const program = latest.current.response;
|
|
1649
|
-
if (typeof program !== "string") return;
|
|
1650
|
-
const next = updateDocumentInProgram(program, change.documentId, { title, content: markdown });
|
|
1651
|
-
if (next === null || next === program) return;
|
|
1652
|
-
rememberDocumentEcho(store, change.documentId, markdown);
|
|
1653
|
-
latest.current.onResponseChange?.(next, { documentId: change.documentId, title, markdown, source: change.source });
|
|
1654
|
-
} catch (error) {
|
|
1655
|
-
latest.current.onJuneError?.(toJuneError(error, "DOCUMENT_ERROR", "Updating the program failed"));
|
|
1656
|
-
}
|
|
1657
|
-
}, []);
|
|
1658
|
-
const handleAction = (0, import_react5.useCallback)((event) => {
|
|
1659
|
-
const l = latest.current;
|
|
1660
|
-
l.onAction?.(event);
|
|
1661
|
-
if (l.actions) {
|
|
1662
|
-
void runAction(event, {
|
|
1663
|
-
actions: l.actions,
|
|
1664
|
-
parseEvent: l.parseActionEvent,
|
|
1665
|
-
confirm: l.confirmAction,
|
|
1666
|
-
onError: (e) => l.onJuneError?.(e)
|
|
1667
|
-
});
|
|
1668
|
-
}
|
|
1669
|
-
}, []);
|
|
1670
|
-
const handleParserErrors = (0, import_react5.useCallback)((errors) => {
|
|
1671
|
-
const list2 = Array.isArray(errors) ? errors : [];
|
|
1672
|
-
const l = latest.current;
|
|
1673
|
-
l.onError?.(list2);
|
|
1674
|
-
const real = list2.filter((e) => e?.severity !== "warning");
|
|
1675
|
-
if (real.length > 0) {
|
|
1676
|
-
l.onJuneError?.(
|
|
1677
|
-
new JuneError("PARSE_ERROR", `OpenUI reported ${real.length} error(s)`, { details: real })
|
|
1678
|
-
);
|
|
1679
|
-
}
|
|
1680
|
-
if (list2.length > 0 && !l.onError && !l.onJuneError) {
|
|
1681
|
-
console.warn("[june-ui] OpenUI reported errors:", list2);
|
|
1682
|
-
}
|
|
1683
|
-
}, []);
|
|
1684
|
-
const handleBoundaryError = (0, import_react5.useCallback)((error, info) => {
|
|
1685
|
-
latest.current.onJuneError?.(
|
|
1686
|
-
new JuneError("RENDER_ERROR", error.message, {
|
|
1687
|
-
cause: error,
|
|
1688
|
-
details: { componentStack: info.componentStack }
|
|
1689
|
-
})
|
|
1690
|
-
);
|
|
1691
|
-
}, []);
|
|
1692
|
-
const runtime = (0, import_react5.useMemo)(() => ({ isStreaming }), [isStreaming]);
|
|
1693
|
-
const documentOptions = (0, import_react5.useMemo)(
|
|
1694
|
-
() => ({
|
|
1695
|
-
...documents,
|
|
1696
|
-
onDocumentChange: (change) => {
|
|
1697
|
-
documents?.onDocumentChange?.(change);
|
|
1698
|
-
if (!latest.current.onResponseChange || change.source === "ai") return;
|
|
1699
|
-
const store = documents?.store ?? getDefaultDocumentStore();
|
|
1700
|
-
const timers = syncTimers.current;
|
|
1701
|
-
const prev = timers.get(change.documentId);
|
|
1702
|
-
if (prev) clearTimeout(prev);
|
|
1703
|
-
timers.set(
|
|
1704
|
-
change.documentId,
|
|
1705
|
-
setTimeout(() => {
|
|
1706
|
-
timers.delete(change.documentId);
|
|
1707
|
-
void syncProgram(change, store);
|
|
1708
|
-
}, Math.max(0, latest.current.responseChangeDelay))
|
|
1709
|
-
);
|
|
1710
|
-
},
|
|
1711
|
-
onError: (error) => {
|
|
1712
|
-
documents?.onError?.(error);
|
|
1713
|
-
latest.current.onJuneError?.(error);
|
|
1714
|
-
}
|
|
1715
|
-
}),
|
|
1716
|
-
[documents, syncProgram]
|
|
1717
|
-
);
|
|
1718
|
-
const parts = (0, import_react5.useMemo)(
|
|
1719
|
-
() => mixedContent && response ? splitResponse(response, { streaming: isStreaming }) : null,
|
|
1720
|
-
[mixedContent, response, isStreaming]
|
|
1721
|
-
);
|
|
1722
|
-
const uiText = (0, import_react5.useMemo)(() => {
|
|
1723
|
-
const raw = parts && !parts.pure ? parts.ui : response;
|
|
1724
|
-
if (!repair || !mixedContent || isStreaming || typeof raw !== "string" || raw.length === 0) return raw;
|
|
1725
|
-
return normalizeProgram(raw);
|
|
1726
|
-
}, [parts, response, mixedContent, isStreaming, repair]);
|
|
1727
|
-
const hasUi = typeof uiText === "string" && uiText.trim().length > 0;
|
|
1728
|
-
const before = parts?.before ?? [];
|
|
1729
|
-
const after = parts?.after ?? [];
|
|
1730
|
-
const hasText = before.length + after.length > 0;
|
|
1731
|
-
const text = (value, index, key) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react5.Fragment, { children: renderText ? renderText(value, index) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "june-text", children: value }) }, key);
|
|
1732
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(JuneThemeProvider, { mode: theme, vars: themeVars, className, style, children: [
|
|
1733
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(OpenUIDevtoolsGate, {}),
|
|
1734
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(JuneRuntimeContext.Provider, { value: runtime, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(JuneDocumentContext.Provider, { value: documentOptions, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
1735
|
-
JuneErrorBoundary,
|
|
1736
|
-
{
|
|
1737
|
-
fallback: errorFallback,
|
|
1738
|
-
onError: handleBoundaryError,
|
|
1739
|
-
resetKeys: resetKeys ?? [response],
|
|
1740
|
-
children: [
|
|
1741
|
-
before.map((t, i) => text(t, i, `b${i}`)),
|
|
1742
|
-
hasUi && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1743
|
-
import_react_lang.Renderer,
|
|
1744
|
-
{
|
|
1745
|
-
...rendererProps,
|
|
1746
|
-
library,
|
|
1747
|
-
response: uiText,
|
|
1748
|
-
isStreaming,
|
|
1749
|
-
onAction: handleAction,
|
|
1750
|
-
onError: handleParserErrors
|
|
1751
|
-
}
|
|
1752
|
-
),
|
|
1753
|
-
after.map((t, i) => text(t, before.length + i, `a${i}`)),
|
|
1754
|
-
!hasUi && !hasText && (isStreaming ? loadingFallback : emptyFallback)
|
|
1755
|
-
]
|
|
1756
|
-
}
|
|
1757
|
-
) }) })
|
|
1758
|
-
] });
|
|
1759
|
-
}
|
|
1760
14
|
|
|
1761
|
-
// src/components/library.ts
|
|
1762
|
-
var import_react_lang2 = require("@openuidev/react-lang");
|
|
1763
|
-
init_errors();
|
|
1764
|
-
var defineJuneComponent = import_react_lang2.defineComponent;
|
|
1765
|
-
function createJuneLibrary(options) {
|
|
1766
|
-
const { allow, deny, ...rest } = options;
|
|
1767
|
-
const input = rest;
|
|
1768
|
-
const raw = input;
|
|
1769
|
-
const components = raw.components ?? [];
|
|
1770
|
-
const names = /* @__PURE__ */ new Set();
|
|
1771
|
-
for (const component of components) {
|
|
1772
|
-
if (typeof component?.name !== "string" || component.name.length === 0) {
|
|
1773
|
-
throw new JuneError("LIBRARY_ERROR", "Every component needs a non-empty string name");
|
|
1774
|
-
}
|
|
1775
|
-
if (names.has(component.name)) {
|
|
1776
|
-
throw new JuneError("LIBRARY_ERROR", `Duplicate component name "${component.name}"`);
|
|
1777
|
-
}
|
|
1778
|
-
names.add(component.name);
|
|
1779
|
-
}
|
|
1780
|
-
const allowSet = allow ? new Set(allow) : null;
|
|
1781
|
-
const denySet = deny ? new Set(deny) : null;
|
|
1782
|
-
if (allowSet) {
|
|
1783
|
-
for (const n of allowSet) {
|
|
1784
|
-
if (!names.has(n)) throw new JuneError("LIBRARY_ERROR", `Allowed component "${n}" is not registered`);
|
|
1785
|
-
}
|
|
1786
|
-
}
|
|
1787
|
-
const keep = components.filter((c) => {
|
|
1788
|
-
const n = c.name;
|
|
1789
|
-
return (!allowSet || allowSet.has(n)) && !(denySet && denySet.has(n));
|
|
1790
|
-
});
|
|
1791
|
-
if (raw.root !== void 0 && !keep.some((c) => c.name === raw.root)) {
|
|
1792
|
-
throw new JuneError("LIBRARY_ERROR", `Root component "${raw.root}" is missing after filtering`);
|
|
1793
|
-
}
|
|
1794
|
-
try {
|
|
1795
|
-
const unfiltered = keep.length === components.length;
|
|
1796
|
-
return (0, import_react_lang2.createLibrary)(
|
|
1797
|
-
unfiltered ? input : { ...input, components: keep }
|
|
1798
|
-
);
|
|
1799
|
-
} catch (error) {
|
|
1800
|
-
throw new JuneError("LIBRARY_ERROR", "OpenUI rejected the component library", { cause: error });
|
|
1801
|
-
}
|
|
1802
|
-
}
|
|
1803
15
|
|
|
1804
|
-
// src/actions/define-action.ts
|
|
1805
|
-
init_errors();
|
|
1806
|
-
function defineJuneAction(definition) {
|
|
1807
|
-
if (typeof definition.handler !== "function") {
|
|
1808
|
-
throw new JuneError("ACTION_VALIDATION_ERROR", "defineJuneAction requires a handler function");
|
|
1809
|
-
}
|
|
1810
|
-
return Object.freeze({ ...definition, __june: "action" });
|
|
1811
|
-
}
|
|
1812
16
|
|
|
1813
|
-
// src/streaming/use-june-stream.ts
|
|
1814
|
-
var import_react6 = require("react");
|
|
1815
|
-
init_errors();
|
|
1816
17
|
|
|
1817
|
-
// src/streaming/fetch-adapter.ts
|
|
1818
|
-
init_errors();
|
|
1819
18
|
|
|
1820
|
-
// src/streaming/sse-adapter.ts
|
|
1821
|
-
init_errors();
|
|
1822
19
|
|
|
1823
|
-
// src/streaming/stream-handler.ts
|
|
1824
|
-
init_errors();
|
|
1825
|
-
function isReadableStream(source) {
|
|
1826
|
-
return typeof source.getReader === "function";
|
|
1827
|
-
}
|
|
1828
|
-
async function* iterateReadable(stream, signal) {
|
|
1829
|
-
const reader = stream.getReader();
|
|
1830
|
-
const onAbort = () => {
|
|
1831
|
-
void reader.cancel().catch(() => {
|
|
1832
|
-
});
|
|
1833
|
-
};
|
|
1834
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
1835
|
-
try {
|
|
1836
|
-
while (true) {
|
|
1837
|
-
const { done, value } = await reader.read();
|
|
1838
|
-
if (done) return;
|
|
1839
|
-
yield value;
|
|
1840
|
-
}
|
|
1841
|
-
} finally {
|
|
1842
|
-
signal?.removeEventListener("abort", onAbort);
|
|
1843
|
-
try {
|
|
1844
|
-
reader.releaseLock();
|
|
1845
|
-
} catch {
|
|
1846
|
-
}
|
|
1847
|
-
}
|
|
1848
|
-
}
|
|
1849
|
-
function toAsyncIterable(source, signal) {
|
|
1850
|
-
return isReadableStream(source) ? iterateReadable(source, signal) : source;
|
|
1851
|
-
}
|
|
1852
|
-
function abortedError(partial) {
|
|
1853
|
-
return new JuneError("STREAM_ABORTED", "Stream was aborted", { details: { partial } });
|
|
1854
|
-
}
|
|
1855
|
-
async function consumeStream(source, options = {}) {
|
|
1856
|
-
const { signal, onText, allowEmpty = false } = options;
|
|
1857
|
-
if (signal?.aborted) throw abortedError("");
|
|
1858
|
-
const decoder = new TextDecoder();
|
|
1859
|
-
let text = "";
|
|
1860
|
-
let received = false;
|
|
1861
|
-
const push = (delta) => {
|
|
1862
|
-
if (!delta) return;
|
|
1863
|
-
received = true;
|
|
1864
|
-
text += delta;
|
|
1865
|
-
onText?.(delta, text);
|
|
1866
|
-
};
|
|
1867
|
-
try {
|
|
1868
|
-
for await (const chunk of toAsyncIterable(source, signal)) {
|
|
1869
|
-
if (signal?.aborted) break;
|
|
1870
|
-
push(typeof chunk === "string" ? chunk : decoder.decode(chunk, { stream: true }));
|
|
1871
|
-
}
|
|
1872
|
-
push(decoder.decode());
|
|
1873
|
-
} catch (error) {
|
|
1874
|
-
if (signal?.aborted) throw abortedError(text);
|
|
1875
|
-
if (error instanceof JuneError) throw error;
|
|
1876
|
-
throw new JuneError("STREAM_ERROR", "Stream was interrupted", {
|
|
1877
|
-
cause: error,
|
|
1878
|
-
details: { partial: text }
|
|
1879
|
-
});
|
|
1880
|
-
}
|
|
1881
|
-
if (signal?.aborted) throw abortedError(text);
|
|
1882
|
-
if (!received && !allowEmpty) {
|
|
1883
|
-
throw new JuneError("STREAM_EMPTY", "Stream completed without any content");
|
|
1884
|
-
}
|
|
1885
|
-
return text;
|
|
1886
|
-
}
|
|
1887
20
|
|
|
1888
|
-
// src/streaming/sse-adapter.ts
|
|
1889
|
-
var BOUNDARY = /\r\n\r\n|\n\n|\r\r/;
|
|
1890
|
-
function parseFrame(raw) {
|
|
1891
|
-
let event = "message";
|
|
1892
|
-
const data = [];
|
|
1893
|
-
for (const line of raw.split(/\r\n|\n|\r/)) {
|
|
1894
|
-
if (!line || line.startsWith(":")) continue;
|
|
1895
|
-
const i = line.indexOf(":");
|
|
1896
|
-
const field = i === -1 ? line : line.slice(0, i);
|
|
1897
|
-
let value = i === -1 ? "" : line.slice(i + 1);
|
|
1898
|
-
if (value.startsWith(" ")) value = value.slice(1);
|
|
1899
|
-
if (field === "event") event = value;
|
|
1900
|
-
else if (field === "data") data.push(value);
|
|
1901
|
-
}
|
|
1902
|
-
if (data.length === 0 && event === "message") return null;
|
|
1903
|
-
return { event, data: data.join("\n") };
|
|
1904
|
-
}
|
|
1905
|
-
async function* sseToText(source, options = {}) {
|
|
1906
|
-
const { extract, doneSentinel = "[DONE]", signal } = options;
|
|
1907
|
-
const decoder = new TextDecoder();
|
|
1908
|
-
let buffer = "";
|
|
1909
|
-
const handle = (raw) => {
|
|
1910
|
-
const frame = parseFrame(raw);
|
|
1911
|
-
if (!frame) return { done: false, text: null };
|
|
1912
|
-
if (frame.event === "error") {
|
|
1913
|
-
throw new JuneError("STREAM_ERROR", frame.data || "Server sent an error event", {
|
|
1914
|
-
details: frame
|
|
1915
|
-
});
|
|
1916
|
-
}
|
|
1917
|
-
if (doneSentinel !== null && frame.data === doneSentinel) {
|
|
1918
|
-
return { done: true, text: null };
|
|
1919
|
-
}
|
|
1920
|
-
const text = extract ? extract(frame.data, frame.event) : frame.data;
|
|
1921
|
-
return { done: false, text: text ? text : null };
|
|
1922
|
-
};
|
|
1923
|
-
for await (const chunk of toAsyncIterable(source, signal)) {
|
|
1924
|
-
buffer += typeof chunk === "string" ? chunk : decoder.decode(chunk, { stream: true });
|
|
1925
|
-
let match;
|
|
1926
|
-
while ((match = BOUNDARY.exec(buffer)) !== null) {
|
|
1927
|
-
const raw = buffer.slice(0, match.index);
|
|
1928
|
-
buffer = buffer.slice(match.index + match[0].length);
|
|
1929
|
-
const result = handle(raw);
|
|
1930
|
-
if (result.done) return;
|
|
1931
|
-
if (result.text) yield result.text;
|
|
1932
|
-
}
|
|
1933
|
-
}
|
|
1934
|
-
buffer += decoder.decode();
|
|
1935
|
-
if (buffer.trim()) {
|
|
1936
|
-
const result = handle(buffer);
|
|
1937
|
-
if (!result.done && result.text) yield result.text;
|
|
1938
|
-
}
|
|
1939
|
-
}
|
|
1940
|
-
function jsonFieldExtractor(path) {
|
|
1941
|
-
const keys = path.split(".");
|
|
1942
|
-
return (data) => {
|
|
1943
|
-
try {
|
|
1944
|
-
let current = JSON.parse(data);
|
|
1945
|
-
for (const key of keys) {
|
|
1946
|
-
if (current === null || typeof current !== "object") return null;
|
|
1947
|
-
current = current[key];
|
|
1948
|
-
}
|
|
1949
|
-
return typeof current === "string" ? current : null;
|
|
1950
|
-
} catch {
|
|
1951
|
-
return null;
|
|
1952
|
-
}
|
|
1953
|
-
};
|
|
1954
|
-
}
|
|
1955
21
|
|
|
1956
|
-
// src/streaming/fetch-adapter.ts
|
|
1957
|
-
async function fetchStream(input, options = {}) {
|
|
1958
|
-
const { sse, ...init } = options;
|
|
1959
|
-
let response;
|
|
1960
|
-
try {
|
|
1961
|
-
response = await fetch(input, init);
|
|
1962
|
-
} catch (error) {
|
|
1963
|
-
if (init.signal?.aborted) {
|
|
1964
|
-
throw new JuneError("STREAM_ABORTED", "Request was aborted", { cause: error });
|
|
1965
|
-
}
|
|
1966
|
-
throw new JuneError("NETWORK_ERROR", "Network request failed", { cause: error });
|
|
1967
|
-
}
|
|
1968
|
-
if (!response.ok) {
|
|
1969
|
-
throw new JuneError("NETWORK_ERROR", `Request failed with status ${response.status}`, {
|
|
1970
|
-
details: { status: response.status, statusText: response.statusText }
|
|
1971
|
-
});
|
|
1972
|
-
}
|
|
1973
|
-
if (!response.body) {
|
|
1974
|
-
throw new JuneError("STREAM_EMPTY", "Response has no body");
|
|
1975
|
-
}
|
|
1976
|
-
const body = response.body;
|
|
1977
|
-
if (sse) {
|
|
1978
|
-
return sseToText(body, {
|
|
1979
|
-
...sse === true ? {} : sse,
|
|
1980
|
-
signal: init.signal ?? void 0
|
|
1981
|
-
});
|
|
1982
|
-
}
|
|
1983
|
-
return body;
|
|
1984
|
-
}
|
|
1985
22
|
|
|
1986
|
-
// src/streaming/use-june-stream.ts
|
|
1987
|
-
var FLUSH_MS = 16;
|
|
1988
|
-
var INITIAL = {
|
|
1989
|
-
response: "",
|
|
1990
|
-
isStreaming: false,
|
|
1991
|
-
status: "idle",
|
|
1992
|
-
error: null
|
|
1993
|
-
};
|
|
1994
|
-
function useJuneStream(options = {}) {
|
|
1995
|
-
const [state, setState] = (0, import_react6.useState)(INITIAL);
|
|
1996
|
-
const optionsRef = (0, import_react6.useRef)(options);
|
|
1997
|
-
optionsRef.current = options;
|
|
1998
|
-
const controllerRef = (0, import_react6.useRef)(null);
|
|
1999
|
-
const runIdRef = (0, import_react6.useRef)(0);
|
|
2000
|
-
const textRef = (0, import_react6.useRef)("");
|
|
2001
|
-
const timerRef = (0, import_react6.useRef)(null);
|
|
2002
|
-
const clearTimer = (0, import_react6.useCallback)(() => {
|
|
2003
|
-
if (timerRef.current !== null) {
|
|
2004
|
-
clearTimeout(timerRef.current);
|
|
2005
|
-
timerRef.current = null;
|
|
2006
|
-
}
|
|
2007
|
-
}, []);
|
|
2008
|
-
const schedule = (0, import_react6.useCallback)(() => {
|
|
2009
|
-
if (timerRef.current !== null) return;
|
|
2010
|
-
timerRef.current = setTimeout(() => {
|
|
2011
|
-
timerRef.current = null;
|
|
2012
|
-
const text = textRef.current;
|
|
2013
|
-
setState(
|
|
2014
|
-
(s) => s.status !== "streaming" || s.response === text ? s : { ...s, response: text }
|
|
2015
|
-
);
|
|
2016
|
-
}, FLUSH_MS);
|
|
2017
|
-
}, []);
|
|
2018
|
-
const start = (0, import_react6.useCallback)(
|
|
2019
|
-
async (input) => {
|
|
2020
|
-
controllerRef.current?.abort();
|
|
2021
|
-
const controller = new AbortController();
|
|
2022
|
-
controllerRef.current = controller;
|
|
2023
|
-
const runId = ++runIdRef.current;
|
|
2024
|
-
const stale = () => runId !== runIdRef.current;
|
|
2025
|
-
textRef.current = "";
|
|
2026
|
-
clearTimer();
|
|
2027
|
-
setState({ response: "", isStreaming: true, status: "streaming", error: null });
|
|
2028
|
-
try {
|
|
2029
|
-
const source = typeof input === "function" ? await input(controller.signal) : input;
|
|
2030
|
-
if (stale()) return null;
|
|
2031
|
-
const text = await consumeStream(source, {
|
|
2032
|
-
signal: controller.signal,
|
|
2033
|
-
allowEmpty: optionsRef.current.allowEmpty,
|
|
2034
|
-
onText: (_delta, full) => {
|
|
2035
|
-
if (stale()) return;
|
|
2036
|
-
textRef.current = full;
|
|
2037
|
-
schedule();
|
|
2038
|
-
}
|
|
2039
|
-
});
|
|
2040
|
-
if (stale()) return null;
|
|
2041
|
-
clearTimer();
|
|
2042
|
-
setState({ response: text, isStreaming: false, status: "done", error: null });
|
|
2043
|
-
optionsRef.current.onComplete?.(text);
|
|
2044
|
-
return text;
|
|
2045
|
-
} catch (caught) {
|
|
2046
|
-
if (stale()) return null;
|
|
2047
|
-
clearTimer();
|
|
2048
|
-
const error = toJuneError(caught, "STREAM_ERROR");
|
|
2049
|
-
const aborted = controller.signal.aborted || error.code === "STREAM_ABORTED";
|
|
2050
|
-
setState({
|
|
2051
|
-
response: textRef.current,
|
|
2052
|
-
// keep partial output
|
|
2053
|
-
isStreaming: false,
|
|
2054
|
-
status: aborted ? "aborted" : "error",
|
|
2055
|
-
error: aborted ? null : error
|
|
2056
|
-
});
|
|
2057
|
-
if (!aborted) optionsRef.current.onError?.(error);
|
|
2058
|
-
return null;
|
|
2059
|
-
}
|
|
2060
|
-
},
|
|
2061
|
-
[clearTimer, schedule]
|
|
2062
|
-
);
|
|
2063
|
-
const startFetch = (0, import_react6.useCallback)(
|
|
2064
|
-
(input, fetchOptions) => start((signal) => fetchStream(input, { ...fetchOptions, signal })),
|
|
2065
|
-
[start]
|
|
2066
|
-
);
|
|
2067
|
-
const abort = (0, import_react6.useCallback)(() => {
|
|
2068
|
-
controllerRef.current?.abort();
|
|
2069
|
-
}, []);
|
|
2070
|
-
const reset = (0, import_react6.useCallback)(() => {
|
|
2071
|
-
controllerRef.current?.abort();
|
|
2072
|
-
runIdRef.current++;
|
|
2073
|
-
textRef.current = "";
|
|
2074
|
-
clearTimer();
|
|
2075
|
-
setState(INITIAL);
|
|
2076
|
-
}, [clearTimer]);
|
|
2077
|
-
(0, import_react6.useEffect)(
|
|
2078
|
-
() => () => {
|
|
2079
|
-
runIdRef.current++;
|
|
2080
|
-
controllerRef.current?.abort();
|
|
2081
|
-
clearTimer();
|
|
2082
|
-
},
|
|
2083
|
-
[clearTimer]
|
|
2084
|
-
);
|
|
2085
|
-
return (0, import_react6.useMemo)(
|
|
2086
|
-
() => ({ ...state, start, startFetch, abort, reset }),
|
|
2087
|
-
[state, start, startFetch, abort, reset]
|
|
2088
|
-
);
|
|
2089
|
-
}
|
|
2090
23
|
|
|
2091
|
-
// src/entry-core.ts
|
|
2092
|
-
init_errors();
|
|
2093
24
|
|
|
2094
|
-
// src/components/document-editor/document-component.tsx
|
|
2095
|
-
var import_react_lang3 = require("@openuidev/react-lang");
|
|
2096
|
-
var import_v4 = require("zod/v4");
|
|
2097
25
|
|
|
2098
|
-
// src/components/document-editor/document-draft.tsx
|
|
2099
|
-
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
2100
|
-
function DocumentDraft({ title, words, state }) {
|
|
2101
|
-
if (state === "empty") {
|
|
2102
|
-
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "june-doc june-doc--draft", role: "alert", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "june-doc__draft-text", children: "No document content was received." }) });
|
|
2103
|
-
}
|
|
2104
|
-
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "june-doc june-doc--draft", role: "status", "aria-live": "polite", children: [
|
|
2105
|
-
title ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "june-doc__draft-title", children: title }) : null,
|
|
2106
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "june-doc__draft-text", children: state === "drafting" ? `Drafting document\u2026${words ? ` ${words} words so far` : ""}` : "Loading editor\u2026" }),
|
|
2107
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "june-doc__pulse", "aria-hidden": "true", children: [
|
|
2108
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", {}),
|
|
2109
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", {}),
|
|
2110
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", {})
|
|
2111
|
-
] })
|
|
2112
|
-
] });
|
|
2113
|
-
}
|
|
2114
26
|
|
|
2115
|
-
// src/components/document-editor/document-editor.tsx
|
|
2116
|
-
var import_react15 = require("@tiptap/react");
|
|
2117
|
-
var import_react16 = require("react");
|
|
2118
|
-
init_errors();
|
|
2119
|
-
|
|
2120
|
-
// src/components/document-editor/document-bubble.tsx
|
|
2121
|
-
var import_react10 = require("@tiptap/react");
|
|
2122
|
-
var import_menus = require("@tiptap/react/menus");
|
|
2123
|
-
|
|
2124
|
-
// src/components/document-editor/document-toolbar.tsx
|
|
2125
|
-
var import_react8 = require("@tiptap/react");
|
|
2126
|
-
var import_react9 = require("react");
|
|
2127
|
-
|
|
2128
|
-
// src/components/document-editor/document-icons.tsx
|
|
2129
|
-
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
2130
|
-
var PATHS = {
|
|
2131
|
-
undo: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2132
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M9 14 4 9l5-5" }),
|
|
2133
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M4 9h10.5a5.5 5.5 0 0 1 0 11H11" })
|
|
2134
|
-
] }),
|
|
2135
|
-
redo: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2136
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "m15 14 5-5-5-5" }),
|
|
2137
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M20 9H9.5a5.5 5.5 0 0 0 0 11H13" })
|
|
2138
|
-
] }),
|
|
2139
|
-
bold: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M6 12h9a4 4 0 0 1 0 8H7a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h7a4 4 0 0 1 0 8" }),
|
|
2140
|
-
italic: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2141
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("line", { x1: "19", x2: "10", y1: "4", y2: "4" }),
|
|
2142
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("line", { x1: "14", x2: "5", y1: "20", y2: "20" }),
|
|
2143
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("line", { x1: "15", x2: "9", y1: "4", y2: "20" })
|
|
2144
|
-
] }),
|
|
2145
|
-
underline: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2146
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M6 4v6a6 6 0 0 0 12 0V4" }),
|
|
2147
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("line", { x1: "4", x2: "20", y1: "20", y2: "20" })
|
|
2148
|
-
] }),
|
|
2149
|
-
strike: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2150
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M16 4H9a3 3 0 0 0-2.83 4" }),
|
|
2151
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M14 12a4 4 0 0 1 0 8H6" }),
|
|
2152
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("line", { x1: "4", x2: "20", y1: "12", y2: "12" })
|
|
2153
|
-
] }),
|
|
2154
|
-
code: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2155
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "m16 18 6-6-6-6" }),
|
|
2156
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "m8 6-6 6 6 6" })
|
|
2157
|
-
] }),
|
|
2158
|
-
codeBlock: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2159
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2" }),
|
|
2160
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "m10 9-3 3 3 3" }),
|
|
2161
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "m14 15 3-3-3-3" })
|
|
2162
|
-
] }),
|
|
2163
|
-
superscript: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2164
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "m4 19 8-8" }),
|
|
2165
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "m12 19-8-8" }),
|
|
2166
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M20 12h-4c0-1.5.44-2 1.5-2.5S20 8.33 20 7c0-.47-.17-.93-.48-1.29a2.11 2.11 0 0 0-2.62-.44c-.42.24-.74.62-.9 1.07" })
|
|
2167
|
-
] }),
|
|
2168
|
-
subscript: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2169
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "m4 5 8 8" }),
|
|
2170
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "m12 5-8 8" }),
|
|
2171
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M20 19h-4c0-1.5.44-2 1.5-2.5S20 15.33 20 14c0-.47-.17-.93-.48-1.29a2.11 2.11 0 0 0-2.62-.44c-.42.24-.74.62-.9 1.07" })
|
|
2172
|
-
] }),
|
|
2173
|
-
alignLeft: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2174
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M15 12H3" }),
|
|
2175
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M17 18H3" }),
|
|
2176
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M21 6H3" })
|
|
2177
|
-
] }),
|
|
2178
|
-
alignCenter: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2179
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M17 12H7" }),
|
|
2180
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M19 18H5" }),
|
|
2181
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M21 6H3" })
|
|
2182
|
-
] }),
|
|
2183
|
-
alignRight: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2184
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M21 12H9" }),
|
|
2185
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M21 18H7" }),
|
|
2186
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M21 6H3" })
|
|
2187
|
-
] }),
|
|
2188
|
-
alignJustify: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2189
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M3 12h18" }),
|
|
2190
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M3 18h18" }),
|
|
2191
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M3 6h18" })
|
|
2192
|
-
] }),
|
|
2193
|
-
list: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2194
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M3 12h.01" }),
|
|
2195
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M3 18h.01" }),
|
|
2196
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M3 6h.01" }),
|
|
2197
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M8 12h13" }),
|
|
2198
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M8 18h13" }),
|
|
2199
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M8 6h13" })
|
|
2200
|
-
] }),
|
|
2201
|
-
listOrdered: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2202
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M10 12h11" }),
|
|
2203
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M10 18h11" }),
|
|
2204
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M10 6h11" }),
|
|
2205
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M4 10h2" }),
|
|
2206
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M4 6h1v4" }),
|
|
2207
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M6 18H4c0-1 2-2 2-3s-1-1.5-2-1" })
|
|
2208
|
-
] }),
|
|
2209
|
-
outdent: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2210
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M21 12H11" }),
|
|
2211
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M21 18H11" }),
|
|
2212
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M21 6H11" }),
|
|
2213
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "m7 8-4 4 4 4" })
|
|
2214
|
-
] }),
|
|
2215
|
-
indent: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2216
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M21 12H11" }),
|
|
2217
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M21 18H11" }),
|
|
2218
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M21 6H11" }),
|
|
2219
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "m3 8 4 4-4 4" })
|
|
2220
|
-
] }),
|
|
2221
|
-
quote: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2222
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M17 6H3" }),
|
|
2223
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M21 12H8" }),
|
|
2224
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M21 18H8" }),
|
|
2225
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M3 12v6" })
|
|
2226
|
-
] }),
|
|
2227
|
-
pilcrow: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2228
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M13 4v16" }),
|
|
2229
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M17 4v16" }),
|
|
2230
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M19 4H9.5a4.5 4.5 0 0 0 0 9H13" })
|
|
2231
|
-
] }),
|
|
2232
|
-
pageBreak: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2233
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("line", { x1: "3", x2: "21", y1: "12", y2: "12" }),
|
|
2234
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("polyline", { points: "8 8 12 4 16 8" }),
|
|
2235
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("polyline", { points: "16 16 12 20 8 16" })
|
|
2236
|
-
] }),
|
|
2237
|
-
divider: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2238
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M3 12h18" }),
|
|
2239
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M8 6h8", opacity: ".45" }),
|
|
2240
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M8 18h8", opacity: ".45" })
|
|
2241
|
-
] }),
|
|
2242
|
-
layout: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2243
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("rect", { width: "18", height: "7", x: "3", y: "3", rx: "1" }),
|
|
2244
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("rect", { width: "9", height: "7", x: "3", y: "14", rx: "1" }),
|
|
2245
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("rect", { width: "5", height: "7", x: "16", y: "14", rx: "1" })
|
|
2246
|
-
] }),
|
|
2247
|
-
search: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2248
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("circle", { cx: "11", cy: "11", r: "8" }),
|
|
2249
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "m21 21-4.3-4.3" })
|
|
2250
|
-
] }),
|
|
2251
|
-
palette: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2252
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("circle", { cx: "13.5", cy: "6.5", r: ".5", fill: "currentColor" }),
|
|
2253
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("circle", { cx: "17.5", cy: "10.5", r: ".5", fill: "currentColor" }),
|
|
2254
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("circle", { cx: "8.5", cy: "7.5", r: ".5", fill: "currentColor" }),
|
|
2255
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("circle", { cx: "6.5", cy: "12.5", r: ".5", fill: "currentColor" }),
|
|
2256
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.93 0 1.65-.75 1.65-1.69 0-.44-.18-.84-.44-1.13-.29-.29-.44-.65-.44-1.13a1.64 1.64 0 0 1 1.67-1.67h2c3.05 0 5.55-2.5 5.55-5.55C21.97 6.01 17.46 2 12 2z" })
|
|
2257
|
-
] }),
|
|
2258
|
-
highlighter: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2259
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "m9 11-6 6v3h9l3-3" }),
|
|
2260
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "m22 12-4.6 4.6a2 2 0 0 1-2.8 0l-5.2-5.2a2 2 0 0 1 0-2.8L14 4" })
|
|
2261
|
-
] }),
|
|
2262
|
-
link: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2263
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" }),
|
|
2264
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" })
|
|
2265
|
-
] }),
|
|
2266
|
-
image: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2267
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("rect", { width: "18", height: "18", x: "3", y: "3", rx: "2" }),
|
|
2268
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("circle", { cx: "9", cy: "9", r: "2" }),
|
|
2269
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "m21 15-3.09-3.09a2 2 0 0 0-2.82 0L6 21" })
|
|
2270
|
-
] }),
|
|
2271
|
-
table: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2272
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M12 3v18" }),
|
|
2273
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("rect", { width: "18", height: "18", x: "3", y: "3", rx: "2" }),
|
|
2274
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M3 9h18" }),
|
|
2275
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M3 15h18" })
|
|
2276
|
-
] }),
|
|
2277
|
-
eraser: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2278
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "m7 21-4.3-4.3c-1-1-1-2.5 0-3.4l9.6-9.6c1-1 2.5-1 3.4 0l5.6 5.6c1 1 1 2.5 0 3.4L13 21" }),
|
|
2279
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M22 21H7" }),
|
|
2280
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "m5 11 9 9" })
|
|
2281
|
-
] }),
|
|
2282
|
-
save: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2283
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M15.2 3a2 2 0 0 1 1.4.6l3.8 3.8a2 2 0 0 1 .6 1.4V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2z" }),
|
|
2284
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M17 21v-7a1 1 0 0 0-1-1H8a1 1 0 0 0-1 1v7" }),
|
|
2285
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M7 3v4a1 1 0 0 0 1 1h7" })
|
|
2286
|
-
] }),
|
|
2287
|
-
download: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2288
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
|
|
2289
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("polyline", { points: "7 10 12 15 17 10" }),
|
|
2290
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("line", { x1: "12", x2: "12", y1: "15", y2: "3" })
|
|
2291
|
-
] }),
|
|
2292
|
-
chevronDown: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "m6 9 6 6 6-6" }),
|
|
2293
|
-
chevronUp: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "m18 15-6-6-6 6" }),
|
|
2294
|
-
close: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2295
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M18 6 6 18" }),
|
|
2296
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "m6 6 12 12" })
|
|
2297
|
-
] }),
|
|
2298
|
-
maximize: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2299
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M8 3H5a2 2 0 0 0-2 2v3" }),
|
|
2300
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M21 8V5a2 2 0 0 0-2-2h-3" }),
|
|
2301
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M3 16v3a2 2 0 0 0 2 2h3" }),
|
|
2302
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M16 21h3a2 2 0 0 0 2-2v-3" })
|
|
2303
|
-
] }),
|
|
2304
|
-
copy: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2305
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("rect", { width: "14", height: "14", x: "8", y: "8", rx: "2" }),
|
|
2306
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" })
|
|
2307
|
-
] }),
|
|
2308
|
-
file: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2309
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" }),
|
|
2310
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M14 2v4a2 2 0 0 0 2 2h4" })
|
|
2311
|
-
] }),
|
|
2312
|
-
plus: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2313
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M5 12h14" }),
|
|
2314
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M12 5v14" })
|
|
2315
|
-
] }),
|
|
2316
|
-
minus: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M5 12h14" }),
|
|
2317
|
-
check: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M20 6 9 17l-5-5" }),
|
|
2318
|
-
sparkles: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2319
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M9.94 14.06 8 20l-1.94-5.94L0 12l6.06-1.94L8 4l1.94 6.06L16 12z", transform: "translate(3 -1) scale(.85)" }),
|
|
2320
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M20 3v4" }),
|
|
2321
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M22 5h-4" })
|
|
2322
|
-
] }),
|
|
2323
|
-
upload: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2324
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
|
|
2325
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("polyline", { points: "17 8 12 3 7 8" }),
|
|
2326
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("line", { x1: "12", x2: "12", y1: "3", y2: "15" })
|
|
2327
|
-
] })
|
|
2328
|
-
};
|
|
2329
|
-
function Icon({ name, size = 16 }) {
|
|
2330
|
-
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2331
|
-
"svg",
|
|
2332
|
-
{
|
|
2333
|
-
className: "june-doc__icon",
|
|
2334
|
-
width: size,
|
|
2335
|
-
height: size,
|
|
2336
|
-
viewBox: "0 0 24 24",
|
|
2337
|
-
fill: "none",
|
|
2338
|
-
stroke: "currentColor",
|
|
2339
|
-
strokeWidth: 2,
|
|
2340
|
-
strokeLinecap: "round",
|
|
2341
|
-
strokeLinejoin: "round",
|
|
2342
|
-
"aria-hidden": "true",
|
|
2343
|
-
focusable: "false",
|
|
2344
|
-
children: PATHS[name]
|
|
2345
|
-
}
|
|
2346
|
-
);
|
|
2347
|
-
}
|
|
2348
27
|
|
|
2349
|
-
// src/components/document-editor/document-popover.tsx
|
|
2350
|
-
var import_react7 = require("react");
|
|
2351
|
-
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
2352
|
-
function Dropdown({ trigger, children, align = "start", className, onOpen }) {
|
|
2353
|
-
const [open, setOpen] = (0, import_react7.useState)(false);
|
|
2354
|
-
const anchor = (0, import_react7.useRef)(null);
|
|
2355
|
-
(0, import_react7.useEffect)(() => {
|
|
2356
|
-
if (!open) return;
|
|
2357
|
-
const onDown = (e) => {
|
|
2358
|
-
if (anchor.current && !anchor.current.contains(e.target)) setOpen(false);
|
|
2359
|
-
};
|
|
2360
|
-
document.addEventListener("mousedown", onDown);
|
|
2361
|
-
return () => document.removeEventListener("mousedown", onDown);
|
|
2362
|
-
}, [open]);
|
|
2363
|
-
const toggle = () => setOpen((v) => {
|
|
2364
|
-
if (!v) onOpen?.();
|
|
2365
|
-
return !v;
|
|
2366
|
-
});
|
|
2367
|
-
const close = () => setOpen(false);
|
|
2368
|
-
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
2369
|
-
"div",
|
|
2370
|
-
{
|
|
2371
|
-
ref: anchor,
|
|
2372
|
-
className: "june-doc__anchor",
|
|
2373
|
-
onKeyDown: (e) => {
|
|
2374
|
-
if (e.key === "Escape" && open) {
|
|
2375
|
-
e.stopPropagation();
|
|
2376
|
-
close();
|
|
2377
|
-
}
|
|
2378
|
-
},
|
|
2379
|
-
children: [
|
|
2380
|
-
trigger({ open, toggle }),
|
|
2381
|
-
open ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: `june-doc__pop june-doc__pop--${align}${className ? ` ${className}` : ""}`, children: children(close) }) : null
|
|
2382
|
-
]
|
|
2383
|
-
}
|
|
2384
|
-
);
|
|
2385
|
-
}
|
|
2386
28
|
|
|
2387
|
-
// src/components/document-editor/document-toolbar.tsx
|
|
2388
|
-
init_document_utils();
|
|
2389
|
-
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
2390
|
-
var FONT_FAMILIES = [
|
|
2391
|
-
{ label: "Default", value: "" },
|
|
2392
|
-
{ label: "Arial", value: "Arial, Helvetica, sans-serif" },
|
|
2393
|
-
{ label: "Calibri", value: "Calibri, Carlito, sans-serif" },
|
|
2394
|
-
{ label: "Georgia", value: "Georgia, serif" },
|
|
2395
|
-
{ label: "Garamond", value: "Garamond, 'EB Garamond', serif" },
|
|
2396
|
-
{ label: "Times New Roman", value: "'Times New Roman', Times, serif" },
|
|
2397
|
-
{ label: "Verdana", value: "Verdana, Geneva, sans-serif" },
|
|
2398
|
-
{ label: "Trebuchet MS", value: "'Trebuchet MS', sans-serif" },
|
|
2399
|
-
{ label: "Courier New", value: "'Courier New', Courier, monospace" }
|
|
2400
|
-
];
|
|
2401
|
-
var FONT_SIZES = [8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 24, 28, 32, 36, 48, 60, 72];
|
|
2402
|
-
var TEXT_COLORS = [
|
|
2403
|
-
"#111827",
|
|
2404
|
-
"#374151",
|
|
2405
|
-
"#6b7280",
|
|
2406
|
-
"#9ca3af",
|
|
2407
|
-
"#dc2626",
|
|
2408
|
-
"#ea580c",
|
|
2409
|
-
"#ca8a04",
|
|
2410
|
-
"#16a34a",
|
|
2411
|
-
"#0d9488",
|
|
2412
|
-
"#0284c7",
|
|
2413
|
-
"#2563eb",
|
|
2414
|
-
"#4f46e5",
|
|
2415
|
-
"#9333ea",
|
|
2416
|
-
"#db2777",
|
|
2417
|
-
"#7f1d1d",
|
|
2418
|
-
"#1e3a8a"
|
|
2419
|
-
];
|
|
2420
|
-
var HIGHLIGHT_COLORS = [
|
|
2421
|
-
"#fef08a",
|
|
2422
|
-
"#fde68a",
|
|
2423
|
-
"#fed7aa",
|
|
2424
|
-
"#fecaca",
|
|
2425
|
-
"#fbcfe8",
|
|
2426
|
-
"#e9d5ff",
|
|
2427
|
-
"#c7d2fe",
|
|
2428
|
-
"#bfdbfe",
|
|
2429
|
-
"#a5f3fc",
|
|
2430
|
-
"#bbf7d0",
|
|
2431
|
-
"#d9f99d",
|
|
2432
|
-
"#e5e7eb"
|
|
2433
|
-
];
|
|
2434
|
-
var MAX_IMAGE_BYTES = 8 * 1024 * 1024;
|
|
2435
|
-
function Btn({ label, icon, active, disabled, toggle, onClick, children, className, text }) {
|
|
2436
|
-
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
2437
|
-
"button",
|
|
2438
|
-
{
|
|
2439
|
-
type: "button",
|
|
2440
|
-
className: `june-doc__btn${icon && !text && !children ? " june-doc__btn--icon" : ""}${className ? ` ${className}` : ""}`,
|
|
2441
|
-
"aria-label": label,
|
|
2442
|
-
title: label,
|
|
2443
|
-
"aria-pressed": toggle ? !!active : void 0,
|
|
2444
|
-
"data-active": active || void 0,
|
|
2445
|
-
disabled,
|
|
2446
|
-
onMouseDown: (e) => e.preventDefault(),
|
|
2447
|
-
onClick,
|
|
2448
|
-
children: [
|
|
2449
|
-
icon ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Icon, { name: icon }) : null,
|
|
2450
|
-
children ?? (text ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: label }) : null)
|
|
2451
|
-
]
|
|
2452
|
-
}
|
|
2453
|
-
);
|
|
2454
|
-
}
|
|
2455
|
-
function Group({ label, children }) {
|
|
2456
|
-
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "june-doc__group", role: "group", "aria-label": label, children: [
|
|
2457
|
-
label ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "june-doc__group-label", "aria-hidden": "true", children: label }) : null,
|
|
2458
|
-
children
|
|
2459
|
-
] });
|
|
2460
|
-
}
|
|
2461
|
-
function Field({ label, children }) {
|
|
2462
|
-
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "june-doc__field", children: [
|
|
2463
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "june-doc__field-label", children: label }),
|
|
2464
|
-
children
|
|
2465
|
-
] });
|
|
2466
|
-
}
|
|
2467
|
-
function ColorPicker({ label, icon, colors, current, disabled, resetLabel, onPick, onReset }) {
|
|
2468
|
-
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2469
|
-
Dropdown,
|
|
2470
|
-
{
|
|
2471
|
-
trigger: ({ open, toggle }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
2472
|
-
"button",
|
|
2473
|
-
{
|
|
2474
|
-
type: "button",
|
|
2475
|
-
className: "june-doc__btn june-doc__btn--icon june-doc__btn--color",
|
|
2476
|
-
"aria-label": label,
|
|
2477
|
-
title: label,
|
|
2478
|
-
"aria-expanded": open,
|
|
2479
|
-
"aria-haspopup": "dialog",
|
|
2480
|
-
disabled,
|
|
2481
|
-
onMouseDown: (e) => e.preventDefault(),
|
|
2482
|
-
onClick: toggle,
|
|
2483
|
-
children: [
|
|
2484
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Icon, { name: icon }),
|
|
2485
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "june-doc__color-bar", style: { background: current ?? "transparent" } })
|
|
2486
|
-
]
|
|
2487
|
-
}
|
|
2488
|
-
),
|
|
2489
|
-
children: (close) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "june-doc__swatches-wrap", role: "dialog", "aria-label": label, children: [
|
|
2490
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "june-doc__pop-title", children: label }),
|
|
2491
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "june-doc__swatches", children: colors.map((c) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2492
|
-
"button",
|
|
2493
|
-
{
|
|
2494
|
-
type: "button",
|
|
2495
|
-
className: "june-doc__swatch",
|
|
2496
|
-
style: { background: c },
|
|
2497
|
-
"aria-label": c,
|
|
2498
|
-
title: c,
|
|
2499
|
-
"data-active": current?.toLowerCase() === c ? true : void 0,
|
|
2500
|
-
onMouseDown: (e) => e.preventDefault(),
|
|
2501
|
-
onClick: () => {
|
|
2502
|
-
onPick(c);
|
|
2503
|
-
close();
|
|
2504
|
-
}
|
|
2505
|
-
},
|
|
2506
|
-
c
|
|
2507
|
-
)) }),
|
|
2508
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "june-doc__pop-row", children: [
|
|
2509
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2510
|
-
"button",
|
|
2511
|
-
{
|
|
2512
|
-
type: "button",
|
|
2513
|
-
className: "june-doc__btn june-doc__btn--ghost",
|
|
2514
|
-
onMouseDown: (e) => e.preventDefault(),
|
|
2515
|
-
onClick: () => {
|
|
2516
|
-
onReset();
|
|
2517
|
-
close();
|
|
2518
|
-
},
|
|
2519
|
-
children: resetLabel
|
|
2520
|
-
}
|
|
2521
|
-
),
|
|
2522
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "june-doc__custom-color", title: "Custom color", children: [
|
|
2523
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: "Custom" }),
|
|
2524
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2525
|
-
"input",
|
|
2526
|
-
{
|
|
2527
|
-
type: "color",
|
|
2528
|
-
"aria-label": `${label}: custom`,
|
|
2529
|
-
defaultValue: current && /^#[0-9a-f]{6}$/i.test(current) ? current : "#000000",
|
|
2530
|
-
onChange: (e) => onPick(e.target.value)
|
|
2531
|
-
}
|
|
2532
|
-
)
|
|
2533
|
-
] })
|
|
2534
|
-
] })
|
|
2535
|
-
] })
|
|
2536
|
-
}
|
|
2537
|
-
);
|
|
2538
|
-
}
|
|
2539
|
-
function LinkPanel({
|
|
2540
|
-
editor,
|
|
2541
|
-
href,
|
|
2542
|
-
isLink,
|
|
2543
|
-
close
|
|
2544
|
-
}) {
|
|
2545
|
-
const [value, setValue] = (0, import_react9.useState)(href);
|
|
2546
|
-
const apply = () => {
|
|
2547
|
-
const safe = sanitizeHref(value);
|
|
2548
|
-
if (safe) editor.chain().focus().extendMarkRange("link").setLink({ href: safe }).run();
|
|
2549
|
-
close();
|
|
2550
|
-
};
|
|
2551
|
-
const remove = () => {
|
|
2552
|
-
editor.chain().focus().extendMarkRange("link").unsetLink().run();
|
|
2553
|
-
close();
|
|
2554
|
-
};
|
|
2555
|
-
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "june-doc__form", role: "dialog", "aria-label": "Edit link", children: [
|
|
2556
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "june-doc__pop-title", children: "Link" }),
|
|
2557
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2558
|
-
"input",
|
|
2559
|
-
{
|
|
2560
|
-
"aria-label": "Link address",
|
|
2561
|
-
className: "june-doc__input",
|
|
2562
|
-
placeholder: "https://example.com",
|
|
2563
|
-
value,
|
|
2564
|
-
autoFocus: true,
|
|
2565
|
-
onChange: (e) => setValue(e.target.value),
|
|
2566
|
-
onKeyDown: (e) => {
|
|
2567
|
-
if (e.key === "Enter") {
|
|
2568
|
-
e.preventDefault();
|
|
2569
|
-
apply();
|
|
2570
|
-
}
|
|
2571
|
-
}
|
|
2572
|
-
}
|
|
2573
|
-
),
|
|
2574
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "june-doc__pop-row june-doc__pop-row--end", children: [
|
|
2575
|
-
isLink ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: "june-doc__btn june-doc__btn--ghost", onClick: remove, children: "Remove" }) : null,
|
|
2576
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: "june-doc__btn", onClick: close, children: "Cancel" }),
|
|
2577
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: "june-doc__btn june-doc__btn--primary", onClick: apply, children: "Apply" })
|
|
2578
|
-
] })
|
|
2579
|
-
] });
|
|
2580
|
-
}
|
|
2581
|
-
function ImagePanel({ editor, close, onNotice }) {
|
|
2582
|
-
const [url, setUrl] = (0, import_react9.useState)("");
|
|
2583
|
-
const [alt, setAlt] = (0, import_react9.useState)("");
|
|
2584
|
-
const file = (0, import_react9.useRef)(null);
|
|
2585
|
-
const insert = (src) => {
|
|
2586
|
-
editor.chain().focus().setImage({ src, alt: alt || void 0 }).run();
|
|
2587
|
-
close();
|
|
2588
|
-
};
|
|
2589
|
-
const fromUrl = () => {
|
|
2590
|
-
const safe = sanitizeHref(url);
|
|
2591
|
-
if (!safe || !/^https?:/i.test(safe)) {
|
|
2592
|
-
onNotice("Enter an http(s) image address");
|
|
2593
|
-
return;
|
|
2594
|
-
}
|
|
2595
|
-
insert(safe);
|
|
2596
|
-
};
|
|
2597
|
-
const fromFile = (f) => {
|
|
2598
|
-
if (!f) return;
|
|
2599
|
-
if (!f.type.startsWith("image/")) return onNotice("That file is not an image");
|
|
2600
|
-
if (f.size > MAX_IMAGE_BYTES) return onNotice("Images must be 8 MB or smaller");
|
|
2601
|
-
const reader = new FileReader();
|
|
2602
|
-
reader.onload = () => typeof reader.result === "string" && insert(reader.result);
|
|
2603
|
-
reader.onerror = () => onNotice("The image could not be read");
|
|
2604
|
-
reader.readAsDataURL(f);
|
|
2605
|
-
};
|
|
2606
|
-
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "june-doc__form", role: "dialog", "aria-label": "Insert image", children: [
|
|
2607
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "june-doc__pop-title", children: "Image" }),
|
|
2608
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
2609
|
-
"button",
|
|
2610
|
-
{
|
|
2611
|
-
type: "button",
|
|
2612
|
-
className: "june-doc__dropzone",
|
|
2613
|
-
onClick: () => file.current?.click(),
|
|
2614
|
-
onDragOver: (e) => e.preventDefault(),
|
|
2615
|
-
onDrop: (e) => {
|
|
2616
|
-
e.preventDefault();
|
|
2617
|
-
fromFile(e.dataTransfer.files[0]);
|
|
2618
|
-
},
|
|
2619
|
-
children: [
|
|
2620
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Icon, { name: "upload", size: 18 }),
|
|
2621
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: "Upload or drop an image" })
|
|
2622
|
-
]
|
|
2623
|
-
}
|
|
2624
|
-
),
|
|
2625
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2626
|
-
"input",
|
|
2627
|
-
{
|
|
2628
|
-
ref: file,
|
|
2629
|
-
type: "file",
|
|
2630
|
-
accept: "image/*",
|
|
2631
|
-
hidden: true,
|
|
2632
|
-
onChange: (e) => fromFile(e.target.files?.[0])
|
|
2633
|
-
}
|
|
2634
|
-
),
|
|
2635
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "june-doc__or", children: "or" }),
|
|
2636
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2637
|
-
"input",
|
|
2638
|
-
{
|
|
2639
|
-
"aria-label": "Image address",
|
|
2640
|
-
className: "june-doc__input",
|
|
2641
|
-
placeholder: "https://example.com/image.png",
|
|
2642
|
-
value: url,
|
|
2643
|
-
onChange: (e) => setUrl(e.target.value),
|
|
2644
|
-
onKeyDown: (e) => e.key === "Enter" && fromUrl()
|
|
2645
|
-
}
|
|
2646
|
-
),
|
|
2647
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2648
|
-
"input",
|
|
2649
|
-
{
|
|
2650
|
-
"aria-label": "Alternative text",
|
|
2651
|
-
className: "june-doc__input",
|
|
2652
|
-
placeholder: "Alt text (optional)",
|
|
2653
|
-
value: alt,
|
|
2654
|
-
onChange: (e) => setAlt(e.target.value)
|
|
2655
|
-
}
|
|
2656
|
-
),
|
|
2657
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "june-doc__pop-row june-doc__pop-row--end", children: [
|
|
2658
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: "june-doc__btn", onClick: close, children: "Cancel" }),
|
|
2659
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: "june-doc__btn june-doc__btn--primary", disabled: !url.trim(), onClick: fromUrl, children: "Insert" })
|
|
2660
|
-
] })
|
|
2661
|
-
] });
|
|
2662
|
-
}
|
|
2663
|
-
function TablePanel({ editor, close }) {
|
|
2664
|
-
const [hover, setHover] = (0, import_react9.useState)([0, 0]);
|
|
2665
|
-
const N = 8;
|
|
2666
|
-
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "june-doc__form", role: "dialog", "aria-label": "Insert table", children: [
|
|
2667
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "june-doc__pop-title", children: [
|
|
2668
|
-
"Table ",
|
|
2669
|
-
hover[0] ? `${hover[0]} \xD7 ${hover[1]}` : ""
|
|
2670
|
-
] }),
|
|
2671
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "june-doc__grid", onMouseLeave: () => setHover([0, 0]), children: Array.from({ length: N * N }, (_, i) => {
|
|
2672
|
-
const r = Math.floor(i / N) + 1;
|
|
2673
|
-
const c = i % N + 1;
|
|
2674
|
-
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2675
|
-
"button",
|
|
2676
|
-
{
|
|
2677
|
-
type: "button",
|
|
2678
|
-
className: "june-doc__cell",
|
|
2679
|
-
"aria-label": `${r} by ${c} table`,
|
|
2680
|
-
"data-active": r <= hover[0] && c <= hover[1] ? true : void 0,
|
|
2681
|
-
onMouseEnter: () => setHover([r, c]),
|
|
2682
|
-
onFocus: () => setHover([r, c]),
|
|
2683
|
-
onMouseDown: (e) => e.preventDefault(),
|
|
2684
|
-
onClick: () => {
|
|
2685
|
-
editor.chain().focus().insertTable({ rows: r, cols: c, withHeaderRow: true }).run();
|
|
2686
|
-
close();
|
|
2687
|
-
}
|
|
2688
|
-
},
|
|
2689
|
-
i
|
|
2690
|
-
);
|
|
2691
|
-
}) })
|
|
2692
|
-
] });
|
|
2693
|
-
}
|
|
2694
|
-
var px = (v) => typeof v === "string" ? v.replace(/px$/, "") : "";
|
|
2695
|
-
function DocumentToolbar(props) {
|
|
2696
|
-
const { editor, editable, expanded, onToggleExpanded, showMarks, onToggleMarks, layout, onToggleLayout, findOpen, onToggleFind, onNotice } = props;
|
|
2697
|
-
const s = (0, import_react8.useEditorState)({
|
|
2698
|
-
editor,
|
|
2699
|
-
selector: ({ editor: ed }) => {
|
|
2700
|
-
if (!ed) return null;
|
|
2701
|
-
const ts = ed.getAttributes("textStyle");
|
|
2702
|
-
return {
|
|
2703
|
-
bold: ed.isActive("bold"),
|
|
2704
|
-
italic: ed.isActive("italic"),
|
|
2705
|
-
underline: ed.isActive("underline"),
|
|
2706
|
-
strike: ed.isActive("strike"),
|
|
2707
|
-
code: ed.isActive("code"),
|
|
2708
|
-
sup: ed.isActive("superscript"),
|
|
2709
|
-
sub: ed.isActive("subscript"),
|
|
2710
|
-
bullet: ed.isActive("bulletList"),
|
|
2711
|
-
ordered: ed.isActive("orderedList"),
|
|
2712
|
-
quote: ed.isActive("blockquote"),
|
|
2713
|
-
codeBlock: ed.isActive("codeBlock"),
|
|
2714
|
-
link: ed.isActive("link"),
|
|
2715
|
-
linkHref: ed.getAttributes("link").href ?? "",
|
|
2716
|
-
h1: ed.isActive("heading", { level: 1 }),
|
|
2717
|
-
h2: ed.isActive("heading", { level: 2 }),
|
|
2718
|
-
h3: ed.isActive("heading", { level: 3 }),
|
|
2719
|
-
left: ed.isActive({ textAlign: "left" }),
|
|
2720
|
-
center: ed.isActive({ textAlign: "center" }),
|
|
2721
|
-
right: ed.isActive({ textAlign: "right" }),
|
|
2722
|
-
justify: ed.isActive({ textAlign: "justify" }),
|
|
2723
|
-
inTable: ed.isActive("table"),
|
|
2724
|
-
color: ts.color ?? null,
|
|
2725
|
-
fontFamily: ts.fontFamily ?? "",
|
|
2726
|
-
fontSize: px(ts.fontSize),
|
|
2727
|
-
highlight: ed.isActive("highlight") ? ed.getAttributes("highlight").color ?? "#fef08a" : null,
|
|
2728
|
-
canUndo: ed.can().undo(),
|
|
2729
|
-
canRedo: ed.can().redo(),
|
|
2730
|
-
canSink: ed.can().sinkListItem("listItem"),
|
|
2731
|
-
canLift: ed.can().liftListItem("listItem"),
|
|
2732
|
-
canMerge: ed.can().mergeCells(),
|
|
2733
|
-
canSplit: ed.can().splitCell()
|
|
2734
|
-
};
|
|
2735
|
-
}
|
|
2736
|
-
});
|
|
2737
|
-
const run = () => editor?.chain().focus();
|
|
2738
|
-
const off = !editor || !editable;
|
|
2739
|
-
const style = s?.codeBlock ? "code" : s?.h1 ? "1" : s?.h2 ? "2" : s?.h3 ? "3" : s?.quote ? "quote" : "p";
|
|
2740
|
-
const setStyle = (v) => {
|
|
2741
|
-
if (!editor || !s) return;
|
|
2742
|
-
let c = editor.chain().focus();
|
|
2743
|
-
if (v === "quote") {
|
|
2744
|
-
if (!s.quote) c = c.setParagraph().toggleBlockquote();
|
|
2745
|
-
} else if (v === "code") {
|
|
2746
|
-
if (!s.codeBlock) c = c.toggleCodeBlock();
|
|
2747
|
-
} else {
|
|
2748
|
-
if (s.quote) c = c.lift("blockquote");
|
|
2749
|
-
c = v === "p" ? c.setParagraph() : c.setHeading({ level: Number(v) });
|
|
2750
|
-
}
|
|
2751
|
-
c.run();
|
|
2752
|
-
};
|
|
2753
|
-
const fontKnown = FONT_FAMILIES.some((f) => f.value === s?.fontFamily);
|
|
2754
|
-
const sizes = s?.fontSize && !FONT_SIZES.includes(Number(s.fontSize)) ? [...FONT_SIZES, Number(s.fontSize)].sort((a, b) => a - b) : FONT_SIZES;
|
|
2755
|
-
if (!editable) return null;
|
|
2756
|
-
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "june-doc__ribbon", role: "toolbar", "aria-label": "Document formatting", children: [
|
|
2757
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "june-doc__row", children: [
|
|
2758
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Group, { label: "History", children: [
|
|
2759
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Btn, { label: "Undo", icon: "undo", disabled: off || !s?.canUndo, onClick: () => run()?.undo().run() }),
|
|
2760
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Btn, { label: "Redo", icon: "redo", disabled: off || !s?.canRedo, onClick: () => run()?.redo().run() })
|
|
2761
|
-
] }),
|
|
2762
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Group, { label: "Format", children: [
|
|
2763
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Btn, { label: "Bold", icon: "bold", toggle: true, active: s?.bold, disabled: off, onClick: () => run()?.toggleBold().run() }),
|
|
2764
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Btn, { label: "Italic", icon: "italic", toggle: true, active: s?.italic, disabled: off, onClick: () => run()?.toggleItalic().run() }),
|
|
2765
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Btn, { label: "Underline", icon: "underline", toggle: true, active: s?.underline, disabled: off, onClick: () => run()?.toggleUnderline().run() }),
|
|
2766
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Btn, { label: "Strikethrough", icon: "strike", toggle: true, active: s?.strike, disabled: off, onClick: () => run()?.toggleStrike().run() }),
|
|
2767
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Btn, { label: "Inline code", icon: "code", toggle: true, active: s?.code, disabled: off, onClick: () => run()?.toggleCode().run() }),
|
|
2768
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Btn, { label: "Superscript", icon: "superscript", toggle: true, active: s?.sup, disabled: off, onClick: () => run()?.toggleSuperscript().run() }),
|
|
2769
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Btn, { label: "Subscript", icon: "subscript", toggle: true, active: s?.sub, disabled: off, onClick: () => run()?.toggleSubscript().run() })
|
|
2770
|
-
] }),
|
|
2771
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Group, { label: "Align", children: [
|
|
2772
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Btn, { label: "Align left", icon: "alignLeft", toggle: true, active: s?.left, disabled: off, onClick: () => run()?.setTextAlign("left").run() }),
|
|
2773
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Btn, { label: "Align center", icon: "alignCenter", toggle: true, active: s?.center, disabled: off, onClick: () => run()?.setTextAlign("center").run() }),
|
|
2774
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Btn, { label: "Align right", icon: "alignRight", toggle: true, active: s?.right, disabled: off, onClick: () => run()?.setTextAlign("right").run() }),
|
|
2775
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Btn, { label: "Justify", icon: "alignJustify", toggle: true, active: s?.justify, disabled: off, onClick: () => run()?.setTextAlign("justify").run() })
|
|
2776
|
-
] }),
|
|
2777
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Group, { label: "Lists", children: [
|
|
2778
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Btn, { label: "Bullet list", icon: "list", toggle: true, active: s?.bullet, disabled: off, onClick: () => run()?.toggleBulletList().run() }),
|
|
2779
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Btn, { label: "Numbered list", icon: "listOrdered", toggle: true, active: s?.ordered, disabled: off, onClick: () => run()?.toggleOrderedList().run() }),
|
|
2780
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Btn, { label: "Decrease indent", icon: "outdent", disabled: off || !s?.canLift, onClick: () => run()?.liftListItem("listItem").run() }),
|
|
2781
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Btn, { label: "Increase indent", icon: "indent", disabled: off || !s?.canSink, onClick: () => run()?.sinkListItem("listItem").run() })
|
|
2782
|
-
] }),
|
|
2783
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
2784
|
-
"button",
|
|
2785
|
-
{
|
|
2786
|
-
type: "button",
|
|
2787
|
-
className: "june-doc__btn june-doc__more",
|
|
2788
|
-
"aria-expanded": expanded,
|
|
2789
|
-
"aria-label": expanded ? "Show fewer tools" : "Show more tools",
|
|
2790
|
-
onMouseDown: (e) => e.preventDefault(),
|
|
2791
|
-
onClick: onToggleExpanded,
|
|
2792
|
-
children: [
|
|
2793
|
-
expanded ? "Less" : "More",
|
|
2794
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Icon, { name: expanded ? "chevronUp" : "chevronDown", size: 14 })
|
|
2795
|
-
]
|
|
2796
|
-
}
|
|
2797
|
-
)
|
|
2798
|
-
] }),
|
|
2799
|
-
expanded ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "june-doc__row june-doc__row--secondary", children: [
|
|
2800
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Group, { label: "Style", children: [
|
|
2801
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Field, { label: "Style", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("select", { className: "june-doc__select", "aria-label": "Text style", disabled: off, value: style, onChange: (e) => setStyle(e.target.value), children: [
|
|
2802
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "p", children: "Paragraph" }),
|
|
2803
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "1", children: "Heading 1" }),
|
|
2804
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "2", children: "Heading 2" }),
|
|
2805
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "3", children: "Heading 3" }),
|
|
2806
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "quote", children: "Quote" }),
|
|
2807
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "code", children: "Code block" })
|
|
2808
|
-
] }) }),
|
|
2809
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Field, { label: "Font", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
2810
|
-
"select",
|
|
2811
|
-
{
|
|
2812
|
-
className: "june-doc__select june-doc__select--font",
|
|
2813
|
-
"aria-label": "Font family",
|
|
2814
|
-
disabled: off,
|
|
2815
|
-
value: s?.fontFamily ?? "",
|
|
2816
|
-
onChange: (e) => {
|
|
2817
|
-
const v = e.target.value;
|
|
2818
|
-
if (v) run()?.setFontFamily(v).run();
|
|
2819
|
-
else run()?.unsetFontFamily().run();
|
|
2820
|
-
},
|
|
2821
|
-
children: [
|
|
2822
|
-
FONT_FAMILIES.map((f) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: f.value, style: { fontFamily: f.value || void 0 }, children: f.label }, f.label)),
|
|
2823
|
-
!fontKnown && s?.fontFamily ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: s.fontFamily, children: s.fontFamily.split(",")[0].replace(/['"]/g, "") }) : null
|
|
2824
|
-
]
|
|
2825
|
-
}
|
|
2826
|
-
) }),
|
|
2827
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Field, { label: "Size", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
2828
|
-
"select",
|
|
2829
|
-
{
|
|
2830
|
-
className: "june-doc__select june-doc__select--size",
|
|
2831
|
-
"aria-label": "Font size",
|
|
2832
|
-
disabled: off,
|
|
2833
|
-
value: s?.fontSize ?? "",
|
|
2834
|
-
onChange: (e) => {
|
|
2835
|
-
const v = e.target.value;
|
|
2836
|
-
if (v) run()?.setFontSize(`${v}px`).run();
|
|
2837
|
-
else run()?.unsetFontSize().run();
|
|
2838
|
-
},
|
|
2839
|
-
children: [
|
|
2840
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "", children: "Auto" }),
|
|
2841
|
-
sizes.map((n) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: String(n), children: n }, n))
|
|
2842
|
-
]
|
|
2843
|
-
}
|
|
2844
|
-
) })
|
|
2845
|
-
] }),
|
|
2846
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Btn, { label: "Show formatting marks", icon: "pilcrow", toggle: true, active: showMarks, onClick: onToggleMarks, text: true, className: "june-doc__btn--marks", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: "Paragraph" }) }),
|
|
2847
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Group, { label: "Document", children: [
|
|
2848
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Btn, { label: "Insert page break", icon: "pageBreak", disabled: off, onClick: () => run()?.setPageBreak().run() }),
|
|
2849
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Btn, { label: "Insert divider", icon: "divider", disabled: off, onClick: () => run()?.setHorizontalRule().run() }),
|
|
2850
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Btn, { label: layout === "page" ? "Switch to full-width layout" : "Switch to page layout", icon: "layout", toggle: true, active: layout === "fluid", onClick: onToggleLayout }),
|
|
2851
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Btn, { label: "Find and replace", icon: "search", toggle: true, active: findOpen, onClick: onToggleFind })
|
|
2852
|
-
] }),
|
|
2853
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Group, { label: "Color", children: [
|
|
2854
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2855
|
-
ColorPicker,
|
|
2856
|
-
{
|
|
2857
|
-
label: "Text color",
|
|
2858
|
-
icon: "palette",
|
|
2859
|
-
colors: TEXT_COLORS,
|
|
2860
|
-
current: s?.color ?? null,
|
|
2861
|
-
disabled: off,
|
|
2862
|
-
resetLabel: "Default color",
|
|
2863
|
-
onPick: (c) => run()?.setColor(c).run(),
|
|
2864
|
-
onReset: () => run()?.unsetColor().run()
|
|
2865
|
-
}
|
|
2866
|
-
),
|
|
2867
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2868
|
-
ColorPicker,
|
|
2869
|
-
{
|
|
2870
|
-
label: "Highlight",
|
|
2871
|
-
icon: "highlighter",
|
|
2872
|
-
colors: HIGHLIGHT_COLORS,
|
|
2873
|
-
current: s?.highlight ?? null,
|
|
2874
|
-
disabled: off,
|
|
2875
|
-
resetLabel: "No highlight",
|
|
2876
|
-
onPick: (c) => run()?.setHighlight({ color: c }).run(),
|
|
2877
|
-
onReset: () => run()?.unsetHighlight().run()
|
|
2878
|
-
}
|
|
2879
|
-
)
|
|
2880
|
-
] }),
|
|
2881
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Group, { label: "Insert", children: [
|
|
2882
|
-
editor ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2883
|
-
Dropdown,
|
|
2884
|
-
{
|
|
2885
|
-
trigger: ({ open, toggle }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Btn, { label: "Link", icon: "link", toggle: true, active: s?.link || open, disabled: off, onClick: toggle }),
|
|
2886
|
-
children: (close) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(LinkPanel, { editor, href: s?.linkHref ?? "", isLink: !!s?.link, close })
|
|
2887
|
-
}
|
|
2888
|
-
) : null,
|
|
2889
|
-
editor ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Dropdown, { trigger: ({ open, toggle }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Btn, { label: "Insert image", icon: "image", active: open, disabled: off, onClick: toggle }), children: (close) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ImagePanel, { editor, close, onNotice }) }) : null,
|
|
2890
|
-
editor ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Dropdown, { trigger: ({ open, toggle }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Btn, { label: "Insert table", icon: "table", active: open, disabled: off, onClick: toggle }), children: (close) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(TablePanel, { editor, close }) }) : null
|
|
2891
|
-
] }),
|
|
2892
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Group, { label: "Actions", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Btn, { label: "Clear formatting", icon: "eraser", disabled: off, onClick: () => run()?.unsetAllMarks().clearNodes().run() }) })
|
|
2893
|
-
] }) : null,
|
|
2894
|
-
s?.inTable ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "june-doc__row june-doc__row--context", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Group, { label: "Table", children: [
|
|
2895
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Btn, { label: "Add row below", disabled: off, onClick: () => run()?.addRowAfter().run(), children: "+ Row" }),
|
|
2896
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Btn, { label: "Add column right", disabled: off, onClick: () => run()?.addColumnAfter().run(), children: "+ Column" }),
|
|
2897
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Btn, { label: "Delete row", disabled: off, onClick: () => run()?.deleteRow().run(), children: "\u2212 Row" }),
|
|
2898
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Btn, { label: "Delete column", disabled: off, onClick: () => run()?.deleteColumn().run(), children: "\u2212 Column" }),
|
|
2899
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Btn, { label: "Merge cells", disabled: off || !s?.canMerge, onClick: () => run()?.mergeCells().run(), children: "Merge" }),
|
|
2900
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Btn, { label: "Split cell", disabled: off || !s?.canSplit, onClick: () => run()?.splitCell().run(), children: "Split" }),
|
|
2901
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Btn, { label: "Toggle header row", disabled: off, onClick: () => run()?.toggleHeaderRow().run(), children: "Header row" }),
|
|
2902
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Btn, { label: "Delete table", disabled: off, onClick: () => run()?.deleteTable().run(), className: "june-doc__btn--danger", children: "Delete table" })
|
|
2903
|
-
] }) }) : null
|
|
2904
|
-
] });
|
|
2905
|
-
}
|
|
2906
29
|
|
|
2907
|
-
// src/components/document-editor/document-bubble.tsx
|
|
2908
|
-
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
2909
|
-
function DocumentBubbleMenu({ editor }) {
|
|
2910
|
-
const s = (0, import_react10.useEditorState)({
|
|
2911
|
-
editor,
|
|
2912
|
-
selector: ({ editor: ed }) => ({
|
|
2913
|
-
bold: ed.isActive("bold"),
|
|
2914
|
-
italic: ed.isActive("italic"),
|
|
2915
|
-
underline: ed.isActive("underline"),
|
|
2916
|
-
strike: ed.isActive("strike"),
|
|
2917
|
-
link: ed.isActive("link"),
|
|
2918
|
-
linkHref: ed.getAttributes("link").href ?? "",
|
|
2919
|
-
color: ed.getAttributes("textStyle").color ?? null,
|
|
2920
|
-
highlight: ed.isActive("highlight") ? ed.getAttributes("highlight").color ?? "#fef08a" : null
|
|
2921
|
-
})
|
|
2922
|
-
});
|
|
2923
|
-
const run = () => editor.chain().focus();
|
|
2924
|
-
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
2925
|
-
import_menus.BubbleMenu,
|
|
2926
|
-
{
|
|
2927
|
-
editor,
|
|
2928
|
-
className: "june-doc__bubble",
|
|
2929
|
-
options: { placement: "top", offset: 8 },
|
|
2930
|
-
shouldShow: ({ editor: ed, state }) => {
|
|
2931
|
-
const { empty } = state.selection;
|
|
2932
|
-
if (empty || !ed.isEditable) return false;
|
|
2933
|
-
if (ed.isActive("image") || ed.isActive("pageBreak") || ed.isActive("codeBlock")) return false;
|
|
2934
|
-
return state.doc.textBetween(state.selection.from, state.selection.to).trim().length > 0;
|
|
2935
|
-
},
|
|
2936
|
-
children: [
|
|
2937
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Btn, { label: "Bold", icon: "bold", toggle: true, active: s.bold, onClick: () => run().toggleBold().run() }),
|
|
2938
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Btn, { label: "Italic", icon: "italic", toggle: true, active: s.italic, onClick: () => run().toggleItalic().run() }),
|
|
2939
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Btn, { label: "Underline", icon: "underline", toggle: true, active: s.underline, onClick: () => run().toggleUnderline().run() }),
|
|
2940
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Btn, { label: "Strikethrough", icon: "strike", toggle: true, active: s.strike, onClick: () => run().toggleStrike().run() }),
|
|
2941
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "june-doc__bubble-sep", "aria-hidden": "true" }),
|
|
2942
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Dropdown, { trigger: ({ open, toggle }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Btn, { label: "Link", icon: "link", toggle: true, active: s.link || open, onClick: toggle }), children: (close) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(LinkPanel, { editor, href: s.linkHref, isLink: s.link, close }) }),
|
|
2943
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
2944
|
-
ColorPicker,
|
|
2945
|
-
{
|
|
2946
|
-
label: "Text color",
|
|
2947
|
-
icon: "palette",
|
|
2948
|
-
colors: TEXT_COLORS,
|
|
2949
|
-
current: s.color,
|
|
2950
|
-
resetLabel: "Default color",
|
|
2951
|
-
onPick: (c) => run().setColor(c).run(),
|
|
2952
|
-
onReset: () => run().unsetColor().run()
|
|
2953
|
-
}
|
|
2954
|
-
),
|
|
2955
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
2956
|
-
ColorPicker,
|
|
2957
|
-
{
|
|
2958
|
-
label: "Highlight",
|
|
2959
|
-
icon: "highlighter",
|
|
2960
|
-
colors: HIGHLIGHT_COLORS,
|
|
2961
|
-
current: s.highlight,
|
|
2962
|
-
resetLabel: "No highlight",
|
|
2963
|
-
onPick: (c) => run().setHighlight({ color: c }).run(),
|
|
2964
|
-
onReset: () => run().unsetHighlight().run()
|
|
2965
|
-
}
|
|
2966
|
-
),
|
|
2967
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "june-doc__bubble-sep", "aria-hidden": "true" }),
|
|
2968
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Btn, { label: "Clear formatting", icon: "eraser", onClick: () => run().unsetAllMarks().run() })
|
|
2969
|
-
]
|
|
2970
|
-
}
|
|
2971
|
-
);
|
|
2972
|
-
}
|
|
2973
30
|
|
|
2974
|
-
// src/components/document-editor/document-content.tsx
|
|
2975
|
-
var import_react11 = require("@tiptap/react");
|
|
2976
|
-
var import_react12 = require("react");
|
|
2977
|
-
init_document_pagination();
|
|
2978
|
-
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
2979
|
-
var PAGE_WIDTH = 794;
|
|
2980
|
-
var PAGE_HEIGHT = 1123;
|
|
2981
|
-
var PAGE_GAP = 28;
|
|
2982
|
-
var CANVAS_PAD_X = 24;
|
|
2983
|
-
var useIsoLayoutEffect = typeof window === "undefined" ? import_react12.useEffect : import_react12.useLayoutEffect;
|
|
2984
|
-
function geometry(width) {
|
|
2985
|
-
const ratio = width / PAGE_WIDTH;
|
|
2986
|
-
const height = Math.round(PAGE_HEIGHT * ratio);
|
|
2987
|
-
const padX = Math.round(Math.min(96, Math.max(20, width * 0.12)));
|
|
2988
|
-
const padY = Math.round(Math.min(96, Math.max(36, 96 * ratio)));
|
|
2989
|
-
return { width, height, padX, padY };
|
|
2990
|
-
}
|
|
2991
|
-
function DocumentContent({ editor, layout = "page", zoom = 1, showMarks = false, onMetrics }) {
|
|
2992
|
-
const canvas = (0, import_react12.useRef)(null);
|
|
2993
|
-
const sheet = (0, import_react12.useRef)(null);
|
|
2994
|
-
const [avail, setAvail] = (0, import_react12.useState)(PAGE_WIDTH);
|
|
2995
|
-
const [sheetH, setSheetH] = (0, import_react12.useState)(0);
|
|
2996
|
-
const [pages, setPages] = (0, import_react12.useState)(1);
|
|
2997
|
-
const metricsRef = (0, import_react12.useRef)(onMetrics);
|
|
2998
|
-
metricsRef.current = onMetrics;
|
|
2999
|
-
const last = (0, import_react12.useRef)({ page: 0, pages: 0 });
|
|
3000
|
-
const paged = layout === "page";
|
|
3001
|
-
const width = paged ? Math.max(260, Math.min(PAGE_WIDTH, Math.floor(avail / zoom))) : Math.max(260, Math.floor(avail / zoom));
|
|
3002
|
-
const g = geometry(width);
|
|
3003
|
-
const stride = g.height + PAGE_GAP;
|
|
3004
|
-
useIsoLayoutEffect(() => {
|
|
3005
|
-
const c = canvas.current;
|
|
3006
|
-
if (!c) return;
|
|
3007
|
-
const read = () => {
|
|
3008
|
-
const cs = typeof getComputedStyle === "function" ? getComputedStyle(c) : null;
|
|
3009
|
-
const padX = cs ? (parseFloat(cs.paddingLeft) || 0) + (parseFloat(cs.paddingRight) || 0) : CANVAS_PAD_X * 2;
|
|
3010
|
-
const w = c.clientWidth - padX;
|
|
3011
|
-
if (w > 0) setAvail(w);
|
|
3012
|
-
};
|
|
3013
|
-
read();
|
|
3014
|
-
if (typeof ResizeObserver === "undefined") return;
|
|
3015
|
-
const ro = new ResizeObserver(read);
|
|
3016
|
-
ro.observe(c);
|
|
3017
|
-
return () => ro.disconnect();
|
|
3018
|
-
}, []);
|
|
3019
|
-
(0, import_react12.useEffect)(() => {
|
|
3020
|
-
if (!editor) return;
|
|
3021
|
-
setPaginationConfig(editor, {
|
|
3022
|
-
enabled: paged,
|
|
3023
|
-
pageHeight: g.height,
|
|
3024
|
-
gap: PAGE_GAP,
|
|
3025
|
-
padTop: g.padY,
|
|
3026
|
-
padBottom: g.padY
|
|
3027
|
-
});
|
|
3028
|
-
}, [editor, paged, g.height, g.padY, width]);
|
|
3029
|
-
(0, import_react12.useEffect)(() => {
|
|
3030
|
-
const c = canvas.current;
|
|
3031
|
-
const s = sheet.current;
|
|
3032
|
-
if (!editor || !c || !s) return;
|
|
3033
|
-
const prose = editor.view.dom;
|
|
3034
|
-
const report = () => {
|
|
3035
|
-
const total = paged ? getPageCount(editor) : 1;
|
|
3036
|
-
setPages(total);
|
|
3037
|
-
setSheetH(s.offsetHeight);
|
|
3038
|
-
const cRect = c.getBoundingClientRect();
|
|
3039
|
-
const sRect = s.getBoundingClientRect();
|
|
3040
|
-
const y = (cRect.top + c.clientHeight * 0.35 - sRect.top) / zoom;
|
|
3041
|
-
const page = paged ? Math.min(total, Math.max(1, Math.floor(y / stride) + 1)) : 1;
|
|
3042
|
-
if (last.current.page !== page || last.current.pages !== total) {
|
|
3043
|
-
last.current = { page, pages: total };
|
|
3044
|
-
metricsRef.current?.({ page, pages: total });
|
|
3045
|
-
}
|
|
3046
|
-
};
|
|
3047
|
-
report();
|
|
3048
|
-
editor.on("transaction", report);
|
|
3049
|
-
c.addEventListener("scroll", report, { passive: true });
|
|
3050
|
-
const onLoad = () => remeasurePagination(editor);
|
|
3051
|
-
prose.addEventListener("load", onLoad, true);
|
|
3052
|
-
const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(report) : null;
|
|
3053
|
-
ro?.observe(s);
|
|
3054
|
-
return () => {
|
|
3055
|
-
editor.off("transaction", report);
|
|
3056
|
-
c.removeEventListener("scroll", report);
|
|
3057
|
-
prose.removeEventListener("load", onLoad, true);
|
|
3058
|
-
ro?.disconnect();
|
|
3059
|
-
};
|
|
3060
|
-
}, [editor, paged, zoom, stride]);
|
|
3061
|
-
const minHeight = paged ? pages * g.height + (pages - 1) * PAGE_GAP : void 0;
|
|
3062
|
-
const sheetStyle = {
|
|
3063
|
-
width,
|
|
3064
|
-
minHeight,
|
|
3065
|
-
transform: zoom === 1 ? void 0 : `scale(${zoom})`,
|
|
3066
|
-
"--jd-pad-x": `${g.padX}px`,
|
|
3067
|
-
"--jd-pad-y": `${g.padY}px`
|
|
3068
|
-
};
|
|
3069
|
-
const zoomerStyle = {
|
|
3070
|
-
width: width * zoom,
|
|
3071
|
-
height: zoom === 1 ? void 0 : Math.max(sheetH, minHeight ?? 0) * zoom
|
|
3072
|
-
};
|
|
3073
|
-
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { ref: canvas, className: "june-doc__content june-doc__canvas", "data-layout": layout, "data-marks": showMarks || void 0, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "june-doc__zoomer", style: zoomerStyle, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { ref: sheet, className: "june-doc__sheet", style: sheetStyle, children: [
|
|
3074
|
-
paged ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "june-doc__pages", "aria-hidden": "true", children: Array.from({ length: pages }, (_, i) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "june-doc__page", style: { top: i * stride, height: g.height }, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "june-doc__page-num", children: [
|
|
3075
|
-
i + 1,
|
|
3076
|
-
" / ",
|
|
3077
|
-
pages
|
|
3078
|
-
] }) }, i)) }) : null,
|
|
3079
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react11.EditorContent, { editor })
|
|
3080
|
-
] }) }) });
|
|
3081
|
-
}
|
|
3082
31
|
|
|
3083
|
-
// src/components/document-editor/document-findbar.tsx
|
|
3084
|
-
var import_react13 = require("@tiptap/react");
|
|
3085
|
-
var import_react14 = require("react");
|
|
3086
|
-
init_document_search();
|
|
3087
|
-
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
3088
|
-
function DocumentFindBar({ editor, editable, onClose, onNotice }) {
|
|
3089
|
-
const [term, setTerm] = (0, import_react14.useState)(() => {
|
|
3090
|
-
const { from, to, empty } = editor.state.selection;
|
|
3091
|
-
return empty ? "" : editor.state.doc.textBetween(from, to, " ").slice(0, 100);
|
|
3092
|
-
});
|
|
3093
|
-
const [replacement, setReplacement] = (0, import_react14.useState)("");
|
|
3094
|
-
const [caseSensitive, setCaseSensitive] = (0, import_react14.useState)(false);
|
|
3095
|
-
const input = (0, import_react14.useRef)(null);
|
|
3096
|
-
const info = (0, import_react13.useEditorState)({
|
|
3097
|
-
editor,
|
|
3098
|
-
selector: ({ editor: ed }) => {
|
|
3099
|
-
const s = getSearchState(ed);
|
|
3100
|
-
return { count: s?.matches.length ?? 0, current: s?.current ?? -1 };
|
|
3101
|
-
}
|
|
3102
|
-
});
|
|
3103
|
-
(0, import_react14.useEffect)(() => {
|
|
3104
|
-
input.current?.focus();
|
|
3105
|
-
input.current?.select();
|
|
3106
|
-
}, []);
|
|
3107
|
-
(0, import_react14.useEffect)(() => {
|
|
3108
|
-
setSearch(editor, { term, caseSensitive, current: 0 });
|
|
3109
|
-
}, [editor, term, caseSensitive]);
|
|
3110
|
-
(0, import_react14.useEffect)(() => () => {
|
|
3111
|
-
if (!editor.isDestroyed) setSearch(editor, { term: "" });
|
|
3112
|
-
}, [editor]);
|
|
3113
|
-
const count = info?.count ?? 0;
|
|
3114
|
-
const current = info?.current ?? -1;
|
|
3115
|
-
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
3116
|
-
"div",
|
|
3117
|
-
{
|
|
3118
|
-
className: "june-doc__findbar",
|
|
3119
|
-
role: "search",
|
|
3120
|
-
onKeyDown: (e) => {
|
|
3121
|
-
if (e.key === "Escape") {
|
|
3122
|
-
e.stopPropagation();
|
|
3123
|
-
onClose();
|
|
3124
|
-
editor.commands.focus();
|
|
3125
|
-
}
|
|
3126
|
-
},
|
|
3127
|
-
children: [
|
|
3128
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "june-doc__find-field", children: [
|
|
3129
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Icon, { name: "search", size: 14 }),
|
|
3130
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
3131
|
-
"input",
|
|
3132
|
-
{
|
|
3133
|
-
ref: input,
|
|
3134
|
-
className: "june-doc__find-input",
|
|
3135
|
-
"aria-label": "Find in document",
|
|
3136
|
-
placeholder: "Find in document",
|
|
3137
|
-
value: term,
|
|
3138
|
-
onChange: (e) => setTerm(e.target.value),
|
|
3139
|
-
onKeyDown: (e) => {
|
|
3140
|
-
if (e.key === "Enter") {
|
|
3141
|
-
e.preventDefault();
|
|
3142
|
-
gotoMatch(editor, e.shiftKey ? -1 : 1);
|
|
3143
|
-
}
|
|
3144
|
-
}
|
|
3145
|
-
}
|
|
3146
|
-
),
|
|
3147
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "june-doc__find-count", "aria-live": "polite", children: term ? count ? `${current + 1} of ${count}` : "No results" : "" })
|
|
3148
|
-
] }),
|
|
3149
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: "june-doc__btn june-doc__btn--icon", "aria-label": "Previous match", title: "Previous (Shift+Enter)", disabled: !count, onClick: () => gotoMatch(editor, -1), children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Icon, { name: "chevronUp" }) }),
|
|
3150
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: "june-doc__btn june-doc__btn--icon", "aria-label": "Next match", title: "Next (Enter)", disabled: !count, onClick: () => gotoMatch(editor, 1), children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Icon, { name: "chevronDown" }) }),
|
|
3151
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
3152
|
-
"button",
|
|
3153
|
-
{
|
|
3154
|
-
type: "button",
|
|
3155
|
-
className: "june-doc__btn june-doc__btn--icon june-doc__btn--case",
|
|
3156
|
-
"aria-label": "Match case",
|
|
3157
|
-
title: "Match case",
|
|
3158
|
-
"aria-pressed": caseSensitive,
|
|
3159
|
-
"data-active": caseSensitive || void 0,
|
|
3160
|
-
onClick: () => setCaseSensitive((v) => !v),
|
|
3161
|
-
children: "Aa"
|
|
3162
|
-
}
|
|
3163
|
-
),
|
|
3164
|
-
editable ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
|
|
3165
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "june-doc__find-sep", "aria-hidden": "true" }),
|
|
3166
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
3167
|
-
"input",
|
|
3168
|
-
{
|
|
3169
|
-
className: "june-doc__input june-doc__replace-input",
|
|
3170
|
-
"aria-label": "Replace with",
|
|
3171
|
-
placeholder: "Replace with",
|
|
3172
|
-
value: replacement,
|
|
3173
|
-
onChange: (e) => setReplacement(e.target.value),
|
|
3174
|
-
onKeyDown: (e) => {
|
|
3175
|
-
if (e.key === "Enter") {
|
|
3176
|
-
e.preventDefault();
|
|
3177
|
-
replaceCurrent(editor, replacement);
|
|
3178
|
-
}
|
|
3179
|
-
}
|
|
3180
|
-
}
|
|
3181
|
-
),
|
|
3182
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: "june-doc__btn", disabled: !count, onClick: () => replaceCurrent(editor, replacement), children: "Replace" }),
|
|
3183
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
3184
|
-
"button",
|
|
3185
|
-
{
|
|
3186
|
-
type: "button",
|
|
3187
|
-
className: "june-doc__btn",
|
|
3188
|
-
disabled: !count,
|
|
3189
|
-
onClick: () => {
|
|
3190
|
-
const n = replaceAll(editor, replacement);
|
|
3191
|
-
onNotice(`Replaced ${n} ${n === 1 ? "match" : "matches"}`);
|
|
3192
|
-
},
|
|
3193
|
-
children: "Replace all"
|
|
3194
|
-
}
|
|
3195
|
-
)
|
|
3196
|
-
] }) : null,
|
|
3197
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: "june-doc__btn june-doc__btn--icon june-doc__btn--ghost june-doc__find-close", "aria-label": "Close find", onClick: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Icon, { name: "close" }) })
|
|
3198
|
-
]
|
|
3199
|
-
}
|
|
3200
|
-
);
|
|
3201
|
-
}
|
|
3202
32
|
|
|
3203
|
-
// src/components/document-editor/document-title.tsx
|
|
3204
|
-
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
3205
|
-
function DocumentTitle({ value, disabled, onChange }) {
|
|
3206
|
-
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
3207
|
-
"input",
|
|
3208
|
-
{
|
|
3209
|
-
className: "june-doc__title",
|
|
3210
|
-
"aria-label": "Document title",
|
|
3211
|
-
value,
|
|
3212
|
-
disabled,
|
|
3213
|
-
placeholder: "Untitled document",
|
|
3214
|
-
onChange: (e) => onChange(e.target.value)
|
|
3215
|
-
}
|
|
3216
|
-
);
|
|
3217
|
-
}
|
|
3218
33
|
|
|
3219
|
-
// src/components/document-editor/document-header.tsx
|
|
3220
|
-
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
3221
|
-
var FORMATS = {
|
|
3222
|
-
docx: { label: "Word document", hint: ".docx", icon: "file" },
|
|
3223
|
-
pdf: { label: "PDF", hint: "Print / Save as PDF", icon: "file" },
|
|
3224
|
-
html: { label: "Web page", hint: ".html", icon: "code" },
|
|
3225
|
-
markdown: { label: "Markdown", hint: ".md", icon: "file" },
|
|
3226
|
-
txt: { label: "Plain text", hint: ".txt", icon: "file" }
|
|
3227
|
-
};
|
|
3228
|
-
function DocumentHeader(props) {
|
|
3229
|
-
const { title, editable, isDraft, fullscreen, onToggleFullscreen, onTitle, exportFormats, canSave, showSave = canSave, saveState, onExport, onCopy, onSave } = props;
|
|
3230
|
-
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "june-doc__header", children: [
|
|
3231
|
-
fullscreen ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", className: "june-doc__btn june-doc__btn--icon june-doc__btn--ghost", "aria-label": "Close full screen", title: "Close (Esc)", onClick: onToggleFullscreen, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Icon, { name: "close", size: 18 }) }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "june-doc__doc-icon", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Icon, { name: "file", size: 16 }) }),
|
|
3232
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DocumentTitle, { value: title, disabled: !editable, onChange: onTitle }),
|
|
3233
|
-
isDraft ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "june-doc__badge", children: [
|
|
3234
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Icon, { name: "sparkles", size: 12 }),
|
|
3235
|
-
"AI draft"
|
|
3236
|
-
] }) : null,
|
|
3237
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "june-doc__header-actions", children: [
|
|
3238
|
-
showSave ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
3239
|
-
"button",
|
|
3240
|
-
{
|
|
3241
|
-
type: "button",
|
|
3242
|
-
className: "june-doc__btn june-doc__btn--outline june-doc__save",
|
|
3243
|
-
"data-state": saveState,
|
|
3244
|
-
"aria-label": "Save",
|
|
3245
|
-
title: "Save (Ctrl+S)",
|
|
3246
|
-
disabled: saveState === "saving" || saveState === "saved" || saveState === "idle",
|
|
3247
|
-
onClick: onSave,
|
|
3248
|
-
children: [
|
|
3249
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Icon, { name: saveState === "saved" ? "check" : "save" }),
|
|
3250
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: saveState === "saving" ? "Saving\u2026" : saveState === "saved" ? "Saved" : "Save" })
|
|
3251
|
-
]
|
|
3252
|
-
}
|
|
3253
|
-
) : null,
|
|
3254
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3255
|
-
Dropdown,
|
|
3256
|
-
{
|
|
3257
|
-
align: "end",
|
|
3258
|
-
className: "june-doc__menu",
|
|
3259
|
-
trigger: ({ open, toggle }) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
3260
|
-
"button",
|
|
3261
|
-
{
|
|
3262
|
-
type: "button",
|
|
3263
|
-
className: "june-doc__btn june-doc__btn--solid",
|
|
3264
|
-
"aria-label": "Download",
|
|
3265
|
-
"aria-haspopup": "menu",
|
|
3266
|
-
"aria-expanded": open,
|
|
3267
|
-
onClick: toggle,
|
|
3268
|
-
children: [
|
|
3269
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: "Download" }),
|
|
3270
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Icon, { name: "chevronDown", size: 14 })
|
|
3271
|
-
]
|
|
3272
|
-
}
|
|
3273
|
-
),
|
|
3274
|
-
children: (close) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { role: "menu", "aria-label": "Download options", children: [
|
|
3275
|
-
exportFormats.map((f) => {
|
|
3276
|
-
const meta = FORMATS[f] ?? { label: f.toUpperCase(), hint: "", icon: "file" };
|
|
3277
|
-
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
3278
|
-
"button",
|
|
3279
|
-
{
|
|
3280
|
-
type: "button",
|
|
3281
|
-
role: "menuitem",
|
|
3282
|
-
className: "june-doc__menu-item",
|
|
3283
|
-
onClick: () => {
|
|
3284
|
-
close();
|
|
3285
|
-
onExport(f);
|
|
3286
|
-
},
|
|
3287
|
-
children: [
|
|
3288
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Icon, { name: meta.icon }),
|
|
3289
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "june-doc__menu-label", children: meta.label }),
|
|
3290
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "june-doc__menu-hint", children: meta.hint })
|
|
3291
|
-
]
|
|
3292
|
-
},
|
|
3293
|
-
f
|
|
3294
|
-
);
|
|
3295
|
-
}),
|
|
3296
|
-
exportFormats.length ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "june-doc__menu-sep", role: "separator" }) : null,
|
|
3297
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
3298
|
-
"button",
|
|
3299
|
-
{
|
|
3300
|
-
type: "button",
|
|
3301
|
-
role: "menuitem",
|
|
3302
|
-
className: "june-doc__menu-item",
|
|
3303
|
-
"aria-label": "Copy document",
|
|
3304
|
-
onClick: () => {
|
|
3305
|
-
close();
|
|
3306
|
-
onCopy();
|
|
3307
|
-
},
|
|
3308
|
-
children: [
|
|
3309
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Icon, { name: "copy" }),
|
|
3310
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "june-doc__menu-label", children: "Copy to clipboard" })
|
|
3311
|
-
]
|
|
3312
|
-
}
|
|
3313
|
-
)
|
|
3314
|
-
] })
|
|
3315
|
-
}
|
|
3316
|
-
),
|
|
3317
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3318
|
-
"button",
|
|
3319
|
-
{
|
|
3320
|
-
type: "button",
|
|
3321
|
-
className: "june-doc__btn june-doc__btn--icon june-doc__btn--ghost",
|
|
3322
|
-
"aria-label": fullscreen ? "Exit full screen" : "Open full screen",
|
|
3323
|
-
title: fullscreen ? "Exit full screen" : "Open full screen",
|
|
3324
|
-
"aria-pressed": fullscreen,
|
|
3325
|
-
onClick: onToggleFullscreen,
|
|
3326
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Icon, { name: "maximize" })
|
|
3327
|
-
}
|
|
3328
|
-
)
|
|
3329
|
-
] })
|
|
3330
|
-
] });
|
|
3331
|
-
}
|
|
3332
34
|
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
};
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
let m = /^#([0-9a-f]{3})$/i.exec(v);
|
|
3382
|
-
if (m) return m[1].split("").map((c) => c + c).join("").toUpperCase();
|
|
3383
|
-
m = /^#([0-9a-f]{6})$/i.exec(v);
|
|
3384
|
-
if (m) return m[1].toUpperCase();
|
|
3385
|
-
m = /^rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/i.exec(v);
|
|
3386
|
-
if (m) {
|
|
3387
|
-
return [m[1], m[2], m[3]].map((n) => Math.min(255, Number(n)).toString(16).padStart(2, "0")).join("").toUpperCase();
|
|
3388
|
-
}
|
|
3389
|
-
return void 0;
|
|
3390
|
-
}
|
|
3391
|
-
function toHalfPoints(value) {
|
|
3392
|
-
if (typeof value !== "string") return void 0;
|
|
3393
|
-
const m = /^([\d.]+)\s*(px|pt)?$/i.exec(value.trim());
|
|
3394
|
-
if (!m) return void 0;
|
|
3395
|
-
const n = Number(m[1]);
|
|
3396
|
-
if (!Number.isFinite(n) || n <= 0) return void 0;
|
|
3397
|
-
const pt = m[2]?.toLowerCase() === "pt" ? n : n * 0.75;
|
|
3398
|
-
return Math.round(pt * 2);
|
|
3399
|
-
}
|
|
3400
|
-
function firstFontFamily(value) {
|
|
3401
|
-
if (typeof value !== "string") return void 0;
|
|
3402
|
-
const first = value.split(",")[0]?.trim().replace(/^['"]|['"]$/g, "");
|
|
3403
|
-
return first || void 0;
|
|
3404
|
-
}
|
|
3405
|
-
var ORDERED_REF = "june-ordered";
|
|
3406
|
-
var DOCX_MIME = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
|
|
3407
|
-
function runs(d, node, fmt) {
|
|
3408
|
-
const out = [];
|
|
3409
|
-
for (const child of node.content ?? []) {
|
|
3410
|
-
if (child.type === "hardBreak") {
|
|
3411
|
-
out.push(new d.TextRun({ break: 1 }));
|
|
3412
|
-
continue;
|
|
3413
|
-
}
|
|
3414
|
-
if (child.type !== "text" || !child.text) continue;
|
|
3415
|
-
const marks = child.marks ?? [];
|
|
3416
|
-
const has = (type) => marks.some((m) => m.type === type);
|
|
3417
|
-
const link = marks.find((m) => m.type === "link");
|
|
3418
|
-
const style = marks.find((m) => m.type === "textStyle")?.attrs ?? {};
|
|
3419
|
-
const highlight = marks.find((m) => m.type === "highlight");
|
|
3420
|
-
const fill = highlight ? toDocxColor(highlight.attrs?.color) ?? "FFF59D" : void 0;
|
|
3421
|
-
const run = new d.TextRun({
|
|
3422
|
-
text: child.text,
|
|
3423
|
-
bold: fmt.bold || has("bold") || void 0,
|
|
3424
|
-
italics: has("italic") || void 0,
|
|
3425
|
-
underline: has("underline") || link ? {} : void 0,
|
|
3426
|
-
strike: has("strike") || void 0,
|
|
3427
|
-
superScript: has("superscript") || void 0,
|
|
3428
|
-
subScript: has("subscript") || void 0,
|
|
3429
|
-
font: has("code") ? "Courier New" : firstFontFamily(style.fontFamily),
|
|
3430
|
-
size: toHalfPoints(style.fontSize),
|
|
3431
|
-
color: toDocxColor(style.color) ?? (link ? "0563C1" : void 0),
|
|
3432
|
-
shading: fill ? { type: d.ShadingType.CLEAR, fill, color: "auto" } : void 0
|
|
3433
|
-
});
|
|
3434
|
-
const href = typeof link?.attrs?.href === "string" ? sanitizeHref(link.attrs.href) : null;
|
|
3435
|
-
out.push(href ? new d.ExternalHyperlink({ link: href, children: [run] }) : run);
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
var _chunkGFCROSGQcjs = require('./chunk-GFCROSGQ.cjs');
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
var _chunkG6YPSE6Jcjs = require('./chunk-G6YPSE6J.cjs');
|
|
76
|
+
|
|
77
|
+
// src/core/config.ts
|
|
78
|
+
function mergeDefined(...sources) {
|
|
79
|
+
const out = {};
|
|
80
|
+
for (const source of sources) {
|
|
81
|
+
if (!source) continue;
|
|
82
|
+
for (const [key, value] of Object.entries(source)) if (value !== void 0) out[key] = value;
|
|
3436
83
|
}
|
|
3437
84
|
return out;
|
|
3438
85
|
}
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
spacing: { after: 120 },
|
|
3447
|
-
...extra
|
|
3448
|
-
});
|
|
3449
|
-
}
|
|
3450
|
-
function list(d, node, fmt, level, state) {
|
|
3451
|
-
const ordered = node.type === "orderedList";
|
|
3452
|
-
const instance = ordered ? ++state.instance : 0;
|
|
3453
|
-
const out = [];
|
|
3454
|
-
for (const item of node.content ?? []) {
|
|
3455
|
-
let first = true;
|
|
3456
|
-
for (const child of item.content ?? []) {
|
|
3457
|
-
if (child.type === "bulletList" || child.type === "orderedList") {
|
|
3458
|
-
out.push(...list(d, child, fmt, level + 1, state));
|
|
3459
|
-
} else if (child.type === "paragraph" && first) {
|
|
3460
|
-
first = false;
|
|
3461
|
-
const lvl = Math.min(level, 2);
|
|
3462
|
-
out.push(
|
|
3463
|
-
paragraph(
|
|
3464
|
-
d,
|
|
3465
|
-
child,
|
|
3466
|
-
fmt,
|
|
3467
|
-
ordered ? { numbering: { reference: ORDERED_REF, level: lvl, instance } } : { bullet: { level: lvl } }
|
|
3468
|
-
)
|
|
3469
|
-
);
|
|
3470
|
-
} else {
|
|
3471
|
-
out.push(...blocks(d, [child], { ...fmt, indent: (fmt.indent ?? 0) + 720 * (level + 1) }, state));
|
|
3472
|
-
}
|
|
3473
|
-
}
|
|
86
|
+
|
|
87
|
+
// src/core/default-library.ts
|
|
88
|
+
var _reactui = require('@openuidev/react-ui');
|
|
89
|
+
function libraryComponent(library, name) {
|
|
90
|
+
const found = library.components[name];
|
|
91
|
+
if (!found) {
|
|
92
|
+
throw new Error(`OpenUI library is missing "${name}"`);
|
|
3474
93
|
}
|
|
3475
|
-
return
|
|
3476
|
-
}
|
|
3477
|
-
function code(d, node) {
|
|
3478
|
-
const lines = (node.content ?? []).map((c) => c.text ?? "").join("").split("\n");
|
|
3479
|
-
return new d.Paragraph({
|
|
3480
|
-
children: lines.map((line, i) => new d.TextRun({ text: line, font: "Courier New", break: i ? 1 : void 0 })),
|
|
3481
|
-
spacing: { after: 120 },
|
|
3482
|
-
shading: { type: d.ShadingType.CLEAR, fill: "F3F4F6" }
|
|
3483
|
-
});
|
|
94
|
+
return found;
|
|
3484
95
|
}
|
|
3485
|
-
function
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
return new d.TableCell({
|
|
3492
|
-
children: children.length ? children : [new d.Paragraph("")],
|
|
3493
|
-
shading: header ? { type: d.ShadingType.CLEAR, fill: "F3F4F6" } : void 0
|
|
3494
|
-
});
|
|
3495
|
-
})
|
|
3496
|
-
})
|
|
3497
|
-
);
|
|
3498
|
-
if (rows.length === 0) return new d.Paragraph("");
|
|
3499
|
-
return new d.Table({ rows, width: { size: 100, type: d.WidthType.PERCENTAGE } });
|
|
3500
|
-
}
|
|
3501
|
-
function image(d, node, state) {
|
|
3502
|
-
const src = typeof node.attrs?.src === "string" ? node.attrs.src : "";
|
|
3503
|
-
const alt = typeof node.attrs?.alt === "string" ? node.attrs.alt : "";
|
|
3504
|
-
const img = state.images.get(src);
|
|
3505
|
-
if (img) {
|
|
3506
|
-
return [
|
|
3507
|
-
new d.Paragraph({
|
|
3508
|
-
children: [
|
|
3509
|
-
new d.ImageRun({
|
|
3510
|
-
type: img.type,
|
|
3511
|
-
data: img.data,
|
|
3512
|
-
transformation: { width: img.width, height: img.height },
|
|
3513
|
-
altText: alt ? { name: alt, description: alt, title: alt } : void 0
|
|
3514
|
-
})
|
|
3515
|
-
],
|
|
3516
|
-
spacing: { after: 120 }
|
|
3517
|
-
})
|
|
3518
|
-
];
|
|
3519
|
-
}
|
|
3520
|
-
const href = src && !src.startsWith("data:") ? sanitizeHref(src) : null;
|
|
3521
|
-
if (!href) return [];
|
|
3522
|
-
return [
|
|
3523
|
-
new d.Paragraph({
|
|
3524
|
-
children: [
|
|
3525
|
-
new d.ExternalHyperlink({
|
|
3526
|
-
link: href,
|
|
3527
|
-
children: [new d.TextRun({ text: alt || href, color: "0563C1", underline: {} })]
|
|
3528
|
-
})
|
|
96
|
+
function withChatLayout(library) {
|
|
97
|
+
return library.extend({
|
|
98
|
+
components: {
|
|
99
|
+
add: [
|
|
100
|
+
{ component: libraryComponent(_reactui.openuiLibrary, "Stack"), slots: ["Card"] },
|
|
101
|
+
{ component: libraryComponent(_reactui.openuiLibrary, "Modal"), slots: ["Card"] }
|
|
3529
102
|
]
|
|
3530
|
-
})
|
|
3531
|
-
];
|
|
3532
|
-
}
|
|
3533
|
-
function collectImages(nodes, out) {
|
|
3534
|
-
for (const node of nodes ?? []) {
|
|
3535
|
-
const src = node.attrs?.src;
|
|
3536
|
-
if (node.type === "image" && typeof src === "string" && src && !out.has(src)) out.set(src, node.attrs);
|
|
3537
|
-
if (node.content) collectImages(node.content, out);
|
|
3538
|
-
}
|
|
3539
|
-
return out;
|
|
3540
|
-
}
|
|
3541
|
-
var IMAGE_TYPES = {
|
|
3542
|
-
"image/png": "png",
|
|
3543
|
-
"image/jpeg": "jpg",
|
|
3544
|
-
"image/jpg": "jpg",
|
|
3545
|
-
"image/gif": "gif",
|
|
3546
|
-
"image/bmp": "bmp"
|
|
3547
|
-
};
|
|
3548
|
-
var MAX_IMAGE_WIDTH = 600;
|
|
3549
|
-
function naturalSize(blob) {
|
|
3550
|
-
const fallback = { width: 400, height: 300 };
|
|
3551
|
-
return new Promise((resolve) => {
|
|
3552
|
-
if (typeof Image === "undefined" || typeof URL.createObjectURL !== "function") return resolve(fallback);
|
|
3553
|
-
const url = URL.createObjectURL(blob);
|
|
3554
|
-
const img = new Image();
|
|
3555
|
-
const done = (size) => {
|
|
3556
|
-
URL.revokeObjectURL(url);
|
|
3557
|
-
resolve(size);
|
|
3558
|
-
};
|
|
3559
|
-
img.onload = () => done({ width: img.naturalWidth || 400, height: img.naturalHeight || 300 });
|
|
3560
|
-
img.onerror = () => done(fallback);
|
|
3561
|
-
img.src = url;
|
|
3562
|
-
});
|
|
3563
|
-
}
|
|
3564
|
-
async function loadImage(src, attrs) {
|
|
3565
|
-
try {
|
|
3566
|
-
const res = await fetch(src);
|
|
3567
|
-
if (!res.ok) return null;
|
|
3568
|
-
const blob = await res.blob();
|
|
3569
|
-
const type = IMAGE_TYPES[blob.type.toLowerCase()];
|
|
3570
|
-
if (!type) return null;
|
|
3571
|
-
const natural = await naturalSize(blob);
|
|
3572
|
-
let width = Number(attrs?.width) || natural.width;
|
|
3573
|
-
let height = Number(attrs?.height) || natural.height * width / natural.width;
|
|
3574
|
-
if (width > MAX_IMAGE_WIDTH) {
|
|
3575
|
-
height = height * MAX_IMAGE_WIDTH / width;
|
|
3576
|
-
width = MAX_IMAGE_WIDTH;
|
|
3577
103
|
}
|
|
3578
|
-
return { data: new Uint8Array(await blob.arrayBuffer()), type, width: Math.round(width), height: Math.round(height) };
|
|
3579
|
-
} catch {
|
|
3580
|
-
return null;
|
|
3581
|
-
}
|
|
3582
|
-
}
|
|
3583
|
-
async function resolveImages(doc) {
|
|
3584
|
-
const map = /* @__PURE__ */ new Map();
|
|
3585
|
-
if (typeof fetch !== "function") return map;
|
|
3586
|
-
const found = collectImages(doc.content, /* @__PURE__ */ new Map());
|
|
3587
|
-
await Promise.all(
|
|
3588
|
-
[...found].map(async ([src, attrs]) => {
|
|
3589
|
-
const info = await loadImage(src, attrs);
|
|
3590
|
-
if (info) map.set(src, info);
|
|
3591
|
-
})
|
|
3592
|
-
);
|
|
3593
|
-
return map;
|
|
3594
|
-
}
|
|
3595
|
-
function blocks(d, nodes, fmt, state) {
|
|
3596
|
-
const headings = [d.HeadingLevel.HEADING_1, d.HeadingLevel.HEADING_2, d.HeadingLevel.HEADING_3];
|
|
3597
|
-
const out = [];
|
|
3598
|
-
for (const node of nodes ?? []) {
|
|
3599
|
-
switch (node.type) {
|
|
3600
|
-
case "paragraph":
|
|
3601
|
-
out.push(paragraph(d, node, fmt));
|
|
3602
|
-
break;
|
|
3603
|
-
case "heading": {
|
|
3604
|
-
const level = Math.min(Math.max(Number(node.attrs?.level) || 1, 1), 3);
|
|
3605
|
-
out.push(paragraph(d, node, fmt, { heading: headings[level - 1] }));
|
|
3606
|
-
break;
|
|
3607
|
-
}
|
|
3608
|
-
case "bulletList":
|
|
3609
|
-
case "orderedList":
|
|
3610
|
-
out.push(...list(d, node, fmt, 0, state));
|
|
3611
|
-
break;
|
|
3612
|
-
case "blockquote":
|
|
3613
|
-
out.push(...blocks(d, node.content, { ...fmt, quote: true, indent: (fmt.indent ?? 0) + 360 }, state));
|
|
3614
|
-
break;
|
|
3615
|
-
case "codeBlock":
|
|
3616
|
-
out.push(code(d, node));
|
|
3617
|
-
break;
|
|
3618
|
-
case "horizontalRule":
|
|
3619
|
-
out.push(
|
|
3620
|
-
new d.Paragraph({
|
|
3621
|
-
border: { bottom: { color: "9CA3AF", space: 1, style: d.BorderStyle.SINGLE, size: 6 } },
|
|
3622
|
-
spacing: { after: 120 }
|
|
3623
|
-
})
|
|
3624
|
-
);
|
|
3625
|
-
break;
|
|
3626
|
-
case "table":
|
|
3627
|
-
out.push(table(d, node, state));
|
|
3628
|
-
break;
|
|
3629
|
-
case "pageBreak":
|
|
3630
|
-
out.push(new d.Paragraph({ children: [new d.PageBreak()] }));
|
|
3631
|
-
break;
|
|
3632
|
-
case "image":
|
|
3633
|
-
out.push(...image(d, node, state));
|
|
3634
|
-
break;
|
|
3635
|
-
default:
|
|
3636
|
-
if (node.content) out.push(...blocks(d, node.content, fmt, state));
|
|
3637
|
-
}
|
|
3638
|
-
}
|
|
3639
|
-
return out;
|
|
3640
|
-
}
|
|
3641
|
-
var exportDocx = async (ctx) => {
|
|
3642
|
-
const d = await import("docx");
|
|
3643
|
-
const state = { instance: 0, images: await resolveImages(ctx.json) };
|
|
3644
|
-
const children = [
|
|
3645
|
-
new d.Paragraph({ text: ctx.title, heading: d.HeadingLevel.TITLE }),
|
|
3646
|
-
...blocks(d, ctx.json.content, {}, state)
|
|
3647
|
-
];
|
|
3648
|
-
const doc = new d.Document({
|
|
3649
|
-
title: ctx.title,
|
|
3650
|
-
numbering: {
|
|
3651
|
-
config: [
|
|
3652
|
-
{
|
|
3653
|
-
reference: ORDERED_REF,
|
|
3654
|
-
levels: [0, 1, 2].map((level) => ({
|
|
3655
|
-
level,
|
|
3656
|
-
format: d.LevelFormat.DECIMAL,
|
|
3657
|
-
text: `%${level + 1}.`,
|
|
3658
|
-
alignment: d.AlignmentType.START,
|
|
3659
|
-
style: { paragraph: { indent: { left: 720 * (level + 1), hanging: 360 } } }
|
|
3660
|
-
}))
|
|
3661
|
-
}
|
|
3662
|
-
]
|
|
3663
|
-
},
|
|
3664
|
-
sections: [{ children }]
|
|
3665
|
-
});
|
|
3666
|
-
const blob = await d.Packer.toBlob(doc);
|
|
3667
|
-
return { filename: `${ctx.basename}.docx`, mimeType: DOCX_MIME, blob };
|
|
3668
|
-
};
|
|
3669
|
-
function printHtml(html) {
|
|
3670
|
-
return new Promise((resolve, reject) => {
|
|
3671
|
-
const frame = document.createElement("iframe");
|
|
3672
|
-
frame.setAttribute("aria-hidden", "true");
|
|
3673
|
-
frame.style.cssText = "position:fixed;right:0;bottom:0;width:0;height:0;border:0;";
|
|
3674
|
-
const cleanup = () => setTimeout(() => frame.remove(), 500);
|
|
3675
|
-
frame.onload = () => {
|
|
3676
|
-
try {
|
|
3677
|
-
const win = frame.contentWindow;
|
|
3678
|
-
if (!win) throw new Error("The print frame is unavailable");
|
|
3679
|
-
win.addEventListener("afterprint", cleanup);
|
|
3680
|
-
win.focus();
|
|
3681
|
-
win.print();
|
|
3682
|
-
setTimeout(cleanup, 12e4);
|
|
3683
|
-
resolve();
|
|
3684
|
-
} catch (error) {
|
|
3685
|
-
cleanup();
|
|
3686
|
-
reject(error);
|
|
3687
|
-
}
|
|
3688
|
-
};
|
|
3689
|
-
frame.srcdoc = html;
|
|
3690
|
-
document.body.appendChild(frame);
|
|
3691
104
|
});
|
|
3692
105
|
}
|
|
3693
|
-
var
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
return
|
|
3697
|
-
};
|
|
3698
|
-
var registry = /* @__PURE__ */ new Map([
|
|
3699
|
-
["html", exportHtml],
|
|
3700
|
-
["markdown", exportMarkdown],
|
|
3701
|
-
["txt", exportTxt],
|
|
3702
|
-
["docx", exportDocx],
|
|
3703
|
-
["pdf", exportPdf]
|
|
3704
|
-
]);
|
|
3705
|
-
function registerDocumentExporter(format, exporter) {
|
|
3706
|
-
registry.set(format, exporter);
|
|
106
|
+
var juneLibrary = _chunkGFCROSGQcjs.withDocumentEditor.call(void 0, withChatLayout(_reactui.openuiChatLibrary));
|
|
107
|
+
var defaultRegistry = _chunkGFCROSGQcjs.createComponentRegistry.call(void 0, { base: juneLibrary });
|
|
108
|
+
function registerComponent(components, options) {
|
|
109
|
+
return defaultRegistry.register(components, options);
|
|
3707
110
|
}
|
|
3708
|
-
function
|
|
3709
|
-
return
|
|
111
|
+
function unregisterComponent(name) {
|
|
112
|
+
return defaultRegistry.unregister(name);
|
|
3710
113
|
}
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
}
|
|
114
|
+
|
|
115
|
+
// src/core/june-ui-provider.tsx
|
|
116
|
+
var _react = require('react');
|
|
117
|
+
var _jsxruntime = require('react/jsx-runtime');
|
|
118
|
+
var JuneUIContext = _react.createContext.call(void 0, null);
|
|
119
|
+
function JuneUIProvider({ june, defaults, children }) {
|
|
120
|
+
const value = _react.useMemo.call(void 0, () => ({ june, defaults }), [june, defaults]);
|
|
121
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, JuneUIContext.Provider, { value, children });
|
|
3719
122
|
}
|
|
3720
|
-
function
|
|
3721
|
-
|
|
3722
|
-
const url = URL.createObjectURL(result.blob);
|
|
3723
|
-
const link = document.createElement("a");
|
|
3724
|
-
link.href = url;
|
|
3725
|
-
link.download = result.filename;
|
|
3726
|
-
document.body.appendChild(link);
|
|
3727
|
-
link.click();
|
|
3728
|
-
link.remove();
|
|
3729
|
-
setTimeout(() => URL.revokeObjectURL(url), 1e3);
|
|
123
|
+
function useJuneUIContext() {
|
|
124
|
+
return _react.useContext.call(void 0, JuneUIContext);
|
|
3730
125
|
}
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
new ClipboardItem({
|
|
3741
|
-
"text/html": new Blob([html], { type: "text/html" }),
|
|
3742
|
-
"text/plain": new Blob([text], { type: "text/plain" })
|
|
3743
|
-
})
|
|
3744
|
-
]);
|
|
3745
|
-
return true;
|
|
3746
|
-
}
|
|
3747
|
-
await navigator.clipboard.writeText(text);
|
|
3748
|
-
return true;
|
|
3749
|
-
} catch {
|
|
3750
|
-
return false;
|
|
3751
|
-
}
|
|
126
|
+
|
|
127
|
+
// src/core/june-ui.tsx
|
|
128
|
+
|
|
129
|
+
function JuneUI({ library, june, ...props }) {
|
|
130
|
+
const context = useJuneUIContext();
|
|
131
|
+
const instance = _nullishCoalesce(june, () => ( _optionalChain([context, 'optionalAccess', _ => _.june])));
|
|
132
|
+
const registryLibrary = _chunkGFCROSGQcjs.useRegistryLibrary.call(void 0, _nullishCoalesce(_optionalChain([instance, 'optionalAccess', _2 => _2.registry]), () => ( defaultRegistry)));
|
|
133
|
+
const merged = mergeDefined(_optionalChain([instance, 'optionalAccess', _3 => _3.defaults]), _optionalChain([context, 'optionalAccess', _4 => _4.defaults]), props);
|
|
134
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkGFCROSGQcjs.JuneRenderer, { ...merged, library: _nullishCoalesce(library, () => ( registryLibrary)) });
|
|
3752
135
|
}
|
|
3753
136
|
|
|
3754
|
-
// src/
|
|
3755
|
-
|
|
3756
|
-
|
|
3757
|
-
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
"txt",
|
|
3762
|
-
"docx",
|
|
3763
|
-
"pdf"
|
|
3764
|
-
];
|
|
3765
|
-
|
|
3766
|
-
// src/components/document-editor/document-editor.tsx
|
|
3767
|
-
init_document_utils();
|
|
3768
|
-
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
3769
|
-
var snapshotOf = (r) => ({
|
|
3770
|
-
documentId: r.id,
|
|
3771
|
-
title: r.title,
|
|
3772
|
-
documentType: r.documentType,
|
|
3773
|
-
status: r.status,
|
|
3774
|
-
json: r.json
|
|
3775
|
-
});
|
|
3776
|
-
var SAVE_LABEL = {
|
|
3777
|
-
idle: "",
|
|
3778
|
-
dirty: "Unsaved changes",
|
|
3779
|
-
saving: "Saving\u2026",
|
|
3780
|
-
saved: "Saved",
|
|
3781
|
-
error: "Save failed"
|
|
3782
|
-
};
|
|
3783
|
-
var ZOOM_STEPS = [0.5, 0.67, 0.75, 0.9, 1, 1.1, 1.25, 1.5, 1.75, 2];
|
|
3784
|
-
var stepZoom = (z2, dir) => dir > 0 ? ZOOM_STEPS.find((s) => s > z2 + 1e-3) ?? z2 : [...ZOOM_STEPS].reverse().find((s) => s < z2 - 1e-3) ?? z2;
|
|
3785
|
-
function DocumentEditorImpl(props) {
|
|
3786
|
-
const {
|
|
3787
|
-
documentId,
|
|
3788
|
-
title: titleProp = "Untitled document",
|
|
3789
|
-
content,
|
|
3790
|
-
documentType,
|
|
3791
|
-
status = "draft",
|
|
3792
|
-
editable = true,
|
|
3793
|
-
exportFormats,
|
|
3794
|
-
theme = "auto",
|
|
3795
|
-
className
|
|
3796
|
-
} = props;
|
|
3797
|
-
const ctxOptions = useDocumentOptions();
|
|
3798
|
-
const options = (0, import_react16.useMemo)(() => ({ ...ctxOptions, ...props.options }), [ctxOptions, props.options]);
|
|
3799
|
-
const optionsRef = (0, import_react16.useRef)(options);
|
|
3800
|
-
optionsRef.current = options;
|
|
3801
|
-
const store = (0, import_react16.useMemo)(() => options.store ?? getDefaultDocumentStore(), [options.store]);
|
|
3802
|
-
const instanceId = (0, import_react16.useId)();
|
|
3803
|
-
const { theme: contextTheme } = useJuneTheme();
|
|
3804
|
-
const resolvedTheme = theme === "auto" ? contextTheme : theme;
|
|
3805
|
-
const contentKey = typeof content === "string" ? content : content ? JSON.stringify(content) : "";
|
|
3806
|
-
const parsed = (0, import_react16.useMemo)(() => {
|
|
3807
|
-
if (!contentKey) return { json: null, error: null };
|
|
3808
|
-
try {
|
|
3809
|
-
return { json: parseDocumentContent(contentKey), error: null };
|
|
3810
|
-
} catch (e) {
|
|
3811
|
-
return { json: null, error: toJuneError(e, "DOCUMENT_ERROR") };
|
|
3812
|
-
}
|
|
3813
|
-
}, [contentKey]);
|
|
3814
|
-
(0, import_react16.useEffect)(() => {
|
|
3815
|
-
if (parsed.error) optionsRef.current.onError?.(parsed.error);
|
|
3816
|
-
}, [parsed.error]);
|
|
3817
|
-
const title = useDocumentValue(store, documentId, (r) => r?.title ?? titleProp);
|
|
3818
|
-
const pending = useDocumentValue(store, documentId, (r) => r?.pending ?? null);
|
|
3819
|
-
const words = useDocumentValue(store, documentId, (r) => r ? wordCountOf(r.json) : 0);
|
|
3820
|
-
const recordStatus = useDocumentValue(store, documentId, (r) => r?.status ?? status);
|
|
3821
|
-
const [saveState, setSaveState] = (0, import_react16.useState)("idle");
|
|
3822
|
-
const [notice, setNotice] = (0, import_react16.useState)(null);
|
|
3823
|
-
const [fullscreen, setFullscreen] = (0, import_react16.useState)(false);
|
|
3824
|
-
const [expanded, setExpanded] = (0, import_react16.useState)(true);
|
|
3825
|
-
const [showMarks, setShowMarks] = (0, import_react16.useState)(false);
|
|
3826
|
-
const [layout, setLayout] = (0, import_react16.useState)("page");
|
|
3827
|
-
const [findOpen, setFindOpen] = (0, import_react16.useState)(false);
|
|
3828
|
-
const [zoom, setZoom] = (0, import_react16.useState)(1);
|
|
3829
|
-
const [metrics, setMetrics] = (0, import_react16.useState)({ page: 1, pages: 1 });
|
|
3830
|
-
(0, import_react16.useEffect)(() => {
|
|
3831
|
-
if (!fullscreen || typeof document === "undefined") return;
|
|
3832
|
-
const prev = document.body.style.overflow;
|
|
3833
|
-
document.body.style.overflow = "hidden";
|
|
3834
|
-
return () => {
|
|
3835
|
-
document.body.style.overflow = prev;
|
|
3836
|
-
};
|
|
3837
|
-
}, [fullscreen]);
|
|
3838
|
-
const lastSavedKey = (0, import_react16.useRef)("");
|
|
3839
|
-
const seenRevision = (0, import_react16.useRef)(store.get(documentId)?.revision ?? 0);
|
|
3840
|
-
const readyRef = (0, import_react16.useRef)(false);
|
|
3841
|
-
const flash = (0, import_react16.useCallback)((message) => {
|
|
3842
|
-
setNotice(message);
|
|
3843
|
-
}, []);
|
|
3844
|
-
(0, import_react16.useEffect)(() => {
|
|
3845
|
-
if (!notice) return;
|
|
3846
|
-
const t = setTimeout(() => setNotice(null), 3e3);
|
|
3847
|
-
return () => clearTimeout(t);
|
|
3848
|
-
}, [notice]);
|
|
3849
|
-
const emitChange = (0, import_react16.useCallback)(
|
|
3850
|
-
(source) => {
|
|
3851
|
-
const record = store.get(documentId);
|
|
3852
|
-
if (record) optionsRef.current.onDocumentChange?.({ ...snapshotOf(record), source });
|
|
3853
|
-
},
|
|
3854
|
-
[store, documentId]
|
|
3855
|
-
);
|
|
3856
|
-
const saveRef = (0, import_react16.useRef)(async () => {
|
|
137
|
+
// src/core/create-june-ui.ts
|
|
138
|
+
function createJuneUI(options = {}) {
|
|
139
|
+
const registry = _chunkGFCROSGQcjs.createComponentRegistry.call(void 0, {
|
|
140
|
+
base: _nullishCoalesce(options.baseLibrary, () => ( juneLibrary)),
|
|
141
|
+
components: options.components,
|
|
142
|
+
overrides: options.overrides,
|
|
143
|
+
remove: options.remove
|
|
3857
144
|
});
|
|
3858
|
-
const
|
|
3859
|
-
|
|
3860
|
-
|
|
3861
|
-
|
|
3862
|
-
|
|
3863
|
-
saveRef.current = async () => {
|
|
3864
|
-
const record = store.get(documentId);
|
|
3865
|
-
const onSave = optionsRef.current.onSave;
|
|
3866
|
-
if (!record) return;
|
|
3867
|
-
const key = JSON.stringify([record.title, docKey(record.json)]);
|
|
3868
|
-
if (!onSave) {
|
|
3869
|
-
lastSavedKey.current = key;
|
|
3870
|
-
setSaveState("saved");
|
|
3871
|
-
return;
|
|
3872
|
-
}
|
|
3873
|
-
if (key === lastSavedKey.current) {
|
|
3874
|
-
setSaveState("saved");
|
|
3875
|
-
return;
|
|
3876
|
-
}
|
|
3877
|
-
setSaveState("saving");
|
|
3878
|
-
try {
|
|
3879
|
-
await onSave({
|
|
3880
|
-
...snapshotOf(record),
|
|
3881
|
-
html: docToHtml(record.json),
|
|
3882
|
-
markdown: docToMarkdown(record.json)
|
|
3883
|
-
});
|
|
3884
|
-
lastSavedKey.current = key;
|
|
3885
|
-
const latest = store.get(documentId);
|
|
3886
|
-
const latestKey = latest ? JSON.stringify([latest.title, docKey(latest.json)]) : key;
|
|
3887
|
-
setSaveState(latestKey === key ? "saved" : "dirty");
|
|
3888
|
-
} catch (error) {
|
|
3889
|
-
setSaveState("error");
|
|
3890
|
-
optionsRef.current.onError?.(toJuneError(error, "DOCUMENT_ERROR", "Saving the document failed"));
|
|
3891
|
-
}
|
|
3892
|
-
};
|
|
3893
|
-
const markDirty = (0, import_react16.useCallback)(
|
|
3894
|
-
(userEdit = true) => {
|
|
3895
|
-
if (!optionsRef.current.onSave) {
|
|
3896
|
-
if (userEdit) setSaveState("dirty");
|
|
3897
|
-
return;
|
|
3898
|
-
}
|
|
3899
|
-
setSaveState("dirty");
|
|
3900
|
-
autosave?.();
|
|
145
|
+
const defaults = Object.freeze({ ...options.defaults });
|
|
146
|
+
const instance = {
|
|
147
|
+
registry,
|
|
148
|
+
get library() {
|
|
149
|
+
return registry.library;
|
|
3901
150
|
},
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
const t = setTimeout(() => setSaveState((s) => s === "saved" ? "idle" : s), 2500);
|
|
3907
|
-
return () => clearTimeout(t);
|
|
3908
|
-
}, [saveState, options.onSave]);
|
|
3909
|
-
const [initialJson] = (0, import_react16.useState)(() => store.get(documentId)?.json ?? parsed.json ?? emptyDoc());
|
|
3910
|
-
const extensions = (0, import_react16.useMemo)(() => createDocumentExtensions(), []);
|
|
3911
|
-
const onUpdateRef = (0, import_react16.useRef)(() => {
|
|
3912
|
-
});
|
|
3913
|
-
onUpdateRef.current = (json) => {
|
|
3914
|
-
store.edit(documentId, json, instanceId);
|
|
3915
|
-
emitChange("user");
|
|
3916
|
-
markDirty();
|
|
3917
|
-
};
|
|
3918
|
-
const editor = (0, import_react15.useEditor)({
|
|
3919
|
-
extensions,
|
|
3920
|
-
content: initialJson,
|
|
3921
|
-
editable,
|
|
3922
|
-
immediatelyRender: false,
|
|
3923
|
-
editorProps: {
|
|
3924
|
-
attributes: {
|
|
3925
|
-
class: "june-doc__prose",
|
|
3926
|
-
role: "textbox",
|
|
3927
|
-
"aria-multiline": "true",
|
|
3928
|
-
"aria-label": "Document content"
|
|
3929
|
-
}
|
|
151
|
+
defaults,
|
|
152
|
+
register(components, registerOptions) {
|
|
153
|
+
registry.register(components, registerOptions);
|
|
154
|
+
return instance;
|
|
3930
155
|
},
|
|
3931
|
-
|
|
3932
|
-
});
|
|
3933
|
-
(0, import_react16.useEffect)(() => {
|
|
3934
|
-
if (!editor || editor.isEditable === editable) return;
|
|
3935
|
-
editor.setEditable(editable);
|
|
3936
|
-
}, [editor, editable]);
|
|
3937
|
-
(0, import_react16.useEffect)(() => {
|
|
3938
|
-
if (!parsed.json) return;
|
|
3939
|
-
if (isDocumentEcho(store, documentId, contentKey)) return;
|
|
3940
|
-
const outcome = store.receive({
|
|
3941
|
-
id: documentId,
|
|
3942
|
-
title: titleProp,
|
|
3943
|
-
json: parsed.json,
|
|
3944
|
-
documentType,
|
|
3945
|
-
status
|
|
3946
|
-
});
|
|
3947
|
-
if (outcome === "applied" || outcome === "merged") {
|
|
3948
|
-
emitChange(outcome === "applied" ? "ai" : "merge");
|
|
3949
|
-
markDirty(false);
|
|
3950
|
-
} else if (outcome === "conflict") {
|
|
3951
|
-
const record = store.get(documentId);
|
|
3952
|
-
optionsRef.current.onConflict?.({
|
|
3953
|
-
documentId,
|
|
3954
|
-
title: record?.title ?? titleProp,
|
|
3955
|
-
conflicts: record?.pending?.conflicts ?? 1
|
|
3956
|
-
});
|
|
3957
|
-
}
|
|
3958
|
-
}, [store, documentId, titleProp, parsed.json, documentType, status, emitChange, markDirty]);
|
|
3959
|
-
(0, import_react16.useEffect)(() => {
|
|
3960
|
-
if (!editor) return;
|
|
3961
|
-
const apply = () => {
|
|
3962
|
-
const record = store.get(documentId);
|
|
3963
|
-
if (!record || record.revision === seenRevision.current) return;
|
|
3964
|
-
seenRevision.current = record.revision;
|
|
3965
|
-
if (record.origin === instanceId) return;
|
|
3966
|
-
const { from, to } = editor.state.selection;
|
|
3967
|
-
editor.commands.setContent(record.json, { emitUpdate: false });
|
|
3968
|
-
if (editor.isFocused) {
|
|
3969
|
-
const size = editor.state.doc.content.size;
|
|
3970
|
-
editor.commands.setTextSelection({ from: Math.min(from, size), to: Math.min(to, size) });
|
|
3971
|
-
}
|
|
3972
|
-
};
|
|
3973
|
-
apply();
|
|
3974
|
-
return store.subscribe(apply);
|
|
3975
|
-
}, [editor, store, documentId, instanceId]);
|
|
3976
|
-
(0, import_react16.useEffect)(() => {
|
|
3977
|
-
if (!editor || readyRef.current) return;
|
|
3978
|
-
const record = store.get(documentId);
|
|
3979
|
-
if (!record) return;
|
|
3980
|
-
readyRef.current = true;
|
|
3981
|
-
lastSavedKey.current = JSON.stringify([record.title, docKey(record.json)]);
|
|
3982
|
-
optionsRef.current.onDocumentReady?.(snapshotOf(record));
|
|
3983
|
-
}, [editor, store, documentId, title]);
|
|
3984
|
-
const handleTitle = (value) => {
|
|
3985
|
-
store.setTitle(documentId, value);
|
|
3986
|
-
emitChange("user");
|
|
3987
|
-
markDirty();
|
|
3988
|
-
};
|
|
3989
|
-
const resolve = (choice) => {
|
|
3990
|
-
store.resolve(documentId, choice);
|
|
3991
|
-
if (choice !== "keep") {
|
|
3992
|
-
emitChange(choice === "merge" ? "merge" : "resolve");
|
|
3993
|
-
markDirty();
|
|
3994
|
-
}
|
|
156
|
+
prompt: (promptOptions) => registry.prompt(promptOptions)
|
|
3995
157
|
};
|
|
3996
|
-
|
|
3997
|
-
const record = store.get(documentId);
|
|
3998
|
-
if (!record) return;
|
|
3999
|
-
try {
|
|
4000
|
-
const result = await exportDocument(format, {
|
|
4001
|
-
documentId,
|
|
4002
|
-
title: record.title,
|
|
4003
|
-
json: record.json
|
|
4004
|
-
// always the latest editor content
|
|
4005
|
-
});
|
|
4006
|
-
if (result.blob) downloadResult(result);
|
|
4007
|
-
optionsRef.current.onExport?.({ documentId, format, ...result });
|
|
4008
|
-
} catch (error) {
|
|
4009
|
-
optionsRef.current.onError?.(toJuneError(error, "EXPORT_ERROR"));
|
|
4010
|
-
flash("Export failed");
|
|
4011
|
-
}
|
|
4012
|
-
};
|
|
4013
|
-
const handleCopy = async () => {
|
|
4014
|
-
const record = store.get(documentId);
|
|
4015
|
-
if (!record) return;
|
|
4016
|
-
flash(await copyDocumentToClipboard({ title: record.title, json: record.json }) ? "Copied" : "Copy failed");
|
|
4017
|
-
};
|
|
4018
|
-
const formats = (exportFormats ?? [...ALL_EXPORT_FORMATS]).filter((f) => listDocumentExporters().includes(f));
|
|
4019
|
-
if (parsed.error && !store.get(documentId)) {
|
|
4020
|
-
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "june-doc june-doc--error", "data-theme": resolvedTheme, role: "alert", children: [
|
|
4021
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "june-doc__draft-text", children: "This document could not be displayed." }),
|
|
4022
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("details", { children: [
|
|
4023
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("summary", { children: "Show raw content" }),
|
|
4024
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("pre", { className: "june-doc__raw", children: contentKey })
|
|
4025
|
-
] })
|
|
4026
|
-
] });
|
|
4027
|
-
}
|
|
4028
|
-
if (!editor) return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocumentDraft, { title, state: "loading" });
|
|
4029
|
-
const isDraft = recordStatus === "draft";
|
|
4030
|
-
const classes = ["june-doc", fullscreen ? "june-doc--fullscreen" : "", className ?? ""].filter(Boolean).join(" ");
|
|
4031
|
-
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
4032
|
-
"div",
|
|
4033
|
-
{
|
|
4034
|
-
className: classes,
|
|
4035
|
-
"data-theme": resolvedTheme,
|
|
4036
|
-
"data-status": recordStatus,
|
|
4037
|
-
role: fullscreen ? "dialog" : void 0,
|
|
4038
|
-
"aria-modal": fullscreen || void 0,
|
|
4039
|
-
"aria-label": fullscreen ? title : void 0,
|
|
4040
|
-
onKeyDown: (e) => {
|
|
4041
|
-
const mod = e.ctrlKey || e.metaKey;
|
|
4042
|
-
if (mod && e.key.toLowerCase() === "s" && options.onSave) {
|
|
4043
|
-
e.preventDefault();
|
|
4044
|
-
void saveRef.current();
|
|
4045
|
-
} else if (mod && e.key.toLowerCase() === "f") {
|
|
4046
|
-
e.preventDefault();
|
|
4047
|
-
setFindOpen(true);
|
|
4048
|
-
} else if (e.key === "Escape" && fullscreen && !e.defaultPrevented) {
|
|
4049
|
-
setFullscreen(false);
|
|
4050
|
-
}
|
|
4051
|
-
},
|
|
4052
|
-
children: [
|
|
4053
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
4054
|
-
DocumentHeader,
|
|
4055
|
-
{
|
|
4056
|
-
title,
|
|
4057
|
-
editable,
|
|
4058
|
-
isDraft,
|
|
4059
|
-
fullscreen,
|
|
4060
|
-
onToggleFullscreen: () => setFullscreen((v) => !v),
|
|
4061
|
-
onTitle: handleTitle,
|
|
4062
|
-
exportFormats: formats,
|
|
4063
|
-
canSave: !!options.onSave,
|
|
4064
|
-
showSave: !!options.onSave || editable && saveState !== "idle",
|
|
4065
|
-
saveState,
|
|
4066
|
-
onExport: (f) => void handleExport(f),
|
|
4067
|
-
onCopy: () => void handleCopy(),
|
|
4068
|
-
onSave: () => void saveRef.current()
|
|
4069
|
-
}
|
|
4070
|
-
),
|
|
4071
|
-
pending ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "june-doc__banner", role: "status", children: [
|
|
4072
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { children: [
|
|
4073
|
-
"The assistant suggested changes that overlap your edits (",
|
|
4074
|
-
pending.conflicts,
|
|
4075
|
-
" ",
|
|
4076
|
-
pending.conflicts === 1 ? "section" : "sections",
|
|
4077
|
-
")."
|
|
4078
|
-
] }),
|
|
4079
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { className: "june-doc__banner-actions", children: [
|
|
4080
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: "june-doc__btn", onClick: () => resolve("merge"), children: "Merge, keep my edits" }),
|
|
4081
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: "june-doc__btn", onClick: () => resolve("replace"), children: "Use AI version" }),
|
|
4082
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: "june-doc__btn", onClick: () => resolve("keep"), children: "Keep mine" })
|
|
4083
|
-
] })
|
|
4084
|
-
] }) : null,
|
|
4085
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
4086
|
-
DocumentToolbar,
|
|
4087
|
-
{
|
|
4088
|
-
editor,
|
|
4089
|
-
editable,
|
|
4090
|
-
expanded,
|
|
4091
|
-
onToggleExpanded: () => setExpanded((v) => !v),
|
|
4092
|
-
showMarks,
|
|
4093
|
-
onToggleMarks: () => setShowMarks((v) => !v),
|
|
4094
|
-
layout,
|
|
4095
|
-
onToggleLayout: () => setLayout((v) => v === "page" ? "fluid" : "page"),
|
|
4096
|
-
findOpen,
|
|
4097
|
-
onToggleFind: () => setFindOpen((v) => !v),
|
|
4098
|
-
onNotice: flash
|
|
4099
|
-
}
|
|
4100
|
-
),
|
|
4101
|
-
findOpen ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocumentFindBar, { editor, editable, onClose: () => setFindOpen(false), onNotice: flash }) : null,
|
|
4102
|
-
editable ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocumentBubbleMenu, { editor }) : null,
|
|
4103
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocumentContent, { editor, layout, zoom, showMarks, onMetrics: setMetrics }),
|
|
4104
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "june-doc__footer", children: [
|
|
4105
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "june-doc__stats", children: [
|
|
4106
|
-
layout === "page" ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
|
|
4107
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { children: [
|
|
4108
|
-
"Page ",
|
|
4109
|
-
metrics.page,
|
|
4110
|
-
" of ",
|
|
4111
|
-
metrics.pages
|
|
4112
|
-
] }),
|
|
4113
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "june-doc__stats-sep", "aria-hidden": "true" })
|
|
4114
|
-
] }) : null,
|
|
4115
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { children: [
|
|
4116
|
-
words,
|
|
4117
|
-
" words"
|
|
4118
|
-
] })
|
|
4119
|
-
] }),
|
|
4120
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "june-doc__status", "aria-live": "polite", "data-state": notice ? "notice" : saveState, children: notice ?? SAVE_LABEL[saveState] }),
|
|
4121
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "june-doc__zoom", role: "group", "aria-label": "Zoom", children: [
|
|
4122
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: "june-doc__btn june-doc__btn--icon june-doc__btn--ghost", "aria-label": "Zoom out", disabled: zoom <= ZOOM_STEPS[0], onClick: () => setZoom(stepZoom(zoom, -1)), children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Icon, { name: "minus", size: 14 }) }),
|
|
4123
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("button", { type: "button", className: "june-doc__zoom-value", "aria-label": "Reset zoom", title: "Reset zoom", onClick: () => setZoom(1), children: [
|
|
4124
|
-
Math.round(zoom * 100),
|
|
4125
|
-
"%"
|
|
4126
|
-
] }),
|
|
4127
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: "june-doc__btn june-doc__btn--icon june-doc__btn--ghost", "aria-label": "Zoom in", disabled: zoom >= ZOOM_STEPS[ZOOM_STEPS.length - 1], onClick: () => setZoom(stepZoom(zoom, 1)), children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Icon, { name: "plus", size: 14 }) })
|
|
4128
|
-
] })
|
|
4129
|
-
] })
|
|
4130
|
-
]
|
|
4131
|
-
}
|
|
4132
|
-
);
|
|
158
|
+
return Object.freeze(instance);
|
|
4133
159
|
}
|
|
4134
160
|
|
|
4135
|
-
// src/components/document-editor/document-component.tsx
|
|
4136
|
-
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
4137
|
-
var DOCUMENT_COMPONENT_DESCRIPTION = 'Custom component. An editable document. DocumentEditor(documentId, title, content, documentType?, status?, editable?, exportFormats?). Place it in the root container (Card or Stack). "content" is the full document body as one Markdown string. Reuse documentId when revising the same document. Use it only when the user asks to create or revise a document.';
|
|
4138
|
-
var documentProps = import_v4.z.object({
|
|
4139
|
-
documentId: import_v4.z.string().describe("Stable id. Reuse it when revising the same document."),
|
|
4140
|
-
title: import_v4.z.string().describe("Document title. Do not repeat it as a heading in content."),
|
|
4141
|
-
content: import_v4.z.string().describe("The whole document body as Markdown."),
|
|
4142
|
-
documentType: import_v4.z.string().optional().describe("Kind of document, such as proposal, contract or invoice."),
|
|
4143
|
-
status: import_v4.z.string().optional().describe('Use "draft" for generated documents.'),
|
|
4144
|
-
editable: import_v4.z.boolean().optional().describe("Whether the user can edit. Defaults to true."),
|
|
4145
|
-
exportFormats: import_v4.z.array(import_v4.z.string()).optional().describe("Export formats to offer, such as html, markdown, docx.")
|
|
4146
|
-
});
|
|
4147
|
-
function DocumentEditor(props) {
|
|
4148
|
-
const { isStreaming } = useJuneRuntime();
|
|
4149
|
-
if (props.generating || isStreaming) {
|
|
4150
|
-
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocumentDraft, { title: props.title, state: "drafting" });
|
|
4151
|
-
}
|
|
4152
|
-
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocumentEditorImpl, { ...props });
|
|
4153
|
-
}
|
|
4154
|
-
function OpenUIDocument({ props }) {
|
|
4155
|
-
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
4156
|
-
DocumentEditor,
|
|
4157
|
-
{
|
|
4158
|
-
documentId: props.documentId,
|
|
4159
|
-
title: props.title,
|
|
4160
|
-
content: props.content,
|
|
4161
|
-
documentType: props.documentType,
|
|
4162
|
-
status: props.status,
|
|
4163
|
-
editable: props.editable,
|
|
4164
|
-
exportFormats: props.exportFormats
|
|
4165
|
-
}
|
|
4166
|
-
);
|
|
4167
|
-
}
|
|
4168
|
-
var JuneDocumentEditorComponent = (0, import_react_lang3.defineComponent)({
|
|
4169
|
-
name: "DocumentEditor",
|
|
4170
|
-
description: DOCUMENT_COMPONENT_DESCRIPTION,
|
|
4171
|
-
props: documentProps,
|
|
4172
|
-
component: OpenUIDocument
|
|
4173
|
-
});
|
|
4174
|
-
function withDocumentEditor(library) {
|
|
4175
|
-
try {
|
|
4176
|
-
return library.extend({
|
|
4177
|
-
components: {
|
|
4178
|
-
add: [{ component: JuneDocumentEditorComponent, slots: ["Card"] }]
|
|
4179
|
-
}
|
|
4180
|
-
});
|
|
4181
|
-
} catch {
|
|
4182
|
-
return library.extend({ components: { add: [JuneDocumentEditorComponent] } });
|
|
4183
|
-
}
|
|
4184
|
-
}
|
|
4185
161
|
|
|
4186
|
-
// src/components/document-editor/document-instructions.ts
|
|
4187
|
-
var DEFAULT_TYPES = [
|
|
4188
|
-
"proposal",
|
|
4189
|
-
"report",
|
|
4190
|
-
"email",
|
|
4191
|
-
"letter",
|
|
4192
|
-
"invoice",
|
|
4193
|
-
"contract",
|
|
4194
|
-
"NDA",
|
|
4195
|
-
"memo",
|
|
4196
|
-
"meeting notes"
|
|
4197
|
-
];
|
|
4198
|
-
function getDocumentEditorRules(options = {}) {
|
|
4199
|
-
const name = options.componentName ?? "DocumentEditor";
|
|
4200
|
-
const types = (options.documentTypes ?? DEFAULT_TYPES).join(", ");
|
|
4201
|
-
return [
|
|
4202
|
-
`WHEN TO USE ${name}: use it only when the user asks you to create, draft, write, prepare, generate or revise an editable document (${types}, or similar). Put the finished document inside ${name}.`,
|
|
4203
|
-
`WHEN NOT TO USE ${name}: for explanations ("explain what an NDA is"), factual answers, comparisons, brainstorming and general questions, answer with normal text and the other components. Never open ${name} for those.`,
|
|
4204
|
-
`${name}(documentId, title, content, documentType?, status?, editable?, exportFormats?): "content" is the whole document body as Markdown inside ONE double-quoted string. Write line breaks as \\n and escape double quotes as \\". Supported Markdown: headings (#, ##, ###), paragraphs, **bold**, *italic*, lists, > quotes, [links](https://...), and tables.`,
|
|
4205
|
-
`Do not repeat the title as a heading inside "content"; the title is shown separately. Structure the document with headings, short paragraphs and tables where useful. Keep a professional tone.`,
|
|
4206
|
-
`EDITING: when the user asks to change an existing document (add a section, rewrite a part, change the title), write ${name} again with the SAME documentId and the COMPLETE updated content, starting from the current document text you were given. Copy every unchanged section exactly as it was. Change only what was requested. The app merges your version with the user's own edits.`,
|
|
4207
|
-
`If the user asks for a document but leaves out details, write the document anyway and use clear placeholders such as [CLIENT NAME], [DATE], [AMOUNT]. Do not stop to ask unless the request is impossible to interpret.`,
|
|
4208
|
-
`Never invent legal, financial or business facts, prices, dates, names or figures. Use placeholders instead. Set status to "draft" for generated documents, and for legal or financial documents say in one short sentence outside the component that the document is a draft that should be reviewed by a professional.`,
|
|
4209
|
-
`You may add one short sentence before or after the component. Do not repeat the document text outside the component.`,
|
|
4210
|
-
...options.extraRules ?? []
|
|
4211
|
-
];
|
|
4212
|
-
}
|
|
4213
|
-
function getDocumentEditorInstructions(options = {}) {
|
|
4214
|
-
const rules = getDocumentEditorRules(options);
|
|
4215
|
-
return ["Document drafting:", ...rules.map((rule, i) => `${i + 1}. ${rule}`)].join("\n");
|
|
4216
|
-
}
|
|
4217
|
-
var EXAMPLE_NEW = 'root = Stack([doc])\ndoc = DocumentEditor("business-proposal", "Business Proposal", "## Executive Summary\\n\\nThis proposal outlines [SERVICE] for [CLIENT NAME].\\n\\n## Scope of Work\\n\\n- Discovery\\n- Delivery\\n\\n## Pricing\\n\\n| Item | Cost |\\n| --- | --- |\\n| Discovery | [AMOUNT] |", "proposal", "draft")';
|
|
4218
|
-
var EXAMPLE_EDIT = 'root = Stack([doc])\ndoc = DocumentEditor("business-proposal", "Business Proposal", "## Executive Summary\\n\\nThis proposal outlines [SERVICE] for [CLIENT NAME].\\n\\n## Scope of Work\\n\\n- Discovery\\n- Delivery\\n\\n## Pricing\\n\\n| Item | Cost |\\n| --- | --- |\\n| Discovery | [AMOUNT] |\\n| Delivery | [AMOUNT] |", "proposal", "draft")';
|
|
4219
|
-
function documentPromptOptions(options = {}) {
|
|
4220
|
-
return {
|
|
4221
|
-
additionalRules: getDocumentEditorRules(options),
|
|
4222
|
-
examples: [EXAMPLE_NEW, EXAMPLE_EDIT]
|
|
4223
|
-
};
|
|
4224
|
-
}
|
|
4225
162
|
|
|
4226
|
-
// src/components/document-editor/document-agent.ts
|
|
4227
|
-
var attr = (value) => value.replace(/"/g, """);
|
|
4228
|
-
async function serializeDocumentsForAgent(options = {}) {
|
|
4229
|
-
const store = options.store ?? getDefaultDocumentStore();
|
|
4230
|
-
const { docToMarkdown: docToMarkdown2 } = await Promise.resolve().then(() => (init_document_engine(), document_engine_exports));
|
|
4231
|
-
return store.list().filter((r) => !options.ids || options.ids.includes(r.id)).map(
|
|
4232
|
-
(r) => `<document id="${attr(r.id)}" title="${attr(r.title)}"${r.documentType ? ` type="${attr(r.documentType)}"` : ""}>
|
|
4233
|
-
${docToMarkdown2(r.json)}
|
|
4234
|
-
</document>`
|
|
4235
|
-
).join("\n\n");
|
|
4236
|
-
}
|
|
4237
163
|
|
|
4238
|
-
// src/components/june-library.ts
|
|
4239
|
-
var import_react_ui = require("@openuidev/react-ui");
|
|
4240
|
-
var juneLibrary = withDocumentEditor(import_react_ui.openuiLibrary);
|
|
4241
164
|
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
|
|
4277
|
-
|
|
4278
|
-
|
|
4279
|
-
|
|
4280
|
-
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
|
|
4284
|
-
|
|
4285
|
-
|
|
4286
|
-
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
|
|
4290
|
-
|
|
4291
|
-
|
|
4292
|
-
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
exports.ALL_EXPORT_FORMATS = _chunkGFCROSGQcjs.ALL_EXPORT_FORMATS; exports.ComponentRegistry = _chunkGFCROSGQcjs.ComponentRegistry; exports.DOCUMENT_COMPONENT_DESCRIPTION = _chunkGFCROSGQcjs.DOCUMENT_COMPONENT_DESCRIPTION; exports.DocumentBridge = _chunkGFCROSGQcjs.DocumentBridge; exports.DocumentEditor = _chunkGFCROSGQcjs.DocumentEditor; exports.JuneDocumentContext = _chunkGFCROSGQcjs.JuneDocumentContext; exports.JuneDocumentEditorComponent = _chunkGFCROSGQcjs.JuneDocumentEditorComponent; exports.JuneError = _chunkG6YPSE6Jcjs.JuneError; exports.JuneErrorBoundary = _chunkGFCROSGQcjs.JuneErrorBoundary; exports.JuneRenderer = _chunkGFCROSGQcjs.JuneRenderer; exports.JuneRuntimeContext = _chunkGFCROSGQcjs.JuneRuntimeContext; exports.JuneThemeProvider = _chunkGFCROSGQcjs.JuneThemeProvider; exports.JuneUI = JuneUI; exports.JuneUIProvider = JuneUIProvider; exports.MarkdownText = _chunkGFCROSGQcjs.MarkdownText; exports.ToolApproval = _chunkGFCROSGQcjs.ToolApproval; exports.ToolApprovalList = _chunkGFCROSGQcjs.ToolApprovalList; exports.consumeStream = _chunkGFCROSGQcjs.consumeStream; exports.copyDocumentToClipboard = _chunkGFCROSGQcjs.copyDocumentToClipboard; exports.createActionHandler = _chunkGFCROSGQcjs.createActionHandler; exports.createComponentRegistry = _chunkGFCROSGQcjs.createComponentRegistry; exports.createDocumentStore = _chunkGFCROSGQcjs.createDocumentStore; exports.createJuneLibrary = _chunkGFCROSGQcjs.createJuneLibrary; exports.createJuneUI = createJuneUI; exports.createLangGraphExtractor = _chunkGFCROSGQcjs.createLangGraphExtractor; exports.createTheme = _chunkGFCROSGQcjs.createTheme; exports.darkTheme = _chunkGFCROSGQcjs.darkTheme; exports.defaultParseActionEvent = _chunkGFCROSGQcjs.defaultParseActionEvent; exports.defaultRegistry = defaultRegistry; exports.defaultToolApprovalLabels = _chunkGFCROSGQcjs.defaultToolApprovalLabels; exports.defineComponent = _chunkGFCROSGQcjs.defineComponent; exports.defineJuneAction = _chunkGFCROSGQcjs.defineJuneAction; exports.defineJuneComponent = _chunkGFCROSGQcjs.defineJuneComponent; exports.documentPromptOptions = _chunkGFCROSGQcjs.documentPromptOptions; exports.downloadResult = _chunkGFCROSGQcjs.downloadResult; exports.exportDocument = _chunkGFCROSGQcjs.exportDocument; exports.fetchStream = _chunkGFCROSGQcjs.fetchStream; exports.getDefaultDocumentStore = _chunkGFCROSGQcjs.getDefaultDocumentStore; exports.getDocumentEditorInstructions = _chunkGFCROSGQcjs.getDocumentEditorInstructions; exports.getDocumentEditorRules = _chunkGFCROSGQcjs.getDocumentEditorRules; exports.interruptToApprovalRequests = _chunkGFCROSGQcjs.interruptToApprovalRequests; exports.isDocumentEcho = _chunkGFCROSGQcjs.isDocumentEcho; exports.isJuneComponent = _chunkGFCROSGQcjs.isJuneComponent; exports.isJuneError = _chunkG6YPSE6Jcjs.isJuneError; exports.isThemeSet = _chunkGFCROSGQcjs.isThemeSet; exports.jsonFieldExtractor = _chunkGFCROSGQcjs.jsonFieldExtractor; exports.juneLibrary = juneLibrary; exports.langGraphStreamOptions = _chunkGFCROSGQcjs.langGraphStreamOptions; exports.lightTheme = _chunkGFCROSGQcjs.lightTheme; exports.listDocumentExporters = _chunkGFCROSGQcjs.listDocumentExporters; exports.mergeDocuments = _chunkGFCROSGQcjs.mergeDocuments; exports.messageContentToText = _chunkGFCROSGQcjs.messageContentToText; exports.normalizeProgram = _chunkGFCROSGQcjs.normalizeProgram; exports.readDocumentFromProgram = _chunkGFCROSGQcjs.readDocumentFromProgram; exports.readLangGraphInterrupts = _chunkGFCROSGQcjs.readLangGraphInterrupts; exports.registerComponent = registerComponent; exports.registerDocumentExporter = _chunkGFCROSGQcjs.registerDocumentExporter; exports.rememberDocumentEcho = _chunkGFCROSGQcjs.rememberDocumentEcho; exports.resolveMixedContent = _chunkGFCROSGQcjs.resolveMixedContent; exports.resolveThemeVars = _chunkGFCROSGQcjs.resolveThemeVars; exports.runAction = _chunkGFCROSGQcjs.runAction; exports.serializeDocumentsForAgent = _chunkGFCROSGQcjs.serializeDocumentsForAgent; exports.splitResponse = _chunkGFCROSGQcjs.splitResponse; exports.sseToText = _chunkGFCROSGQcjs.sseToText; exports.toAsyncIterable = _chunkGFCROSGQcjs.toAsyncIterable; exports.toJuneError = _chunkG6YPSE6Jcjs.toJuneError; exports.unregisterComponent = unregisterComponent; exports.updateDocumentInProgram = _chunkGFCROSGQcjs.updateDocumentInProgram; exports.useDocumentBridge = _chunkGFCROSGQcjs.useDocumentBridge; exports.useDocumentOptions = _chunkGFCROSGQcjs.useDocumentOptions; exports.useJuneRuntime = _chunkGFCROSGQcjs.useJuneRuntime; exports.useJuneStream = _chunkGFCROSGQcjs.useJuneStream; exports.useJuneTheme = _chunkGFCROSGQcjs.useJuneTheme; exports.useJuneUIContext = useJuneUIContext; exports.useRegistryLibrary = _chunkGFCROSGQcjs.useRegistryLibrary; exports.useResolvedTheme = _chunkGFCROSGQcjs.useResolvedTheme; exports.useToolApproval = _chunkGFCROSGQcjs.useToolApproval; exports.validateComponentDefinition = _chunkGFCROSGQcjs.validateComponentDefinition; exports.withDocumentEditor = _chunkGFCROSGQcjs.withDocumentEditor;
|