camox 0.67.0 → 0.69.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/editing/createEditableBlock.js +2 -1
- package/dist/features/canvas/canvasFrameDocument.js +25 -2
- package/dist/features/canvas/useCanvasFrame.js +6 -2
- package/dist/features/preview/components/PreviewToolbar.js +77 -68
- package/dist/features/preview/components/previewStyles.js +11 -2
- package/dist/features/preview/repeatableItemTargets.js +13 -7
- package/dist/features/provider/AuthenticatedCamoxProvider.js +33 -28
- package/dist/features/renderer/RendererApp.js +202 -154
- package/dist/features/renderer/RendererFrames.js +87 -55
- package/dist/features/renderer/definitionAnswers.js +1 -0
- package/dist/features/renderer/rendererHost.js +4 -0
- package/dist/features/renderer/studioConnection.js +9 -1
- package/dist/features/runtime/RuntimeChrome.js +47 -61
- package/dist/features/runtime/pageNavigation.js +93 -17
- package/dist/features/runtime/rendererClient.js +13 -6
- package/dist/features/studio/components/ChatWidget.js +3 -4
- package/dist/features/studio/components/ConnectAgent.js +33 -59
- package/dist/features/studio/components/DraftBar.js +139 -0
- package/dist/features/studio/components/DraftsControl.js +129 -164
- package/dist/features/studio/components/LocalePicker.js +22 -4
- package/dist/features/studio/components/Navbar.js +3 -2
- package/dist/features/studio/components/ReviewDraftSheet.js +2 -21
- package/dist/features/studio/components/UserButton.js +7 -11
- package/dist/features/studio/studioStore.js +0 -13
- package/dist/features/studio/viewSwitch.js +64 -0
- package/dist/lib/auth.js +5 -1
- package/dist/lib/draft-scope.js +28 -15
- package/dist/lib/studio-reads.js +46 -13
- package/dist/lib/view-switch.js +64 -0
- package/dist/package.js +1 -1
- package/dist/studio.css +1 -1
- package/package.json +4 -4
- package/dist/features/studio/components/UnnamedDraftBar.js +0 -349
|
@@ -26,7 +26,7 @@ const mirror = (message) => mirrors[message.store]?.send({
|
|
|
26
26
|
* its cache follows the studio's (see `protocol.ts`). The studio's questions are answered from
|
|
27
27
|
* `camoxApp`, the draft's code; without it, none can be.
|
|
28
28
|
*/
|
|
29
|
-
function connectToStudio(handle, { queryClient, studioCache, draftScope, camoxApp }) {
|
|
29
|
+
function connectToStudio(handle, { queryClient, studioCache, draftScope, camoxApp, prepareFrame }) {
|
|
30
30
|
let welcomed = false;
|
|
31
31
|
let frames = [];
|
|
32
32
|
const listeners = /* @__PURE__ */ new Set();
|
|
@@ -109,6 +109,14 @@ function connectToStudio(handle, { queryClient, studioCache, draftScope, camoxAp
|
|
|
109
109
|
return;
|
|
110
110
|
case "ask": {
|
|
111
111
|
const { askId, question } = message;
|
|
112
|
+
if (question.type === "prepareFrame") {
|
|
113
|
+
(prepareFrame?.(question) ?? Promise.resolve()).catch(() => {}).then(() => studio({
|
|
114
|
+
type: "answer",
|
|
115
|
+
askId,
|
|
116
|
+
value: null
|
|
117
|
+
}));
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
112
120
|
if (!camoxApp) {
|
|
113
121
|
studio({
|
|
114
122
|
type: "answer",
|
|
@@ -3,9 +3,9 @@ import { shownRecordPage } from "../preview/pageRecord.js";
|
|
|
3
3
|
import { StudioEditingFallback } from "../preview/components/StudioEditingFallback.js";
|
|
4
4
|
import { Navbar } from "../studio/components/Navbar.js";
|
|
5
5
|
import { EditingFallbackContext } from "./editingFallback.js";
|
|
6
|
+
import { DraftBar } from "../studio/components/DraftBar.js";
|
|
6
7
|
import { PreviewToolbar } from "../preview/components/PreviewToolbar.js";
|
|
7
8
|
import { AgentSidebar } from "../studio/components/AgentSidebar.js";
|
|
8
|
-
import { UnnamedDraftBar } from "../studio/components/UnnamedDraftBar.js";
|
|
9
9
|
import { FollowAgentProvider } from "../studio/FollowAgentProvider.js";
|
|
10
10
|
import { c } from "react/compiler-runtime";
|
|
11
11
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -15,7 +15,7 @@ import studioCssUrl from "virtual:camox-studio-css";
|
|
|
15
15
|
//#region src/features/runtime/RuntimeChrome.tsx
|
|
16
16
|
const renderEditingFallback = ({ layoutPage }) => /* @__PURE__ */ jsx(StudioEditingFallback, { layoutPage });
|
|
17
17
|
function RuntimeChrome(t0) {
|
|
18
|
-
const $ = c(
|
|
18
|
+
const $ = c(35);
|
|
19
19
|
const { input, children } = t0;
|
|
20
20
|
const website = !input.routeKind;
|
|
21
21
|
const hidden = useSelector(previewStore, _temp);
|
|
@@ -93,81 +93,67 @@ function RuntimeChrome(t0) {
|
|
|
93
93
|
$[15] = t11;
|
|
94
94
|
$[16] = t13;
|
|
95
95
|
} else t13 = $[16];
|
|
96
|
-
|
|
97
|
-
const t15 = website ? "max-md:hidden" : void 0;
|
|
98
|
-
let t16;
|
|
96
|
+
let t14;
|
|
99
97
|
if ($[17] !== website) {
|
|
100
|
-
|
|
98
|
+
t14 = !website && /* @__PURE__ */ jsx(DraftBar, {});
|
|
101
99
|
$[17] = website;
|
|
102
|
-
$[18] =
|
|
103
|
-
} else
|
|
104
|
-
let
|
|
105
|
-
if ($[19] !==
|
|
106
|
-
|
|
107
|
-
hidden: t14,
|
|
108
|
-
className: t15,
|
|
109
|
-
children: t16
|
|
110
|
-
});
|
|
111
|
-
$[19] = t14;
|
|
112
|
-
$[20] = t15;
|
|
113
|
-
$[21] = t16;
|
|
114
|
-
$[22] = t17;
|
|
115
|
-
} else t17 = $[22];
|
|
116
|
-
let t18;
|
|
117
|
-
if ($[23] !== t13 || $[24] !== t17 || $[25] !== t9) {
|
|
118
|
-
t18 = /* @__PURE__ */ jsxs("div", {
|
|
100
|
+
$[18] = t14;
|
|
101
|
+
} else t14 = $[18];
|
|
102
|
+
let t15;
|
|
103
|
+
if ($[19] !== t13 || $[20] !== t14 || $[21] !== t9) {
|
|
104
|
+
t15 = /* @__PURE__ */ jsxs("div", {
|
|
119
105
|
className: "relative flex min-h-0 min-w-0 flex-1 flex-col",
|
|
120
106
|
children: [
|
|
121
107
|
t9,
|
|
122
108
|
t13,
|
|
123
|
-
|
|
109
|
+
t14
|
|
124
110
|
]
|
|
125
111
|
});
|
|
126
|
-
$[
|
|
112
|
+
$[19] = t13;
|
|
113
|
+
$[20] = t14;
|
|
114
|
+
$[21] = t9;
|
|
115
|
+
$[22] = t15;
|
|
116
|
+
} else t15 = $[22];
|
|
117
|
+
const t16 = !showAgentSidebar;
|
|
118
|
+
let t17;
|
|
119
|
+
if ($[23] !== t16) {
|
|
120
|
+
t17 = /* @__PURE__ */ jsx(AgentSidebar, { hidden: t16 });
|
|
121
|
+
$[23] = t16;
|
|
127
122
|
$[24] = t17;
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
let t20;
|
|
133
|
-
if ($[27] !== t19) {
|
|
134
|
-
t20 = /* @__PURE__ */ jsx(AgentSidebar, { hidden: t19 });
|
|
135
|
-
$[27] = t19;
|
|
136
|
-
$[28] = t20;
|
|
137
|
-
} else t20 = $[28];
|
|
138
|
-
let t21;
|
|
139
|
-
if ($[29] !== t18 || $[30] !== t20) {
|
|
140
|
-
t21 = /* @__PURE__ */ jsxs("div", {
|
|
123
|
+
} else t17 = $[24];
|
|
124
|
+
let t18;
|
|
125
|
+
if ($[25] !== t15 || $[26] !== t17) {
|
|
126
|
+
t18 = /* @__PURE__ */ jsxs("div", {
|
|
141
127
|
className: "relative flex min-h-0 flex-1",
|
|
142
|
-
children: [
|
|
128
|
+
children: [t15, t17]
|
|
143
129
|
});
|
|
144
|
-
$[
|
|
145
|
-
$[
|
|
146
|
-
$[
|
|
147
|
-
} else
|
|
148
|
-
let
|
|
149
|
-
if ($[
|
|
150
|
-
|
|
130
|
+
$[25] = t15;
|
|
131
|
+
$[26] = t17;
|
|
132
|
+
$[27] = t18;
|
|
133
|
+
} else t18 = $[27];
|
|
134
|
+
let t19;
|
|
135
|
+
if ($[28] !== t18 || $[29] !== t7) {
|
|
136
|
+
t19 = /* @__PURE__ */ jsxs("div", {
|
|
151
137
|
className: "bg-background flex h-screen flex-col overflow-hidden",
|
|
152
|
-
children: [t7,
|
|
138
|
+
children: [t7, t18]
|
|
153
139
|
});
|
|
154
|
-
$[
|
|
155
|
-
$[
|
|
156
|
-
$[
|
|
157
|
-
} else
|
|
158
|
-
let
|
|
159
|
-
if ($[
|
|
160
|
-
|
|
140
|
+
$[28] = t18;
|
|
141
|
+
$[29] = t7;
|
|
142
|
+
$[30] = t19;
|
|
143
|
+
} else t19 = $[30];
|
|
144
|
+
let t20;
|
|
145
|
+
if ($[31] !== input.runtimeBasePath || $[32] !== t19 || $[33] !== website) {
|
|
146
|
+
t20 = /* @__PURE__ */ jsxs(FollowAgentProvider, {
|
|
161
147
|
runtimeBasePath: t1,
|
|
162
148
|
website,
|
|
163
|
-
children: [t2,
|
|
149
|
+
children: [t2, t19]
|
|
164
150
|
});
|
|
165
|
-
$[
|
|
166
|
-
$[
|
|
167
|
-
$[
|
|
168
|
-
$[
|
|
169
|
-
} else
|
|
170
|
-
return
|
|
151
|
+
$[31] = input.runtimeBasePath;
|
|
152
|
+
$[32] = t19;
|
|
153
|
+
$[33] = website;
|
|
154
|
+
$[34] = t20;
|
|
155
|
+
} else t20 = $[34];
|
|
156
|
+
return t20;
|
|
171
157
|
}
|
|
172
158
|
function _temp(state) {
|
|
173
159
|
return state.context.isToolbarHidden;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { DraftScopeContext, draftNamedBy } from "../../lib/draft-scope.js";
|
|
1
|
+
import { DraftScopeContext, ShownDraftContext, draftNamedBy } from "../../lib/draft-scope.js";
|
|
2
2
|
import { PageAlternatesContext, ViewLocaleContext } from "../../lib/view-locale-context.js";
|
|
3
3
|
import { NavigationProvider } from "../navigation/navigation.js";
|
|
4
4
|
import { fetchRuntimeJson, getNavigationTarget } from "./navigationTarget.js";
|
|
5
|
+
import { SWITCH_WAIT_MS, ViewSwitchDeadlineContext, ViewSwitchesContext } from "../../lib/view-switch.js";
|
|
5
6
|
import { reads } from "../../lib/studio-reads.js";
|
|
6
7
|
import { createPrefetchCache, listenForLinkIntent } from "./linkPrefetch.js";
|
|
7
8
|
import { PageViewportContext } from "./pageViewport.js";
|
|
@@ -13,7 +14,7 @@ import { createNavigationRequestTracker } from "./navigationRequest.js";
|
|
|
13
14
|
import { createScrollRestoration } from "./scrollRestoration.js";
|
|
14
15
|
import { c } from "react/compiler-runtime";
|
|
15
16
|
import * as React from "react";
|
|
16
|
-
import { jsx } from "react/jsx-runtime";
|
|
17
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
17
18
|
import { hydrate } from "@tanstack/react-query";
|
|
18
19
|
import { createHead, renderDOMHead } from "@unhead/react/client";
|
|
19
20
|
|
|
@@ -63,13 +64,24 @@ function prefetchKey(pathname, draft) {
|
|
|
63
64
|
function PageNavigationProvider({ camoxApp, children, initialInput, queryClient }) {
|
|
64
65
|
const draftScope = React.useContext(DraftScopeContext);
|
|
65
66
|
if (!draftScope) throw new Error("PageNavigationProvider needs a DraftScopeContext provider");
|
|
66
|
-
const [{ input, source,
|
|
67
|
+
const [{ input, source, switched, navigation }, setLocation] = React.useState(() => {
|
|
67
68
|
draftScope.adopt(initialInput);
|
|
68
69
|
return {
|
|
69
70
|
input: initialInput,
|
|
70
|
-
|
|
71
|
+
navigation: 0
|
|
71
72
|
};
|
|
72
73
|
});
|
|
74
|
+
const [preparers] = React.useState(() => /* @__PURE__ */ new Set());
|
|
75
|
+
const [commits] = React.useState(() => /* @__PURE__ */ new Map());
|
|
76
|
+
const navigations = React.useRef(0);
|
|
77
|
+
const lastShown = React.useRef(Promise.resolve());
|
|
78
|
+
const switches = React.useMemo(() => ({
|
|
79
|
+
prepare(preparer) {
|
|
80
|
+
preparers.add(preparer);
|
|
81
|
+
return () => void preparers.delete(preparer);
|
|
82
|
+
},
|
|
83
|
+
shown: () => lastShown.current
|
|
84
|
+
}), [preparers]);
|
|
73
85
|
const current = React.useRef(initialInput);
|
|
74
86
|
const [requests] = React.useState(createNavigationRequestTracker);
|
|
75
87
|
const ownsWindow = initialInput.presentation !== "studio";
|
|
@@ -88,6 +100,20 @@ function PageNavigationProvider({ camoxApp, children, initialInput, queryClient
|
|
|
88
100
|
}, [restoration]);
|
|
89
101
|
const pendingAnnouncement = React.useRef(null);
|
|
90
102
|
const announcer = React.useRef(null);
|
|
103
|
+
const prepareSwitch = React.useCallback((next) => {
|
|
104
|
+
const view = {
|
|
105
|
+
pathname: next.pathname,
|
|
106
|
+
...next.derived && { derivedLayoutId: next.derived.layoutId },
|
|
107
|
+
draftId: next.draftId ?? null,
|
|
108
|
+
locale: next.locale
|
|
109
|
+
};
|
|
110
|
+
const deadline = Date.now() + SWITCH_WAIT_MS;
|
|
111
|
+
const prepared = Promise.all([...preparers].map((prepare) => Promise.resolve(prepare(view)).catch(() => {})));
|
|
112
|
+
return {
|
|
113
|
+
deadline,
|
|
114
|
+
ready: Promise.race([prepared.then(() => {}), new Promise((resolve) => setTimeout(resolve, SWITCH_WAIT_MS))])
|
|
115
|
+
};
|
|
116
|
+
}, [preparers]);
|
|
91
117
|
const loadPage = React.useCallback(async (pathname, draft, signal) => {
|
|
92
118
|
const response = await fetchRuntimeJson(draftScope, "/_camox/data", initialInput.runtimeBasePath, { path: pathname }, draft, signal);
|
|
93
119
|
if (!response.ok) throw new Error(`Navigation failed: ${response.status}`);
|
|
@@ -106,6 +132,7 @@ function PageNavigationProvider({ camoxApp, children, initialInput, queryClient
|
|
|
106
132
|
const { analytics } = initialInput;
|
|
107
133
|
const navigate = React.useCallback(async ({ to, replace, source, draft, pop = false, refresh = false }) => {
|
|
108
134
|
const request = requests.begin();
|
|
135
|
+
const id = ++navigations.current;
|
|
109
136
|
const href = pop ? to : draftScope.hrefFor(to, {
|
|
110
137
|
from: window.location.href,
|
|
111
138
|
draft
|
|
@@ -122,12 +149,20 @@ function PageNavigationProvider({ camoxApp, children, initialInput, queryClient
|
|
|
122
149
|
if (target.url.hash && viewport) position(viewport, "fragment", target.url.href);
|
|
123
150
|
return;
|
|
124
151
|
}
|
|
152
|
+
lastShown.current = new Promise((resolve) => commits.set(id, resolve));
|
|
153
|
+
const settle = () => {
|
|
154
|
+
for (const [waiting, resolve] of commits) {
|
|
155
|
+
if (waiting > id) continue;
|
|
156
|
+
commits.delete(waiting);
|
|
157
|
+
resolve();
|
|
158
|
+
}
|
|
159
|
+
};
|
|
125
160
|
try {
|
|
126
161
|
let next = current.current;
|
|
127
162
|
const targetDraft = draftNamedBy(target.url.href);
|
|
128
163
|
const fetched = target.pathname !== next.pathname || refresh || targetDraft !== draftNamedBy(next.href);
|
|
129
164
|
if (fetched) next = await (!refresh && prefetched.take(prefetchKey(target.pathname, targetDraft)) || loadPage(target.pathname, targetDraft, request.signal));
|
|
130
|
-
if (!request.isCurrent()) return;
|
|
165
|
+
if (!request.isCurrent()) return settle();
|
|
131
166
|
const switching = (next.draftId ?? null) !== (current.current.draftId ?? null) || !sameLocale(next.locale, current.current.locale);
|
|
132
167
|
const positions = restoration();
|
|
133
168
|
if (!pop) {
|
|
@@ -145,6 +180,7 @@ function PageNavigationProvider({ camoxApp, children, initialInput, queryClient
|
|
|
145
180
|
};
|
|
146
181
|
pendingAnnouncement.current = fetched && !refresh ? next.pathname : null;
|
|
147
182
|
if (fetched) draftScope.adopt(next);
|
|
183
|
+
const switched = switching ? prepareSwitch(next) : void 0;
|
|
148
184
|
hydrate(queryClient, switching ? next.dehydratedState : preserveStableLayoutBlockCaches(next.dehydratedState, current.current.layoutIdentity, next.layoutIdentity));
|
|
149
185
|
next = {
|
|
150
186
|
...next,
|
|
@@ -162,12 +198,14 @@ function PageNavigationProvider({ camoxApp, children, initialInput, queryClient
|
|
|
162
198
|
renderDOMHead(manager.head);
|
|
163
199
|
if (ownsWindow && analytics && next.pathname !== previous.pathname) sendPageView(analytics, window);
|
|
164
200
|
if (ownsWindow) document.documentElement.lang = next.locale.tag;
|
|
165
|
-
React.startTransition(() => setLocation(
|
|
201
|
+
React.startTransition(() => setLocation({
|
|
166
202
|
input: next,
|
|
167
203
|
source: pop ? void 0 : source,
|
|
168
|
-
|
|
169
|
-
|
|
204
|
+
switched,
|
|
205
|
+
navigation: id
|
|
206
|
+
}));
|
|
170
207
|
} catch {
|
|
208
|
+
settle();
|
|
171
209
|
if (!request.isCurrent()) return;
|
|
172
210
|
if (pop) window.location.reload();
|
|
173
211
|
else if (replace) window.location.replace(target.url.href);
|
|
@@ -175,12 +213,14 @@ function PageNavigationProvider({ camoxApp, children, initialInput, queryClient
|
|
|
175
213
|
}
|
|
176
214
|
}, [
|
|
177
215
|
analytics,
|
|
216
|
+
commits,
|
|
178
217
|
draftScope,
|
|
179
218
|
initialInput.runtimeBasePath,
|
|
180
219
|
loadPage,
|
|
181
220
|
ownsWindow,
|
|
182
221
|
position,
|
|
183
222
|
prefetched,
|
|
223
|
+
prepareSwitch,
|
|
184
224
|
queryClient,
|
|
185
225
|
requests,
|
|
186
226
|
restoration
|
|
@@ -250,6 +290,21 @@ function PageNavigationProvider({ camoxApp, children, initialInput, queryClient
|
|
|
250
290
|
prefetched.clear();
|
|
251
291
|
};
|
|
252
292
|
}, [draftScope, prefetched]);
|
|
293
|
+
React.useLayoutEffect(() => {
|
|
294
|
+
for (const [waiting, resolve] of commits) {
|
|
295
|
+
if (waiting > navigation) continue;
|
|
296
|
+
commits.delete(waiting);
|
|
297
|
+
resolve();
|
|
298
|
+
}
|
|
299
|
+
if (switched) setLocation((location) => ({
|
|
300
|
+
...location,
|
|
301
|
+
switched: void 0
|
|
302
|
+
}));
|
|
303
|
+
}, [
|
|
304
|
+
commits,
|
|
305
|
+
navigation,
|
|
306
|
+
switched
|
|
307
|
+
]);
|
|
253
308
|
React.useLayoutEffect(() => {
|
|
254
309
|
const intent = takeScroll(input.href);
|
|
255
310
|
const viewport = scroll.current?.viewport();
|
|
@@ -310,13 +365,14 @@ function PageNavigationProvider({ camoxApp, children, initialInput, queryClient
|
|
|
310
365
|
initialInput.runtimeBasePath,
|
|
311
366
|
requests
|
|
312
367
|
]);
|
|
368
|
+
const hydrated = React.useSyncExternalStore(noSubscription, isClient, isServer);
|
|
313
369
|
const url = new URL(input.href);
|
|
314
370
|
const viewLocale = useSameJson({
|
|
315
371
|
locale: input.locale,
|
|
316
372
|
locales: input.locales
|
|
317
373
|
});
|
|
318
374
|
const alternates = useSameJson(input.alternates ?? null);
|
|
319
|
-
return /* @__PURE__ */
|
|
375
|
+
return /* @__PURE__ */ jsxs(NavigationProvider, {
|
|
320
376
|
location: {
|
|
321
377
|
href: input.href,
|
|
322
378
|
pathname: input.pathname,
|
|
@@ -325,18 +381,38 @@ function PageNavigationProvider({ camoxApp, children, initialInput, queryClient
|
|
|
325
381
|
source
|
|
326
382
|
},
|
|
327
383
|
navigate,
|
|
328
|
-
children: /* @__PURE__ */ jsx(
|
|
329
|
-
value:
|
|
330
|
-
children: /* @__PURE__ */ jsx(
|
|
331
|
-
value:
|
|
332
|
-
children: /* @__PURE__ */ jsx(
|
|
333
|
-
value:
|
|
334
|
-
children: /* @__PURE__ */ jsx(
|
|
384
|
+
children: [/* @__PURE__ */ jsx(ViewSwitchesContext, {
|
|
385
|
+
value: switches,
|
|
386
|
+
children: /* @__PURE__ */ jsx(ViewSwitchDeadlineContext, {
|
|
387
|
+
value: switched?.deadline ?? null,
|
|
388
|
+
children: /* @__PURE__ */ jsx(ShownDraftContext, {
|
|
389
|
+
value: input.draftId ?? null,
|
|
390
|
+
children: /* @__PURE__ */ jsx(ViewLocaleContext, {
|
|
391
|
+
value: viewLocale,
|
|
392
|
+
children: /* @__PURE__ */ jsx(PageAlternatesContext, {
|
|
393
|
+
value: alternates,
|
|
394
|
+
children: /* @__PURE__ */ jsx(PageViewportContext, {
|
|
395
|
+
value: pageViewport,
|
|
396
|
+
children: children(input)
|
|
397
|
+
})
|
|
398
|
+
})
|
|
399
|
+
})
|
|
335
400
|
})
|
|
336
401
|
})
|
|
337
|
-
})
|
|
402
|
+
}), hydrated && /* @__PURE__ */ jsx(React.Suspense, {
|
|
403
|
+
fallback: null,
|
|
404
|
+
children: /* @__PURE__ */ jsx(SwitchGate, { ready: switched?.ready })
|
|
405
|
+
})]
|
|
338
406
|
});
|
|
339
407
|
}
|
|
408
|
+
const noSubscription = () => () => {};
|
|
409
|
+
const isClient = () => true;
|
|
410
|
+
const isServer = () => false;
|
|
411
|
+
/** Suspends the switch's render until the next view is ready. */
|
|
412
|
+
function SwitchGate({ ready }) {
|
|
413
|
+
if (ready) React.use(ready);
|
|
414
|
+
return null;
|
|
415
|
+
}
|
|
340
416
|
|
|
341
417
|
//#endregion
|
|
342
418
|
export { PageNavigationProvider };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DraftScopeContext, createDraftScope, followUrl } from "../../lib/draft-scope.js";
|
|
2
|
-
import { StudioCacheContext, createStudioCache } from "../../lib/studio-reads.js";
|
|
2
|
+
import { StudioCacheContext, createStudioCache, reads } from "../../lib/studio-reads.js";
|
|
3
3
|
import { getDraftReadClient } from "../../lib/api-client.js";
|
|
4
4
|
import { STUDIO_HANDLE_KEY } from "../renderer/protocol.js";
|
|
5
5
|
import { CoreCamoxProvider } from "../provider/CoreCamoxProvider.js";
|
|
@@ -23,7 +23,8 @@ async function startRendererWithApp(camoxApp) {
|
|
|
23
23
|
return;
|
|
24
24
|
}
|
|
25
25
|
const input = readHydrationData();
|
|
26
|
-
|
|
26
|
+
const { projectUuid, runtimeBasePath } = input;
|
|
27
|
+
if (!input.apiUrl || !input.authenticationUrl || !projectUuid) {
|
|
27
28
|
console.error("Camox: the renderer document is missing its API or project.");
|
|
28
29
|
return;
|
|
29
30
|
}
|
|
@@ -44,7 +45,13 @@ async function startRendererWithApp(camoxApp) {
|
|
|
44
45
|
queryClient,
|
|
45
46
|
studioCache,
|
|
46
47
|
draftScope,
|
|
47
|
-
camoxApp
|
|
48
|
+
camoxApp,
|
|
49
|
+
prepareFrame: ({ pathname, derivedLayoutId, locale }) => Promise.all([studioCache.ensure(reads.canvasFrame({
|
|
50
|
+
projectUuid,
|
|
51
|
+
runtimeBasePath,
|
|
52
|
+
pathname,
|
|
53
|
+
...derivedLayoutId && { derivedLayoutId }
|
|
54
|
+
}), { locale }), codeLoaded])
|
|
48
55
|
});
|
|
49
56
|
const container = document.createElement("div");
|
|
50
57
|
document.body.append(container);
|
|
@@ -58,14 +65,14 @@ async function startRendererWithApp(camoxApp) {
|
|
|
58
65
|
apiUrl: input.apiUrl,
|
|
59
66
|
authenticationUrl: input.authenticationUrl,
|
|
60
67
|
camoxApp,
|
|
61
|
-
projectUuid
|
|
68
|
+
projectUuid,
|
|
62
69
|
initialAuthenticated: true,
|
|
63
70
|
children: /* @__PURE__ */ jsx(CompleteBlockEditingRuntimeProvider, { children: /* @__PURE__ */ jsx(RendererApp, {
|
|
64
71
|
connection,
|
|
65
72
|
camoxApp,
|
|
66
73
|
codeLoaded,
|
|
67
|
-
projectUuid
|
|
68
|
-
runtimeBasePath
|
|
74
|
+
projectUuid,
|
|
75
|
+
runtimeBasePath
|
|
69
76
|
}) })
|
|
70
77
|
})
|
|
71
78
|
})
|
|
@@ -9,7 +9,6 @@ import { FollowAgentContext } from "../followAgentContext.js";
|
|
|
9
9
|
import { useThread } from "../../../lib/use-thread.js";
|
|
10
10
|
import { EditorWhereContext } from "../editorWhereContext.js";
|
|
11
11
|
import { useEditorSelection } from "../useEditorSelection.js";
|
|
12
|
-
import { ConnectAgent } from "./ConnectAgent.js";
|
|
13
12
|
import { ThreadComposer, useComposerCarrier } from "./ThreadComposer.js";
|
|
14
13
|
import { ThreadMessages } from "./ThreadMessages.js";
|
|
15
14
|
import { c } from "react/compiler-runtime";
|
|
@@ -27,7 +26,7 @@ import { EMPTY_THREAD_VIEW } from "@camox/api-contract/threads";
|
|
|
27
26
|
* it, if it still shows Live; the card the Live turn ends on opens it too. Each message tells the
|
|
28
27
|
* agent where the editor is: the page they look at, with what they selected on it unless they
|
|
29
28
|
* cleared it from the composer, or the Canvas with no page selected. "Ask the agent" elsewhere in
|
|
30
|
-
* the studio fills its composer.
|
|
29
|
+
* the studio fills its composer.
|
|
31
30
|
*/
|
|
32
31
|
function ChatWidget(t0) {
|
|
33
32
|
const $ = c(6);
|
|
@@ -48,9 +47,9 @@ function ChatWidget(t0) {
|
|
|
48
47
|
children: "Agent"
|
|
49
48
|
})
|
|
50
49
|
});
|
|
51
|
-
t3 = /* @__PURE__ */
|
|
50
|
+
t3 = /* @__PURE__ */ jsx("div", {
|
|
52
51
|
className: cn("bg-background flex min-h-0 flex-1 flex-col", CARD_BODY_EDGES),
|
|
53
|
-
children:
|
|
52
|
+
children: /* @__PURE__ */ jsx(CurrentThread, {})
|
|
54
53
|
});
|
|
55
54
|
$[2] = t2;
|
|
56
55
|
$[3] = t3;
|
|
@@ -6,12 +6,10 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
|
6
6
|
import { Button } from "@camox/ui/button";
|
|
7
7
|
import { Check, Copy, ExternalLink } from "lucide-react";
|
|
8
8
|
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@camox/ui/dialog";
|
|
9
|
-
import { Avatar, AvatarFallback, AvatarGroup } from "@camox/ui/avatar";
|
|
10
9
|
|
|
11
10
|
//#region src/features/studio/components/ConnectAgent.tsx
|
|
12
11
|
/**
|
|
13
|
-
* Common AI apps that take a remote MCP server, with their guide to adding one.
|
|
14
|
-
* each one overlaps the one before it, so the last is on top.
|
|
12
|
+
* Common AI apps that take a remote MCP server, with their guide to adding one.
|
|
15
13
|
*/
|
|
16
14
|
const CLIENTS = [
|
|
17
15
|
{
|
|
@@ -125,56 +123,42 @@ function GrokBotLogo(t0) {
|
|
|
125
123
|
return t7;
|
|
126
124
|
}
|
|
127
125
|
/**
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
126
|
+
* In the navbar, what invites a member to connect their own agent to Camox as a Connected Agent
|
|
127
|
+
* (ADR 0030): a button opening a dialog with the link to Camox's MCP server and each common AI
|
|
128
|
+
* app's guide to adding an MCP server.
|
|
131
129
|
*/
|
|
132
130
|
function ConnectAgent() {
|
|
133
|
-
const $ = c(
|
|
131
|
+
const $ = c(4);
|
|
134
132
|
const [open, setOpen] = React.useState(false);
|
|
135
133
|
let t0;
|
|
136
134
|
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
|
137
|
-
t0 =
|
|
135
|
+
t0 = /* @__PURE__ */ jsx(Button, {
|
|
136
|
+
type: "button",
|
|
137
|
+
variant: "outline",
|
|
138
|
+
onClick: () => setOpen(true),
|
|
139
|
+
children: "Connect your agent"
|
|
140
|
+
});
|
|
138
141
|
$[0] = t0;
|
|
139
142
|
} else t0 = $[0];
|
|
140
143
|
let t1;
|
|
141
144
|
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
|
|
142
|
-
t1 = /* @__PURE__ */
|
|
143
|
-
type: "button",
|
|
144
|
-
onClick: t0,
|
|
145
|
-
className: "hover:bg-muted text-muted-foreground hover:text-foreground mx-2 mb-2 flex items-center gap-2.5 rounded-md px-2 py-1.5 text-sm transition-colors",
|
|
146
|
-
children: [/* @__PURE__ */ jsx(AvatarGroup, { children: CLIENTS.map(_temp) }), "Connect your AI"]
|
|
147
|
-
});
|
|
145
|
+
t1 = /* @__PURE__ */ jsx(DialogContent, { children: /* @__PURE__ */ jsx(ConnectAgentContent, {}) });
|
|
148
146
|
$[1] = t1;
|
|
149
147
|
} else t1 = $[1];
|
|
150
148
|
let t2;
|
|
151
|
-
if ($[2]
|
|
152
|
-
t2 = /* @__PURE__ */
|
|
153
|
-
$[2] = t2;
|
|
154
|
-
} else t2 = $[2];
|
|
155
|
-
let t3;
|
|
156
|
-
if ($[3] !== open) {
|
|
157
|
-
t3 = /* @__PURE__ */ jsxs(Fragment, { children: [t1, /* @__PURE__ */ jsx(Dialog, {
|
|
149
|
+
if ($[2] !== open) {
|
|
150
|
+
t2 = /* @__PURE__ */ jsxs(Fragment, { children: [t0, /* @__PURE__ */ jsx(Dialog, {
|
|
158
151
|
open,
|
|
159
152
|
onOpenChange: setOpen,
|
|
160
|
-
children:
|
|
153
|
+
children: t1
|
|
161
154
|
})] });
|
|
162
|
-
$[
|
|
163
|
-
$[
|
|
164
|
-
} else
|
|
165
|
-
return
|
|
166
|
-
}
|
|
167
|
-
function _temp(client) {
|
|
168
|
-
return /* @__PURE__ */ jsx(Avatar, {
|
|
169
|
-
size: "sm",
|
|
170
|
-
children: /* @__PURE__ */ jsx(AvatarFallback, {
|
|
171
|
-
className: "bg-background text-foreground",
|
|
172
|
-
children: /* @__PURE__ */ jsx(client.Logo, { className: "size-3.5" })
|
|
173
|
-
})
|
|
174
|
-
}, client.name);
|
|
155
|
+
$[2] = open;
|
|
156
|
+
$[3] = t2;
|
|
157
|
+
} else t2 = $[3];
|
|
158
|
+
return t2;
|
|
175
159
|
}
|
|
176
160
|
function ConnectAgentContent() {
|
|
177
|
-
const $ = c(
|
|
161
|
+
const $ = c(22);
|
|
178
162
|
const { apiUrl } = React.useContext(AuthContext);
|
|
179
163
|
const url = `${apiUrl}/mcp`;
|
|
180
164
|
const [copied, setCopied] = React.useState(false);
|
|
@@ -207,7 +191,7 @@ function ConnectAgentContent() {
|
|
|
207
191
|
const copy = t2;
|
|
208
192
|
let t3;
|
|
209
193
|
if ($[5] === Symbol.for("react.memo_cache_sentinel")) {
|
|
210
|
-
t3 = /* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsx(DialogTitle, { children: "Connect your
|
|
194
|
+
t3 = /* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsx(DialogTitle, { children: "Connect your agent" }), /* @__PURE__ */ jsx(DialogDescription, { children: "Add this URL to your agent as an MCP server. It acts as you, but can't publish." })] });
|
|
211
195
|
$[5] = t3;
|
|
212
196
|
} else t3 = $[5];
|
|
213
197
|
let t4;
|
|
@@ -255,44 +239,34 @@ function ConnectAgentContent() {
|
|
|
255
239
|
if ($[18] === Symbol.for("react.memo_cache_sentinel")) {
|
|
256
240
|
t9 = /* @__PURE__ */ jsx("p", {
|
|
257
241
|
className: "text-muted-foreground text-xs font-medium",
|
|
258
|
-
children: "How to add
|
|
242
|
+
children: "How to add it in"
|
|
259
243
|
});
|
|
260
244
|
$[18] = t9;
|
|
261
245
|
} else t9 = $[18];
|
|
262
246
|
let t10;
|
|
263
|
-
let t11;
|
|
264
247
|
if ($[19] === Symbol.for("react.memo_cache_sentinel")) {
|
|
265
248
|
t10 = /* @__PURE__ */ jsxs("div", {
|
|
266
249
|
className: "flex flex-col gap-2",
|
|
267
250
|
children: [t9, /* @__PURE__ */ jsx("ul", {
|
|
268
251
|
className: "grid grid-cols-2 gap-1",
|
|
269
|
-
children: CLIENTS.map(
|
|
252
|
+
children: CLIENTS.map(_temp)
|
|
270
253
|
})]
|
|
271
254
|
});
|
|
272
|
-
t11 = /* @__PURE__ */ jsx("p", {
|
|
273
|
-
className: "text-muted-foreground text-xs",
|
|
274
|
-
children: "It acts as you, with your permissions. It can't publish: you review and publish here."
|
|
275
|
-
});
|
|
276
255
|
$[19] = t10;
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
t11 =
|
|
281
|
-
}
|
|
282
|
-
let t12;
|
|
283
|
-
if ($[21] !== t8) {
|
|
284
|
-
t12 = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
256
|
+
} else t10 = $[19];
|
|
257
|
+
let t11;
|
|
258
|
+
if ($[20] !== t8) {
|
|
259
|
+
t11 = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
285
260
|
t3,
|
|
286
261
|
t8,
|
|
287
|
-
t10
|
|
288
|
-
t11
|
|
262
|
+
t10
|
|
289
263
|
] });
|
|
290
|
-
$[
|
|
291
|
-
$[
|
|
292
|
-
} else
|
|
293
|
-
return
|
|
264
|
+
$[20] = t8;
|
|
265
|
+
$[21] = t11;
|
|
266
|
+
} else t11 = $[21];
|
|
267
|
+
return t11;
|
|
294
268
|
}
|
|
295
|
-
function
|
|
269
|
+
function _temp(client) {
|
|
296
270
|
return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs("a", {
|
|
297
271
|
href: client.docs,
|
|
298
272
|
target: "_blank",
|