camox 0.18.1 → 0.19.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/features/content/CamoxContent.js +131 -105
- package/dist/features/preview/components/DebouncedFieldEditor.js +47 -74
- package/dist/features/preview/components/LinkFieldEditor.js +291 -340
- package/dist/features/vite/definitionsSync.js +1 -0
- package/dist/features/vite/vite.js +50 -52
- package/dist/hooks/use-debounced-field.js +73 -0
- package/dist/lib/normalized-data.js +98 -44
- package/dist/studio.css +1 -1
- package/package.json +4 -4
|
@@ -118,6 +118,7 @@ async function ssrLoadModule(server, modulePath) {
|
|
|
118
118
|
const tempServer = await createServer({
|
|
119
119
|
configFile: false,
|
|
120
120
|
root: server.config.root,
|
|
121
|
+
cacheDir: path.join(server.config.root, "node_modules", ".vite-camox-temp"),
|
|
121
122
|
resolve: server.config.resolve,
|
|
122
123
|
server: { middlewareMode: true },
|
|
123
124
|
logLevel: "silent"
|
|
@@ -102,58 +102,55 @@ function camox(options) {
|
|
|
102
102
|
__CAMOX_API_URL__: JSON.stringify(apiUrl),
|
|
103
103
|
__CAMOX_PROJECT_SLUG__: JSON.stringify(options.projectSlug)
|
|
104
104
|
},
|
|
105
|
-
optimizeDeps: {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
"camox > partysocket/react"
|
|
155
|
-
]
|
|
156
|
-
}
|
|
105
|
+
optimizeDeps: { include: [
|
|
106
|
+
"react",
|
|
107
|
+
"react-dom",
|
|
108
|
+
"react-dom/client",
|
|
109
|
+
"react/jsx-runtime",
|
|
110
|
+
"react/jsx-dev-runtime",
|
|
111
|
+
"camox > @base-ui/react/accordion",
|
|
112
|
+
"camox > @base-ui/react/alert-dialog",
|
|
113
|
+
"camox > @base-ui/react/avatar",
|
|
114
|
+
"camox > @base-ui/react/dialog",
|
|
115
|
+
"camox > @base-ui/react/input",
|
|
116
|
+
"camox > @base-ui/react/menu",
|
|
117
|
+
"camox > @base-ui/react/merge-props",
|
|
118
|
+
"camox > @base-ui/react/popover",
|
|
119
|
+
"camox > @base-ui/react/select",
|
|
120
|
+
"camox > @base-ui/react/separator",
|
|
121
|
+
"camox > @base-ui/react/switch",
|
|
122
|
+
"camox > @base-ui/react/tabs",
|
|
123
|
+
"camox > @base-ui/react/toggle",
|
|
124
|
+
"camox > @base-ui/react/tooltip",
|
|
125
|
+
"camox > @base-ui/react/use-render",
|
|
126
|
+
"camox > @dnd-kit/core",
|
|
127
|
+
"camox > @dnd-kit/modifiers",
|
|
128
|
+
"camox > @dnd-kit/sortable",
|
|
129
|
+
"camox > @dnd-kit/utilities",
|
|
130
|
+
"camox > @lexical/react/LexicalComposer",
|
|
131
|
+
"camox > @lexical/react/LexicalComposerContext",
|
|
132
|
+
"camox > @lexical/react/LexicalContentEditable",
|
|
133
|
+
"camox > @lexical/react/LexicalHistoryPlugin",
|
|
134
|
+
"camox > @lexical/react/LexicalOnChangePlugin",
|
|
135
|
+
"camox > @lexical/react/LexicalRichTextPlugin",
|
|
136
|
+
"camox > @orpc/client",
|
|
137
|
+
"camox > @orpc/client/fetch",
|
|
138
|
+
"camox > @orpc/tanstack-query",
|
|
139
|
+
"camox > @sinclair/typebox",
|
|
140
|
+
"camox > @takumi-rs/image-response",
|
|
141
|
+
"camox > @tanstack/react-form",
|
|
142
|
+
"camox > @xstate/store-react",
|
|
143
|
+
"camox > @camox/ui > cmdk",
|
|
144
|
+
"camox > fractional-indexing",
|
|
145
|
+
"camox > lexical",
|
|
146
|
+
"camox > posthog-js",
|
|
147
|
+
"camox > shiki",
|
|
148
|
+
"camox > @camox/ui > sonner",
|
|
149
|
+
"camox > @camox/ui > lucide-react",
|
|
150
|
+
"camox > lucide-react",
|
|
151
|
+
"camox > @tanstack/react-query-devtools/production",
|
|
152
|
+
"camox > partysocket/react"
|
|
153
|
+
] }
|
|
157
154
|
};
|
|
158
155
|
},
|
|
159
156
|
configResolved(config) {
|
|
@@ -206,6 +203,7 @@ function camox(options) {
|
|
|
206
203
|
const tempServer = await createServer({
|
|
207
204
|
configFile: false,
|
|
208
205
|
root: resolvedConfig.root,
|
|
206
|
+
cacheDir: resolve(resolvedConfig.root, "node_modules", ".vite-camox-temp"),
|
|
209
207
|
resolve: resolvedConfig.resolve,
|
|
210
208
|
server: { middlewareMode: true },
|
|
211
209
|
logLevel: "silent"
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
4
|
+
|
|
5
|
+
//#region src/hooks/use-debounced-field.ts
|
|
6
|
+
/**
|
|
7
|
+
* Local state for a field that autosaves to a server value, debouncing the
|
|
8
|
+
* save and refusing to overwrite the user's in-progress edit when the server
|
|
9
|
+
* response lands.
|
|
10
|
+
*
|
|
11
|
+
* Without focus tracking, a fast typist can lose characters: their first
|
|
12
|
+
* keystroke triggers a debounced save → the mutation roundtrips → react-query
|
|
13
|
+
* pushes the (now stale) server value back through props → the input is reset
|
|
14
|
+
* to the just-saved value, dropping whatever the user typed in the meantime.
|
|
15
|
+
* While `isFocused` is true we ignore `serverValue` changes; when the user
|
|
16
|
+
* leaves the input we resync.
|
|
17
|
+
*/
|
|
18
|
+
function useDebouncedField(serverValue, onSave, delay = 500) {
|
|
19
|
+
const [value, setLocal] = useState(serverValue);
|
|
20
|
+
const [isFocused, setIsFocused] = useState(false);
|
|
21
|
+
const saveRef = useRef(onSave);
|
|
22
|
+
saveRef.current = onSave;
|
|
23
|
+
const timerRef = useRef(null);
|
|
24
|
+
const pendingRef = useRef(null);
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
if (!isFocused) setLocal(serverValue);
|
|
27
|
+
}, [serverValue, isFocused]);
|
|
28
|
+
const flush = useCallback(() => {
|
|
29
|
+
if (timerRef.current) {
|
|
30
|
+
clearTimeout(timerRef.current);
|
|
31
|
+
timerRef.current = null;
|
|
32
|
+
}
|
|
33
|
+
if (pendingRef.current) {
|
|
34
|
+
const { value: v } = pendingRef.current;
|
|
35
|
+
pendingRef.current = null;
|
|
36
|
+
saveRef.current(v);
|
|
37
|
+
}
|
|
38
|
+
}, []);
|
|
39
|
+
const cancel = useCallback(() => {
|
|
40
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
41
|
+
timerRef.current = null;
|
|
42
|
+
pendingRef.current = null;
|
|
43
|
+
}, []);
|
|
44
|
+
const setValue = useCallback((v_0) => {
|
|
45
|
+
setLocal(v_0);
|
|
46
|
+
pendingRef.current = { value: v_0 };
|
|
47
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
48
|
+
timerRef.current = window.setTimeout(() => {
|
|
49
|
+
timerRef.current = null;
|
|
50
|
+
const p = pendingRef.current;
|
|
51
|
+
pendingRef.current = null;
|
|
52
|
+
if (p) saveRef.current(p.value);
|
|
53
|
+
}, delay);
|
|
54
|
+
}, [delay]);
|
|
55
|
+
const onFocus = useCallback(() => setIsFocused(true), []);
|
|
56
|
+
const onBlur = useCallback(() => {
|
|
57
|
+
setIsFocused(false);
|
|
58
|
+
flush();
|
|
59
|
+
}, [flush]);
|
|
60
|
+
useEffect(() => () => flush(), [flush]);
|
|
61
|
+
return {
|
|
62
|
+
value,
|
|
63
|
+
setValue,
|
|
64
|
+
isFocused,
|
|
65
|
+
onFocus,
|
|
66
|
+
onBlur,
|
|
67
|
+
flush,
|
|
68
|
+
cancel
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
//#endregion
|
|
73
|
+
export { useDebouncedField };
|
|
@@ -11,9 +11,9 @@ const NormalizedDataContext = React.createContext({
|
|
|
11
11
|
});
|
|
12
12
|
const NormalizedDataProvider = (t0) => {
|
|
13
13
|
const $ = c(13);
|
|
14
|
-
if ($[0] !== "
|
|
14
|
+
if ($[0] !== "a0f4a795dddd4ca9e7a329b1dc44ac458e5aff0b7cf376e05306b8ccf0cac2a8") {
|
|
15
15
|
for (let $i = 0; $i < 13; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
|
|
16
|
-
$[0] = "
|
|
16
|
+
$[0] = "a0f4a795dddd4ca9e7a329b1dc44ac458e5aff0b7cf376e05306b8ccf0cac2a8";
|
|
17
17
|
}
|
|
18
18
|
const { files, repeatableItems, children } = t0;
|
|
19
19
|
let t1;
|
|
@@ -58,11 +58,25 @@ function useNormalizedData() {
|
|
|
58
58
|
return React.use(NormalizedDataContext);
|
|
59
59
|
}
|
|
60
60
|
const EMPTY_IDS = [];
|
|
61
|
+
/**
|
|
62
|
+
* Returns the previously-returned array when `next` is element-wise identical to
|
|
63
|
+
* it. `useQueries` hands back a fresh `results` array whenever *any* subscribed
|
|
64
|
+
* block refetches, which otherwise produces new `pageBlocks` / `beforeBlocks` /
|
|
65
|
+
* `afterBlocks` / layout-data references on every keystroke-triggered refetch and
|
|
66
|
+
* re-renders unrelated blocks (e.g. the layout's navbar/footer) — even with
|
|
67
|
+
* React Compiler, since its memoization keys on input identity.
|
|
68
|
+
*/
|
|
69
|
+
function useStableArray(next) {
|
|
70
|
+
const ref = React.useRef(next);
|
|
71
|
+
const prev = ref.current;
|
|
72
|
+
if (prev !== next && (prev.length !== next.length || prev.some((v, i) => v !== next[i]))) ref.current = next;
|
|
73
|
+
return ref.current;
|
|
74
|
+
}
|
|
61
75
|
function usePageBlocks(pageStructure) {
|
|
62
|
-
const $ = c(
|
|
63
|
-
if ($[0] !== "
|
|
64
|
-
for (let $i = 0; $i <
|
|
65
|
-
$[0] = "
|
|
76
|
+
const $ = c(36);
|
|
77
|
+
if ($[0] !== "a0f4a795dddd4ca9e7a329b1dc44ac458e5aff0b7cf376e05306b8ccf0cac2a8") {
|
|
78
|
+
for (let $i = 0; $i < 36; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
|
|
79
|
+
$[0] = "a0f4a795dddd4ca9e7a329b1dc44ac458e5aff0b7cf376e05306b8ccf0cac2a8";
|
|
66
80
|
}
|
|
67
81
|
const blockIds = pageStructure.page.blockIds;
|
|
68
82
|
const beforeIds = pageStructure.layout?.beforeBlockIds ?? EMPTY_IDS;
|
|
@@ -87,52 +101,92 @@ function usePageBlocks(pageStructure) {
|
|
|
87
101
|
$[6] = t1;
|
|
88
102
|
} else t1 = $[6];
|
|
89
103
|
const results = useQueries(t1);
|
|
90
|
-
let
|
|
91
|
-
if ($[7] !==
|
|
92
|
-
|
|
104
|
+
let map;
|
|
105
|
+
if ($[7] !== allIds || $[8] !== results) {
|
|
106
|
+
map = /* @__PURE__ */ new Map();
|
|
93
107
|
for (let i = 0; i < allIds.length; i++) {
|
|
94
108
|
const data = results[i]?.data;
|
|
95
|
-
if (data)
|
|
96
|
-
}
|
|
97
|
-
const layoutFiles = [];
|
|
98
|
-
const layoutItems = [];
|
|
99
|
-
let t3;
|
|
100
|
-
if ($[13] !== afterIds || $[14] !== beforeIds) {
|
|
101
|
-
t3 = [...beforeIds, ...afterIds];
|
|
102
|
-
$[13] = afterIds;
|
|
103
|
-
$[14] = beforeIds;
|
|
104
|
-
$[15] = t3;
|
|
105
|
-
} else t3 = $[15];
|
|
106
|
-
for (const id_0 of t3) {
|
|
107
|
-
const bundle = bundleMap.get(id_0);
|
|
108
|
-
if (bundle) {
|
|
109
|
-
layoutFiles.push(...bundle.files);
|
|
110
|
-
layoutItems.push(...bundle.repeatableItems);
|
|
111
|
-
}
|
|
109
|
+
if (data) map.set(allIds[i], data);
|
|
112
110
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
111
|
+
$[7] = allIds;
|
|
112
|
+
$[8] = results;
|
|
113
|
+
$[9] = map;
|
|
114
|
+
} else map = $[9];
|
|
115
|
+
const bundleMap = map;
|
|
116
|
+
let t2;
|
|
117
|
+
if ($[10] !== afterIds || $[11] !== beforeIds) {
|
|
118
|
+
t2 = [...beforeIds, ...afterIds];
|
|
119
|
+
$[10] = afterIds;
|
|
120
|
+
$[11] = beforeIds;
|
|
121
|
+
$[12] = t2;
|
|
122
|
+
} else t2 = $[12];
|
|
123
|
+
const layoutIds = t2;
|
|
124
|
+
let t3;
|
|
125
|
+
if ($[13] !== bundleMap) {
|
|
126
|
+
t3 = (ids) => ids.map((id_0) => bundleMap.get(id_0)?.block).filter(_temp4);
|
|
127
|
+
$[13] = bundleMap;
|
|
128
|
+
$[14] = t3;
|
|
129
|
+
} else t3 = $[14];
|
|
130
|
+
const resolveBlocks = t3;
|
|
131
|
+
let t4;
|
|
132
|
+
if ($[15] !== blockIds || $[16] !== resolveBlocks) {
|
|
133
|
+
t4 = resolveBlocks(blockIds);
|
|
134
|
+
$[15] = blockIds;
|
|
135
|
+
$[16] = resolveBlocks;
|
|
136
|
+
$[17] = t4;
|
|
137
|
+
} else t4 = $[17];
|
|
138
|
+
const pageBlocks = useStableArray(t4);
|
|
139
|
+
let t5;
|
|
140
|
+
if ($[18] !== beforeIds || $[19] !== resolveBlocks) {
|
|
141
|
+
t5 = resolveBlocks(beforeIds);
|
|
142
|
+
$[18] = beforeIds;
|
|
143
|
+
$[19] = resolveBlocks;
|
|
144
|
+
$[20] = t5;
|
|
145
|
+
} else t5 = $[20];
|
|
146
|
+
const beforeBlocks = useStableArray(t5);
|
|
147
|
+
let t6;
|
|
148
|
+
if ($[21] !== afterIds || $[22] !== resolveBlocks) {
|
|
149
|
+
t6 = resolveBlocks(afterIds);
|
|
150
|
+
$[21] = afterIds;
|
|
151
|
+
$[22] = resolveBlocks;
|
|
152
|
+
$[23] = t6;
|
|
153
|
+
} else t6 = $[23];
|
|
154
|
+
const afterBlocks = useStableArray(t6);
|
|
155
|
+
let t7;
|
|
156
|
+
if ($[24] !== bundleMap || $[25] !== layoutIds) {
|
|
157
|
+
t7 = layoutIds.flatMap((id_1) => bundleMap.get(id_1)?.files ?? []);
|
|
158
|
+
$[24] = bundleMap;
|
|
159
|
+
$[25] = layoutIds;
|
|
160
|
+
$[26] = t7;
|
|
161
|
+
} else t7 = $[26];
|
|
162
|
+
const layoutFiles = useStableArray(t7);
|
|
163
|
+
let t8;
|
|
164
|
+
if ($[27] !== bundleMap || $[28] !== layoutIds) {
|
|
165
|
+
t8 = layoutIds.flatMap((id_2) => bundleMap.get(id_2)?.repeatableItems ?? []);
|
|
166
|
+
$[27] = bundleMap;
|
|
167
|
+
$[28] = layoutIds;
|
|
168
|
+
$[29] = t8;
|
|
169
|
+
} else t8 = $[29];
|
|
170
|
+
const layoutItems = useStableArray(t8);
|
|
171
|
+
let t9;
|
|
172
|
+
if ($[30] !== afterBlocks || $[31] !== beforeBlocks || $[32] !== layoutFiles || $[33] !== layoutItems || $[34] !== pageBlocks) {
|
|
173
|
+
t9 = {
|
|
174
|
+
pageBlocks,
|
|
175
|
+
beforeBlocks,
|
|
176
|
+
afterBlocks,
|
|
117
177
|
layoutFiles,
|
|
118
178
|
layoutItems
|
|
119
179
|
};
|
|
120
|
-
$[
|
|
121
|
-
$[
|
|
122
|
-
$[
|
|
123
|
-
$[
|
|
124
|
-
$[
|
|
125
|
-
$[
|
|
126
|
-
} else
|
|
127
|
-
return
|
|
180
|
+
$[30] = afterBlocks;
|
|
181
|
+
$[31] = beforeBlocks;
|
|
182
|
+
$[32] = layoutFiles;
|
|
183
|
+
$[33] = layoutItems;
|
|
184
|
+
$[34] = pageBlocks;
|
|
185
|
+
$[35] = t9;
|
|
186
|
+
} else t9 = $[35];
|
|
187
|
+
return t9;
|
|
128
188
|
}
|
|
129
189
|
/** Check if a value is a { _fileId } marker */
|
|
130
|
-
function _temp6(b_1) {
|
|
131
|
-
return b_1 != null;
|
|
132
|
-
}
|
|
133
|
-
function _temp5(b_0) {
|
|
134
|
-
return b_0 != null;
|
|
135
|
-
}
|
|
136
190
|
function _temp4(b) {
|
|
137
191
|
return b != null;
|
|
138
192
|
}
|