@june-ai/june-ui 0.2.10 → 0.2.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/{chunk-JFIMNFNJ.js → chunk-2TBT4VRQ.js} +162 -54
- package/dist/{chunk-GS4J6OAF.cjs → chunk-TD6GKOUR.cjs} +275 -167
- package/dist/entry-core.cjs +10 -2
- package/dist/entry-core.d.cts +44 -3
- package/dist/entry-core.d.ts +44 -3
- package/dist/entry-core.js +9 -1
- package/dist/index.cjs +15 -7
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +9 -1
- package/dist/june.css +19 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -645,6 +645,7 @@ Any other prop of OpenUI's `Renderer` is forwarded and typed from your installed
|
|
|
645
645
|
| `onError` | `(errors: unknown[]) => void` | — | Raw OpenUI errors (`[]` when cleared). |
|
|
646
646
|
| `onJuneError` | `(error: JuneError) => void` | — | Structured errors. |
|
|
647
647
|
| `documents` | `JuneDocumentOptions` | — | Document store and callbacks. Memoize. |
|
|
648
|
+
| `documentEditor` | `DocumentEditorConfig` | `{ presentation: "inline" }` | Where Edit opens the editor. `"side-panel"` uses `width` (for example `"65%"`). A document's `presentation` argument wins. |
|
|
648
649
|
| `onResponseChange` | `(response, info) => void` | — | Program rewritten with user document edits. |
|
|
649
650
|
| `responseChangeDelay` | `number` | `300` | Debounce in ms. |
|
|
650
651
|
| `loadingFallback` | `ReactNode` | `null` | Streaming, nothing to draw yet. |
|
|
@@ -141,7 +141,7 @@ function OpenUIDevtoolsGate() {
|
|
|
141
141
|
|
|
142
142
|
// src/engine/renderer/june-renderer.tsx
|
|
143
143
|
import { Renderer } from "@openuidev/react-lang";
|
|
144
|
-
import { Fragment, useCallback as useCallback2, useMemo as
|
|
144
|
+
import { Fragment, useCallback as useCallback2, useMemo as useMemo4, useRef as useRef2 } from "react";
|
|
145
145
|
|
|
146
146
|
// src/core/context.ts
|
|
147
147
|
import { createContext as createContext2, useContext as useContext2 } from "react";
|
|
@@ -224,9 +224,16 @@ function createActionHandler(options) {
|
|
|
224
224
|
};
|
|
225
225
|
}
|
|
226
226
|
|
|
227
|
+
// src/features/document-editor/document-bridge.tsx
|
|
228
|
+
import { useMemo as useMemo2 } from "react";
|
|
229
|
+
|
|
227
230
|
// src/features/document-editor/document-context.ts
|
|
228
231
|
import { createContext as createContext3, useContext as useContext3, useSyncExternalStore } from "react";
|
|
229
232
|
var JuneDocumentContext = createContext3({});
|
|
233
|
+
var DocumentEditorConfigContext = createContext3({});
|
|
234
|
+
function useDocumentEditorConfig() {
|
|
235
|
+
return useContext3(DocumentEditorConfigContext);
|
|
236
|
+
}
|
|
230
237
|
function useDocumentOptions() {
|
|
231
238
|
return useContext3(JuneDocumentContext);
|
|
232
239
|
}
|
|
@@ -608,13 +615,20 @@ function useDocumentBridge(options) {
|
|
|
608
615
|
|
|
609
616
|
// src/features/document-editor/document-bridge.tsx
|
|
610
617
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
611
|
-
function DocumentBridge({
|
|
618
|
+
function DocumentBridge({
|
|
619
|
+
children,
|
|
620
|
+
documentEditor,
|
|
621
|
+
...options
|
|
622
|
+
}) {
|
|
612
623
|
const value = useDocumentBridge(options);
|
|
613
|
-
|
|
624
|
+
const presentation = documentEditor?.presentation;
|
|
625
|
+
const width = documentEditor?.width;
|
|
626
|
+
const config = useMemo2(() => ({ presentation, width }), [presentation, width]);
|
|
627
|
+
return /* @__PURE__ */ jsx2(JuneDocumentContext.Provider, { value, children: /* @__PURE__ */ jsx2(DocumentEditorConfigContext.Provider, { value: config, children }) });
|
|
614
628
|
}
|
|
615
629
|
|
|
616
630
|
// src/themes/theme-provider.tsx
|
|
617
|
-
import { useMemo as
|
|
631
|
+
import { useMemo as useMemo3, useSyncExternalStore as useSyncExternalStore2 } from "react";
|
|
618
632
|
|
|
619
633
|
// src/themes/dark.ts
|
|
620
634
|
var darkTheme = {
|
|
@@ -675,7 +689,7 @@ function useResolvedTheme(mode) {
|
|
|
675
689
|
function JuneThemeProvider({ mode, vars, className, style, children }) {
|
|
676
690
|
const explicit = mode !== void 0;
|
|
677
691
|
const resolved = useResolvedTheme(mode ?? "system");
|
|
678
|
-
const mergedStyle =
|
|
692
|
+
const mergedStyle = useMemo3(() => {
|
|
679
693
|
const own = resolveThemeVars(vars, resolved);
|
|
680
694
|
if (!explicit && !own && !style) return void 0;
|
|
681
695
|
const base = explicit ? resolved === "dark" ? darkTheme : lightTheme : void 0;
|
|
@@ -686,7 +700,7 @@ function JuneThemeProvider({ mode, vars, className, style, children }) {
|
|
|
686
700
|
...style
|
|
687
701
|
};
|
|
688
702
|
}, [explicit, resolved, vars, style]);
|
|
689
|
-
const context =
|
|
703
|
+
const context = useMemo3(() => ({ mode: mode ?? "system", theme: resolved }), [mode, resolved]);
|
|
690
704
|
return /* @__PURE__ */ jsx3(JuneContext.Provider, { value: context, children: /* @__PURE__ */ jsx3(
|
|
691
705
|
"div",
|
|
692
706
|
{
|
|
@@ -1320,6 +1334,7 @@ function JuneRenderer(props) {
|
|
|
1320
1334
|
onError,
|
|
1321
1335
|
onJuneError,
|
|
1322
1336
|
documents,
|
|
1337
|
+
documentEditor,
|
|
1323
1338
|
onResponseChange,
|
|
1324
1339
|
responseChangeDelay,
|
|
1325
1340
|
loadingFallback = null,
|
|
@@ -1363,8 +1378,8 @@ function JuneRenderer(props) {
|
|
|
1363
1378
|
);
|
|
1364
1379
|
}, []);
|
|
1365
1380
|
const handleDocumentError = useCallback2((error) => latest.current.onJuneError?.(error), []);
|
|
1366
|
-
const runtime =
|
|
1367
|
-
const content =
|
|
1381
|
+
const runtime = useMemo4(() => ({ isStreaming }), [isStreaming]);
|
|
1382
|
+
const content = useMemo4(
|
|
1368
1383
|
() => resolveMixedContent(response, { mixedContent, isStreaming, repair, markdown: textFormat === "markdown" }),
|
|
1369
1384
|
[response, mixedContent, isStreaming, repair, textFormat]
|
|
1370
1385
|
);
|
|
@@ -1376,6 +1391,7 @@ function JuneRenderer(props) {
|
|
|
1376
1391
|
DocumentBridge,
|
|
1377
1392
|
{
|
|
1378
1393
|
documents,
|
|
1394
|
+
documentEditor,
|
|
1379
1395
|
response,
|
|
1380
1396
|
onResponseChange,
|
|
1381
1397
|
responseChangeDelay,
|
|
@@ -1739,7 +1755,7 @@ function defineJuneAction(definition) {
|
|
|
1739
1755
|
}
|
|
1740
1756
|
|
|
1741
1757
|
// src/features/streaming/use-june-stream.ts
|
|
1742
|
-
import { useCallback as useCallback3, useEffect as useEffect3, useMemo as
|
|
1758
|
+
import { useCallback as useCallback3, useEffect as useEffect3, useMemo as useMemo5, useRef as useRef3, useState } from "react";
|
|
1743
1759
|
|
|
1744
1760
|
// src/features/streaming/stream-handler.ts
|
|
1745
1761
|
function isReadableStream(source) {
|
|
@@ -2002,7 +2018,7 @@ function useJuneStream(options = {}) {
|
|
|
2002
2018
|
},
|
|
2003
2019
|
[clearTimer]
|
|
2004
2020
|
);
|
|
2005
|
-
return
|
|
2021
|
+
return useMemo5(
|
|
2006
2022
|
() => ({ ...state, start, startFetch, abort, reset }),
|
|
2007
2023
|
[state, start, startFetch, abort, reset]
|
|
2008
2024
|
);
|
|
@@ -2031,7 +2047,7 @@ function DocumentDraft({ title, words, state }) {
|
|
|
2031
2047
|
|
|
2032
2048
|
// src/features/document-editor/document-editor.tsx
|
|
2033
2049
|
import { useEditor } from "@tiptap/react";
|
|
2034
|
-
import { useCallback as useCallback4, useEffect as useEffect7, useId, useMemo as
|
|
2050
|
+
import { useCallback as useCallback4, useEffect as useEffect7, useId, useMemo as useMemo6, useRef as useRef8, useState as useState6 } from "react";
|
|
2035
2051
|
|
|
2036
2052
|
// src/features/document-editor/document-bubble.tsx
|
|
2037
2053
|
import { useEditorState as useEditorState2 } from "@tiptap/react";
|
|
@@ -3703,15 +3719,15 @@ function DocumentEditorImpl(props) {
|
|
|
3703
3719
|
className
|
|
3704
3720
|
} = props;
|
|
3705
3721
|
const ctxOptions = useDocumentOptions();
|
|
3706
|
-
const options =
|
|
3722
|
+
const options = useMemo6(() => ({ ...ctxOptions, ...props.options }), [ctxOptions, props.options]);
|
|
3707
3723
|
const optionsRef = useRef8(options);
|
|
3708
3724
|
optionsRef.current = options;
|
|
3709
|
-
const store =
|
|
3725
|
+
const store = useMemo6(() => options.store ?? getDefaultDocumentStore(), [options.store]);
|
|
3710
3726
|
const instanceId = useId();
|
|
3711
3727
|
const { theme: contextTheme } = useJuneTheme();
|
|
3712
3728
|
const resolvedTheme = theme === "auto" ? contextTheme : theme;
|
|
3713
3729
|
const contentKey = typeof content === "string" ? content : content ? JSON.stringify(content) : "";
|
|
3714
|
-
const parsed =
|
|
3730
|
+
const parsed = useMemo6(() => {
|
|
3715
3731
|
if (!contentKey) return { json: null, error: null };
|
|
3716
3732
|
try {
|
|
3717
3733
|
return { json: parseDocumentContent(contentKey), error: null };
|
|
@@ -3763,7 +3779,7 @@ function DocumentEditorImpl(props) {
|
|
|
3763
3779
|
);
|
|
3764
3780
|
const saveRef = useRef8(async () => {
|
|
3765
3781
|
});
|
|
3766
|
-
const autosave =
|
|
3782
|
+
const autosave = useMemo6(() => {
|
|
3767
3783
|
const delay = options.autosaveDelay ?? 1500;
|
|
3768
3784
|
return delay > 0 ? debounce(() => void saveRef.current(), delay) : null;
|
|
3769
3785
|
}, [options.autosaveDelay]);
|
|
@@ -3815,7 +3831,7 @@ function DocumentEditorImpl(props) {
|
|
|
3815
3831
|
return () => clearTimeout(t);
|
|
3816
3832
|
}, [saveState, options.onSave]);
|
|
3817
3833
|
const [initialJson] = useState6(() => store.get(documentId)?.json ?? parsed.json ?? emptyDoc());
|
|
3818
|
-
const extensions =
|
|
3834
|
+
const extensions = useMemo6(() => createDocumentExtensions(), []);
|
|
3819
3835
|
const onUpdateRef = useRef8(() => {
|
|
3820
3836
|
});
|
|
3821
3837
|
onUpdateRef.current = (json) => {
|
|
@@ -4041,52 +4057,155 @@ function DocumentEditorImpl(props) {
|
|
|
4041
4057
|
}
|
|
4042
4058
|
|
|
4043
4059
|
// src/features/document-editor/document-preview.tsx
|
|
4044
|
-
import { useEffect as useEffect8, useMemo as
|
|
4060
|
+
import { useEffect as useEffect8, useMemo as useMemo7, useState as useState7 } from "react";
|
|
4045
4061
|
import { createPortal } from "react-dom";
|
|
4062
|
+
|
|
4063
|
+
// src/features/document-editor/document-presentation.ts
|
|
4064
|
+
function resolveDocumentPresentation(documentPresentation, configured) {
|
|
4065
|
+
if (documentPresentation === "inline" || documentPresentation === "side-panel") return documentPresentation;
|
|
4066
|
+
if (configured === "inline" || configured === "side-panel") return configured;
|
|
4067
|
+
return "inline";
|
|
4068
|
+
}
|
|
4069
|
+
function documentPanelWidth(width) {
|
|
4070
|
+
if (typeof width === "number" && Number.isFinite(width)) return `${width}px`;
|
|
4071
|
+
if (typeof width === "string" && width.trim()) return width.trim();
|
|
4072
|
+
return void 0;
|
|
4073
|
+
}
|
|
4074
|
+
|
|
4075
|
+
// src/features/document-editor/document-preview.tsx
|
|
4046
4076
|
import { Fragment as Fragment5, jsx as jsx17, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
4077
|
+
var FORMAT_LABEL = {
|
|
4078
|
+
docx: "Word document",
|
|
4079
|
+
pdf: "PDF",
|
|
4080
|
+
html: "Web page",
|
|
4081
|
+
markdown: "Markdown",
|
|
4082
|
+
txt: "Plain text"
|
|
4083
|
+
};
|
|
4047
4084
|
function DocumentPreview(props) {
|
|
4048
|
-
const { documentId, title = "Untitled document", content, editable = true } = props;
|
|
4085
|
+
const { documentId, title = "Untitled document", content, editable = true, exportFormats } = props;
|
|
4049
4086
|
const { theme: contextTheme } = useJuneTheme();
|
|
4050
4087
|
const resolvedTheme = props.theme && props.theme !== "auto" ? props.theme : contextTheme;
|
|
4051
4088
|
const ctxOptions = useDocumentOptions();
|
|
4052
|
-
const
|
|
4089
|
+
const editorConfig = useDocumentEditorConfig();
|
|
4090
|
+
const presentation = resolveDocumentPresentation(props.presentation, editorConfig.presentation);
|
|
4091
|
+
const panelWidth = documentPanelWidth(editorConfig.width);
|
|
4092
|
+
const store = useMemo7(() => props.options?.store ?? ctxOptions.store ?? getDefaultDocumentStore(), [props.options?.store, ctxOptions.store]);
|
|
4053
4093
|
const storedJson = useDocumentValue(store, documentId, (record) => record?.json);
|
|
4054
4094
|
const [open, setOpen] = useState7(false);
|
|
4055
4095
|
const [preferStore, setPreferStore] = useState7(false);
|
|
4096
|
+
const [notice, setNotice] = useState7(null);
|
|
4056
4097
|
const contentKey = typeof content === "string" ? content : content ? JSON.stringify(content) : "";
|
|
4098
|
+
const options = props.options ?? ctxOptions;
|
|
4057
4099
|
useEffect8(() => {
|
|
4058
4100
|
setPreferStore(false);
|
|
4059
4101
|
}, [contentKey]);
|
|
4060
|
-
const
|
|
4102
|
+
const doc = useMemo7(() => {
|
|
4061
4103
|
try {
|
|
4062
4104
|
const fromContent = contentKey ? parseDocumentContent(contentKey) : null;
|
|
4063
|
-
|
|
4064
|
-
return doc ? docToHtml(doc) : "";
|
|
4105
|
+
return preferStore && storedJson ? storedJson : fromContent;
|
|
4065
4106
|
} catch {
|
|
4066
|
-
return
|
|
4107
|
+
return null;
|
|
4067
4108
|
}
|
|
4068
4109
|
}, [contentKey, preferStore, storedJson]);
|
|
4110
|
+
const html = useMemo7(() => doc ? docToHtml(doc) : "", [doc]);
|
|
4111
|
+
const formats = (exportFormats ?? [...ALL_EXPORT_FORMATS]).filter((format2) => listDocumentExporters().includes(format2));
|
|
4069
4112
|
useEffect8(() => {
|
|
4070
|
-
if (!
|
|
4113
|
+
if (!notice) return;
|
|
4114
|
+
const timer = setTimeout(() => setNotice(null), 2e3);
|
|
4115
|
+
return () => clearTimeout(timer);
|
|
4116
|
+
}, [notice]);
|
|
4117
|
+
useEffect8(() => {
|
|
4118
|
+
if (!open || presentation !== "side-panel" || typeof document === "undefined") return;
|
|
4071
4119
|
const prev = document.body.style.overflow;
|
|
4072
4120
|
document.body.style.overflow = "hidden";
|
|
4073
4121
|
return () => {
|
|
4074
4122
|
document.body.style.overflow = prev;
|
|
4075
4123
|
};
|
|
4076
|
-
}, [open]);
|
|
4124
|
+
}, [open, presentation]);
|
|
4077
4125
|
const close = () => {
|
|
4078
4126
|
setPreferStore(true);
|
|
4079
4127
|
setOpen(false);
|
|
4080
4128
|
};
|
|
4129
|
+
const handleExport = async (format2) => {
|
|
4130
|
+
if (!doc) return;
|
|
4131
|
+
try {
|
|
4132
|
+
const result = await exportDocument(format2, { documentId, title, json: doc });
|
|
4133
|
+
if (result.blob) downloadResult(result);
|
|
4134
|
+
options.onExport?.({ documentId, format: format2, ...result });
|
|
4135
|
+
} catch (error) {
|
|
4136
|
+
options.onError?.(toJuneError(error, "EXPORT_ERROR"));
|
|
4137
|
+
setNotice("Export failed");
|
|
4138
|
+
}
|
|
4139
|
+
};
|
|
4140
|
+
const handleCopy = async () => {
|
|
4141
|
+
if (!doc) return;
|
|
4142
|
+
setNotice(await copyDocumentToClipboard({ title, json: doc }) ? "Copied" : "Copy failed");
|
|
4143
|
+
};
|
|
4144
|
+
const editor = /* @__PURE__ */ jsx17(
|
|
4145
|
+
DocumentEditorImpl,
|
|
4146
|
+
{
|
|
4147
|
+
documentId: props.documentId,
|
|
4148
|
+
title: props.title,
|
|
4149
|
+
content: props.content,
|
|
4150
|
+
documentType: props.documentType,
|
|
4151
|
+
status: props.status,
|
|
4152
|
+
editable: props.editable,
|
|
4153
|
+
exportFormats: props.exportFormats,
|
|
4154
|
+
theme: props.theme,
|
|
4155
|
+
generating: props.generating,
|
|
4156
|
+
options: props.options
|
|
4157
|
+
}
|
|
4158
|
+
);
|
|
4159
|
+
const closeBar = /* @__PURE__ */ jsx17("div", { className: "june-doc-editor__bar", children: /* @__PURE__ */ jsxs11("button", { type: "button", className: "june-doc__btn june-doc__btn--ghost", "aria-label": "Close document", onClick: close, children: [
|
|
4160
|
+
/* @__PURE__ */ jsx17(Icon, { name: "close", size: 16 }),
|
|
4161
|
+
/* @__PURE__ */ jsx17("span", { children: "Close" })
|
|
4162
|
+
] }) });
|
|
4081
4163
|
return /* @__PURE__ */ jsxs11(Fragment5, { children: [
|
|
4082
4164
|
!open ? /* @__PURE__ */ jsxs11("section", { className: "june-doc june-doc-card", "data-theme": resolvedTheme, "aria-label": title, children: [
|
|
4083
4165
|
/* @__PURE__ */ jsxs11("div", { className: "june-doc-card__bar", children: [
|
|
4084
4166
|
/* @__PURE__ */ jsx17("span", { className: "june-doc-card__title", children: title }),
|
|
4085
|
-
|
|
4167
|
+
/* @__PURE__ */ jsxs11("div", { className: "june-doc-card__actions", children: [
|
|
4168
|
+
notice ? /* @__PURE__ */ jsx17("span", { className: "june-doc-card__notice", children: notice }) : null,
|
|
4169
|
+
/* @__PURE__ */ jsx17(
|
|
4170
|
+
Dropdown,
|
|
4171
|
+
{
|
|
4172
|
+
align: "end",
|
|
4173
|
+
className: "june-doc__menu",
|
|
4174
|
+
trigger: ({ open: menuOpen, toggle }) => /* @__PURE__ */ jsxs11("button", { type: "button", className: "june-doc__btn june-doc__btn--ghost", "aria-label": "Download", "aria-haspopup": "menu", "aria-expanded": menuOpen, onClick: toggle, children: [
|
|
4175
|
+
/* @__PURE__ */ jsx17(Icon, { name: "download", size: 16 }),
|
|
4176
|
+
/* @__PURE__ */ jsx17("span", { children: "Download" })
|
|
4177
|
+
] }),
|
|
4178
|
+
children: (dismiss) => /* @__PURE__ */ jsx17("div", { role: "menu", "aria-label": "Download options", children: formats.map((format2) => /* @__PURE__ */ jsx17(
|
|
4179
|
+
"button",
|
|
4180
|
+
{
|
|
4181
|
+
type: "button",
|
|
4182
|
+
role: "menuitem",
|
|
4183
|
+
className: "june-doc__menu-item",
|
|
4184
|
+
onClick: () => {
|
|
4185
|
+
dismiss();
|
|
4186
|
+
void handleExport(format2);
|
|
4187
|
+
},
|
|
4188
|
+
children: /* @__PURE__ */ jsx17("span", { className: "june-doc__menu-label", children: FORMAT_LABEL[format2] ?? format2.toUpperCase() })
|
|
4189
|
+
},
|
|
4190
|
+
format2
|
|
4191
|
+
)) })
|
|
4192
|
+
}
|
|
4193
|
+
),
|
|
4194
|
+
/* @__PURE__ */ jsx17("button", { type: "button", className: "june-doc__btn june-doc__btn--icon june-doc__btn--ghost", "aria-label": "Copy document", title: "Copy", onClick: () => void handleCopy(), children: /* @__PURE__ */ jsx17(Icon, { name: "copy", size: 16 }) }),
|
|
4195
|
+
editable ? /* @__PURE__ */ jsx17("button", { type: "button", className: "june-doc__btn june-doc__btn--icon june-doc__btn--ghost", "aria-label": "Edit document", title: "Edit", onClick: () => setOpen(true), children: /* @__PURE__ */ jsx17(Icon, { name: "pencil", size: 16 }) }) : null
|
|
4196
|
+
] })
|
|
4086
4197
|
] }),
|
|
4087
4198
|
/* @__PURE__ */ jsx17("div", { className: "june-doc-card__canvas", children: /* @__PURE__ */ jsx17("div", { className: "june-doc-card__sheet", children: /* @__PURE__ */ jsx17("div", { className: "june-doc__prose", dangerouslySetInnerHTML: { __html: html } }) }) })
|
|
4088
4199
|
] }) : null,
|
|
4089
|
-
open &&
|
|
4200
|
+
open && presentation === "inline" ? /* @__PURE__ */ jsxs11("section", { className: "june-doc june-doc-inline", "data-theme": resolvedTheme, "aria-label": title, onKeyDown: (event) => {
|
|
4201
|
+
if (event.key !== "Escape" || event.defaultPrevented) return;
|
|
4202
|
+
if (event.currentTarget.querySelector(".june-doc--fullscreen")) return;
|
|
4203
|
+
close();
|
|
4204
|
+
}, children: [
|
|
4205
|
+
closeBar,
|
|
4206
|
+
editor
|
|
4207
|
+
] }) : null,
|
|
4208
|
+
open && presentation === "side-panel" && typeof document !== "undefined" ? createPortal(
|
|
4090
4209
|
/* @__PURE__ */ jsx17("div", { className: "june-doc-modal", "data-theme": resolvedTheme, onMouseDown: close, children: /* @__PURE__ */ jsxs11(
|
|
4091
4210
|
"div",
|
|
4092
4211
|
{
|
|
@@ -4096,6 +4215,7 @@ function DocumentPreview(props) {
|
|
|
4096
4215
|
"aria-label": title,
|
|
4097
4216
|
tabIndex: -1,
|
|
4098
4217
|
"data-theme": resolvedTheme,
|
|
4218
|
+
style: panelWidth ? { width: panelWidth, maxWidth: "100vw" } : void 0,
|
|
4099
4219
|
onMouseDown: (event) => event.stopPropagation(),
|
|
4100
4220
|
onKeyDown: (event) => {
|
|
4101
4221
|
if (event.key !== "Escape" || event.defaultPrevented) return;
|
|
@@ -4103,25 +4223,8 @@ function DocumentPreview(props) {
|
|
|
4103
4223
|
close();
|
|
4104
4224
|
},
|
|
4105
4225
|
children: [
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
/* @__PURE__ */ jsx17("span", { children: "Close" })
|
|
4109
|
-
] }) }),
|
|
4110
|
-
/* @__PURE__ */ jsx17("div", { className: "june-doc-modal__body", children: /* @__PURE__ */ jsx17(
|
|
4111
|
-
DocumentEditorImpl,
|
|
4112
|
-
{
|
|
4113
|
-
documentId: props.documentId,
|
|
4114
|
-
title: props.title,
|
|
4115
|
-
content: props.content,
|
|
4116
|
-
documentType: props.documentType,
|
|
4117
|
-
status: props.status,
|
|
4118
|
-
editable: props.editable,
|
|
4119
|
-
exportFormats: props.exportFormats,
|
|
4120
|
-
theme: props.theme,
|
|
4121
|
-
generating: props.generating,
|
|
4122
|
-
options: props.options
|
|
4123
|
-
}
|
|
4124
|
-
) })
|
|
4226
|
+
closeBar,
|
|
4227
|
+
/* @__PURE__ */ jsx17("div", { className: "june-doc-modal__body", children: editor })
|
|
4125
4228
|
]
|
|
4126
4229
|
}
|
|
4127
4230
|
) }),
|
|
@@ -4132,7 +4235,7 @@ function DocumentPreview(props) {
|
|
|
4132
4235
|
|
|
4133
4236
|
// src/features/document-editor/document-component.tsx
|
|
4134
4237
|
import { jsx as jsx18 } from "react/jsx-runtime";
|
|
4135
|
-
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.';
|
|
4238
|
+
var DOCUMENT_COMPONENT_DESCRIPTION = 'Custom component. An editable document. DocumentEditor(documentId, title, content, documentType?, status?, editable?, exportFormats?, presentation?). 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. presentation is "inline" or "side-panel"; omit it to use the app default.';
|
|
4136
4239
|
var documentProps = z.object({
|
|
4137
4240
|
documentId: z.string().describe("Stable id. Reuse it when revising the same document."),
|
|
4138
4241
|
title: z.string().describe("Document title. Do not repeat it as a heading in content."),
|
|
@@ -4140,7 +4243,8 @@ var documentProps = z.object({
|
|
|
4140
4243
|
documentType: z.string().optional().describe("Kind of document, such as proposal, contract or invoice."),
|
|
4141
4244
|
status: z.string().optional().describe('Use "draft" for generated documents.'),
|
|
4142
4245
|
editable: z.boolean().optional().describe("Whether the user can edit. Defaults to true."),
|
|
4143
|
-
exportFormats: z.array(z.string()).optional().describe("Export formats to offer, such as html, markdown, docx.")
|
|
4246
|
+
exportFormats: z.array(z.string()).optional().describe("Export formats to offer, such as html, markdown, docx."),
|
|
4247
|
+
presentation: z.enum(["inline", "side-panel"]).optional().describe('Where Edit opens the editor: "inline" in the chat, or "side-panel". Omit to use the app default.')
|
|
4144
4248
|
});
|
|
4145
4249
|
function DocumentEditor(props) {
|
|
4146
4250
|
const { isStreaming } = useJuneRuntime();
|
|
@@ -4158,10 +4262,10 @@ function OpenUIDocument({ props }) {
|
|
|
4158
4262
|
documentType: props.documentType,
|
|
4159
4263
|
status: props.status,
|
|
4160
4264
|
editable: props.editable,
|
|
4161
|
-
exportFormats: props.exportFormats
|
|
4265
|
+
exportFormats: props.exportFormats,
|
|
4266
|
+
presentation: props.presentation
|
|
4162
4267
|
};
|
|
4163
4268
|
if (isStreaming) return /* @__PURE__ */ jsx18(DocumentDraft, { title: props.title, state: "drafting" });
|
|
4164
|
-
if (props.editable === false) return /* @__PURE__ */ jsx18(DocumentEditor, { ...shared });
|
|
4165
4269
|
return /* @__PURE__ */ jsx18(DocumentPreview, { ...shared });
|
|
4166
4270
|
}
|
|
4167
4271
|
var JuneDocumentEditorComponent = defineComponent3({
|
|
@@ -4200,7 +4304,7 @@ function getDocumentEditorRules(options = {}) {
|
|
|
4200
4304
|
return [
|
|
4201
4305
|
`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}.`,
|
|
4202
4306
|
`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.`,
|
|
4203
|
-
`${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.`,
|
|
4307
|
+
`${name}(documentId, title, content, documentType?, status?, editable?, exportFormats?, presentation?): "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. presentation is optional: "inline" or "side-panel". Omit it to use the app default.`,
|
|
4204
4308
|
`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.`,
|
|
4205
4309
|
`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.`,
|
|
4206
4310
|
`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.`,
|
|
@@ -4365,7 +4469,7 @@ function ToolApprovalList({ approvals, pendingOnly = false, renderItem, labels,
|
|
|
4365
4469
|
}
|
|
4366
4470
|
|
|
4367
4471
|
// src/features/tool-approval/use-tool-approval.ts
|
|
4368
|
-
import { useCallback as useCallback5, useEffect as useEffect9, useMemo as
|
|
4472
|
+
import { useCallback as useCallback5, useEffect as useEffect9, useMemo as useMemo8, useRef as useRef9, useState as useState9 } from "react";
|
|
4369
4473
|
var counter = 0;
|
|
4370
4474
|
var nextId = () => `june-approval-${++counter}`;
|
|
4371
4475
|
function useToolApproval() {
|
|
@@ -4421,8 +4525,8 @@ function useToolApproval() {
|
|
|
4421
4525
|
map.clear();
|
|
4422
4526
|
};
|
|
4423
4527
|
}, []);
|
|
4424
|
-
const pending =
|
|
4425
|
-
return
|
|
4528
|
+
const pending = useMemo8(() => entries.filter((e) => e.status === "pending"), [entries]);
|
|
4529
|
+
return useMemo8(
|
|
4426
4530
|
() => ({ entries, pending, request, decide, setStatus, dismiss, confirmAction }),
|
|
4427
4531
|
[entries, pending, request, decide, setStatus, dismiss, confirmAction]
|
|
4428
4532
|
);
|
|
@@ -4526,6 +4630,8 @@ export {
|
|
|
4526
4630
|
runAction,
|
|
4527
4631
|
createActionHandler,
|
|
4528
4632
|
JuneDocumentContext,
|
|
4633
|
+
DocumentEditorConfigContext,
|
|
4634
|
+
useDocumentEditorConfig,
|
|
4529
4635
|
useDocumentOptions,
|
|
4530
4636
|
mergeDocuments,
|
|
4531
4637
|
createDocumentStore,
|
|
@@ -4570,6 +4676,8 @@ export {
|
|
|
4570
4676
|
downloadResult,
|
|
4571
4677
|
copyDocumentToClipboard,
|
|
4572
4678
|
ALL_EXPORT_FORMATS,
|
|
4679
|
+
resolveDocumentPresentation,
|
|
4680
|
+
documentPanelWidth,
|
|
4573
4681
|
DOCUMENT_COMPONENT_DESCRIPTION,
|
|
4574
4682
|
DocumentEditor,
|
|
4575
4683
|
JuneDocumentEditorComponent,
|