@questpie/admin 3.2.0 → 3.2.1

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.
Files changed (85) hide show
  1. package/dist/client/blocks/block-renderer.d.mts +12 -2
  2. package/dist/client/blocks/block-renderer.mjs +357 -49
  3. package/dist/client/components/blocks/block-editor-context.mjs +11 -1
  4. package/dist/client/components/blocks/block-editor-provider.mjs +68 -26
  5. package/dist/client/components/blocks/block-item.mjs +181 -170
  6. package/dist/client/components/blocks/utils/tree-utils.mjs +13 -1
  7. package/dist/client/components/fields/array-field.mjs +177 -118
  8. package/dist/client/components/filter-builder/filter-builder-sheet.mjs +305 -310
  9. package/dist/client/components/filter-builder/filters-tab.mjs +1 -1
  10. package/dist/client/components/history-sidebar.mjs +121 -114
  11. package/dist/client/components/preview/live-preview-mode.mjs +140 -114
  12. package/dist/client/components/preview/preview-pane.mjs +288 -333
  13. package/dist/client/components/primitives/option-label.mjs +44 -0
  14. package/dist/client/components/primitives/select-multi.mjs +408 -383
  15. package/dist/client/components/primitives/select-single.mjs +387 -357
  16. package/dist/client/components/widgets/chart-widget.mjs +168 -143
  17. package/dist/client/contexts/focus-context.d.mts +11 -0
  18. package/dist/client/contexts/focus-context.mjs +51 -34
  19. package/dist/client/hooks/use-brand.mjs +2 -1
  20. package/dist/client/preview/block-scope-context.d.mts +2 -2
  21. package/dist/client/preview/block-scope-context.mjs +10 -20
  22. package/dist/client/preview/index.d.mts +1 -1
  23. package/dist/client/preview/patch.mjs +100 -0
  24. package/dist/client/preview/preview-banner.d.mts +2 -2
  25. package/dist/client/preview/preview-field.d.mts +34 -5
  26. package/dist/client/preview/preview-field.mjs +385 -118
  27. package/dist/client/preview/types.d.mts +82 -3
  28. package/dist/client/preview/types.mjs +85 -6
  29. package/dist/client/preview/use-collection-preview.d.mts +19 -1
  30. package/dist/client/preview/use-collection-preview.mjs +182 -58
  31. package/dist/client/runtime/index.d.mts +2 -2
  32. package/dist/client/runtime/index.mjs +2 -2
  33. package/dist/client/runtime/provider.d.mts +5 -5
  34. package/dist/client/utils/build-field-definitions-from-schema.mjs +8 -3
  35. package/dist/client/views/auth/reset-password-form.d.mts +2 -2
  36. package/dist/client/views/auth/setup-form.d.mts +2 -2
  37. package/dist/client/views/collection/bulk-action-toolbar.mjs +23 -25
  38. package/dist/client/views/collection/cells/primitive-cells.mjs +63 -13
  39. package/dist/client/views/collection/columns/build-columns.mjs +1 -0
  40. package/dist/client/views/collection/form-view.mjs +262 -33
  41. package/dist/client/views/collection/table-view.mjs +16 -11
  42. package/dist/client/views/layout/admin-layout-provider.d.mts +5 -5
  43. package/dist/client/views/layout/admin-layout-provider.mjs +107 -16
  44. package/dist/client.d.mts +2 -2
  45. package/dist/client.mjs +1 -1
  46. package/dist/components/rich-text/rich-text-renderer.d.mts +2 -2
  47. package/dist/index.d.mts +2 -2
  48. package/dist/index.mjs +1 -1
  49. package/dist/server/augmentation/common.d.mts +8 -4
  50. package/dist/server/augmentation/form-layout.d.mts +1 -1
  51. package/dist/server/i18n/messages/cs.mjs +11 -0
  52. package/dist/server/i18n/messages/de.mjs +11 -0
  53. package/dist/server/i18n/messages/en.mjs +11 -0
  54. package/dist/server/i18n/messages/es.mjs +11 -0
  55. package/dist/server/i18n/messages/fr.mjs +11 -0
  56. package/dist/server/i18n/messages/pl.mjs +11 -0
  57. package/dist/server/i18n/messages/pt.mjs +11 -0
  58. package/dist/server/i18n/messages/sk.mjs +11 -0
  59. package/dist/server/modules/admin/block/block-builder.d.mts +7 -10
  60. package/dist/server/modules/admin/block/block-builder.mjs +7 -10
  61. package/dist/server/modules/admin/collections/account.d.mts +50 -50
  62. package/dist/server/modules/admin/collections/admin-locks.d.mts +54 -54
  63. package/dist/server/modules/admin/collections/admin-preferences.d.mts +39 -39
  64. package/dist/server/modules/admin/collections/admin-saved-views.d.mts +47 -47
  65. package/dist/server/modules/admin/collections/apikey.d.mts +68 -68
  66. package/dist/server/modules/admin/collections/assets.d.mts +57 -20
  67. package/dist/server/modules/admin/collections/session.d.mts +42 -42
  68. package/dist/server/modules/admin/collections/user.d.mts +100 -34
  69. package/dist/server/modules/admin/collections/user.mjs +4 -4
  70. package/dist/server/modules/admin/collections/verification.d.mts +32 -32
  71. package/dist/server/modules/admin/index.d.mts +3 -3
  72. package/dist/server/modules/admin/routes/admin-config.d.mts +2 -2
  73. package/dist/server/modules/admin/routes/admin-config.mjs +9 -12
  74. package/dist/server/modules/admin/routes/execute-action.d.mts +9 -9
  75. package/dist/server/modules/admin/routes/locales.d.mts +2 -2
  76. package/dist/server/modules/admin/routes/preview.d.mts +11 -11
  77. package/dist/server/modules/admin/routes/reactive.d.mts +9 -9
  78. package/dist/server/modules/admin/routes/setup.d.mts +7 -7
  79. package/dist/server/modules/admin/routes/translations.d.mts +4 -4
  80. package/dist/server/modules/admin/routes/translations.mjs +1 -1
  81. package/dist/server/modules/admin/routes/widget-data.d.mts +5 -5
  82. package/dist/server/modules/admin-preferences/collections/admin-preferences.mjs +4 -6
  83. package/dist/server/modules/admin-preferences/collections/saved-views.d.mts +31 -33
  84. package/dist/server/modules/admin-preferences/collections/saved-views.mjs +4 -6
  85. package/package.json +3 -3
