@questpie/admin 3.2.2 → 3.2.4

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 (53) hide show
  1. package/dist/client/blocks/block-renderer.d.mts +2 -2
  2. package/dist/client/components/blocks/block-library-sidebar.mjs +126 -113
  3. package/dist/client/components/fields/json-field.mjs +114 -118
  4. package/dist/client/components/fields/rich-text-editor/bubble-menu.mjs +38 -40
  5. package/dist/client/components/fields/rich-text-editor/image-popover.mjs +6 -17
  6. package/dist/client/components/fields/rich-text-editor/index.mjs +71 -87
  7. package/dist/client/components/history-sidebar.mjs +25 -10
  8. package/dist/client/components/media/media-picker-dialog.mjs +237 -254
  9. package/dist/client/components/preview/live-preview-mode.mjs +230 -203
  10. package/dist/client/components/primitives/asset-preview.mjs +1 -1
  11. package/dist/client/contexts/focus-context.d.mts +4 -0
  12. package/dist/client/contexts/focus-context.mjs +106 -86
  13. package/dist/client/preview/block-scope-context.d.mts +2 -2
  14. package/dist/client/preview/diff.mjs +110 -0
  15. package/dist/client/preview/preview-banner.d.mts +2 -2
  16. package/dist/client/preview/preview-field.d.mts +4 -4
  17. package/dist/client/preview/preview-field.mjs +125 -187
  18. package/dist/client/preview/use-collection-preview.mjs +49 -21
  19. package/dist/client/views/auth/accept-invite-form.d.mts +2 -2
  20. package/dist/client/views/auth/auth-layout.d.mts +3 -3
  21. package/dist/client/views/auth/forgot-password-form.d.mts +2 -2
  22. package/dist/client/views/auth/reset-password-form.d.mts +2 -2
  23. package/dist/client/views/collection/bulk-action-toolbar.mjs +135 -156
  24. package/dist/client/views/collection/field-renderer.mjs +162 -51
  25. package/dist/client/views/collection/form-view.mjs +43 -81
  26. package/dist/client/views/collection/table-view.mjs +12 -10
  27. package/dist/client/views/common/global-search.mjs +199 -182
  28. package/dist/client/views/globals/global-form-view.mjs +625 -621
  29. package/dist/client/views/layout/admin-router.mjs +84 -100
  30. package/dist/client/views/pages/forgot-password-page.d.mts +2 -2
  31. package/dist/client/views/pages/invite-page.d.mts +2 -2
  32. package/dist/server/modules/admin/collections/account.d.mts +50 -50
  33. package/dist/server/modules/admin/collections/admin-locks.d.mts +54 -54
  34. package/dist/server/modules/admin/collections/admin-preferences.d.mts +39 -39
  35. package/dist/server/modules/admin/collections/admin-saved-views.d.mts +47 -47
  36. package/dist/server/modules/admin/collections/apikey.d.mts +67 -67
  37. package/dist/server/modules/admin/collections/assets.d.mts +39 -39
  38. package/dist/server/modules/admin/collections/session.d.mts +42 -42
  39. package/dist/server/modules/admin/collections/user.d.mts +62 -62
  40. package/dist/server/modules/admin/collections/verification.d.mts +23 -23
  41. package/dist/server/modules/admin/routes/admin-config.d.mts +2 -2
  42. package/dist/server/modules/admin/routes/execute-action.d.mts +9 -9
  43. package/dist/server/modules/admin/routes/locales.d.mts +2 -2
  44. package/dist/server/modules/admin/routes/preview.d.mts +11 -11
  45. package/dist/server/modules/admin/routes/reactive.d.mts +9 -9
  46. package/dist/server/modules/admin/routes/setup.d.mts +7 -7
  47. package/dist/server/modules/admin/routes/translations.d.mts +4 -4
  48. package/dist/server/modules/admin/routes/widget-data.d.mts +5 -5
  49. package/dist/server/modules/admin-preferences/collections/saved-views.d.mts +41 -41
  50. package/dist/server/modules/audit/.generated/module.d.mts +6 -6
  51. package/dist/server/modules/audit/collections/audit-log.d.mts +78 -78
  52. package/dist/server/modules/audit/jobs/audit-cleanup.d.mts +2 -2
  53. package/package.json +3 -3
@@ -13,8 +13,21 @@ import { jsx } from "react/jsx-runtime";
13
13
  * Used for preview click-to-focus functionality.
14
14
  */
15
15
  const FocusContext = React.createContext(null);
