@june-ai/june-ui 0.2.8 → 0.2.10
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 +5 -0
- package/dist/{chunk-3NVO336D.cjs → chunk-GS4J6OAF.cjs} +477 -201
- package/dist/{chunk-H26BMR5S.js → chunk-JFIMNFNJ.js} +375 -99
- package/dist/entry-core.cjs +2 -2
- package/dist/entry-core.js +1 -1
- package/dist/index.cjs +24 -7
- package/dist/index.d.cts +2 -3
- package/dist/index.d.ts +2 -3
- package/dist/index.js +20 -3
- package/dist/june.css +41 -0
- package/docs/troubleshooting.md +1 -1
- package/package.json +1 -1
|
@@ -22,49 +22,120 @@ import {
|
|
|
22
22
|
} from "./chunk-27XM6EVX.js";
|
|
23
23
|
|
|
24
24
|
// src/engine/openui-devtools.tsx
|
|
25
|
+
import { useEffect } from "react";
|
|
25
26
|
import { OpenUIDevtools } from "@openuidev/devtools";
|
|
26
27
|
import { jsx } from "react/jsx-runtime";
|
|
27
28
|
var AUTO_MOUNT_FLAG = /* @__PURE__ */ Symbol.for("openui.devtools.autoMount");
|
|
28
29
|
var BLOCKED_BY_JUNE = /* @__PURE__ */ Symbol.for("openui.devtools.blockedByJune");
|
|
30
|
+
var AUTO_MOUNT_HOST = "data-openui-devtools-auto-mount";
|
|
29
31
|
var flags = globalThis;
|
|
30
|
-
var scheduledByOpenUI = flags[AUTO_MOUNT_FLAG] === true && flags[BLOCKED_BY_JUNE] !== true;
|
|
31
32
|
flags[AUTO_MOUNT_FLAG] = true;
|
|
32
33
|
flags[BLOCKED_BY_JUNE] = true;
|
|
33
34
|
var DEVTOOLS_BUNDLE = "https://cdn.jsdelivr.net/npm/@openuidev/devtools@0/dist/devtools.browser.js";
|
|
34
35
|
var ALIAS_CACHE_MS = 5 * 60 * 1e3;
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
};
|
|
36
|
+
var LOCAL_WIDGET = "../../node_modules/@openuidev/devtools/dist/devtools.browser.js";
|
|
37
|
+
var loadFromCdn = () => {
|
|
38
38
|
const url = `${DEVTOOLS_BUNDLE}?t=${Math.floor(Date.now() / ALIAS_CACHE_MS)}`;
|
|
39
|
-
|
|
40
|
-
let unmount = () => {
|
|
41
|
-
cancelled = true;
|
|
42
|
-
};
|
|
43
|
-
void Promise.all([
|
|
39
|
+
return Promise.all([
|
|
44
40
|
import(
|
|
41
|
+
/* webpackIgnore: true */
|
|
45
42
|
/* @vite-ignore */
|
|
46
43
|
url
|
|
47
44
|
),
|
|
48
45
|
import("react"),
|
|
49
46
|
import("react-dom"),
|
|
50
47
|
import("react-dom/client")
|
|
51
|
-
])
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
48
|
+
]);
|
|
49
|
+
};
|
|
50
|
+
var loadInstalledOrCdn = async () => {
|
|
51
|
+
const [react, reactDom, reactDomClient] = await Promise.all([
|
|
52
|
+
import("react"),
|
|
53
|
+
import("react-dom"),
|
|
54
|
+
import("react-dom/client")
|
|
55
|
+
]);
|
|
56
|
+
try {
|
|
57
|
+
const devtools = await import(LOCAL_WIDGET);
|
|
58
|
+
return [devtools, react, reactDom, reactDomClient];
|
|
59
|
+
} catch {
|
|
60
|
+
const [devtools] = await loadFromCdn();
|
|
61
|
+
return [devtools, react, reactDom, reactDomClient];
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
function nodeEnv() {
|
|
65
|
+
try {
|
|
66
|
+
return process.env.NODE_ENV;
|
|
67
|
+
} catch {
|
|
68
|
+
return void 0;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
var isAutoMountHost = (node) => node instanceof Element && node.hasAttribute(AUTO_MOUNT_HOST);
|
|
72
|
+
function createDevtoolsGuard(load = loadInstalledOrCdn) {
|
|
73
|
+
let started = false;
|
|
74
|
+
let claimed = false;
|
|
75
|
+
let observer = null;
|
|
76
|
+
let unmount = null;
|
|
77
|
+
let stopped = false;
|
|
78
|
+
const claim = () => {
|
|
79
|
+
if (claimed) return;
|
|
80
|
+
claimed = true;
|
|
81
|
+
observer?.disconnect();
|
|
82
|
+
observer = null;
|
|
83
|
+
load().then(([devtools, react, reactDom, reactDomClient]) => {
|
|
84
|
+
if (stopped) return;
|
|
85
|
+
unmount = devtools.mountOpenUIDevtools({
|
|
86
|
+
React: react,
|
|
87
|
+
ReactDOM: reactDom,
|
|
88
|
+
ReactDOMClient: reactDomClient,
|
|
89
|
+
loadReactLang: () => import("@openuidev/react-lang"),
|
|
90
|
+
props: { enabled: false }
|
|
91
|
+
});
|
|
92
|
+
}).catch(() => {
|
|
59
93
|
});
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
|
|
94
|
+
};
|
|
95
|
+
const watch = () => {
|
|
96
|
+
const body = document.body;
|
|
97
|
+
if (!body) return;
|
|
98
|
+
if (Array.from(body.children).some(isAutoMountHost)) {
|
|
99
|
+
claim();
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (typeof MutationObserver === "undefined") return;
|
|
103
|
+
observer = new MutationObserver((records) => {
|
|
104
|
+
if (records.some((r) => Array.from(r.addedNodes).some(isAutoMountHost))) claim();
|
|
105
|
+
});
|
|
106
|
+
observer.observe(body, { childList: true });
|
|
107
|
+
};
|
|
108
|
+
return {
|
|
109
|
+
/** Starts watching (browser only). Safe to call many times. */
|
|
110
|
+
start() {
|
|
111
|
+
if (started || typeof document === "undefined") return;
|
|
112
|
+
started = true;
|
|
113
|
+
if (document.body) watch();
|
|
114
|
+
else document.addEventListener("DOMContentLoaded", watch, { once: true });
|
|
115
|
+
},
|
|
116
|
+
/** True once the disabled widget has been requested. */
|
|
117
|
+
get claimed() {
|
|
118
|
+
return claimed;
|
|
119
|
+
},
|
|
120
|
+
/** Stops watching and removes the disabled widget (tests, teardown). */
|
|
121
|
+
stop() {
|
|
122
|
+
stopped = true;
|
|
123
|
+
observer?.disconnect();
|
|
124
|
+
observer = null;
|
|
125
|
+
unmount?.();
|
|
126
|
+
unmount = null;
|
|
127
|
+
}
|
|
128
|
+
};
|
|
63
129
|
}
|
|
64
|
-
|
|
65
|
-
|
|
130
|
+
var guard = createDevtoolsGuard();
|
|
131
|
+
function hideOpenUIDevtools() {
|
|
132
|
+
if (nodeEnv() === "development") guard.start();
|
|
66
133
|
}
|
|
134
|
+
hideOpenUIDevtools();
|
|
67
135
|
function OpenUIDevtoolsGate() {
|
|
136
|
+
useEffect(() => {
|
|
137
|
+
hideOpenUIDevtools();
|
|
138
|
+
}, []);
|
|
68
139
|
return /* @__PURE__ */ jsx(OpenUIDevtools, { enabled: false });
|
|
69
140
|
}
|
|
70
141
|
|
|
@@ -165,7 +236,7 @@ function useDocumentValue(store, id, selector) {
|
|
|
165
236
|
}
|
|
166
237
|
|
|
167
238
|
// src/features/document-editor/use-document-bridge.ts
|
|
168
|
-
import { useCallback, useEffect, useMemo, useRef } from "react";
|
|
239
|
+
import { useCallback, useEffect as useEffect2, useMemo, useRef } from "react";
|
|
169
240
|
|
|
170
241
|
// src/features/document-editor/document-merge.ts
|
|
171
242
|
var MAX_CELLS = 4e6;
|
|
@@ -483,7 +554,7 @@ function useDocumentBridge(options) {
|
|
|
483
554
|
const latest = useRef({ onResponseChange, responseChangeDelay, response, onJuneError });
|
|
484
555
|
latest.current = { onResponseChange, responseChangeDelay, response, onJuneError };
|
|
485
556
|
const timersRef = useRef(/* @__PURE__ */ new Map());
|
|
486
|
-
|
|
557
|
+
useEffect2(() => {
|
|
487
558
|
const timers = timersRef.current;
|
|
488
559
|
return () => {
|
|
489
560
|
timers.forEach(clearTimeout);
|
|
@@ -652,8 +723,10 @@ var ATTACHABLE = /* @__PURE__ */ new Set([
|
|
|
652
723
|
"ImageGallery",
|
|
653
724
|
"InlineHeader",
|
|
654
725
|
"LineChart",
|
|
726
|
+
"FollowUpBlock",
|
|
655
727
|
"ListBlock",
|
|
656
728
|
"MarkDownRenderer",
|
|
729
|
+
"SectionBlock",
|
|
657
730
|
"Modal",
|
|
658
731
|
"OverviewCardBlock",
|
|
659
732
|
"PieChart",
|
|
@@ -674,7 +747,7 @@ var ATTACHABLE = /* @__PURE__ */ new Set([
|
|
|
674
747
|
]);
|
|
675
748
|
function normalizeProgram(source) {
|
|
676
749
|
const rewritten = rewriteCalls(source);
|
|
677
|
-
return attachOrphans(rewritten);
|
|
750
|
+
return liftStackRoot(attachOrphans(rewritten));
|
|
678
751
|
}
|
|
679
752
|
function rewriteCalls(source) {
|
|
680
753
|
let out = "";
|
|
@@ -818,7 +891,7 @@ function attachOrphans(source) {
|
|
|
818
891
|
if (orphans.length === 0) return source;
|
|
819
892
|
const names = orphans.map((stmt) => stmt.name);
|
|
820
893
|
const root = stmts.find((stmt) => stmt.name === "root");
|
|
821
|
-
if (!root) return `root =
|
|
894
|
+
if (!root) return `root = Card([${names.join(", ")}])
|
|
822
895
|
${text}`;
|
|
823
896
|
const rawRhs = text.slice(root.rhsStart, root.end);
|
|
824
897
|
const lead = /^\s*/.exec(rawRhs)?.[0] ?? "";
|
|
@@ -827,10 +900,22 @@ ${text}`;
|
|
|
827
900
|
return text.slice(0, root.rhsStart) + lead + spliced + text.slice(root.end);
|
|
828
901
|
}
|
|
829
902
|
const body = fresh(new Set(stmts.map((stmt) => stmt.name)), "rootBody");
|
|
830
|
-
const wrapped = `root =
|
|
903
|
+
const wrapped = `root = Card([${body}, ${names.join(", ")}])
|
|
831
904
|
${body} = ${rawRhs.trim()}`;
|
|
832
905
|
return text.slice(0, root.start) + wrapped + text.slice(root.end);
|
|
833
906
|
}
|
|
907
|
+
function liftStackRoot(source) {
|
|
908
|
+
const stmts = parseStatements(source);
|
|
909
|
+
if (!stmts) return source;
|
|
910
|
+
const root = stmts.find((stmt) => stmt.name === "root");
|
|
911
|
+
if (!root) return source;
|
|
912
|
+
const rhs = source.slice(root.rhsStart, root.end).trim();
|
|
913
|
+
if (!/^Stack\s*\(/.test(rhs)) return source;
|
|
914
|
+
const body = fresh(new Set(stmts.map((stmt) => stmt.name)), "rootLayout");
|
|
915
|
+
const wrapped = `root = Card([${body}])
|
|
916
|
+
${body} = ${rhs}`;
|
|
917
|
+
return source.slice(0, root.start) + wrapped + source.slice(root.end);
|
|
918
|
+
}
|
|
834
919
|
function spliceFirstArray(rhs, names) {
|
|
835
920
|
const match = /^([A-Za-z_]\w*)\s*\(/.exec(rhs);
|
|
836
921
|
if (!match || match[1] !== "Stack" && match[1] !== "Card") return null;
|
|
@@ -971,7 +1056,7 @@ var STATEMENT_START = /^\$?[A-Za-z_]\w*\s*=/;
|
|
|
971
1056
|
var PENDING_IDENTIFIER = /^\s*\$?[A-Za-z_]\w*\s*$/;
|
|
972
1057
|
var FENCE = /^(`{3,})\s*([\w-]*)/;
|
|
973
1058
|
var OPENUI_FENCE_LANGS = /* @__PURE__ */ new Set(["", "openui", "openui-lang", "openuilang"]);
|
|
974
|
-
function scan(line, state) {
|
|
1059
|
+
function scan(line, state, preserveQuote = false) {
|
|
975
1060
|
for (let i = 0; i < line.length; i++) {
|
|
976
1061
|
const ch = line[i];
|
|
977
1062
|
if (state.quote) {
|
|
@@ -985,7 +1070,95 @@ function scan(line, state) {
|
|
|
985
1070
|
state.depth = Math.max(0, state.depth - 1);
|
|
986
1071
|
}
|
|
987
1072
|
}
|
|
988
|
-
state.quote = null;
|
|
1073
|
+
if (!preserveQuote) state.quote = null;
|
|
1074
|
+
}
|
|
1075
|
+
function quoteClosesLater(lines, from, state) {
|
|
1076
|
+
const probe = { depth: state.depth, quote: state.quote };
|
|
1077
|
+
for (let i = from; i < lines.length; i++) {
|
|
1078
|
+
const line = lines[i];
|
|
1079
|
+
if (probe.depth === 0 && STATEMENT_START.test(line.trim())) return false;
|
|
1080
|
+
scan(line, probe, true);
|
|
1081
|
+
if (!probe.quote) return true;
|
|
1082
|
+
}
|
|
1083
|
+
return false;
|
|
1084
|
+
}
|
|
1085
|
+
function decodeLangString(raw) {
|
|
1086
|
+
let out = "";
|
|
1087
|
+
for (let i = 0; i < raw.length; i++) {
|
|
1088
|
+
const ch = raw[i];
|
|
1089
|
+
if (ch === "\\" && i + 1 < raw.length) {
|
|
1090
|
+
const next = raw[i + 1];
|
|
1091
|
+
out += next === "n" ? "\n" : next === "t" ? " " : next === "r" ? "\r" : next === "b" ? "\b" : next === "f" ? "\f" : next;
|
|
1092
|
+
i++;
|
|
1093
|
+
continue;
|
|
1094
|
+
}
|
|
1095
|
+
out += ch;
|
|
1096
|
+
}
|
|
1097
|
+
return out.replace(/\r/g, "");
|
|
1098
|
+
}
|
|
1099
|
+
function foldMultilineStrings(source) {
|
|
1100
|
+
let out = "";
|
|
1101
|
+
let i = 0;
|
|
1102
|
+
while (i < source.length) {
|
|
1103
|
+
if (source.startsWith('"""', i)) {
|
|
1104
|
+
const end = source.indexOf('"""', i + 3);
|
|
1105
|
+
if (end < 0) {
|
|
1106
|
+
const nl = source.indexOf("\n", i);
|
|
1107
|
+
if (nl < 0) {
|
|
1108
|
+
out += source.slice(i);
|
|
1109
|
+
break;
|
|
1110
|
+
}
|
|
1111
|
+
out += source.slice(i, nl + 1);
|
|
1112
|
+
i = nl + 1;
|
|
1113
|
+
continue;
|
|
1114
|
+
}
|
|
1115
|
+
out += JSON.stringify(source.slice(i + 3, end).replace(/\r/g, ""));
|
|
1116
|
+
i = end + 3;
|
|
1117
|
+
continue;
|
|
1118
|
+
}
|
|
1119
|
+
if (source[i] !== '"') {
|
|
1120
|
+
out += source[i];
|
|
1121
|
+
i++;
|
|
1122
|
+
continue;
|
|
1123
|
+
}
|
|
1124
|
+
let j = i + 1;
|
|
1125
|
+
let closed = false;
|
|
1126
|
+
let hasNewline = false;
|
|
1127
|
+
while (j < source.length) {
|
|
1128
|
+
const ch = source[j];
|
|
1129
|
+
if (ch === "\\") {
|
|
1130
|
+
j += 2;
|
|
1131
|
+
continue;
|
|
1132
|
+
}
|
|
1133
|
+
if (ch === "\n") {
|
|
1134
|
+
if (STATEMENT_START.test(source.slice(j + 1))) break;
|
|
1135
|
+
hasNewline = true;
|
|
1136
|
+
}
|
|
1137
|
+
if (ch === '"') {
|
|
1138
|
+
closed = true;
|
|
1139
|
+
break;
|
|
1140
|
+
}
|
|
1141
|
+
j++;
|
|
1142
|
+
}
|
|
1143
|
+
if (!closed) {
|
|
1144
|
+
const nl = source.indexOf("\n", i);
|
|
1145
|
+
if (nl < 0) {
|
|
1146
|
+
out += source.slice(i);
|
|
1147
|
+
break;
|
|
1148
|
+
}
|
|
1149
|
+
out += source.slice(i, nl + 1);
|
|
1150
|
+
i = nl + 1;
|
|
1151
|
+
continue;
|
|
1152
|
+
}
|
|
1153
|
+
if (!hasNewline) {
|
|
1154
|
+
out += source.slice(i, j + 1);
|
|
1155
|
+
i = j + 1;
|
|
1156
|
+
continue;
|
|
1157
|
+
}
|
|
1158
|
+
out += JSON.stringify(decodeLangString(source.slice(i + 1, j)));
|
|
1159
|
+
i = j + 1;
|
|
1160
|
+
}
|
|
1161
|
+
return out;
|
|
989
1162
|
}
|
|
990
1163
|
function splitResponse(source, options = {}) {
|
|
991
1164
|
const markdown = options.markdown === true;
|
|
@@ -1007,8 +1180,15 @@ function splitResponse(source, options = {}) {
|
|
|
1007
1180
|
text = [];
|
|
1008
1181
|
if (joined) (seenUi ? after : before).push(joined);
|
|
1009
1182
|
};
|
|
1010
|
-
|
|
1183
|
+
const lines = input.split(/\r?\n/);
|
|
1184
|
+
for (let index = 0; index < lines.length; index++) {
|
|
1185
|
+
const line = lines[index];
|
|
1011
1186
|
const trimmed = line.trim();
|
|
1187
|
+
if (state.quote) {
|
|
1188
|
+
ui.push(line);
|
|
1189
|
+
scan(line, state, true);
|
|
1190
|
+
continue;
|
|
1191
|
+
}
|
|
1012
1192
|
if (codeFence !== null) {
|
|
1013
1193
|
text.push(line);
|
|
1014
1194
|
if (trimmed.startsWith(codeFence)) {
|
|
@@ -1037,7 +1217,8 @@ function splitResponse(source, options = {}) {
|
|
|
1037
1217
|
flushText();
|
|
1038
1218
|
seenUi = true;
|
|
1039
1219
|
ui.push(line);
|
|
1040
|
-
scan(line, state);
|
|
1220
|
+
scan(line, state, true);
|
|
1221
|
+
if (state.quote && !quoteClosesLater(lines, index + 1, state)) state.quote = null;
|
|
1041
1222
|
continue;
|
|
1042
1223
|
}
|
|
1043
1224
|
if (trimmed === "") {
|
|
@@ -1049,7 +1230,7 @@ function splitResponse(source, options = {}) {
|
|
|
1049
1230
|
flushText();
|
|
1050
1231
|
return {
|
|
1051
1232
|
before,
|
|
1052
|
-
ui: ui.join("\n"),
|
|
1233
|
+
ui: foldMultilineStrings(ui.join("\n")),
|
|
1053
1234
|
after,
|
|
1054
1235
|
pure: !sawFence && before.length === 0 && after.length === 0
|
|
1055
1236
|
};
|
|
@@ -1059,7 +1240,7 @@ function splitResponse(source, options = {}) {
|
|
|
1059
1240
|
function resolveMixedContent(response, options = {}) {
|
|
1060
1241
|
const { mixedContent = true, isStreaming = false, repair = true, markdown = false } = options;
|
|
1061
1242
|
const parts = mixedContent && response ? splitResponse(response, { streaming: isStreaming, markdown }) : null;
|
|
1062
|
-
const raw = parts && !parts.pure ? parts.ui : response;
|
|
1243
|
+
const raw = parts && !parts.pure ? parts.ui : typeof response === "string" ? foldMultilineStrings(response) : response;
|
|
1063
1244
|
const ui = !repair || !mixedContent || isStreaming || typeof raw !== "string" || raw.length === 0 ? raw : normalizeProgram(raw);
|
|
1064
1245
|
const before = parts?.before ?? [];
|
|
1065
1246
|
const after = parts?.after ?? [];
|
|
@@ -1558,7 +1739,7 @@ function defineJuneAction(definition) {
|
|
|
1558
1739
|
}
|
|
1559
1740
|
|
|
1560
1741
|
// src/features/streaming/use-june-stream.ts
|
|
1561
|
-
import { useCallback as useCallback3, useEffect as
|
|
1742
|
+
import { useCallback as useCallback3, useEffect as useEffect3, useMemo as useMemo4, useRef as useRef3, useState } from "react";
|
|
1562
1743
|
|
|
1563
1744
|
// src/features/streaming/stream-handler.ts
|
|
1564
1745
|
function isReadableStream(source) {
|
|
@@ -1813,7 +1994,7 @@ function useJuneStream(options = {}) {
|
|
|
1813
1994
|
clearTimer();
|
|
1814
1995
|
setState(INITIAL);
|
|
1815
1996
|
}, [clearTimer]);
|
|
1816
|
-
|
|
1997
|
+
useEffect3(
|
|
1817
1998
|
() => () => {
|
|
1818
1999
|
runIdRef.current++;
|
|
1819
2000
|
controllerRef.current?.abort();
|
|
@@ -1850,7 +2031,7 @@ function DocumentDraft({ title, words, state }) {
|
|
|
1850
2031
|
|
|
1851
2032
|
// src/features/document-editor/document-editor.tsx
|
|
1852
2033
|
import { useEditor } from "@tiptap/react";
|
|
1853
|
-
import { useCallback as useCallback4, useEffect as
|
|
2034
|
+
import { useCallback as useCallback4, useEffect as useEffect7, useId, useMemo as useMemo5, useRef as useRef8, useState as useState6 } from "react";
|
|
1854
2035
|
|
|
1855
2036
|
// src/features/document-editor/document-bubble.tsx
|
|
1856
2037
|
import { useEditorState as useEditorState2 } from "@tiptap/react";
|
|
@@ -2030,6 +2211,10 @@ var PATHS = {
|
|
|
2030
2211
|
/* @__PURE__ */ jsx8("path", { d: "M18 6 6 18" }),
|
|
2031
2212
|
/* @__PURE__ */ jsx8("path", { d: "m6 6 12 12" })
|
|
2032
2213
|
] }),
|
|
2214
|
+
pencil: /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
2215
|
+
/* @__PURE__ */ jsx8("path", { d: "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z" }),
|
|
2216
|
+
/* @__PURE__ */ jsx8("path", { d: "m15 5 4 4" })
|
|
2217
|
+
] }),
|
|
2033
2218
|
maximize: /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
2034
2219
|
/* @__PURE__ */ jsx8("path", { d: "M8 3H5a2 2 0 0 0-2 2v3" }),
|
|
2035
2220
|
/* @__PURE__ */ jsx8("path", { d: "M21 8V5a2 2 0 0 0-2-2h-3" }),
|
|
@@ -2082,12 +2267,12 @@ function Icon({ name, size = 16 }) {
|
|
|
2082
2267
|
}
|
|
2083
2268
|
|
|
2084
2269
|
// src/features/document-editor/document-popover.tsx
|
|
2085
|
-
import { useEffect as
|
|
2270
|
+
import { useEffect as useEffect4, useRef as useRef4, useState as useState2 } from "react";
|
|
2086
2271
|
import { jsx as jsx9, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
2087
2272
|
function Dropdown({ trigger, children, align = "start", className, onOpen }) {
|
|
2088
2273
|
const [open, setOpen] = useState2(false);
|
|
2089
2274
|
const anchor = useRef4(null);
|
|
2090
|
-
|
|
2275
|
+
useEffect4(() => {
|
|
2091
2276
|
if (!open) return;
|
|
2092
2277
|
const onDown = (e) => {
|
|
2093
2278
|
if (anchor.current && !anchor.current.contains(e.target)) setOpen(false);
|
|
@@ -2707,13 +2892,13 @@ function DocumentBubbleMenu({ editor }) {
|
|
|
2707
2892
|
|
|
2708
2893
|
// src/features/document-editor/document-content.tsx
|
|
2709
2894
|
import { EditorContent } from "@tiptap/react";
|
|
2710
|
-
import { useEffect as
|
|
2895
|
+
import { useEffect as useEffect5, useLayoutEffect, useRef as useRef6, useState as useState4 } from "react";
|
|
2711
2896
|
import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
2712
2897
|
var PAGE_WIDTH = 794;
|
|
2713
2898
|
var PAGE_HEIGHT = 1123;
|
|
2714
2899
|
var PAGE_GAP = 28;
|
|
2715
2900
|
var CANVAS_PAD_X = 24;
|
|
2716
|
-
var useIsoLayoutEffect = typeof window === "undefined" ?
|
|
2901
|
+
var useIsoLayoutEffect = typeof window === "undefined" ? useEffect5 : useLayoutEffect;
|
|
2717
2902
|
function geometry(width) {
|
|
2718
2903
|
const ratio = width / PAGE_WIDTH;
|
|
2719
2904
|
const height = Math.round(PAGE_HEIGHT * ratio);
|
|
@@ -2749,7 +2934,7 @@ function DocumentContent({ editor, layout = "page", zoom = 1, showMarks = false,
|
|
|
2749
2934
|
ro.observe(c);
|
|
2750
2935
|
return () => ro.disconnect();
|
|
2751
2936
|
}, []);
|
|
2752
|
-
|
|
2937
|
+
useEffect5(() => {
|
|
2753
2938
|
if (!editor) return;
|
|
2754
2939
|
setPaginationConfig(editor, {
|
|
2755
2940
|
enabled: paged,
|
|
@@ -2759,7 +2944,7 @@ function DocumentContent({ editor, layout = "page", zoom = 1, showMarks = false,
|
|
|
2759
2944
|
padBottom: g.padY
|
|
2760
2945
|
});
|
|
2761
2946
|
}, [editor, paged, g.height, g.padY, width]);
|
|
2762
|
-
|
|
2947
|
+
useEffect5(() => {
|
|
2763
2948
|
const c = canvas.current;
|
|
2764
2949
|
const s = sheet.current;
|
|
2765
2950
|
if (!editor || !c || !s) return;
|
|
@@ -2815,7 +3000,7 @@ function DocumentContent({ editor, layout = "page", zoom = 1, showMarks = false,
|
|
|
2815
3000
|
|
|
2816
3001
|
// src/features/document-editor/document-findbar.tsx
|
|
2817
3002
|
import { useEditorState as useEditorState3 } from "@tiptap/react";
|
|
2818
|
-
import { useEffect as
|
|
3003
|
+
import { useEffect as useEffect6, useRef as useRef7, useState as useState5 } from "react";
|
|
2819
3004
|
import { Fragment as Fragment3, jsx as jsx13, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
2820
3005
|
function DocumentFindBar({ editor, editable, onClose, onNotice }) {
|
|
2821
3006
|
const [term, setTerm] = useState5(() => {
|
|
@@ -2832,14 +3017,14 @@ function DocumentFindBar({ editor, editable, onClose, onNotice }) {
|
|
|
2832
3017
|
return { count: s?.matches.length ?? 0, current: s?.current ?? -1 };
|
|
2833
3018
|
}
|
|
2834
3019
|
});
|
|
2835
|
-
|
|
3020
|
+
useEffect6(() => {
|
|
2836
3021
|
input.current?.focus();
|
|
2837
3022
|
input.current?.select();
|
|
2838
3023
|
}, []);
|
|
2839
|
-
|
|
3024
|
+
useEffect6(() => {
|
|
2840
3025
|
setSearch(editor, { term, caseSensitive, current: 0 });
|
|
2841
3026
|
}, [editor, term, caseSensitive]);
|
|
2842
|
-
|
|
3027
|
+
useEffect6(() => () => {
|
|
2843
3028
|
if (!editor.isDestroyed) setSearch(editor, { term: "" });
|
|
2844
3029
|
}, [editor]);
|
|
2845
3030
|
const count = info?.count ?? 0;
|
|
@@ -3534,7 +3719,7 @@ function DocumentEditorImpl(props) {
|
|
|
3534
3719
|
return { json: null, error: toJuneError(e, "DOCUMENT_ERROR") };
|
|
3535
3720
|
}
|
|
3536
3721
|
}, [contentKey]);
|
|
3537
|
-
|
|
3722
|
+
useEffect7(() => {
|
|
3538
3723
|
if (parsed.error) optionsRef.current.onError?.(parsed.error);
|
|
3539
3724
|
}, [parsed.error]);
|
|
3540
3725
|
const title = useDocumentValue(store, documentId, (r) => r?.title ?? titleProp);
|
|
@@ -3550,7 +3735,7 @@ function DocumentEditorImpl(props) {
|
|
|
3550
3735
|
const [findOpen, setFindOpen] = useState6(false);
|
|
3551
3736
|
const [zoom, setZoom] = useState6(1);
|
|
3552
3737
|
const [metrics, setMetrics] = useState6({ page: 1, pages: 1 });
|
|
3553
|
-
|
|
3738
|
+
useEffect7(() => {
|
|
3554
3739
|
if (!fullscreen || typeof document === "undefined") return;
|
|
3555
3740
|
const prev = document.body.style.overflow;
|
|
3556
3741
|
document.body.style.overflow = "hidden";
|
|
@@ -3564,7 +3749,7 @@ function DocumentEditorImpl(props) {
|
|
|
3564
3749
|
const flash = useCallback4((message) => {
|
|
3565
3750
|
setNotice(message);
|
|
3566
3751
|
}, []);
|
|
3567
|
-
|
|
3752
|
+
useEffect7(() => {
|
|
3568
3753
|
if (!notice) return;
|
|
3569
3754
|
const t = setTimeout(() => setNotice(null), 3e3);
|
|
3570
3755
|
return () => clearTimeout(t);
|
|
@@ -3582,7 +3767,7 @@ function DocumentEditorImpl(props) {
|
|
|
3582
3767
|
const delay = options.autosaveDelay ?? 1500;
|
|
3583
3768
|
return delay > 0 ? debounce(() => void saveRef.current(), delay) : null;
|
|
3584
3769
|
}, [options.autosaveDelay]);
|
|
3585
|
-
|
|
3770
|
+
useEffect7(() => () => autosave?.flush(), [autosave]);
|
|
3586
3771
|
saveRef.current = async () => {
|
|
3587
3772
|
const record = store.get(documentId);
|
|
3588
3773
|
const onSave = optionsRef.current.onSave;
|
|
@@ -3624,7 +3809,7 @@ function DocumentEditorImpl(props) {
|
|
|
3624
3809
|
},
|
|
3625
3810
|
[autosave]
|
|
3626
3811
|
);
|
|
3627
|
-
|
|
3812
|
+
useEffect7(() => {
|
|
3628
3813
|
if (saveState !== "saved" || options.onSave) return;
|
|
3629
3814
|
const t = setTimeout(() => setSaveState((s) => s === "saved" ? "idle" : s), 2500);
|
|
3630
3815
|
return () => clearTimeout(t);
|
|
@@ -3653,11 +3838,11 @@ function DocumentEditorImpl(props) {
|
|
|
3653
3838
|
},
|
|
3654
3839
|
onUpdate: ({ editor: ed }) => onUpdateRef.current(ed.getJSON())
|
|
3655
3840
|
});
|
|
3656
|
-
|
|
3841
|
+
useEffect7(() => {
|
|
3657
3842
|
if (!editor || editor.isEditable === editable) return;
|
|
3658
3843
|
editor.setEditable(editable);
|
|
3659
3844
|
}, [editor, editable]);
|
|
3660
|
-
|
|
3845
|
+
useEffect7(() => {
|
|
3661
3846
|
if (!parsed.json) return;
|
|
3662
3847
|
if (isDocumentEcho(store, documentId, contentKey)) return;
|
|
3663
3848
|
const outcome = store.receive({
|
|
@@ -3679,7 +3864,7 @@ function DocumentEditorImpl(props) {
|
|
|
3679
3864
|
});
|
|
3680
3865
|
}
|
|
3681
3866
|
}, [store, documentId, titleProp, parsed.json, documentType, status, emitChange, markDirty]);
|
|
3682
|
-
|
|
3867
|
+
useEffect7(() => {
|
|
3683
3868
|
if (!editor) return;
|
|
3684
3869
|
const apply = () => {
|
|
3685
3870
|
const record = store.get(documentId);
|
|
@@ -3696,7 +3881,7 @@ function DocumentEditorImpl(props) {
|
|
|
3696
3881
|
apply();
|
|
3697
3882
|
return store.subscribe(apply);
|
|
3698
3883
|
}, [editor, store, documentId, instanceId]);
|
|
3699
|
-
|
|
3884
|
+
useEffect7(() => {
|
|
3700
3885
|
if (!editor || readyRef.current) return;
|
|
3701
3886
|
const record = store.get(documentId);
|
|
3702
3887
|
if (!record) return;
|
|
@@ -3855,8 +4040,98 @@ function DocumentEditorImpl(props) {
|
|
|
3855
4040
|
);
|
|
3856
4041
|
}
|
|
3857
4042
|
|
|
4043
|
+
// src/features/document-editor/document-preview.tsx
|
|
4044
|
+
import { useEffect as useEffect8, useMemo as useMemo6, useState as useState7 } from "react";
|
|
4045
|
+
import { createPortal } from "react-dom";
|
|
4046
|
+
import { Fragment as Fragment5, jsx as jsx17, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
4047
|
+
function DocumentPreview(props) {
|
|
4048
|
+
const { documentId, title = "Untitled document", content, editable = true } = props;
|
|
4049
|
+
const { theme: contextTheme } = useJuneTheme();
|
|
4050
|
+
const resolvedTheme = props.theme && props.theme !== "auto" ? props.theme : contextTheme;
|
|
4051
|
+
const ctxOptions = useDocumentOptions();
|
|
4052
|
+
const store = useMemo6(() => props.options?.store ?? ctxOptions.store ?? getDefaultDocumentStore(), [props.options?.store, ctxOptions.store]);
|
|
4053
|
+
const storedJson = useDocumentValue(store, documentId, (record) => record?.json);
|
|
4054
|
+
const [open, setOpen] = useState7(false);
|
|
4055
|
+
const [preferStore, setPreferStore] = useState7(false);
|
|
4056
|
+
const contentKey = typeof content === "string" ? content : content ? JSON.stringify(content) : "";
|
|
4057
|
+
useEffect8(() => {
|
|
4058
|
+
setPreferStore(false);
|
|
4059
|
+
}, [contentKey]);
|
|
4060
|
+
const html = useMemo6(() => {
|
|
4061
|
+
try {
|
|
4062
|
+
const fromContent = contentKey ? parseDocumentContent(contentKey) : null;
|
|
4063
|
+
const doc = preferStore && storedJson ? storedJson : fromContent;
|
|
4064
|
+
return doc ? docToHtml(doc) : "";
|
|
4065
|
+
} catch {
|
|
4066
|
+
return "";
|
|
4067
|
+
}
|
|
4068
|
+
}, [contentKey, preferStore, storedJson]);
|
|
4069
|
+
useEffect8(() => {
|
|
4070
|
+
if (!open || typeof document === "undefined") return;
|
|
4071
|
+
const prev = document.body.style.overflow;
|
|
4072
|
+
document.body.style.overflow = "hidden";
|
|
4073
|
+
return () => {
|
|
4074
|
+
document.body.style.overflow = prev;
|
|
4075
|
+
};
|
|
4076
|
+
}, [open]);
|
|
4077
|
+
const close = () => {
|
|
4078
|
+
setPreferStore(true);
|
|
4079
|
+
setOpen(false);
|
|
4080
|
+
};
|
|
4081
|
+
return /* @__PURE__ */ jsxs11(Fragment5, { children: [
|
|
4082
|
+
!open ? /* @__PURE__ */ jsxs11("section", { className: "june-doc june-doc-card", "data-theme": resolvedTheme, "aria-label": title, children: [
|
|
4083
|
+
/* @__PURE__ */ jsxs11("div", { className: "june-doc-card__bar", children: [
|
|
4084
|
+
/* @__PURE__ */ jsx17("span", { className: "june-doc-card__title", children: title }),
|
|
4085
|
+
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
|
|
4086
|
+
] }),
|
|
4087
|
+
/* @__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
|
+
] }) : null,
|
|
4089
|
+
open && typeof document !== "undefined" ? createPortal(
|
|
4090
|
+
/* @__PURE__ */ jsx17("div", { className: "june-doc-modal", "data-theme": resolvedTheme, onMouseDown: close, children: /* @__PURE__ */ jsxs11(
|
|
4091
|
+
"div",
|
|
4092
|
+
{
|
|
4093
|
+
className: "june-doc june-doc-modal__panel",
|
|
4094
|
+
role: "dialog",
|
|
4095
|
+
"aria-modal": "true",
|
|
4096
|
+
"aria-label": title,
|
|
4097
|
+
tabIndex: -1,
|
|
4098
|
+
"data-theme": resolvedTheme,
|
|
4099
|
+
onMouseDown: (event) => event.stopPropagation(),
|
|
4100
|
+
onKeyDown: (event) => {
|
|
4101
|
+
if (event.key !== "Escape" || event.defaultPrevented) return;
|
|
4102
|
+
if (event.currentTarget.querySelector(".june-doc--fullscreen")) return;
|
|
4103
|
+
close();
|
|
4104
|
+
},
|
|
4105
|
+
children: [
|
|
4106
|
+
/* @__PURE__ */ jsx17("div", { className: "june-doc-modal__bar", children: /* @__PURE__ */ jsxs11("button", { type: "button", className: "june-doc__btn june-doc__btn--ghost", "aria-label": "Close document", onClick: close, children: [
|
|
4107
|
+
/* @__PURE__ */ jsx17(Icon, { name: "close", size: 16 }),
|
|
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
|
+
) })
|
|
4125
|
+
]
|
|
4126
|
+
}
|
|
4127
|
+
) }),
|
|
4128
|
+
document.body
|
|
4129
|
+
) : null
|
|
4130
|
+
] });
|
|
4131
|
+
}
|
|
4132
|
+
|
|
3858
4133
|
// src/features/document-editor/document-component.tsx
|
|
3859
|
-
import { jsx as
|
|
4134
|
+
import { jsx as jsx18 } from "react/jsx-runtime";
|
|
3860
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.';
|
|
3861
4136
|
var documentProps = z.object({
|
|
3862
4137
|
documentId: z.string().describe("Stable id. Reuse it when revising the same document."),
|
|
@@ -3870,23 +4145,24 @@ var documentProps = z.object({
|
|
|
3870
4145
|
function DocumentEditor(props) {
|
|
3871
4146
|
const { isStreaming } = useJuneRuntime();
|
|
3872
4147
|
if (props.generating || isStreaming) {
|
|
3873
|
-
return /* @__PURE__ */
|
|
4148
|
+
return /* @__PURE__ */ jsx18(DocumentDraft, { title: props.title, state: "drafting" });
|
|
3874
4149
|
}
|
|
3875
|
-
return /* @__PURE__ */
|
|
4150
|
+
return /* @__PURE__ */ jsx18(DocumentEditorImpl, { ...props });
|
|
3876
4151
|
}
|
|
3877
4152
|
function OpenUIDocument({ props }) {
|
|
3878
|
-
|
|
3879
|
-
|
|
3880
|
-
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
|
|
3884
|
-
|
|
3885
|
-
|
|
3886
|
-
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
);
|
|
4153
|
+
const { isStreaming } = useJuneRuntime();
|
|
4154
|
+
const shared = {
|
|
4155
|
+
documentId: props.documentId,
|
|
4156
|
+
title: props.title,
|
|
4157
|
+
content: props.content,
|
|
4158
|
+
documentType: props.documentType,
|
|
4159
|
+
status: props.status,
|
|
4160
|
+
editable: props.editable,
|
|
4161
|
+
exportFormats: props.exportFormats
|
|
4162
|
+
};
|
|
4163
|
+
if (isStreaming) return /* @__PURE__ */ jsx18(DocumentDraft, { title: props.title, state: "drafting" });
|
|
4164
|
+
if (props.editable === false) return /* @__PURE__ */ jsx18(DocumentEditor, { ...shared });
|
|
4165
|
+
return /* @__PURE__ */ jsx18(DocumentPreview, { ...shared });
|
|
3890
4166
|
}
|
|
3891
4167
|
var JuneDocumentEditorComponent = defineComponent3({
|
|
3892
4168
|
name: "DocumentEditor",
|
|
@@ -3937,8 +4213,8 @@ function getDocumentEditorInstructions(options = {}) {
|
|
|
3937
4213
|
const rules = getDocumentEditorRules(options);
|
|
3938
4214
|
return ["Document drafting:", ...rules.map((rule, i) => `${i + 1}. ${rule}`)].join("\n");
|
|
3939
4215
|
}
|
|
3940
|
-
var EXAMPLE_NEW = 'root =
|
|
3941
|
-
var EXAMPLE_EDIT = 'root =
|
|
4216
|
+
var EXAMPLE_NEW = 'root = Card([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")';
|
|
4217
|
+
var EXAMPLE_EDIT = 'root = Card([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")';
|
|
3942
4218
|
function documentPromptOptions(options = {}) {
|
|
3943
4219
|
return {
|
|
3944
4220
|
additionalRules: getDocumentEditorRules(options),
|
|
@@ -3959,8 +4235,8 @@ ${docToMarkdown2(r.json)}
|
|
|
3959
4235
|
}
|
|
3960
4236
|
|
|
3961
4237
|
// src/features/tool-approval/tool-approval.tsx
|
|
3962
|
-
import { useId as useId2, useState as
|
|
3963
|
-
import { Fragment as
|
|
4238
|
+
import { useId as useId2, useState as useState8 } from "react";
|
|
4239
|
+
import { Fragment as Fragment6, jsx as jsx19, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
3964
4240
|
var defaultToolApprovalLabels = {
|
|
3965
4241
|
approve: "Approve",
|
|
3966
4242
|
reject: "Reject",
|
|
@@ -3998,8 +4274,8 @@ function ToolApproval({
|
|
|
3998
4274
|
}) {
|
|
3999
4275
|
const labels = { ...defaultToolApprovalLabels, ...labelOverrides };
|
|
4000
4276
|
const options = request.options?.length ? request.options : ["approve", "reject"];
|
|
4001
|
-
const [draft, setDraft] =
|
|
4002
|
-
const [draftError, setDraftError] =
|
|
4277
|
+
const [draft, setDraft] = useState8(null);
|
|
4278
|
+
const [draftError, setDraftError] = useState8(null);
|
|
4003
4279
|
const titleId = useId2();
|
|
4004
4280
|
const pending = status === "pending";
|
|
4005
4281
|
const decide = (decision) => {
|
|
@@ -4017,7 +4293,7 @@ function ToolApproval({
|
|
|
4017
4293
|
setDraft(null);
|
|
4018
4294
|
decide({ choice: "edit", editedArguments });
|
|
4019
4295
|
};
|
|
4020
|
-
return /* @__PURE__ */
|
|
4296
|
+
return /* @__PURE__ */ jsxs12(
|
|
4021
4297
|
"section",
|
|
4022
4298
|
{
|
|
4023
4299
|
className: className ? `june-approval ${className}` : "june-approval",
|
|
@@ -4025,14 +4301,14 @@ function ToolApproval({
|
|
|
4025
4301
|
"data-status": status,
|
|
4026
4302
|
"data-risk": request.risk,
|
|
4027
4303
|
children: [
|
|
4028
|
-
/* @__PURE__ */
|
|
4029
|
-
/* @__PURE__ */
|
|
4030
|
-
request.risk && /* @__PURE__ */
|
|
4031
|
-
request.sideEffect && /* @__PURE__ */
|
|
4304
|
+
/* @__PURE__ */ jsxs12("header", { className: "june-approval__header", children: [
|
|
4305
|
+
/* @__PURE__ */ jsx19("strong", { id: titleId, className: "june-approval__tool", children: request.tool }),
|
|
4306
|
+
request.risk && /* @__PURE__ */ jsx19("span", { className: "june-approval__badge", "data-risk": request.risk, children: labels.risk(request.risk) }),
|
|
4307
|
+
request.sideEffect && /* @__PURE__ */ jsx19("span", { className: "june-approval__badge", children: labels.sideEffect[request.sideEffect] })
|
|
4032
4308
|
] }),
|
|
4033
|
-
request.description && /* @__PURE__ */
|
|
4034
|
-
draft !== null ? /* @__PURE__ */
|
|
4035
|
-
/* @__PURE__ */
|
|
4309
|
+
request.description && /* @__PURE__ */ jsx19("p", { className: "june-approval__description", children: request.description }),
|
|
4310
|
+
draft !== null ? /* @__PURE__ */ jsxs12("div", { className: "june-approval__edit", children: [
|
|
4311
|
+
/* @__PURE__ */ jsx19(
|
|
4036
4312
|
"textarea",
|
|
4037
4313
|
{
|
|
4038
4314
|
"aria-label": labels.edit,
|
|
@@ -4043,12 +4319,12 @@ function ToolApproval({
|
|
|
4043
4319
|
spellCheck: false
|
|
4044
4320
|
}
|
|
4045
4321
|
),
|
|
4046
|
-
draftError && /* @__PURE__ */
|
|
4047
|
-
] }) : hasArguments(request.arguments) ? renderArguments ? renderArguments(request.arguments) : /* @__PURE__ */
|
|
4048
|
-
pending ? /* @__PURE__ */
|
|
4049
|
-
/* @__PURE__ */
|
|
4050
|
-
/* @__PURE__ */
|
|
4051
|
-
] }) : options.map((choice) => /* @__PURE__ */
|
|
4322
|
+
draftError && /* @__PURE__ */ jsx19("p", { role: "alert", className: "june-approval__error", children: draftError })
|
|
4323
|
+
] }) : hasArguments(request.arguments) ? renderArguments ? renderArguments(request.arguments) : /* @__PURE__ */ jsx19("pre", { className: "june-approval__args", children: format(request.arguments) }) : null,
|
|
4324
|
+
pending ? /* @__PURE__ */ jsx19("div", { className: "june-approval__actions", children: draft !== null ? /* @__PURE__ */ jsxs12(Fragment6, { children: [
|
|
4325
|
+
/* @__PURE__ */ jsx19("button", { type: "button", className: "june-approval__button", "data-variant": "primary", onClick: saveEdit, disabled, children: labels.save }),
|
|
4326
|
+
/* @__PURE__ */ jsx19("button", { type: "button", className: "june-approval__button", onClick: () => setDraft(null), disabled, children: labels.cancel })
|
|
4327
|
+
] }) : options.map((choice) => /* @__PURE__ */ jsx19(
|
|
4052
4328
|
"button",
|
|
4053
4329
|
{
|
|
4054
4330
|
type: "button",
|
|
@@ -4059,7 +4335,7 @@ function ToolApproval({
|
|
|
4059
4335
|
children: labels[choice]
|
|
4060
4336
|
},
|
|
4061
4337
|
choice
|
|
4062
|
-
)) }) : /* @__PURE__ */
|
|
4338
|
+
)) }) : /* @__PURE__ */ jsxs12("p", { className: "june-approval__status", role: "status", children: [
|
|
4063
4339
|
labels.status[status],
|
|
4064
4340
|
status === "failed" && error ? `: ${error}` : null
|
|
4065
4341
|
] })
|
|
@@ -4069,12 +4345,12 @@ function ToolApproval({
|
|
|
4069
4345
|
}
|
|
4070
4346
|
|
|
4071
4347
|
// src/features/tool-approval/tool-approval-list.tsx
|
|
4072
|
-
import { jsx as
|
|
4348
|
+
import { jsx as jsx20 } from "react/jsx-runtime";
|
|
4073
4349
|
function ToolApprovalList({ approvals, pendingOnly = false, renderItem, labels, className }) {
|
|
4074
4350
|
const entries = pendingOnly ? approvals.entries.filter((e) => e.status === "pending") : approvals.entries;
|
|
4075
4351
|
if (entries.length === 0) return null;
|
|
4076
|
-
return /* @__PURE__ */
|
|
4077
|
-
(entry) => renderItem ? /* @__PURE__ */
|
|
4352
|
+
return /* @__PURE__ */ jsx20("div", { className: className ? `june-approval-list ${className}` : "june-approval-list", children: entries.map(
|
|
4353
|
+
(entry) => renderItem ? /* @__PURE__ */ jsx20("div", { children: renderItem(entry, approvals.decide) }, entry.request.id) : /* @__PURE__ */ jsx20(
|
|
4078
4354
|
ToolApproval,
|
|
4079
4355
|
{
|
|
4080
4356
|
request: entry.request,
|
|
@@ -4089,11 +4365,11 @@ function ToolApprovalList({ approvals, pendingOnly = false, renderItem, labels,
|
|
|
4089
4365
|
}
|
|
4090
4366
|
|
|
4091
4367
|
// src/features/tool-approval/use-tool-approval.ts
|
|
4092
|
-
import { useCallback as useCallback5, useEffect as
|
|
4368
|
+
import { useCallback as useCallback5, useEffect as useEffect9, useMemo as useMemo7, useRef as useRef9, useState as useState9 } from "react";
|
|
4093
4369
|
var counter = 0;
|
|
4094
4370
|
var nextId = () => `june-approval-${++counter}`;
|
|
4095
4371
|
function useToolApproval() {
|
|
4096
|
-
const [entries, setEntries] =
|
|
4372
|
+
const [entries, setEntries] = useState9([]);
|
|
4097
4373
|
const waiters = useRef9(/* @__PURE__ */ new Map());
|
|
4098
4374
|
const settle = useCallback5((id, decision) => {
|
|
4099
4375
|
const resolve = waiters.current.get(id);
|
|
@@ -4138,15 +4414,15 @@ function useToolApproval() {
|
|
|
4138
4414
|
},
|
|
4139
4415
|
[request]
|
|
4140
4416
|
);
|
|
4141
|
-
|
|
4417
|
+
useEffect9(() => {
|
|
4142
4418
|
const map = waiters.current;
|
|
4143
4419
|
return () => {
|
|
4144
4420
|
map.forEach((resolve) => resolve({ choice: "reject" }));
|
|
4145
4421
|
map.clear();
|
|
4146
4422
|
};
|
|
4147
4423
|
}, []);
|
|
4148
|
-
const pending =
|
|
4149
|
-
return
|
|
4424
|
+
const pending = useMemo7(() => entries.filter((e) => e.status === "pending"), [entries]);
|
|
4425
|
+
return useMemo7(
|
|
4150
4426
|
() => ({ entries, pending, request, decide, setStatus, dismiss, confirmAction }),
|
|
4151
4427
|
[entries, pending, request, decide, setStatus, dismiss, confirmAction]
|
|
4152
4428
|
);
|