@@ -1,19 +1,98 @@
1
1
  //#region src/client/preview/types.ts
2
+ const MAX_INLINE_EDIT_PAYLOAD_BYTES = 64 * 1024;
3
+ const MAX_PATCH_BATCH_OPS = 500;
4
+ function isRecord(data) {
5
+ return !!data && typeof data === "object" && !Array.isArray(data);
6
+ }
7
+ function isString(value) {
8
+ return typeof value === "string";
9
+ }
10
+ function isNumber(value) {
11
+ return typeof value === "number" && Number.isFinite(value);
12
+ }
13
+ function isPositiveInteger(value) {
14
+ return Number.isInteger(value) && value >= 0;
15
+ }
16
+ function isInputKind(value) {
17
+ return value === "text" || value === "textarea" || value === "number" || value === "boolean";
18
+ }
19
+ function isPreviewFieldType(value) {
20
+ return value === "regular" || value === "block" || value === "relation";
21
+ }
22
+ function isBlockInsertPosition(value) {
23
+ if (!isRecord(value)) return false;
24
+ return (value.parentId === null || isString(value.parentId)) && isPositiveInteger(value.index);
25
+ }
26
+ function isSerializableValue(value) {
27
+ try {
28
+ const seen = /* @__PURE__ */ new WeakSet();
29
+ JSON.stringify(value, (_key, nestedValue) => {
30
+ if (typeof nestedValue === "function") throw new TypeError("Functions are not serializable");
31
+ if (typeof nestedValue === "symbol") throw new TypeError("Symbols are not serializable");
32
+ if (typeof nestedValue === "bigint") throw new TypeError("BigInts are not JSON serializable");
33
+ if (nestedValue && typeof nestedValue === "object") {
34
+ if (seen.has(nestedValue)) throw new TypeError("Circular values are not serializable");
35
+ seen.add(nestedValue);
36
+ }
37
+ return nestedValue;
38
+ });
39
+ return true;
40
+ } catch {
41
+ return false;
42
+ }
43
+ }
44
+ function getJsonByteLength(value) {
45
+ try {
46
+ const json = JSON.stringify(value);
47
+ if (json === void 0) return 0;
48
+ if (typeof TextEncoder === "undefined") return json.length;
49
+ return new TextEncoder().encode(json).length;
50
+ } catch {
51
+ return Number.POSITIVE_INFINITY;
52
+ }
53
+ }
54
+ function isReasonablePayload(value, maxBytes) {
55
+ return isSerializableValue(value) && getJsonByteLength(value) <= maxBytes;
56
+ }
57
+ function isPreviewPatchOp(value) {
58
+ if (!isRecord(value)) return false;
59
+ if (value.op !== "set" && value.op !== "remove") return false;
60
+ if (!isString(value.path) || value.path.length === 0) return false;
61
+ if (value.op === "set" && !isSerializableValue(value.value)) return false;
62
+ return true;
63
+ }
2
64
  /**
3
65
  * Check if a message is from admin to preview.
4
66
  */