16
+ function areBlockInsertPositionsEqual(left, right) {
17
+ return left.parentId === right.parentId && left.index === right.index;
18
+ }
19
+ function areFocusStatesEqual(left, right) {
20
+ if (left.type !== right.type) return false;
21
+ switch (left.type) {
22
+ case "idle": return true;
23
+ case "field": return right.type === "field" && left.fieldPath === right.fieldPath;
24
+ case "block": return right.type === "block" && left.blockId === right.blockId && left.fieldPath === right.fieldPath;
25
+ case "block-insert": return right.type === "block-insert" && areBlockInsertPositionsEqual(left.position, right.position) && left.referenceBlockId === right.referenceBlockId;
26
+ case "relation": return right.type === "relation" && left.fieldPath === right.fieldPath && left.targetCollection === right.targetCollection;
27
+ }
28
+ }
16
29
  function FocusProvider(t0) {
17
- const $ = c(27);
30
+ const $ = c(29);
18
31
  const { children, onFocusChange } = t0;
19
32
  let t1;
20
33
  if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
@@ -22,124 +35,127 @@ function FocusProvider(t0) {
22
35
  $[0] = t1;
23
36
  } else t1 = $[0];
24
37
  const [state, setState] = React.useState(t1);
38
+ const stateRef = React.useRef(state);
25
39
  let t2;
26
40
  if ($[1] !== onFocusChange) {
27
- t2 = (fieldPath) => {
28
- const newState = {
29
- type: "field",
30
- fieldPath
31
- };
32
- setState(newState);
33
- onFocusChange?.(newState);
41
+ t2 = (nextState) => {
42
+ if (areFocusStatesEqual(stateRef.current, nextState)) return;
43
+ stateRef.current = nextState;
44
+ setState(nextState);
45
+ onFocusChange?.(nextState);
34
46
  };
35
47
  $[1] = onFocusChange;
36
48
  $[2] = t2;
37
49
  } else t2 = $[2];
38
- const focusField = t2;
50
+ const setFocusState = t2;
39
51
  let t3;
40
- if ($[3] !== onFocusChange) {
41
- t3 = (blockId, fieldPath_0) => {
42
- const newState_0 = {
43
- type: "block",
44
- blockId,
45
- fieldPath: fieldPath_0
46
- };
47
- setState(newState_0);
48
- onFocusChange?.(newState_0);
52
+ if ($[3] !== setFocusState) {
53
+ t3 = (fieldPath) => {
54
+ setFocusState({
55
+ type: "field",
56
+ fieldPath
57
+ });
49
58
  };
50
- $[3] = onFocusChange;
59
+ $[3] = setFocusState;
51
60
  $[4] = t3;
52
61
  } else t3 = $[4];
53
- const focusBlock = t3;
62
+ const focusField = t3;
54
63
  let t4;
55
- if ($[5] !== onFocusChange) {
56
- t4 = (fieldPath_1, targetCollection) => {
57
- const newState_1 = {
58
- type: "relation",
59
- fieldPath: fieldPath_1,
60
- targetCollection
61
- };
62
- setState(newState_1);
63
- onFocusChange?.(newState_1);
64
+ if ($[5] !== setFocusState) {
65
+ t4 = (blockId, fieldPath_0) => {
66
+ setFocusState({
67
+ type: "block",
68
+ blockId,
69
+ fieldPath: fieldPath_0
70
+ });
64
71
  };
65
- $[5] = onFocusChange;
72
+ $[5] = setFocusState;
66
73
  $[6] = t4;
67
74
  } else t4 = $[6];
68
- const focusRelation = t4;
75
+ const focusBlock = t4;
69
76
  let t5;
70
- if ($[7] !== onFocusChange) {
71
- t5 = (position, referenceBlockId) => {
72
- const newState_2 = {
73
- type: "block-insert",
74
- position,
75
- referenceBlockId
76
- };
77
- setState(newState_2);
78
- onFocusChange?.(newState_2);
77
+ if ($[7] !== setFocusState) {
78
+ t5 = (fieldPath_1, targetCollection) => {
79
+ setFocusState({
80
+ type: "relation",
81
+ fieldPath: fieldPath_1,
82
+ targetCollection
83
+ });
79
84
  };
80
- $[7] = onFocusChange;
85
+ $[7] = setFocusState;
81
86
  $[8] = t5;
82
87
  } else t5 = $[8];
83
- const requestBlockInsert = t5;
88
+ const focusRelation = t5;
84
89
  let t6;
85
- if ($[9] !== onFocusChange) {
86
- t6 = () => {
87
- const newState_3 = { type: "idle" };
88
- setState(newState_3);
89
- onFocusChange?.(newState_3);
90
+ if ($[9] !== setFocusState) {
91
+ t6 = (position, referenceBlockId) => {
92
+ setFocusState({
93
+ type: "block-insert",
94
+ position,
95
+ referenceBlockId
96
+ });
90
97
  };
91
- $[9] = onFocusChange;
98
+ $[9] = setFocusState;
92
99
  $[10] = t6;
93
100
  } else t6 = $[10];
94
- const clearFocus = t6;
95
- const focusedFieldPath = state.type === "field" ? state.fieldPath : void 0;
96
- const focusedBlockId = state.type === "block" ? state.blockId : void 0;
101
+ const requestBlockInsert = t6;
97
102
  let t7;
98
- if ($[11] !== focusedFieldPath) {
99
- t7 = (path) => focusedFieldPath === path;
100
- $[11] = focusedFieldPath;
103
+ if ($[11] !== setFocusState) {
104
+ t7 = () => {
105
+ setFocusState({ type: "idle" });
106
+ };
107
+ $[11] = setFocusState;
101
108
  $[12] = t7;
102
109
  } else t7 = $[12];
110
+ const clearFocus = t7;
111
+ const focusedFieldPath = state.type === "field" ? state.fieldPath : void 0;
112
+ const focusedBlockId = state.type === "block" ? state.blockId : void 0;
103
113
  let t8;
104
- if ($[13] !== focusedBlockId) {
105
- t8 = (id) => focusedBlockId === id;
106
- $[13] = focusedBlockId;
114
+ if ($[13] !== focusedFieldPath) {
115
+ t8 = (path) => focusedFieldPath === path;
116
+ $[13] = focusedFieldPath;
107
117
  $[14] = t8;
108
118
  } else t8 = $[14];
109
119
  let t9;
110
- if ($[15] !== clearFocus || $[16] !== focusBlock || $[17] !== focusField || $[18] !== focusRelation || $[19] !== requestBlockInsert || $[20] !== state || $[21] !== t7 || $[22] !== t8) {
111
- t9 = {
120
+ if ($[15] !== focusedBlockId) {
121
+ t9 = (id) => focusedBlockId === id;
122
+ $[15] = focusedBlockId;
123
+ $[16] = t9;
124
+ } else t9 = $[16];
125
+ let t10;
126
+ if ($[17] !== clearFocus || $[18] !== focusBlock || $[19] !== focusField || $[20] !== focusRelation || $[21] !== requestBlockInsert || $[22] !== state || $[23] !== t8 || $[24] !== t9) {
127
+ t10 = {
112
128
  state,
113
129
  focusField,
114
130
  focusBlock,
115
131
  requestBlockInsert,
116
132
  focusRelation,
117
133
  clearFocus,
118
- isFieldFocused: t7,
119
- isBlockFocused: t8
134
+ isFieldFocused: t8,
135
+ isBlockFocused: t9
120
136
  };
121
- $[15] = clearFocus;
122
- $[16] = focusBlock;
123
- $[17] = focusField;
124
- $[18] = focusRelation;
125
- $[19] = requestBlockInsert;
126
- $[20] = state;
127
- $[21] = t7;
128
- $[22] = t8;
129
- $[23] = t9;
130
- } else t9 = $[23];
131
- const value = t9;
132
- let t10;
133
- if ($[24] !== children || $[25] !== value) {
134
- t10 = /* @__PURE__ */ jsx(FocusContext.Provider, {
137
+ $[17] = clearFocus;
138
+ $[18] = focusBlock;
139
+ $[19] = focusField;
140
+ $[20] = focusRelation;
141
+ $[21] = requestBlockInsert;
142
+ $[22] = state;
143
+ $[23] = t8;
144
+ $[24] = t9;
145
+ $[25] = t10;
146
+ } else t10 = $[25];
147
+ const value = t10;
148
+ let t11;
149
+ if ($[26] !== children || $[27] !== value) {
150
+ t11 = /* @__PURE__ */ jsx(FocusContext.Provider, {
135
151
  value,
136
152
  children
137
153
  });
138
- $[24] = children;
139
- $[25] = value;
140
- $[26] = t10;
141
- } else t10 = $[26];
142
- return t10;
154
+ $[26] = children;
155
+ $[27] = value;
156
+ $[28] = t11;
157
+ } else t11 = $[28];
158
+ return t11;
143
159
  }
144
160
  /**
145
161
  * Use the focus context
@@ -273,26 +289,30 @@ function scrollFieldIntoView(fieldPath, options = {}) {
273
289
  const wrapper = findFieldWrapper(fieldPath, options);
274
290
  if (!wrapper) return false;
275
291
  const focusable = wrapper.querySelector("input:not([type=\"hidden\"]), textarea, button, select, [tabindex]:not([tabindex=\"-1\"]), [contenteditable=\"true\"]");
292
+ const { behavior = "auto", block = "nearest", focus = true } = options;
276
293
  (focusable ?? wrapper).scrollIntoView({
277
- behavior: "smooth",
278
- block: "center"
294
+ behavior,
295
+ block
279
296
  });
280
297
  wrapper.classList.add("field-focus-pulse");
281
298
  wrapper.addEventListener("animationend", () => wrapper.classList.remove("field-focus-pulse"), { once: true });
282
- if (focusable) requestAnimationFrame(() => {
299
+ if (focus && focusable) requestAnimationFrame(() => {
283
300
  window.focus();
284
- focusable.focus();
301
+ focusable.focus({ preventScroll: true });
285
302
  });
286
303
  return true;
287
304
  }
288
305
  function scheduleScrollFieldIntoView(fieldPath, options = {}) {
289
306
  if (typeof window === "undefined") return;
290
- const { attempts = 12, delayMs = 80, fallbackToBlock = false } = options;
307
+ const { attempts = 12, delayMs = 80, fallbackToBlock = false, ...scrollOptions } = options;
291
308
  let attempt = 0;
292
309
  const tryScroll = () => {
293
310
  attempt += 1;
294
311
  const isLastAttempt = attempt >= attempts;
295
- if (scrollFieldIntoView(fieldPath, { fallbackToBlock: fallbackToBlock && isLastAttempt }) || isLastAttempt) return;
312
+ if (scrollFieldIntoView(fieldPath, {
313
+ ...scrollOptions,
314
+ fallbackToBlock: fallbackToBlock && isLastAttempt
315
+ }) || isLastAttempt) return;
296
316
  window.setTimeout(tryScroll, delayMs);
297
317
  };
298
318
  tryScroll();
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import * as react_jsx_runtime21 from "react/jsx-runtime";
2
+ import * as react_jsx_runtime25 from "react/jsx-runtime";
3
3
 
4
4
  //#region src/client/preview/block-scope-context.d.ts
5
5
 
@@ -35,7 +35,7 @@ declare function BlockScopeProvider({
35
35
  blockId,
36
36
  basePath,
37
37
  children
38
- }: BlockScopeProviderProps): react_jsx_runtime21.JSX.Element;
38
+ }: BlockScopeProviderProps): react_jsx_runtime25.JSX.Element;
39
39
  /**
40
40
  * Get current block scope context.
41
41
  *
@@ -0,0 +1,110 @@
1
+ import { cloneSnapshot } from "./patch.mjs";
2
+
3
+ //#region src/client/preview/diff.ts
4
+ function diffSnapshot(previous, next, basePath = "") {
5
+ if (isDeepEqual(previous, next)) return [];
6
+ if (Array.isArray(previous) || Array.isArray(next)) return [{
7
+ op: "set",
8
+ path: basePath,
9
+ value: cloneSnapshot(next)
10
+ }];
11
+ if (isPlainObject(previous) && isPlainObject(next)) {
12
+ const ops = [];
13
+ const previousKeys = Object.keys(previous);
14
+ const nextKeys = Object.keys(next);
15
+ for (const key of previousKeys) if (!Object.prototype.hasOwnProperty.call(next, key)) ops.push({
16
+ op: "remove",
17
+ path: joinPath(basePath, key)
18
+ });
19
+ for (const key of nextKeys) {
20
+ const path = joinPath(basePath, key);
21
+ if (!Object.prototype.hasOwnProperty.call(previous, key)) {
22
+ ops.push({
23
+ op: "set",
24
+ path,
25
+ value: cloneSnapshot(next[key])
26
+ });
27
+ continue;
28
+ }
29
+ ops.push(...diffSnapshot(previous[key], next[key], path));
30
+ }
31
+ return ops;
32
+ }
33
+ return [{
34
+ op: "set",
35
+ path: basePath,
36
+ value: cloneSnapshot(next)
37
+ }];
38
+ }
39
+ function diffSnapshotAtPath(previous, next, path) {
40
+ if (!path) return diffSnapshot(previous, next);
41
+ const previousValue = readPath(previous, path);
42
+ const nextValue = readPath(next, path);
43
+ if (!nextValue.exists) return previousValue.exists ? [{
44
+ op: "remove",
45
+ path
46
+ }] : [];
47
+ if (previousValue.exists && isDeepEqual(previousValue.value, nextValue.value)) return [];
48
+ return [{
49
+ op: "set",
50
+ path,
51
+ value: cloneSnapshot(nextValue.value)
52
+ }];
53
+ }
54
+ function joinPath(basePath, key) {
55
+ return basePath ? `${basePath}.${key}` : key;
56
+ }
57
+ function isPlainObject(value) {
58
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
59
+ const proto = Object.getPrototypeOf(value);
60
+ return proto === Object.prototype || proto === null;
61
+ }
62
+ function isDeepEqual(left, right) {
63
+ if (Object.is(left, right)) return true;
64
+ if (Array.isArray(left) || Array.isArray(right)) {
65
+ if (!Array.isArray(left) || !Array.isArray(right)) return false;
66
+ if (left.length !== right.length) return false;
67
+ return left.every((value, index) => isDeepEqual(value, right[index]));
68
+ }
69
+ if (isPlainObject(left) || isPlainObject(right)) {
70
+ if (!isPlainObject(left) || !isPlainObject(right)) return false;
71
+ const leftKeys = Object.keys(left);
72
+ const rightKeys = Object.keys(right);
73
+ if (leftKeys.length !== rightKeys.length) return false;
74
+ return leftKeys.every((key) => Object.prototype.hasOwnProperty.call(right, key) && isDeepEqual(left[key], right[key]));
75
+ }
76
+ return false;
77
+ }
78
+ function isArrayIndex(segment) {
79
+ return /^(0|[1-9]\d*)$/.test(segment);
80
+ }
81
+ function readPath(value, path) {
82
+ let current = value;
83
+ for (const segment of path.split(".")) {
84
+ if (Array.isArray(current) && isArrayIndex(segment)) {
85
+ const index = Number(segment);
86
+ if (index < 0 || index >= current.length) return {
87
+ exists: false,
88
+ value: void 0
89
+ };
90
+ current = current[index];
91
+ continue;
92
+ }
93
+ if (!isPlainObject(current)) return {
94
+ exists: false,
95
+ value: void 0
96
+ };
97
+ if (!Object.prototype.hasOwnProperty.call(current, segment)) return {
98
+ exists: false,
99
+ value: void 0
100
+ };
101
+ current = current[segment];
102
+ }
103
+ return {
104
+ exists: true,
105
+ value: current
106
+ };
107
+ }
108
+
109
+ //#endregion
110
+ export { diffSnapshot, diffSnapshotAtPath };
@@ -1,4 +1,4 @@
1
- import * as react_jsx_runtime22 from "react/jsx-runtime";
1
+ import * as react_jsx_runtime24 from "react/jsx-runtime";
2
2
 
3
3
  //#region src/client/preview/preview-banner.d.ts
4
4
 
@@ -40,6 +40,6 @@ declare function PreviewBanner({
40
40
  isPreviewMode,
41
41
  className,
42
42
  exitPreviewUrl
43
- }: PreviewBannerProps): react_jsx_runtime22.JSX.Element | null;
43
+ }: PreviewBannerProps): react_jsx_runtime24.JSX.Element | null;
44
44
  //#endregion
45
45
  export { PreviewBanner, PreviewBannerProps };
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import * as react_jsx_runtime23 from "react/jsx-runtime";
2
+ import * as react_jsx_runtime21 from "react/jsx-runtime";
3
3
 
4
4
  //#region src/client/preview/preview-field.d.ts
5
5
 
@@ -68,7 +68,7 @@ declare function PreviewProvider({
68
68
  }) => void;
69
69
  onFieldValueEdited?: (payload: PreviewFieldValueEditedPayload) => void;
70
70
  children: React.ReactNode;
71
- }): react_jsx_runtime23.JSX.Element;
71
+ }): react_jsx_runtime21.JSX.Element;
72
72
  /**
73
73
  * Hook to access preview context.
74
74
  */
@@ -107,7 +107,7 @@ declare function PreviewField({
107
107
  style,
108
108
  onClick,
109
109
  onValueCommit
110
- }: PreviewFieldProps): react_jsx_runtime23.JSX.Element;
110
+ }: PreviewFieldProps): react_jsx_runtime21.JSX.Element;
111
111
  /**
112
112
  * Standalone PreviewField that works without context.
113
113
  * Useful when you can't use PreviewProvider.
@@ -131,6 +131,6 @@ declare function StandalonePreviewField({
131
131
  blockId?: string;
132
132
  fieldType?: "regular" | "block" | "relation";
133
133
  }) => void;
134
- }): react_jsx_runtime23.JSX.Element;
134
+ }): react_jsx_runtime21.JSX.Element;
135
135
  //#endregion
136
136
  export { PreviewField, PreviewFieldProps, PreviewProvider, StandalonePreviewField, usePreviewContext };