camox 0.18.2 → 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.
@@ -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] !== "c0a93b833259c3454f5e0be895bfb83e45c46c4f835869bb61d29ad29a8dc786") {
14
+ if ($[0] !== "a0f4a795dddd4ca9e7a329b1dc44ac458e5aff0b7cf376e05306b8ccf0cac2a8") {
15
15
  for (let $i = 0; $i < 13; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
16
- $[0] = "c0a93b833259c3454f5e0be895bfb83e45c46c4f835869bb61d29ad29a8dc786";
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(16);
63
- if ($[0] !== "c0a93b833259c3454f5e0be895bfb83e45c46c4f835869bb61d29ad29a8dc786") {
64
- for (let $i = 0; $i < 16; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
65
- $[0] = "c0a93b833259c3454f5e0be895bfb83e45c46c4f835869bb61d29ad29a8dc786";
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 t2;
91
- if ($[7] !== afterIds || $[8] !== allIds || $[9] !== beforeIds || $[10] !== blockIds || $[11] !== results) {
92
- const bundleMap = /* @__PURE__ */ new Map();
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) bundleMap.set(allIds[i], 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
- t2 = {
114
- pageBlocks: blockIds.map((id_1) => bundleMap.get(id_1)?.block).filter(_temp4),
115
- beforeBlocks: beforeIds.map((id_2) => bundleMap.get(id_2)?.block).filter(_temp5),
116
- afterBlocks: afterIds.map((id_3) => bundleMap.get(id_3)?.block).filter(_temp6),
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
- $[7] = afterIds;
121
- $[8] = allIds;
122
- $[9] = beforeIds;
123
- $[10] = blockIds;
124
- $[11] = results;
125
- $[12] = t2;
126
- } else t2 = $[12];
127
- return t2;
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
  }