5
67
  function isAdminToPreviewMessage(data) {
6
- if (!data || typeof data !== "object") return false;
7
- const msg = data;
8
- return msg.type === "PREVIEW_REFRESH" || msg.type === "SELECT_BLOCK" || msg.type === "FOCUS_FIELD";
68
+ if (!isRecord(data)) return false;
69
+ switch (data.type) {
70
+ case "PREVIEW_REFRESH": return data.changedField === void 0 || isString(data.changedField);
71
+ case "SELECT_BLOCK": return isString(data.blockId) && data.blockId.length > 0;
72
+ case "FOCUS_FIELD": return isString(data.fieldPath) && data.fieldPath.length > 0;
73
+ case "INIT_SNAPSHOT":
74
+ case "COMMIT": return isPositiveInteger(data.seq) && isSerializableValue(data.data);
75
+ case "PATCH_BATCH": return isPositiveInteger(data.seq) && Array.isArray(data.ops) && data.ops.length <= MAX_PATCH_BATCH_OPS && data.ops.every(isPreviewPatchOp) && (data.snapshotVersion === void 0 || isPositiveInteger(data.snapshotVersion));
76
+ case "FULL_RESYNC": return data.reason === void 0 || isString(data.reason);
77
+ default: return false;
78
+ }
9
79
  }
10
80
  /**
11
81
  * Check if a message is from preview to admin.
12
82
  */
13
83
  function isPreviewToAdminMessage(data) {
14
- if (!data || typeof data !== "object") return false;
15
- const msg = data;
16
- return msg.type === "PREVIEW_READY" || msg.type === "FIELD_CLICKED" || msg.type === "BLOCK_CLICKED" || msg.type === "REFRESH_COMPLETE";
84
+ if (!isRecord(data)) return false;
85
+ switch (data.type) {
86
+ case "PREVIEW_READY": return true;
87
+ case "FIELD_CLICKED": return isString(data.fieldPath) && data.fieldPath.length > 0 && (data.blockId === void 0 || isString(data.blockId)) && (data.fieldType === void 0 || isPreviewFieldType(data.fieldType));
88
+ case "BLOCK_CLICKED": return isString(data.blockId) && data.blockId.length > 0;
89
+ case "BLOCK_INSERT_REQUESTED": return isBlockInsertPosition(data.position) && (data.referenceBlockId === void 0 || isString(data.referenceBlockId));
90
+ case "REFRESH_COMPLETE": return isNumber(data.timestamp);
91
+ case "PATCH_APPLIED": return isPositiveInteger(data.seq);
92
+ case "RESYNC_REQUEST": return data.reason === void 0 || isString(data.reason);
93
+ case "FIELD_VALUE_EDITED": return isString(data.path) && data.path.length > 0 && isInputKind(data.inputKind) && (data.blockId === void 0 || isString(data.blockId)) && (data.fieldType === void 0 || isPreviewFieldType(data.fieldType)) && isReasonablePayload(data.value, MAX_INLINE_EDIT_PAYLOAD_BYTES);
94
+ default: return false;
95
+ }
17
96
  }
