@questpie/admin 3.5.0 → 3.5.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 (66) hide show
  1. package/dist/client/components/blocks/block-canvas.mjs +1 -1
  2. package/dist/client/components/blocks/block-editor-layout.mjs +2 -2
  3. package/dist/client/components/blocks/block-insert-button.mjs +3 -3
  4. package/dist/client/components/blocks/block-item-menu.mjs +9 -9
  5. package/dist/client/components/blocks/block-item.mjs +5 -5
  6. package/dist/client/components/blocks/block-library-sidebar.mjs +3 -3
  7. package/dist/client/components/fields/array-field.mjs +2 -2
  8. package/dist/client/components/fields/date-field.mjs +6 -5
  9. package/dist/client/components/fields/datetime-field.mjs +6 -1
  10. package/dist/client/components/fields/object-array-field.mjs +2 -2
  11. package/dist/client/components/fields/relation/displays/cards-display.mjs +1 -1
  12. package/dist/client/components/fields/relation/displays/grid-display.mjs +1 -1
  13. package/dist/client/components/fields/relation/displays/list-display.mjs +3 -3
  14. package/dist/client/components/fields/relation/displays/table-display.mjs +1 -1
  15. package/dist/client/components/fields/relation-picker.mjs +3 -3
  16. package/dist/client/components/fields/relation-select.mjs +2 -2
  17. package/dist/client/components/filter-builder/filter-builder-sheet.mjs +16 -16
  18. package/dist/client/components/history-sidebar.mjs +12 -4
  19. package/dist/client/components/layout/field-layout-renderer.mjs +8 -3
  20. package/dist/client/components/media/media-grid.mjs +2 -2
  21. package/dist/client/components/preview/live-preview-mode.mjs +4 -4
  22. package/dist/client/components/preview/preview-pane.mjs +4 -4
  23. package/dist/client/components/primitives/asset-preview.mjs +5 -5
  24. package/dist/client/components/primitives/dropzone.mjs +1 -1
  25. package/dist/client/components/ui/kbd.mjs +1 -1
  26. package/dist/client/components/ui/scroll-fade.mjs +4 -4
  27. package/dist/client/components/ui/sidebar.mjs +1 -1
  28. package/dist/client/components/ui/skeleton.mjs +1 -1
  29. package/dist/client/components/ui/table.mjs +1 -1
  30. package/dist/client/components/widgets/quick-actions-widget.mjs +6 -6
  31. package/dist/client/components/widgets/timeline-widget.mjs +3 -3
  32. package/dist/client/components/widgets/value-widget.mjs +1 -1
  33. package/dist/client/components/widgets/widget-skeletons.mjs +2 -2
  34. package/dist/client/hooks/typed-hooks.mjs +66 -21
  35. package/dist/client/hooks/use-collection.mjs +48 -7
  36. package/dist/client/i18n/date-locale.mjs +0 -14
  37. package/dist/client/preview/block-scope-context.d.mts +2 -2
  38. package/dist/client/preview/diff.mjs +4 -1
  39. package/dist/client/preview/patch.mjs +1 -1
  40. package/dist/client/preview/paths.mjs +85 -0
  41. package/dist/client/preview/preview-banner.d.mts +2 -2
  42. package/dist/client/preview/preview-field.d.mts +4 -4
  43. package/dist/client/runtime/translations-provider.mjs +1 -1
  44. package/dist/client/scope/picker.d.mts +2 -2
  45. package/dist/client/scope/provider.d.mts +2 -2
  46. package/dist/client/styles/base.css +51 -1
  47. package/dist/client/views/collection/auto-form-fields.mjs +1 -1
  48. package/dist/client/views/collection/cells/primitive-cells.mjs +2 -2
  49. package/dist/client/views/collection/cells/upload-cells.mjs +2 -2
  50. package/dist/client/views/collection/form-view.mjs +45 -26
  51. package/dist/client/views/collection/table-view.mjs +33 -20
  52. package/dist/client/views/collection/view-skeletons.mjs +37 -38
  53. package/dist/client/views/common/global-search.mjs +3 -3
  54. package/dist/client/views/dashboard/widget-card.mjs +7 -7
  55. package/dist/client/views/layout/admin-router.mjs +84 -37
  56. package/dist/client/views/layout/admin-sidebar.mjs +22 -21
  57. package/dist/components/rich-text/rich-text-renderer.d.mts +2 -2
  58. package/dist/server/modules/admin/collections/verification.d.mts +23 -23
  59. package/dist/server/modules/admin/routes/admin-config.d.mts +2 -2
  60. package/dist/server/modules/admin/routes/execute-action.d.mts +9 -9
  61. package/dist/server/modules/admin/routes/preview.d.mts +11 -11
  62. package/dist/server/modules/admin/routes/reactive.d.mts +9 -9
  63. package/dist/server/modules/admin/routes/setup.d.mts +7 -7
  64. package/dist/server/modules/admin/routes/widget-data.d.mts +5 -5
  65. package/dist/server/modules/admin-preferences/collections/saved-views.d.mts +23 -23
  66. package/package.json +3 -3