18
97
 
19
98
  //#endregion
@@ -15,7 +15,7 @@ type UseCollectionPreviewOptions<TData> = {
15
15
  onRefresh: () => void | Promise<void>;
16
16
  };
17
17
  type UseCollectionPreviewResult<TData> = {
18
- /** Current data (from initialData, refreshed via onRefresh) */
18
+ /** Current data from the iframe draft mirror */
19
19
  data: TData;
20
20
  /** Whether we're in preview mode (inside admin iframe) */
21
21
  isPreviewMode: boolean;
@@ -30,6 +30,24 @@ type UseCollectionPreviewResult<TData> = {
30
30
  }) => void;
31
31
  /** Call when a block is clicked in preview */
32
32
  handleBlockClick: (blockId: string) => void;
33
+ /** Call when a preview insert control requests a new block */
34
+ handleBlockInsert: (payload: PreviewBlockInsertRequestedPayload) => void;
35
+ /** Call when an inline preview edit is committed */
36
+ handleFieldValueEdited: (payload: PreviewFieldValueEditedPayload) => void;
37
+ };
38
+ type PreviewBlockInsertRequestedPayload = {
39
+ position: {
40
+ parentId: string | null;
41
+ index: number;
42
+ };
43
+ referenceBlockId?: string;
44
+ };
45
+ type PreviewFieldValueEditedPayload = {
46
+ path: string;
47
+ value: unknown;
48
+ inputKind: "text" | "textarea" | "number" | "boolean";
49
+ blockId?: string;
50
+ fieldType?: "regular" | "block" | "relation";
33
51
  };
34
52
  /**
35
53
  * Hook for receiving live preview data from admin.
@@ -1,5 +1,6 @@
1
1
  "use client";
2
2
 
3
+ import { applyPatchBatchImmutable, cloneSnapshot, shouldApplyPatchBatch } from "./patch.mjs";
3
4
  import { c } from "react/compiler-runtime";
4
5
  import * as React from "react";
5
6
 
@@ -42,84 +43,151 @@ import * as React from "react";
42
43
  * ```
43
44
  */
44
45
  function useCollectionPreview(t0) {
45
- const $ = c(11);
46
+ const $ = c(30);
46
47
  const { initialData, onRefresh } = t0;
48
+ let t1;
49
+ if ($[0] !== initialData) {
50
+ t1 = () => cloneSnapshot(initialData);
51
+ $[0] = initialData;
52
+ $[1] = t1;
53
+ } else t1 = $[1];
54
+ const [draftData, setDraftData] = React.useState(t1);
47
55
  const [selectedBlockId, setSelectedBlockId] = React.useState(null);
48
56
  const [focusedField, setFocusedField] = React.useState(null);
49
- let t1;
50
- bb0: {
51
- if (typeof window === "undefined") {
52
- t1 = false;
53
- break bb0;
54
- }
55
- try {
56
- t1 = window.self !== window.top;
57
- } catch {
58
- t1 = true;
59
- }
60
- }
61
- const isPreviewMode = t1;
62
- const onRefreshRef = React.useRef(onRefresh);
57
+ const [isPreviewMode, setIsPreviewMode] = React.useState(false);
58
+ const lastAppliedSeqRef = React.useRef(null);
59
+ const initialDataRef = React.useRef(initialData);
63
60
  let t2;
64
61
  let t3;
65
- if ($[0] !== onRefresh) {
62
+ if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
66
63
  t2 = () => {
67
- onRefreshRef.current = onRefresh;
64
+ try {
65
+ setIsPreviewMode(window.self !== window.top);
66
+ } catch {
67
+ setIsPreviewMode(true);
68
+ }
68
69
  };
69
- t3 = [onRefresh];
70
- $[0] = onRefresh;
71
- $[1] = t2;
72
- $[2] = t3;
70
+ t3 = [];
71
+ $[2] = t2;
72
+ $[3] = t3;
73
73
  } else {
74
- t2 = $[1];
75
- t3 = $[2];
74
+ t2 = $[2];
75
+ t3 = $[3];
76
76
  }
77
77
  React.useEffect(t2, t3);
78
+ const onRefreshRef = React.useRef(onRefresh);
78
79
  let t4;
79
80
  let t5;
80
- if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
81
+ if ($[4] !== onRefresh) {
81
82
  t4 = () => {
83
+ onRefreshRef.current = onRefresh;
84
+ };
85
+ t5 = [onRefresh];
86
+ $[4] = onRefresh;
87
+ $[5] = t4;
88
+ $[6] = t5;
89
+ } else {
90
+ t4 = $[5];
91
+ t5 = $[6];
92
+ }
93
+ React.useEffect(t4, t5);
94
+ let t6;
95
+ let t7;
96
+ if ($[7] !== initialData) {
97
+ t6 = () => {
98
+ initialDataRef.current = initialData;
99
+ setDraftData(cloneSnapshot(initialData));
100
+ };
101
+ t7 = [initialData];
102
+ $[7] = initialData;
103
+ $[8] = t6;
104
+ $[9] = t7;
105
+ } else {
106
+ t6 = $[8];
107
+ t7 = $[9];
108
+ }
109
+ React.useEffect(t6, t7);
110
+ let t8;
111
+ let t9;
112
+ if ($[10] !== isPreviewMode) {
113
+ t8 = () => {
82
114
  if (!isPreviewMode) return;
83
115
  window.parent.postMessage({ type: "PREVIEW_READY" }, "*");
84
116
  const handleMessage = async (event) => {
85
117
  const message = event.data;
86
- if (!message || typeof message !== "object" || !message.type) return;
87
- bb32: switch (message.type) {
118
+ if (!isPreviewAdminMessage(message)) return;
119
+ bb24: switch (message.type) {
88
120
  case "PREVIEW_REFRESH":
89
121
  await onRefreshRef.current();
122
+ setDraftData(cloneSnapshot(initialDataRef.current));
90
123
  window.parent.postMessage({
91
124
  type: "REFRESH_COMPLETE",
92
125
  timestamp: Date.now()
93
126
  }, "*");
94
- break bb32;
127
+ break bb24;
95
128
  case "SELECT_BLOCK":
96
129
  setSelectedBlockId(message.blockId);
97
- break bb32;
130
+ break bb24;
98
131
  case "FOCUS_FIELD":
99
132
  setFocusedField(message.fieldPath);
100
133
  setTimeout(() => {
101
- const element = document.querySelector(`[data-preview-field="${message.fieldPath}"]`);
134
+ const element = findPreviewFieldElement(message.fieldPath);
102
135
  if (element) element.scrollIntoView({
103
136
  behavior: "smooth",
104
137
  block: "center"
105
138
  });
106
139
  }, 150);
140
+ break bb24;
141
+ case "INIT_SNAPSHOT":
142
+ lastAppliedSeqRef.current = message.seq;
143
+ setDraftData(cloneSnapshot(message.data));
144
+ break bb24;
145
+ case "PATCH_BATCH":
146
+ if (!shouldApplyPatchBatch(lastAppliedSeqRef.current, message.seq)) break bb24;
147
+ try {
148
+ setDraftData((current) => applyPatchBatchImmutable(current, message.ops));
149
+ lastAppliedSeqRef.current = message.seq;
150
+ window.parent.postMessage({
151
+ type: "PATCH_APPLIED",
152
+ seq: message.seq,
153
+ snapshotVersion: message.snapshotVersion
154
+ }, "*");
155
+ } catch (t10$1) {
156
+ const error = t10$1;
157
+ window.parent.postMessage({
158
+ type: "RESYNC_REQUEST",
159
+ reason: error instanceof Error ? error.message : "Failed to apply preview patch batch"
160
+ }, "*");
161
+ }
162
+ break bb24;
163
+ case "COMMIT":
164
+ lastAppliedSeqRef.current = message.seq;
165
+ setDraftData(cloneSnapshot(message.data));
166
+ break bb24;
167
+ case "FULL_RESYNC":
168
+ await onRefreshRef.current();
169
+ setDraftData(cloneSnapshot(initialDataRef.current));
170
+ window.parent.postMessage({
171
+ type: "REFRESH_COMPLETE",
172
+ timestamp: Date.now()
173
+ }, "*");
107
174
  }
108
175
  };
109
176
  window.addEventListener("message", handleMessage);
110
177
  return () => window.removeEventListener("message", handleMessage);
111
178
  };
112
- t5 = [isPreviewMode];
113
- $[3] = t4;
114
- $[4] = t5;
179
+ t9 = [isPreviewMode];
180
+ $[10] = isPreviewMode;
181
+ $[11] = t8;
182
+ $[12] = t9;
115
183
  } else {
116
- t4 = $[3];
117
- t5 = $[4];
184
+ t8 = $[11];
185
+ t9 = $[12];
118
186
  }
119
- React.useEffect(t4, t5);
120
- let t6;
121
- if ($[5] === Symbol.for("react.memo_cache_sentinel")) {
122
- t6 = (fieldPath, context) => {
187
+ React.useEffect(t8, t9);
188
+ let t10;
189
+ if ($[13] !== isPreviewMode) {
190
+ t10 = (fieldPath, context) => {
123
191
  if (isPreviewMode) window.parent.postMessage({
124
192
  type: "FIELD_CLICKED",
125
193
  fieldPath,
@@ -127,36 +195,92 @@ function useCollectionPreview(t0) {
127
195
  fieldType: context?.fieldType
128
196
  }, "*");
129
197
  };
130
- $[5] = t6;
131
- } else t6 = $[5];
132
- const handleFieldClick = t6;
133
- let t7;
134
- if ($[6] === Symbol.for("react.memo_cache_sentinel")) {
135
- t7 = (blockId) => {
198
+ $[13] = isPreviewMode;
199
+ $[14] = t10;
200
+ } else t10 = $[14];
201
+ const handleFieldClick = t10;
202
+ let t11;
203
+ if ($[15] !== isPreviewMode) {
204
+ t11 = (blockId) => {
136
205
  if (isPreviewMode) window.parent.postMessage({
137
206
  type: "BLOCK_CLICKED",
138
207
  blockId
139
208
  }, "*");
140
209
  };
141
- $[6] = t7;
142
- } else t7 = $[6];
143
- const handleBlockClick = t7;
144
- let t8;
145
- if ($[7] !== focusedField || $[8] !== initialData || $[9] !== selectedBlockId) {
146
- t8 = {
147
- data: initialData,
210
+ $[15] = isPreviewMode;
211
+ $[16] = t11;
212
+ } else t11 = $[16];
213
+ const handleBlockClick = t11;
214
+ let t12;
215
+ if ($[17] !== isPreviewMode) {
216
+ t12 = (payload) => {
217
+ if (isPreviewMode) window.parent.postMessage({
218
+ type: "FIELD_VALUE_EDITED",
219
+ ...payload
220
+ }, "*");
221
+ };
222
+ $[17] = isPreviewMode;
223
+ $[18] = t12;
224
+ } else t12 = $[18];
225
+ const handleFieldValueEdited = t12;
226
+ let t13;
227
+ if ($[19] !== isPreviewMode) {
228
+ t13 = (payload_0) => {
229
+ if (isPreviewMode) window.parent.postMessage({
230
+ type: "BLOCK_INSERT_REQUESTED",
231
+ ...payload_0
232
+ }, "*");
233
+ };
234
+ $[19] = isPreviewMode;
235
+ $[20] = t13;
236
+ } else t13 = $[20];
237
+ const handleBlockInsert = t13;
238
+ let t14;
239
+ if ($[21] !== draftData || $[22] !== focusedField || $[23] !== handleBlockClick || $[24] !== handleBlockInsert || $[25] !== handleFieldClick || $[26] !== handleFieldValueEdited || $[27] !== isPreviewMode || $[28] !== selectedBlockId) {
240
+ t14 = {
241
+ data: draftData,
148
242
  isPreviewMode,
149
243
  selectedBlockId,
150
244
  focusedField,
151
245
  handleFieldClick,
152
- handleBlockClick
246
+ handleBlockClick,
247
+ handleBlockInsert,
248
+ handleFieldValueEdited
153
249
  };
154
- $[7] = focusedField;
155
- $[8] = initialData;
156
- $[9] = selectedBlockId;
157
- $[10] = t8;
158
- } else t8 = $[10];
159
- return t8;
250
+ $[21] = draftData;
251
+ $[22] = focusedField;
252
+ $[23] = handleBlockClick;
253
+ $[24] = handleBlockInsert;
254
+ $[25] = handleFieldClick;
255
+ $[26] = handleFieldValueEdited;
256
+ $[27] = isPreviewMode;
257
+ $[28] = selectedBlockId;
258
+ $[29] = t14;
259
+ } else t14 = $[29];
260
+ return t14;
261
+ }
262
+ function isPreviewAdminMessage(data) {
263
+ if (!data || typeof data !== "object") return false;
264
+ const message = data;
265
+ switch (message.type) {
266
+ case "PREVIEW_REFRESH":
267
+ case "FULL_RESYNC": return true;
268
+ case "SELECT_BLOCK": return typeof message.blockId === "string";
269
+ case "FOCUS_FIELD": return typeof message.fieldPath === "string";
270
+ case "INIT_SNAPSHOT":
271
+ case "COMMIT": return typeof message.seq === "number";
272
+ case "PATCH_BATCH": return typeof message.seq === "number" && Array.isArray(message.ops) && message.ops.every(isPreviewPatchOp);
273
+ default: return false;
274
+ }
275
+ }
276
+ function isPreviewPatchOp(value) {
277
+ if (!value || typeof value !== "object") return false;
278
+ const op = value;
279
+ return (op.op === "set" || op.op === "remove") && typeof op.path === "string";
280
+ }
281
+ function findPreviewFieldElement(fieldPath) {
282
+ const escaped = typeof CSS !== "undefined" && typeof CSS.escape === "function" ? CSS.escape(fieldPath) : fieldPath.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
283
+ return document.querySelector(`[data-preview-field="${escaped}"]`);
160
284
  }
161
285
 
162
286
  //#endregion
@@ -1,5 +1,5 @@
1
1
  import "./content-locales-provider.mjs";
2
2
  import "./locale-scope.mjs";
3
3
  import { AdminProvider, AdminProviderProps, AdminState, AdminStore, selectAdmin, selectBasePath, selectClient, selectNavigate, useAdminStore } from "./provider.mjs";
4
- import { useShallow } from "zustand/shallow";
5
- export { useShallow };
4
+ import { useShallow as useShallow$1 } from "zustand/shallow";
5
+ export { useShallow$1 as useShallow };
@@ -1,6 +1,6 @@
1
1
  import { AdminProvider, selectAdmin, selectAuthClient, selectBasePath, selectClient, selectContentLocale, selectNavigate, selectRealtime, selectSetContentLocale, useAdminStore } from "./provider.mjs";
2
2
  import { useSafeContentLocales } from "./content-locales-provider.mjs";
3
3
  import { LocaleScopeProvider, useScopedLocale } from "./locale-scope.mjs";
4
- import { useShallow } from "zustand/shallow";
4
+ import { useShallow as useShallow$1 } from "zustand/shallow";
5
5
 
6
- export { useShallow };
6
+ export { useShallow$1 as useShallow };
@@ -106,17 +106,17 @@ interface AdminProviderProps {
106
106
  /**
107
107
  * Use server-side translations (fetched via getAdminTranslations RPC).
108
108
  * When true, translations are fetched from the server configured via
109
- * .adminLocale() and config translations.
109
+ * config/admin.ts and config translations.
110
110
  *
111
111
  * @default false (for backwards compatibility)
112
112
  *
113
113
  * @example
114
114
  * ```tsx
115
115
  * // Server configures locales and messages
116
- * const app = runtimeConfig({
117
- * modules: [adminModule],
118
- * adminLocale: { locales: ["en", "sk"], defaultLocale: "en" },
119
- * messages: { sk: { "common.save": "Ulozit" } },
116
+ * import { adminConfig } from "#questpie/factories";
117
+ *
118
+ * export default adminConfig({
119
+ * locale: { locales: ["en", "sk"], defaultLocale: "en" },
120
120
  * });
121
121
  *
122
122
  * // Client fetches from server
@@ -78,7 +78,7 @@ function buildFieldDefinition(fieldName, fieldSchema, relations, registry, overr
78
78
  const fieldBuilder = registry[fieldType];
79
79
  if (!fieldBuilder) return null;
80
80
  const config = buildFieldConfig(fieldName, metadata, relations, registry, fieldType);
81
- const adminConfig = metadata.meta?.admin;
81
+ const adminConfig = getAdminConfig(metadata.meta);
82
82
  if (adminConfig) applyAdminConfig(config, adminConfig);
83
83
  if (overrides) Object.assign(config, overrides);
84
84
  return configureField(fieldBuilder, config);
@@ -211,7 +211,7 @@ function buildNestedFieldDefinitions(nestedFields, relations, registry) {
211
211
  const fieldBuilder = registry[fieldType];
212
212
  if (!fieldBuilder) continue;
213
213
  const config = buildFieldConfig(nestedName, nestedMetadata, relations, registry, fieldType);
214
- const adminConfig = nestedMetadata.meta?.admin;
214
+ const adminConfig = getAdminConfig(nestedMetadata.meta);
215
215
  if (adminConfig) applyAdminConfig(config, adminConfig);
216
216
  result[nestedName] = configureField(fieldBuilder, config);
217
217
  }
@@ -233,7 +233,7 @@ function mapArrayItemType(type) {
233
233
  ]).has(type) ? type : null;
234
234
  }
235
235
  /**
236
- * Apply admin config overrides from server meta.admin
236
+ * Apply admin config overrides from server meta
237
237
  *
238
238
  * Since each field type has its own admin meta with only valid properties,
239
239
  * we simply copy all defined properties from adminConfig to config.
@@ -241,6 +241,11 @@ function mapArrayItemType(type) {
241
241
  function applyAdminConfig(config, adminConfig) {
242
242
  for (const [key, value] of Object.entries(adminConfig)) if (value !== void 0) config[key] = value;
243
243
  }
244
+ function getAdminConfig(meta) {
245
+ if (!meta || typeof meta !== "object") return void 0;
246
+ const record = meta;
247
+ return record.admin ?? record;
248
+ }
244
249
  /**
245
250
  * Check if a field is a system field that shouldn't be in forms
246
251
  */
@@ -1,4 +1,4 @@
1
- import * as react_jsx_runtime6 from "react/jsx-runtime";
1
+ import * as react_jsx_runtime5 from "react/jsx-runtime";
2
2
 
3
3
  //#region src/client/views/auth/reset-password-form.d.ts
4
4
  /**
@@ -60,6 +60,6 @@ declare function ResetPasswordForm({
60
60
  minPasswordLength,
61
61
  className,
62
62
  error
63
- }: ResetPasswordFormProps): react_jsx_runtime6.JSX.Element;
63
+ }: ResetPasswordFormProps): react_jsx_runtime5.JSX.Element;
64
64
  //#endregion
65
65
  export { ResetPasswordForm };
@@ -1,4 +1,4 @@
1
- import * as react_jsx_runtime5 from "react/jsx-runtime";
1
+ import * as react_jsx_runtime6 from "react/jsx-runtime";
2
2
 
3
3
  //#region src/client/views/auth/setup-form.d.ts
4
4
  /**
@@ -55,6 +55,6 @@ declare function SetupForm({
55
55
  className,
56
56
  error,
57
57
  minPasswordLength
58
- }: SetupFormProps): react_jsx_runtime5.JSX.Element;
58
+ }: SetupFormProps): react_jsx_runtime6.JSX.Element;
59
59
  //#endregion
60
60
  export { SetupForm, SetupFormValues };