@@ -63,7 +63,7 @@ function BlockCanvas() {
63
63
  children: [
64
64
  /* @__PURE__ */ jsx(Icon, {
65
65
  icon: "ph:dots-six-vertical",
66
- className: "text-muted-foreground h-4 w-4"
66
+ className: "text-muted-foreground size-4"
67
67
  }),
68
68
  /* @__PURE__ */ jsx(BlockIcon, {
69
69
  icon: activeBlockSchema?.admin?.icon,
@@ -67,7 +67,7 @@ function BlockEditorLayout({ className, minHeight = 500 }) {
67
67
  children: [
68
68
  /* @__PURE__ */ jsx(Icon, {
69
69
  icon: "ph:stack",
70
- className: "text-muted-foreground/30 mx-auto mb-4 h-12 w-12"
70
+ className: "text-muted-foreground/30 mx-auto mb-4 size-12"
71
71
  }),
72
72
  /* @__PURE__ */ jsx("p", {
73
73
  className: "text-sm font-medium",
@@ -85,7 +85,7 @@ function BlockEditorLayout({ className, minHeight = 500 }) {
85
85
  onClick: handleOpenSidebar,
86
86
  children: [/* @__PURE__ */ jsx(Icon, {
87
87
  icon: "ph:plus",
88
- className: "mr-2 h-4 w-4"
88
+ className: "mr-2 size-4"
89
89
  }), t("blocks.add")]
90
90
  })]
91
91
  }),
@@ -48,10 +48,10 @@ function BlockInsertButton({ position, compact = false, variant = "default", par
48
48
  className: cn("group text-muted-foreground hover:text-foreground relative flex min-h-10 items-center gap-2 text-xs font-medium transition-colors active:scale-[0.96]", className),
49
49
  onClick: handleOpen,
50
50
  children: [/* @__PURE__ */ jsx("div", {
51
- className: "border-border bg-background text-muted-foreground group-hover:border-foreground group-hover:text-foreground relative z-10 flex h-5 w-5 items-center justify-center rounded-full border transition-[background-color,border-color,color]",
51
+ className: "border-border bg-background text-muted-foreground group-hover:border-foreground group-hover:text-foreground relative z-10 flex size-5 items-center justify-center rounded-full border transition-[background-color,border-color,color]",
52
52
  children: /* @__PURE__ */ jsx(Icon, {
53
53
  icon: "ph:plus",
54
- className: "h-3 w-3"
54
+ className: "size-3"
55
55
  })
56
56
  }), /* @__PURE__ */ jsx("span", {
57
57
  className: "truncate",
@@ -64,7 +64,7 @@ function BlockInsertButton({ position, compact = false, variant = "default", par
64
64
  onClick: handleOpen,
65
65
  children: [/* @__PURE__ */ jsx(Icon, {
66
66
  icon: "ph:plus",
67
- className: "mr-2 h-4 w-4"
67
+ className: "mr-2 size-4"
68
68
  }), t("blocks.add")]
69
69
  });
70
70
  }
@@ -71,32 +71,32 @@ function MenuItems({ blockId, canHaveChildren, onDuplicate, onRemove, MenuItem,
71
71
  blockTypes.length > 0 && blockPosition && /* @__PURE__ */ jsxs(Fragment, { children: [
72
72
  /* @__PURE__ */ jsxs(SubMenu, { children: [/* @__PURE__ */ jsxs(SubMenuTrigger, { children: [/* @__PURE__ */ jsx(Icon, {
73
73
  icon: "ph:arrow-up",
74
- className: "h-4 w-4"
74
+ className: "size-4"
75
75
  }), t("blocks.addAbove")] }), /* @__PURE__ */ jsx(SubMenuContent, { children: blockTypes.map(({ type, label }) => /* @__PURE__ */ jsxs(MenuItem, {
76
76
  onClick: () => handleAddAbove(type),
77
77
  children: [/* @__PURE__ */ jsx(BlockTypeIcon, {
78
78
  type,
79
- className: "h-4 w-4"
79
+ className: "size-4"
80
80
  }), label]
81
81
  }, type)) })] }),
82
82
  /* @__PURE__ */ jsxs(SubMenu, { children: [/* @__PURE__ */ jsxs(SubMenuTrigger, { children: [/* @__PURE__ */ jsx(Icon, {
83
83
  icon: "ph:arrow-down",
84
- className: "h-4 w-4"
84
+ className: "size-4"
85
85
  }), t("blocks.addBelow")] }), /* @__PURE__ */ jsx(SubMenuContent, { children: blockTypes.map(({ type, label }) => /* @__PURE__ */ jsxs(MenuItem, {
86
86
  onClick: () => handleAddBelow(type),
87
87
  children: [/* @__PURE__ */ jsx(BlockTypeIcon, {
88
88
  type,
89
- className: "h-4 w-4"
89
+ className: "size-4"
90
90
  }), label]
91
91
  }, type)) })] }),
92
92
  canHaveChildren && /* @__PURE__ */ jsxs(SubMenu, { children: [/* @__PURE__ */ jsxs(SubMenuTrigger, { children: [/* @__PURE__ */ jsx(Icon, {
93
93
  icon: "ph:plus",
94
- className: "h-4 w-4"
94
+ className: "size-4"
95
95
  }), t("blocks.addChild")] }), /* @__PURE__ */ jsx(SubMenuContent, { children: blockTypes.map(({ type, label }) => /* @__PURE__ */ jsxs(MenuItem, {
96
96
  onClick: () => handleAddChild(type),
97
97
  children: [/* @__PURE__ */ jsx(BlockTypeIcon, {
98
98
  type,
99
- className: "h-4 w-4"
99
+ className: "size-4"
100
100
  }), label]
101
101
  }, type)) })] }),
102
102
  /* @__PURE__ */ jsx(Separator, {})
@@ -105,7 +105,7 @@ function MenuItems({ blockId, canHaveChildren, onDuplicate, onRemove, MenuItem,
105
105
  onClick: handleDuplicate,
106
106
  children: [/* @__PURE__ */ jsx(Icon, {
107
107
  icon: "ph:copy",
108
- className: "h-4 w-4"
108
+ className: "size-4"
109
109
  }), t("common.duplicate")]
110
110
  }),
111
111
  /* @__PURE__ */ jsx(Separator, {}),
@@ -114,7 +114,7 @@ function MenuItems({ blockId, canHaveChildren, onDuplicate, onRemove, MenuItem,
114
114
  onClick: handleRemove,
115
115
  children: [/* @__PURE__ */ jsx(Icon, {
116
116
  icon: "ph:trash",
117
- className: "h-4 w-4"
117
+ className: "size-4"
118
118
  }), t("common.delete")]
119
119
  })
120
120
  ] });
@@ -133,7 +133,7 @@ function BlockItemDropdownMenu({ className, ...menuProps }) {
133
133
  }),
134
134
  children: [/* @__PURE__ */ jsx(Icon, {
135
135
  icon: "ph:dots-three-vertical",
136
- className: "h-4 w-4"
136
+ className: "size-4"
137
137
  }), /* @__PURE__ */ jsx("span", {
138
138
  className: "sr-only",
139
139
  children: "Block actions"
@@ -86,19 +86,19 @@ const BlockItem = React.memo(function BlockItem$1({ block, level, index: _index,
86
86
  onClick: (e) => e.stopPropagation(),
87
87
  children: /* @__PURE__ */ jsx(Icon, {
88
88
  icon: "ph:dots-six-vertical",
89
- className: "text-muted-foreground h-4 w-4"
89
+ className: "text-muted-foreground size-4"
90
90
  })
91
91
  }),
92
92
  /* @__PURE__ */ jsx("div", {
93
93
  className: "text-muted-foreground",
94
94
  children: /* @__PURE__ */ jsx(Icon, {
95
95
  icon: "ph:caret-right",
96
- className: cn("h-4 w-4 transition-transform duration-150 ease-in-out", isExpanded && "rotate-90")
96
+ className: cn("size-4 transition-transform duration-150 ease-in-out", isExpanded && "rotate-90")
97
97
  })
98
98
  }),
99
99
  isUnknownType ? /* @__PURE__ */ jsx(Icon, {
100
100
  icon: "ph:warning",
101
- className: "text-destructive h-3.5 w-3.5"
101
+ className: "text-destructive size-3.5"
102
102
  }) : /* @__PURE__ */ jsx(BlockIcon, {
103
103
  icon: blockSchema?.admin?.icon,
104
104
  size: 14,
@@ -121,7 +121,7 @@ const BlockItem = React.memo(function BlockItem$1({ block, level, index: _index,
121
121
  canHaveChildren,
122
122
  onDuplicate: handleDuplicate,
123
123
  onRemove: handleRemove,
124
- className: "h-7 w-7 opacity-0 transition-opacity group-hover:opacity-100"
124
+ className: "size-7 opacity-0 transition-opacity group-hover:opacity-100"
125
125
  })
126
126
  })
127
127
  ]
@@ -139,7 +139,7 @@ const BlockItem = React.memo(function BlockItem$1({ block, level, index: _index,
139
139
  className: "text-destructive flex items-center gap-2 text-sm",
140
140
  children: [/* @__PURE__ */ jsx(Icon, {
141
141
  icon: "ph:warning",
142
- className: "h-4 w-4 shrink-0"
142
+ className: "size-4 shrink-0"
143
143
  }), /* @__PURE__ */ jsx("span", { children: t("blocks.unknownType", { type: block.type }) })]
144
144
  })
145
145
  })
@@ -100,7 +100,7 @@ function BlockLibrarySidebar({ open, onClose }) {
100
100
  className: "relative",
101
101
  children: [/* @__PURE__ */ jsx(Icon, {
102
102
  icon: "ph:magnifying-glass",
103
- className: "text-muted-foreground absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2"
103
+ className: "text-muted-foreground absolute top-1/2 left-3 size-4 -translate-y-1/2"
104
104
  }), /* @__PURE__ */ jsx(Input, {
105
105
  ref: searchInputRef,
106
106
  placeholder: t("blocks.searchPlaceholder"),
@@ -117,7 +117,7 @@ function BlockLibrarySidebar({ open, onClose }) {
117
117
  children: [
118
118
  /* @__PURE__ */ jsx(Icon, {
119
119
  icon: "ph:cube",
120
- className: "text-muted-foreground/50 mb-4 h-12 w-12"
120
+ className: "text-muted-foreground/50 mb-4 size-12"
121
121
  }),
122
122
  /* @__PURE__ */ jsx("p", {
123
123
  className: "text-muted-foreground text-sm",
@@ -134,7 +134,7 @@ function BlockLibrarySidebar({ open, onClose }) {
134
134
  className: "mb-3 flex items-center gap-2",
135
135
  children: [category.config.icon && /* @__PURE__ */ jsx(Icon, {
136
136
  icon: category.config.icon.props.name,
137
- className: "text-muted-foreground h-4 w-4"
137
+ className: "text-muted-foreground size-4"
138
138
  }), /* @__PURE__ */ jsx("h4", {
139
139
  className: "text-muted-foreground font-chrome chrome-meta text-xs font-semibold",
140
140
  children: getCategoryDisplayLabel(category.config)
@@ -145,7 +145,7 @@ function PrimitiveArrayField({ name, value, label, description, placeholder, req
145
145
  children: /* @__PURE__ */ jsxs("div", {
146
146
  className: "qa-array-field space-y-3",
147
147
  children: [fields.length === 0 ? /* @__PURE__ */ jsx("div", {
148
- className: "panel-surface border-border-subtle border-dashed px-3 py-3",
148
+ className: "panel-surface border-border-subtle border-dashed p-3",
149
149
  children: /* @__PURE__ */ jsx("p", {
150
150
  className: "text-muted-foreground text-sm text-pretty",
151
151
  children: resolvedPlaceholder || emptyLabel
@@ -225,7 +225,7 @@ function PrimitiveArrayField({ name, value, label, description, placeholder, req
225
225
  disabled,
226
226
  children: [/* @__PURE__ */ jsx(Icon, {
227
227
  icon: "ph:plus",
228
- className: "h-4 w-4"
228
+ className: "size-4"
229
229
  }), addLabel]
230
230
  })]
231
231
  })
@@ -6,16 +6,17 @@ import { jsx } from "react/jsx-runtime";
6
6
  import { Controller } from "react-hook-form";
7
7
 
8
8
  //#region src/client/components/fields/date-field.tsx
9
+ function parseDateFieldValue(value) {
10
+ if (!value) return null;
11
+ const date = value instanceof Date ? value : new Date(String(value));
12
+ return Number.isNaN(date.getTime()) ? null : date;
13
+ }
9
14
  function DateField({ name, label, description, placeholder, required, disabled, localized, locale, control, className, minDate, maxDate, format }) {
10
15
  return /* @__PURE__ */ jsx(Controller, {
11
16
  name,
12
17
  control: useResolvedControl(control),
13
18
  render: ({ field, fieldState }) => {
14
- const dateValue = (() => {
15
- if (!field.value) return null;
16
- const d = field.value instanceof Date ? field.value : new Date(field.value);
17
- return Number.isNaN(d.getTime()) ? null : d;
18
- })();
19
+ const dateValue = parseDateFieldValue(field.value);
19
20
  return /* @__PURE__ */ jsx(FieldWrapper, {
20
21
  name,
21
22
  label,
@@ -6,12 +6,17 @@ import { jsx } from "react/jsx-runtime";
6
6
  import { Controller } from "react-hook-form";
7
7
 
8
8
  //#region src/client/components/fields/datetime-field.tsx
9
+ function parseDateTimeFieldValue(value) {
10
+ if (!value) return null;
11
+ const date = value instanceof Date ? value : new Date(String(value));
12
+ return Number.isNaN(date.getTime()) ? null : date;
13
+ }
9
14
  function DatetimeField({ name, label, description, placeholder, required, disabled, localized, locale, control, className, minDate, maxDate, format, precision }) {
10
15
  return /* @__PURE__ */ jsx(Controller, {
11
16
  name,
12
17
  control: useResolvedControl(control),
13
18
  render: ({ field, fieldState }) => {
14
- const dateValue = field.value instanceof Date ? field.value : field.value ? new Date(field.value) : null;
19
+ const dateValue = parseDateTimeFieldValue(field.value);
15
20
  return /* @__PURE__ */ jsx(FieldWrapper, {
16
21
  name,
17
22
  label,
@@ -263,7 +263,7 @@ function ObjectArrayField({ name, label, description, placeholder, required, dis
263
263
  if (!open) setActiveIndex(null);
264
264
  }, []);
265
265
  const emptyState = /* @__PURE__ */ jsx("div", {
266
- className: "panel-surface border-border-subtle border-dashed px-3 py-3",
266
+ className: "panel-surface border-border-subtle border-dashed p-3",
267
267
  children: /* @__PURE__ */ jsx("p", {
268
268
  className: "text-muted-foreground text-sm text-pretty",
269
269
  children: resolvedPlaceholder || emptyLabel
@@ -327,7 +327,7 @@ function ObjectArrayField({ name, label, description, placeholder, required, dis
327
327
  disabled,
328
328
  children: [/* @__PURE__ */ jsx(Icon, {
329
329
  icon: "ph:plus",
330
- className: "h-4 w-4"
330
+ className: "size-4"
331
331
  }), addLabel]
332
332
  }),
333
333
  showEditor && mode === "modal" && /* @__PURE__ */ jsx(Dialog, {
@@ -68,7 +68,7 @@ function CardsDisplay({ items, collection, actions, editable = false, fields, gr
68
68
  children: /* @__PURE__ */ jsx("img", {
69
69
  src: image,
70
70
  alt: getTitle(item),
71
- className: "image-outline h-full w-full object-cover"
71
+ className: "image-outline size-full object-cover"
72
72
  })
73
73
  }), /* @__PURE__ */ jsxs("div", {
74
74
  className: "p-3",
@@ -52,7 +52,7 @@ function GridDisplay({ items, collection, collectionIcon, actions, editable = fa
52
52
  children: /* @__PURE__ */ jsx("img", {
53
53
  src: image,
54
54
  alt: getTitle(item),
55
- className: "image-outline h-full w-full object-cover"
55
+ className: "image-outline size-full object-cover"
56
56
  })
57
57
  }) : collectionIcon ? /* @__PURE__ */ jsx("div", {
58
58
  className: "bg-muted flex size-8 shrink-0 items-center justify-center rounded-sm",
@@ -61,7 +61,7 @@ function ListDisplay({ items, collection, collectionIcon, actions, editable = fa
61
61
  "aria-label": t("field.dragToReorder"),
62
62
  children: /* @__PURE__ */ jsx(Icon, {
63
63
  icon: "ph:dots-six-vertical",
64
- className: "h-4 w-4"
64
+ className: "size-4"
65
65
  })
66
66
  }),
67
67
  /* @__PURE__ */ jsxs("div", {
@@ -81,7 +81,7 @@ function ListDisplay({ items, collection, collectionIcon, actions, editable = fa
81
81
  "aria-label": t("field.editItem"),
82
82
  children: /* @__PURE__ */ jsx(Icon, {
83
83
  icon: "ph:pencil",
84
- className: "h-3 w-3"
84
+ className: "size-3"
85
85
  })
86
86
  }),
87
87
  actions?.onRemove && /* @__PURE__ */ jsx(Button, {
@@ -94,7 +94,7 @@ function ListDisplay({ items, collection, collectionIcon, actions, editable = fa
94
94
  "aria-label": t("field.removeItem"),
95
95
  children: /* @__PURE__ */ jsx(Icon, {
96
96
  icon: "ph:x",
97
- className: "h-3 w-3"
97
+ className: "size-3"
98
98
  })
99
99
  })
100
100
  ]
@@ -25,7 +25,7 @@ function TableSkeleton({ count = 3, columns = ["_title"], hasActions = false })
25
25
  className: "flex items-center justify-end gap-1",
26
26
  children: /* @__PURE__ */ jsx(Skeleton, {
27
27
  variant: "text",
28
- className: "h-6 w-6"
28
+ className: "size-6"
29
29
  })
30
30
  }) })] }, key)) })] })
31
31
  });
@@ -80,12 +80,12 @@ function RelationPicker({ name, value, onChange, targetCollection, label, filter
80
80
  if (response?.docs) for (const doc of response.docs) map.set(doc.id, doc);
81
81
  return map;
82
82
  },
83
- enabled: !!client && selectedIds.length > 0,
83
+ enabled: !!client && !!targetCollection && selectedIds.length > 0,
84
84
  staleTime: 3e4,
85
85
  placeholderData: (prev) => prev
86
86
  });
87
87
  const loadOptions = React.useCallback(async (search) => {
88
- if (!client) return [];
88
+ if (!client || !targetCollection) return [];
89
89
  try {
90
90
  const options = { limit: 50 };
91
91
  if (search) options.search = search;
@@ -266,7 +266,7 @@ function RelationPicker({ name, value, onChange, targetCollection, label, filter
266
266
  "aria-label": createLabel,
267
267
  children: /* @__PURE__ */ jsx(Icon, {
268
268
  icon: "ph:plus",
269
- className: "h-4 w-4"
269
+ className: "size-4"
270
270
  })
271
271
  })]
272
272
  }),
@@ -42,7 +42,7 @@ function RelationSelect({ name, value, onChange, targetCollection, label, filter
42
42
  const client = useAdminStore(selectClient);
43
43
  const collectionIconRef = (serverConfig?.collections?.[targetCollection])?.icon;
44
44
  const loadOptions = React.useCallback(async (search) => {
45
- if (!client) return [];
45
+ if (!client || !targetCollection) return [];
46
46
  try {
47
47
  const options = {
48
48
  limit: 50,
@@ -101,7 +101,7 @@ function RelationSelect({ name, value, onChange, targetCollection, label, filter
101
101
  targetCollection,
102
102
  value
103
103
  ]);
104
- const { data: selectedItem, isLoading: isLoadingSelectedItem } = useCollectionItem(targetCollection, value || "", void 0, { enabled: !!value });
104
+ const { data: selectedItem, isLoading: isLoadingSelectedItem } = useCollectionItem(targetCollection, value || "", void 0, { enabled: !!value && !!targetCollection });
105
105
  const selectedOptions = React.useMemo(() => {
106
106
  if (!selectedItem) return [];
107
107
  return [{
@@ -140,10 +140,10 @@ function FilterBuilderSheet({ collection, availableFields, currentConfig, onConf
140
140
  description: t("viewOptions.realtimeDescription"),
141
141
  control: /* @__PURE__ */ jsx(Switch, {
142
142
  checked: localConfig.realtime ?? true,
143
- onCheckedChange: (checked) => setLocalConfig({
144
- ...localConfig,
143
+ onCheckedChange: (checked) => setLocalConfig((prevConfig) => ({
144
+ ...prevConfig,
145
145
  realtime: checked
146
- })
146
+ }))
147
147
  })
148
148
  }),
149
149
  supportsSoftDelete && /* @__PURE__ */ jsx(ViewOptionRow, {
@@ -151,10 +151,10 @@ function FilterBuilderSheet({ collection, availableFields, currentConfig, onConf
151
151
  description: t("viewOptions.showDeletedDescription"),
152
152
  control: /* @__PURE__ */ jsx(Switch, {
153
153
  checked: localConfig.includeDeleted ?? false,
154
- onCheckedChange: (checked) => setLocalConfig({
155
- ...localConfig,
154
+ onCheckedChange: (checked) => setLocalConfig((prevConfig) => ({
155
+ ...prevConfig,
156
156
  includeDeleted: checked
157
- })
157
+ }))
158
158
  })
159
159
  }),
160
160
  groupableFields.length > 0 && /* @__PURE__ */ jsx(ViewOptionRow, {
@@ -165,15 +165,15 @@ function FilterBuilderSheet({ collection, availableFields, currentConfig, onConf
165
165
  value: localConfig.groupBy ?? NO_GROUPING_VALUE,
166
166
  onChange: (value) => {
167
167
  const nextGroupBy = !value || value === NO_GROUPING_VALUE ? null : value;
168
- setLocalConfig({
169
- ...localConfig,
168
+ setLocalConfig((prevConfig) => ({
169
+ ...prevConfig,
170
170
  groupBy: nextGroupBy,
171
171
  collapsedGroups: [],
172
172
  pagination: {
173
- ...localConfig.pagination ?? { pageSize: 25 },
173
+ ...prevConfig.pagination ?? { pageSize: 25 },
174
174
  page: 1
175
175
  }
176
- });
176
+ }));
177
177
  },
178
178
  options: groupByOptions,
179
179
  clearable: false,
@@ -216,10 +216,10 @@ function FilterBuilderSheet({ collection, availableFields, currentConfig, onConf
216
216
  children: /* @__PURE__ */ jsx(ColumnsTab, {
217
217
  fields: availableFields,
218
218
  visibleColumns: localConfig.visibleColumns,
219
- onVisibleColumnsChange: (columns) => setLocalConfig({
220
- ...localConfig,
219
+ onVisibleColumnsChange: (columns) => setLocalConfig((prevConfig) => ({
220
+ ...prevConfig,
221
221
  visibleColumns: columns
222
- })
222
+ }))
223
223
  })
224
224
  }),
225
225
  /* @__PURE__ */ jsx(TabsContent, {
@@ -227,10 +227,10 @@ function FilterBuilderSheet({ collection, availableFields, currentConfig, onConf
227
227
  children: /* @__PURE__ */ jsx(FiltersTab, {
228
228
  fields: availableFields,
229
229
  filters: localConfig.filters,
230
- onFiltersChange: (filters) => setLocalConfig({
231
- ...localConfig,
230
+ onFiltersChange: (filters) => setLocalConfig((prevConfig) => ({
231
+ ...prevConfig,
232
232
  filters
233
- })
233
+ }))
234
234
  })
235
235
  }),
236
236
  /* @__PURE__ */ jsx(TabsContent, {
@@ -27,6 +27,14 @@ const VERSION_META_KEYS = new Set([
27
27
  ]);
28
28
  const EMPTY_AUDIT_ENTRIES = [];
29
29
  const RELATIVE_TIME_FORMATTERS = /* @__PURE__ */ new Map();
30
+ const HISTORY_SKELETON_ROW_KEYS = [
31
+ "first",
32
+ "second",
33
+ "third",
34
+ "fourth",
35
+ "fifth",
36
+ "sixth"
37
+ ];
30
38
  function getRelativeTimeFormatter(locale) {
31
39
  let formatter = RELATIVE_TIME_FORMATTERS.get(locale);
32
40
  if (!formatter) {
@@ -317,7 +325,7 @@ function VersionDiffPanel({ previousVersion, changes, fields }) {
317
325
  const field = fields?.[change.name];
318
326
  const kind = getDiffKindConfig(change.kind);
319
327
  return /* @__PURE__ */ jsxs("div", {
320
- className: "item-surface border-border-subtle bg-surface-low px-3 py-3",
328
+ className: "item-surface border-border-subtle bg-surface-low p-3",
321
329
  children: [
322
330
  /* @__PURE__ */ jsxs("div", {
323
331
  className: "flex items-start justify-between gap-3",
@@ -407,7 +415,7 @@ function HistoryListSkeleton({ rows = 4 }) {
407
415
  return /* @__PURE__ */ jsx("div", {
408
416
  className: "space-y-4 py-2",
409
417
  "aria-busy": "true",
410
- children: Array.from({ length: rows }, (_, index) => /* @__PURE__ */ jsxs("div", {
418
+ children: HISTORY_SKELETON_ROW_KEYS.slice(0, rows).map((rowKey) => /* @__PURE__ */ jsxs("div", {
411
419
  className: "flex gap-3",
412
420
  children: [/* @__PURE__ */ jsx(Skeleton, { className: "mt-1 size-7 shrink-0 rounded-full" }), /* @__PURE__ */ jsxs("div", {
413
421
  className: "min-w-0 flex-1 space-y-2",
@@ -419,7 +427,7 @@ function HistoryListSkeleton({ rows = 4 }) {
419
427
  className: "h-3 w-40"
420
428
  })]
421
429
  })]
422
- }, index))
430
+ }, rowKey))
423
431
  });
424
432
  }
425
433
  function ActivityTimeline({ entries, isLoading }) {
@@ -548,7 +556,7 @@ function VersionsList({ versions, fields, isLoading, isReverting, onRevert }) {
548
556
  value: key,
549
557
  className: "px-0",
550
558
  children: [/* @__PURE__ */ jsx(AccordionTrigger, {
551
- className: "min-h-20 items-start px-3 py-3 hover:no-underline",
559
+ className: "min-h-20 items-start p-3 hover:no-underline",
552
560
  children: /* @__PURE__ */ jsxs("div", {
553
561
  className: "flex min-w-0 flex-1 flex-col gap-2",
554
562
  children: [
@@ -19,6 +19,11 @@ import { jsx, jsxs } from "react/jsx-runtime";
19
19
  * - Object field component (scoped names: parent.field)
20
20
  * - Collection/global forms (via auto-form-fields.tsx)
21
21
  */
22
+ function getLayoutItemKey(item, index) {
23
+ if (isFieldReference(item)) return getFieldName(item) ?? `field-${index}`;
24
+ if (item.type === "section") return `section-${typeof item.label === "string" ? item.label : JSON.stringify(item.label ?? "")}-${index}`;
25
+ return `tabs-${item.tabs.map((tab) => tab.id).join("-") || index}`;
26
+ }
22
27
  /**
23
28
  * Render an array of FieldLayoutItem using the provided context.
24
29
  * Handles field references, sections, and tabs recursively.
@@ -37,11 +42,11 @@ function FieldLayoutRenderer({ items, ctx }) {
37
42
  section: item,
38
43
  index,
39
44
  ctx
40
- }, `section-${index}`);
45
+ }, getLayoutItemKey(item, index));
41
46
  case "tabs": return /* @__PURE__ */ jsx(TabsRenderer, {
42
47
  tabsLayout: item,
43
48
  ctx
44
- }, `tabs-${index}`);
49
+ }, getLayoutItemKey(item, index));
45
50
  default: return null;
46
51
  }
47
52
  return null;
@@ -64,7 +69,7 @@ function SectionRenderer({ section, index, ctx }) {
64
69
  if (!isFieldReference(fieldItem)) return /* @__PURE__ */ jsx(FieldLayoutRenderer, {
65
70
  items: [fieldItem],
66
71
  ctx
67
- }, `nested-${idx}`);
72
+ }, getLayoutItemKey(fieldItem, idx));
68
73
  const fieldName = getFieldName(fieldItem);
69
74
  if (!fieldName) return null;
70
75
  const className = typeof fieldItem === "object" && "className" in fieldItem ? fieldItem.className : void 0;
@@ -77,10 +77,10 @@ function AssetItem({ asset, selected, selectionMode, onToggle, onClick }) {
77
77
  thumbnailUrl && isImageType && !imageError ? /* @__PURE__ */ jsx("img", {
78
78
  src: thumbnailUrl,
79
79
  alt: asset.alt || asset.filename || "Asset",
80
- className: "image-outline h-full w-full object-cover",
80
+ className: "image-outline size-full object-cover",
81
81
  onError: () => setImageError(true)
82
82
  }) : /* @__PURE__ */ jsx("div", {
83
- className: cn("flex h-full w-full items-center justify-center", getAssetTypeColor(asset.mimeType)),
83
+ className: cn("flex size-full items-center justify-center", getAssetTypeColor(asset.mimeType)),
84
84
  children: /* @__PURE__ */ jsx("span", {
85
85
  className: "text-muted-foreground chrome-meta text-xs font-medium",
86
86
  children: asset.mimeType?.split("/")[1]?.slice(0, 4) || "FILE"
@@ -195,7 +195,7 @@ function LivePreviewContent({ open, children, previewUrl, previewRef, onFieldVal
195
195
  className: "flex items-center gap-2",
196
196
  children: [/* @__PURE__ */ jsx(Icon, {
197
197
  icon: "ph:eye",
198
- className: "text-muted-foreground h-4 w-4"
198
+ className: "text-muted-foreground size-4"
199
199
  }), /* @__PURE__ */ jsx("span", {
200
200
  className: "font-medium",
201
201
  children: t("preview.livePreview")
@@ -228,7 +228,7 @@ function LivePreviewContent({ open, children, previewUrl, previewRef, onFieldVal
228
228
  title: t("preview.exitTooltip"),
229
229
  children: [/* @__PURE__ */ jsx(Icon, {
230
230
  icon: "ph:sign-out",
231
- className: "h-4 w-4"
231
+ className: "size-4"
232
232
  }), /* @__PURE__ */ jsx("span", {
233
233
  className: "hidden sm:inline",
234
234
  children: t("preview.exitPreview")
@@ -261,7 +261,7 @@ function LivePreviewContent({ open, children, previewUrl, previewRef, onFieldVal
261
261
  className: "flex h-full items-center justify-center",
262
262
  children: [/* @__PURE__ */ jsx(Icon, {
263
263
  icon: "ph:spinner",
264
- className: "text-muted-foreground h-6 w-6 animate-spin"
264
+ className: "text-muted-foreground size-6 animate-spin"
265
265
  }), /* @__PURE__ */ jsx("span", {
266
266
  className: "text-muted-foreground ml-2 text-sm",
267
267
  children: t("preview.loadingPreview")
@@ -290,7 +290,7 @@ function LivePreviewContent({ open, children, previewUrl, previewRef, onFieldVal
290
290
  className: "flex h-full items-center justify-center",
291
291
  children: [/* @__PURE__ */ jsx(Icon, {
292
292
  icon: "ph:spinner",
293
- className: "text-muted-foreground h-6 w-6 animate-spin"
293
+ className: "text-muted-foreground size-6 animate-spin"
294
294
  }), /* @__PURE__ */ jsx("span", {
295
295
  className: "text-muted-foreground ml-2 text-sm",
296
296
  children: t("preview.loadingPreview")
@@ -294,13 +294,13 @@ const PreviewPane = React.forwardRef(({ url, selectedBlockId, onFieldClick, onBl
294
294
  }, 3e3);
295
295
  }, []);
296
296
  return /* @__PURE__ */ jsxs("div", {
297
- className: cn("relative h-full w-full", className),
297
+ className: cn("relative size-full", className),
298
298
  children: [
299
299
  isLoading && /* @__PURE__ */ jsxs("div", {
300
300
  className: "bg-muted absolute inset-0 z-10 flex items-center justify-center",
301
301
  children: [/* @__PURE__ */ jsx(Icon, {
302
302
  icon: "ph:spinner",
303
- className: "text-muted-foreground h-6 w-6 animate-spin"
303
+ className: "text-muted-foreground size-6 animate-spin"
304
304
  }), /* @__PURE__ */ jsx("span", {
305
305
  className: "text-muted-foreground ml-2 text-sm",
306
306
  children: t("preview.loadingPreview")
@@ -320,7 +320,7 @@ const PreviewPane = React.forwardRef(({ url, selectedBlockId, onFieldClick, onBl
320
320
  className: "bg-background absolute top-4 right-4 z-10 flex items-center gap-2 border px-3 py-2 shadow-md",
321
321
  children: [/* @__PURE__ */ jsx(Icon, {
322
322
  icon: "ph:spinner",
323
- className: "text-muted-foreground h-4 w-4 animate-spin"
323
+ className: "text-muted-foreground size-4 animate-spin"
324
324
  }), /* @__PURE__ */ jsx("span", {
325
325
  className: "text-muted-foreground text-sm",
326
326
  children: t("preview.refreshing")
@@ -329,7 +329,7 @@ const PreviewPane = React.forwardRef(({ url, selectedBlockId, onFieldClick, onBl
329
329
  previewUrlResolved && /* @__PURE__ */ jsx("iframe", {
330
330
  ref: iframeRef,
331
331
  src: previewUrlResolved,
332
- className: "h-full w-full border-0",
332
+ className: "size-full border-0",
333
333
  title: t("common.preview"),
334
334
  onLoad: handleLoad,
335
335
  sandbox: "allow-scripts allow-same-origin allow-forms"