@questpie/admin 3.0.3 → 3.0.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 (249) hide show
  1. package/README.md +34 -5
  2. package/dist/client/blocks/block-renderer.d.mts +2 -2
  3. package/dist/client/blocks/block-renderer.mjs +4 -1
  4. package/dist/client/builder/types/action-types.d.mts +31 -3
  5. package/dist/client/builder/types/collection-types.d.mts +140 -0
  6. package/dist/client/builder/types/ui-config.d.mts +16 -2
  7. package/dist/client/builder/types/views.d.mts +57 -0
  8. package/dist/client/builder/types/widget-types.d.mts +5 -0
  9. package/dist/client/components/actions/action-button.mjs +137 -199
  10. package/dist/client/components/actions/action-dialog.mjs +198 -156
  11. package/dist/client/components/actions/confirmation-dialog.mjs +2 -2
  12. package/dist/client/components/actions/header-actions.mjs +52 -53
  13. package/dist/client/components/admin-link.d.mts +2 -2
  14. package/dist/client/components/auth/auth-loading.mjs +41 -18
  15. package/dist/client/components/blocks/block-fields-renderer.mjs +64 -28
  16. package/dist/client/components/blocks/block-insert-button.mjs +4 -4
  17. package/dist/client/components/blocks/block-item.mjs +2 -2
  18. package/dist/client/components/blocks/block-library-sidebar.mjs +2 -2
  19. package/dist/client/components/component-renderer.mjs +1 -1
  20. package/dist/client/components/fields/array-field.mjs +14 -14
  21. package/dist/client/components/fields/asset-preview-field.mjs +1 -1
  22. package/dist/client/components/fields/blocks-field/blocks-field.mjs +84 -104
  23. package/dist/client/components/fields/json-field.mjs +2 -2
  24. package/dist/client/components/fields/object-array-field.mjs +22 -22
  25. package/dist/client/components/fields/object-field.mjs +5 -5
  26. package/dist/client/components/fields/relation/displays/cards-display.mjs +16 -9
  27. package/dist/client/components/fields/relation/displays/chips-display.mjs +15 -12
  28. package/dist/client/components/fields/relation/displays/grid-display.mjs +15 -11
  29. package/dist/client/components/fields/relation/displays/list-display.mjs +33 -20
  30. package/dist/client/components/fields/relation/displays/table-display.mjs +62 -93
  31. package/dist/client/components/fields/relation/relation-items-display.mjs +1 -1
  32. package/dist/client/components/fields/relation-picker.mjs +7 -6
  33. package/dist/client/components/fields/relation-select.mjs +71 -47
  34. package/dist/client/components/fields/rich-text-editor/bubble-menu.mjs +392 -82
  35. package/dist/client/components/fields/rich-text-editor/extensions.mjs +54 -23
  36. package/dist/client/components/fields/rich-text-editor/image-popover.mjs +24 -50
  37. package/dist/client/components/fields/rich-text-editor/image-upload.mjs +66 -0
  38. package/dist/client/components/fields/rich-text-editor/index.d.mts +38 -0
  39. package/dist/client/components/fields/rich-text-editor/index.mjs +637 -376
  40. package/dist/client/components/fields/rich-text-editor/link-utils.mjs +26 -0
  41. package/dist/client/components/fields/rich-text-editor/presets.d.mts +10 -0
  42. package/dist/client/components/fields/rich-text-editor/slash-commands.mjs +27 -6
  43. package/dist/client/components/fields/rich-text-editor/toolbar.mjs +464 -346
  44. package/dist/client/components/fields/rich-text-editor/types.d.mts +77 -0
  45. package/dist/client/components/fields/upload-field.mjs +45 -49
  46. package/dist/client/components/filter-builder/columns-tab.mjs +69 -62
  47. package/dist/client/components/filter-builder/filter-builder-sheet.mjs +473 -308
  48. package/dist/client/components/filter-builder/filters-tab.mjs +109 -82
  49. package/dist/client/components/filter-builder/saved-views-tab.mjs +300 -198
  50. package/dist/client/components/history-sidebar.mjs +850 -340
  51. package/dist/client/components/layout/field-layout-renderer.mjs +6 -5
  52. package/dist/client/components/locale-switcher.mjs +8 -8
  53. package/dist/client/components/media/media-grid.mjs +12 -9
  54. package/dist/client/components/media/media-picker-dialog.mjs +242 -230
  55. package/dist/client/components/preview/live-preview-mode.mjs +1 -1
  56. package/dist/client/components/primitives/asset-preview.mjs +37 -22
  57. package/dist/client/components/primitives/date-input.mjs +212 -249
  58. package/dist/client/components/primitives/dropzone.mjs +192 -159
  59. package/dist/client/components/primitives/field-select-control.mjs +93 -0
  60. package/dist/client/components/primitives/select-multi.mjs +251 -230
  61. package/dist/client/components/primitives/select-single.mjs +345 -290
  62. package/dist/client/components/primitives/time-input.mjs +2 -2
  63. package/dist/client/components/sheets/resource-sheet.mjs +2 -0
  64. package/dist/client/components/ui/accordion.mjs +4 -4
  65. package/dist/client/components/ui/alert.mjs +3 -3
  66. package/dist/client/components/ui/badge.mjs +4 -4
  67. package/dist/client/components/ui/button.mjs +47 -37
  68. package/dist/client/components/ui/card.mjs +2 -2
  69. package/dist/client/components/ui/checkbox.mjs +1 -1
  70. package/dist/client/components/ui/command.mjs +5 -5
  71. package/dist/client/components/ui/dialog.mjs +3 -3
  72. package/dist/client/components/ui/drawer.mjs +1 -1
  73. package/dist/client/components/ui/dropdown-menu.mjs +157 -15
  74. package/dist/client/components/ui/empty-state.mjs +88 -59
  75. package/dist/client/components/ui/field.mjs +2 -2
  76. package/dist/client/components/ui/input-group.mjs +3 -3
  77. package/dist/client/components/ui/input.mjs +1 -1
  78. package/dist/client/components/ui/kbd.mjs +1 -1
  79. package/dist/client/components/ui/label.mjs +1 -1
  80. package/dist/client/components/ui/popover.mjs +19 -11
  81. package/dist/client/components/ui/scroll-fade.mjs +170 -0
  82. package/dist/client/components/ui/search-input.mjs +1 -1
  83. package/dist/client/components/ui/select.mjs +129 -27
  84. package/dist/client/components/ui/sheet.mjs +54 -34
  85. package/dist/client/components/ui/sidebar.mjs +15 -14
  86. package/dist/client/components/ui/skeleton.mjs +28 -12
  87. package/dist/client/components/ui/switch.mjs +2 -2
  88. package/dist/client/components/ui/table.mjs +82 -74
  89. package/dist/client/components/ui/tabs.mjs +26 -31
  90. package/dist/client/components/ui/textarea.mjs +1 -1
  91. package/dist/client/components/ui/tooltip.mjs +1 -1
  92. package/dist/client/components/widgets/chart-widget.mjs +134 -96
  93. package/dist/client/components/widgets/progress-widget.mjs +59 -34
  94. package/dist/client/components/widgets/quick-actions-widget.mjs +184 -113
  95. package/dist/client/components/widgets/recent-items-widget.mjs +144 -102
  96. package/dist/client/components/widgets/stats-widget.mjs +91 -72
  97. package/dist/client/components/widgets/table-widget.mjs +159 -246
  98. package/dist/client/components/widgets/timeline-widget.mjs +66 -43
  99. package/dist/client/components/widgets/value-widget.mjs +261 -152
  100. package/dist/client/components/widgets/widget-empty-state.mjs +88 -0
  101. package/dist/client/components/widgets/widget-skeletons.mjs +53 -20
  102. package/dist/client/contexts/focus-context.d.mts +2 -2
  103. package/dist/client/hooks/use-action.mjs +63 -55
  104. package/dist/client/hooks/use-audit-history.mjs +1 -65
  105. package/dist/client/hooks/use-collection-validation.mjs +36 -23
  106. package/dist/client/hooks/use-collection.mjs +96 -1
  107. package/dist/client/hooks/use-saved-views.mjs +70 -49
  108. package/dist/client/hooks/use-server-actions.mjs +59 -40
  109. package/dist/client/hooks/use-server-validation.mjs +156 -41
  110. package/dist/client/hooks/use-server-widget-data.mjs +1 -1
  111. package/dist/client/hooks/use-setup-status.d.mts +3 -3
  112. package/dist/client/hooks/use-setup-status.mjs +2 -2
  113. package/dist/client/hooks/use-transition-stage.mjs +2 -10
  114. package/dist/client/hooks/use-validation-error-map.mjs +31 -13
  115. package/dist/client/hooks/use-view-state.mjs +238 -174
  116. package/dist/client/i18n/date-locale.mjs +33 -0
  117. package/dist/client/i18n/hooks.mjs +17 -1
  118. package/dist/client/lib/utils.mjs +3 -2
  119. package/dist/client/preview/block-scope-context.d.mts +2 -2
  120. package/dist/client/preview/preview-banner.d.mts +2 -2
  121. package/dist/client/preview/preview-field.d.mts +4 -4
  122. package/dist/client/preview/preview-field.mjs +2 -2
  123. package/dist/client/runtime/provider.mjs +8 -1
  124. package/dist/client/runtime/translations-provider.mjs +1 -1
  125. package/dist/client/scope/picker.d.mts +2 -2
  126. package/dist/client/scope/provider.d.mts +2 -2
  127. package/dist/client/styles/base.css +1022 -0
  128. package/dist/client/styles/index.css +3 -589
  129. package/dist/client/utils/auto-expand-fields.mjs +4 -2
  130. package/dist/client/utils/keyboard-shortcuts.mjs +26 -0
  131. package/dist/client/utils/use-lazy-component.mjs +80 -0
  132. package/dist/client/views/auth/auth-layout.d.mts +18 -11
  133. package/dist/client/views/auth/auth-layout.mjs +291 -80
  134. package/dist/client/views/auth/forgot-password-form.d.mts +2 -2
  135. package/dist/client/views/auth/forgot-password-form.mjs +2 -2
  136. package/dist/client/views/auth/login-form.d.mts +2 -2
  137. package/dist/client/views/auth/login-form.mjs +1 -1
  138. package/dist/client/views/auth/reset-password-form.d.mts +2 -2
  139. package/dist/client/views/auth/reset-password-form.mjs +2 -2
  140. package/dist/client/views/auth/setup-form.d.mts +2 -2
  141. package/dist/client/views/collection/auto-form-fields.mjs +11 -9
  142. package/dist/client/views/collection/bulk-action-toolbar.mjs +173 -138
  143. package/dist/client/views/collection/cells/complex-cells.mjs +22 -22
  144. package/dist/client/views/collection/cells/primitive-cells.mjs +1 -1
  145. package/dist/client/views/collection/cells/relation-cells.mjs +147 -129
  146. package/dist/client/views/collection/cells/shared/asset-thumbnail.mjs +224 -278
  147. package/dist/client/views/collection/cells/shared/relation-chip.mjs +64 -36
  148. package/dist/client/views/collection/cells/upload-cells.mjs +199 -9
  149. package/dist/client/views/collection/columns/build-columns.mjs +29 -9
  150. package/dist/client/views/collection/columns/column-defaults.mjs +2 -2
  151. package/dist/client/views/collection/field-renderer.mjs +50 -89
  152. package/dist/client/views/collection/form-view.mjs +237 -227
  153. package/dist/client/views/collection/table-view.mjs +1162 -229
  154. package/dist/client/views/collection/view-skeletons.mjs +222 -79
  155. package/dist/client/views/common/global-search.mjs +29 -18
  156. package/dist/client/views/dashboard/dashboard-grid.mjs +678 -501
  157. package/dist/client/views/dashboard/dashboard-widget.mjs +6 -3
  158. package/dist/client/views/dashboard/widget-card.mjs +23 -14
  159. package/dist/client/views/globals/global-form-view.mjs +634 -589
  160. package/dist/client/views/layout/admin-layout-provider.mjs +67 -70
  161. package/dist/client/views/layout/admin-layout.d.mts +3 -6
  162. package/dist/client/views/layout/admin-layout.mjs +149 -172
  163. package/dist/client/views/layout/admin-router.mjs +747 -544
  164. package/dist/client/views/layout/admin-sidebar.d.mts +38 -1
  165. package/dist/client/views/layout/admin-sidebar.mjs +751 -591
  166. package/dist/client/views/layout/admin-theme.d.mts +10 -0
  167. package/dist/client/views/layout/admin-theme.mjs +84 -0
  168. package/dist/client/views/layout/admin-view-layout.mjs +161 -0
  169. package/dist/client/views/pages/accept-invite-page.d.mts +2 -2
  170. package/dist/client/views/pages/accept-invite-page.mjs +49 -26
  171. package/dist/client/views/pages/dashboard-page.d.mts +2 -2
  172. package/dist/client/views/pages/forgot-password-page.d.mts +2 -2
  173. package/dist/client/views/pages/forgot-password-page.mjs +2 -19
  174. package/dist/client/views/pages/invite-page.d.mts +2 -2
  175. package/dist/client/views/pages/invite-page.mjs +2 -19
  176. package/dist/client/views/pages/login-page.d.mts +1 -1
  177. package/dist/client/views/pages/login-page.mjs +4 -21
  178. package/dist/client/views/pages/reset-password-page.d.mts +2 -2
  179. package/dist/client/views/pages/reset-password-page.mjs +3 -20
  180. package/dist/client/views/pages/setup-page.d.mts +2 -2
  181. package/dist/client/views/pages/setup-page.mjs +3 -20
  182. package/dist/client.d.mts +6 -2
  183. package/dist/client.mjs +2 -1
  184. package/dist/components/rich-text/rich-text-renderer.d.mts +2 -2
  185. package/dist/index.d.mts +6 -2
  186. package/dist/index.mjs +2 -1
  187. package/dist/server/augmentation/dashboard.d.mts +67 -3
  188. package/dist/server/augmentation/form-layout.d.mts +21 -0
  189. package/dist/server/augmentation/index.d.mts +1 -1
  190. package/dist/server/codegen/admin-client-template.mjs +4 -0
  191. package/dist/server/fields/blocks.d.mts +1 -1
  192. package/dist/server/fields/blocks.mjs +12 -0
  193. package/dist/server/fields/rich-text.d.mts +1 -1
  194. package/dist/server/fields/rich-text.mjs +8 -0
  195. package/dist/server/i18n/index.mjs +17 -1
  196. package/dist/server/i18n/messages/cs.mjs +23 -0
  197. package/dist/server/i18n/messages/de.mjs +23 -0
  198. package/dist/server/i18n/messages/en.mjs +64 -1
  199. package/dist/server/i18n/messages/es.mjs +23 -0
  200. package/dist/server/i18n/messages/fr.mjs +23 -0
  201. package/dist/server/i18n/messages/pl.mjs +23 -0
  202. package/dist/server/i18n/messages/pt.mjs +23 -0
  203. package/dist/server/i18n/messages/sk.mjs +83 -1
  204. package/dist/server/modules/admin/block/introspection.mjs +4 -1
  205. package/dist/server/modules/admin/block/prefetch.mjs +12 -2
  206. package/dist/server/modules/admin/collections/account.d.mts +50 -50
  207. package/dist/server/modules/admin/collections/admin-locks.d.mts +54 -54
  208. package/dist/server/modules/admin/collections/admin-preferences.d.mts +39 -39
  209. package/dist/server/modules/admin/collections/admin-saved-views.d.mts +47 -47
  210. package/dist/server/modules/admin/collections/apikey.d.mts +68 -68
  211. package/dist/server/modules/admin/collections/assets.d.mts +20 -20
  212. package/dist/server/modules/admin/collections/assets.mjs +0 -1
  213. package/dist/server/modules/admin/collections/session.d.mts +42 -42
  214. package/dist/server/modules/admin/collections/user.d.mts +12 -0
  215. package/dist/server/modules/admin/collections/user.mjs +40 -9
  216. package/dist/server/modules/admin/collections/verification.d.mts +2 -2
  217. package/dist/server/modules/admin/dto/admin-config.dto.mjs +2 -0
  218. package/dist/server/modules/admin/factories.mjs +7 -18
  219. package/dist/server/modules/admin/index.d.mts +1 -1
  220. package/dist/server/modules/admin/routes/admin-config.d.mts +2 -2
  221. package/dist/server/modules/admin/routes/admin-config.mjs +34 -16
  222. package/dist/server/modules/admin/routes/execute-action.d.mts +9 -9
  223. package/dist/server/modules/admin/routes/execute-action.mjs +33 -0
  224. package/dist/server/modules/admin/routes/locales.d.mts +2 -2
  225. package/dist/server/modules/admin/routes/preview.d.mts +11 -11
  226. package/dist/server/modules/admin/routes/reactive.d.mts +9 -9
  227. package/dist/server/modules/admin/routes/setup.d.mts +10 -10
  228. package/dist/server/modules/admin/routes/setup.mjs +7 -7
  229. package/dist/server/modules/admin/routes/translations.d.mts +4 -4
  230. package/dist/server/modules/admin/routes/translations.mjs +5 -1
  231. package/dist/server/modules/admin/routes/widget-data.d.mts +5 -5
  232. package/dist/server/modules/admin-preferences/collections/admin-preferences.mjs +1 -1
  233. package/dist/server/modules/admin-preferences/collections/saved-views.d.mts +27 -27
  234. package/dist/server/modules/audit/.generated/module.d.mts +1 -1
  235. package/dist/server/modules/audit/.generated/module.mjs +1 -1
  236. package/dist/server/modules/audit/collections/audit-log.d.mts +2 -2
  237. package/dist/server/modules/audit/collections/audit-log.mjs +1 -1
  238. package/dist/server/modules/audit/config/app.mjs +99 -42
  239. package/dist/server/modules/audit/jobs/audit-cleanup.mjs +1 -1
  240. package/dist/server/plugin.mjs +4 -2
  241. package/dist/server/proxy-factories.d.mts +4 -3
  242. package/dist/server/proxy-factories.mjs +34 -8
  243. package/dist/shared/types/saved-views.types.d.mts +2 -0
  244. package/package.json +6 -4
  245. package/dist/client/components/fields/rich-text-editor/link-popover.mjs +0 -85
  246. package/dist/client/components/ui/spinner.mjs +0 -52
  247. package/dist/client/components/ui/toolbar.mjs +0 -136
  248. package/dist/client/contexts/breadcrumb-context.mjs +0 -60
  249. package/dist/client/views/layout/admin-topbar.mjs +0 -236
@@ -2,9 +2,10 @@ import { useResolveText, useTranslation } from "../../i18n/hooks.mjs";
2
2
  import { cn } from "../../lib/utils.mjs";
3
3
  import { selectClient, useAdminStore } from "../../runtime/provider.mjs";
4
4
  import { resolveIconElement } from "../component-renderer.mjs";
5
- import { Button } from "../ui/button.mjs";
6
5
  import { LocaleBadge } from "./locale-badge.mjs";
7
6
  import { useAdminConfig } from "../../hooks/use-admin-config.mjs";
7
+ import { InputGroupAddon, InputGroupButton } from "../ui/input-group.mjs";
8
+ import { FieldSelectActionGroup } from "../primitives/field-select-control.mjs";
8
9
  import { SelectSingle } from "../primitives/select-single.mjs";
9
10
  import { useCollectionItem } from "../../hooks/use-collection.mjs";
10
11
  import { ResourceSheet } from "../sheets/resource-sheet.mjs";
@@ -100,7 +101,7 @@ function RelationSelect({ name, value, onChange, targetCollection, label, filter
100
101
  targetCollection,
101
102
  value
102
103
  ]);
103
- const { data: selectedItem } = useCollectionItem(targetCollection, value || "", void 0, { enabled: !!value });
104
+ const { data: selectedItem, isLoading: isLoadingSelectedItem } = useCollectionItem(targetCollection, value || "", void 0, { enabled: !!value });
104
105
  const selectedOptions = React.useMemo(() => {
105
106
  if (!selectedItem) return [];
106
107
  return [{
@@ -140,7 +141,7 @@ function RelationSelect({ name, value, onChange, targetCollection, label, filter
140
141
  className: "flex items-center gap-2",
141
142
  children: [/* @__PURE__ */ jsxs("label", {
142
143
  htmlFor: name,
143
- className: "flex items-center gap-1.5 text-sm font-medium",
144
+ className: "font-chrome flex items-center gap-1.5 text-sm font-medium",
144
145
  children: [
145
146
  resolveIconElement(collectionIconRef, { className: "size-3.5 text-muted-foreground" }),
146
147
  resolvedLabel,
@@ -151,66 +152,89 @@ function RelationSelect({ name, value, onChange, targetCollection, label, filter
151
152
  ]
152
153
  }), localized && /* @__PURE__ */ jsx(LocaleBadge, { locale: locale || "i18n" })]
153
154
  }),
154
- /* @__PURE__ */ jsxs("div", {
155
- className: "flex items-stretch gap-0",
156
- children: [/* @__PURE__ */ jsx("div", {
157
- className: "min-w-0 flex-1",
158
- children: /* @__PURE__ */ jsx(SelectSingle, {
159
- id: name,
160
- value: value || null,
161
- onChange: handleValueChange,
162
- options: selectedOptions,
163
- loadOptions,
164
- queryKey: (search_0) => queryOpts.key([
165
- "collections",
166
- targetCollection,
167
- "find",
168
- {
169
- limit: 50,
170
- locale,
171
- search: search_0,
172
- where: filter ? filter({}) : void 0
173
- }
174
- ]),
175
- prefetchOnMount: true,
176
- placeholder: resolvedPlaceholder || `${selectLabel}...`,
177
- disabled: disabled || readOnly,
178
- clearable: !required,
179
- emptyMessage: noResultsLabel,
180
- drawerTitle: selectLabel,
181
- className: cn(!readOnly && "rounded-r-none", error && "border-destructive"),
182
- "aria-invalid": !!error
183
- })
184
- }), !readOnly && /* @__PURE__ */ jsxs("div", {
185
- className: "flex",
186
- children: [value && /* @__PURE__ */ jsx(Button, {
187
- type: "button",
188
- variant: "outline",
189
- size: "icon",
155
+ !readOnly ? /* @__PURE__ */ jsxs(FieldSelectActionGroup, {
156
+ error: !!error,
157
+ children: [/* @__PURE__ */ jsx(SelectSingle, {
158
+ id: name,
159
+ value: value || null,
160
+ onChange: handleValueChange,
161
+ options: selectedOptions,
162
+ loadOptions,
163
+ queryKey: (search_0) => queryOpts.key([
164
+ "collections",
165
+ targetCollection,
166
+ "find",
167
+ {
168
+ limit: 50,
169
+ locale,
170
+ search: search_0,
171
+ where: filter ? filter({}) : void 0
172
+ }
173
+ ]),
174
+ prefetchOnMount: true,
175
+ placeholder: resolvedPlaceholder || `${selectLabel}...`,
176
+ disabled,
177
+ clearable: !required,
178
+ emptyMessage: noResultsLabel,
179
+ drawerTitle: selectLabel,
180
+ selectedLabel: selectedItem?._title || selectedItem?.id || void 0,
181
+ isLoadingValue: !!value && isLoadingSelectedItem,
182
+ asInputGroupControl: true,
183
+ "aria-invalid": !!error
184
+ }), /* @__PURE__ */ jsxs(InputGroupAddon, {
185
+ align: "inline-end",
186
+ className: "gap-0.5 pr-1",
187
+ children: [value && /* @__PURE__ */ jsx(InputGroupButton, {
188
+ size: "icon-sm",
189
+ className: "text-muted-foreground hover:bg-surface-high hover:text-foreground",
190
190
  onClick: handleOpenEdit,
191
191
  disabled,
192
192
  title: t("collection.edit", { name: labelText }),
193
193
  "aria-label": t("collection.edit", { name: labelText }),
194
- className: "rounded-none border-l-0",
195
194
  children: /* @__PURE__ */ jsx(Icon, {
196
195
  icon: "ph:pencil",
197
- className: "h-4 w-4"
196
+ className: "size-3.5"
198
197
  })
199
- }), /* @__PURE__ */ jsx(Button, {
200
- type: "button",
201
- variant: "outline",
202
- size: "icon",
198
+ }), /* @__PURE__ */ jsx(InputGroupButton, {
199
+ size: "icon-sm",
200
+ className: "text-muted-foreground hover:bg-surface-high hover:text-foreground",
203
201
  onClick: handleOpenCreate,
204
202
  disabled,
205
203
  title: createLabel,
206
204
  "aria-label": createLabel,
207
- className: "rounded-l-none border-l-0",
208
205
  children: /* @__PURE__ */ jsx(Icon, {
209
206
  icon: "ph:plus",
210
- className: "h-4 w-4"
207
+ className: "size-3.5"
211
208
  })
212
209
  })]
213
210
  })]
211
+ }) : /* @__PURE__ */ jsx(SelectSingle, {
212
+ id: name,
213
+ value: value || null,
214
+ onChange: handleValueChange,
215
+ options: selectedOptions,
216
+ loadOptions,
217
+ queryKey: (search_1) => queryOpts.key([
218
+ "collections",
219
+ targetCollection,
220
+ "find",
221
+ {
222
+ limit: 50,
223
+ locale,
224
+ search: search_1,
225
+ where: filter ? filter({}) : void 0
226
+ }
227
+ ]),
228
+ prefetchOnMount: true,
229
+ placeholder: resolvedPlaceholder || `${selectLabel}...`,
230
+ disabled: true,
231
+ clearable: false,
232
+ emptyMessage: noResultsLabel,
233
+ drawerTitle: selectLabel,
234
+ selectedLabel: selectedItem?._title || selectedItem?.id || void 0,
235
+ isLoadingValue: !!value && isLoadingSelectedItem,
236
+ className: cn(error && "border-destructive"),
237
+ "aria-invalid": !!error
214
238
  }),
215
239
  error && /* @__PURE__ */ jsx("p", {
216
240
  className: "text-destructive text-sm",
@@ -1,104 +1,414 @@
1
1
  import { useTranslation } from "../../../i18n/hooks.mjs";
2
+ import { Button } from "../../ui/button.mjs";
3
+ import { Input } from "../../ui/input.mjs";
4
+ import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue } from "../../ui/select.mjs";
5
+ import { createLinkAttributes } from "./link-utils.mjs";
2
6
  import { EDITOR_ICONS, ToolbarButton } from "./toolbar.mjs";
3
7
  import { c } from "react/compiler-runtime";
4
- import "react";
5
- import { jsx, jsxs } from "react/jsx-runtime";
8
+ import { Icon } from "@iconify/react";
9
+ import * as React from "react";
10
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
11
  import { BubbleMenu } from "@tiptap/react";
7
12
 
8
13
  //#region src/client/components/fields/rich-text-editor/bubble-menu.tsx
9
14
  /**
15
+ * Bubble Menu Component
16
+ *
17
+ * Floating toolbar that appears on text selection.
18
+ */
19
+ const BLOCK_OPTIONS = [
20
+ {
21
+ value: "paragraph",
22
+ group: "text"
23
+ },
24
+ {
25
+ value: "h1",
26
+ group: "heading"
27
+ },
28
+ {
29
+ value: "h2",
30
+ group: "heading"
31
+ },
32
+ {
33
+ value: "h3",
34
+ group: "heading"
35
+ },
36
+ {
37
+ value: "bulletList",
38
+ group: "list"
39
+ },
40
+ {
41
+ value: "orderedList",
42
+ group: "list"
43
+ },
44
+ {
45
+ value: "blockquote",
46
+ group: "block"
47
+ }
48
+ ];
49
+ function getCurrentBlockValue(editor) {
50
+ if (editor.isActive("heading", { level: 1 })) return "h1";
51
+ if (editor.isActive("heading", { level: 2 })) return "h2";
52
+ if (editor.isActive("heading", { level: 3 })) return "h3";
53
+ if (editor.isActive("bulletList")) return "bulletList";
54
+ if (editor.isActive("orderedList")) return "orderedList";
55
+ if (editor.isActive("blockquote")) return "blockquote";
56
+ return "paragraph";
57
+ }
58
+ function getBlockOptionLabel(value, t) {
59
+ if (value === "paragraph") return t("editor.paragraph");
60
+ if (value === "h1") return t("editor.heading", { level: 1 });
61
+ if (value === "h2") return t("editor.heading", { level: 2 });
62
+ if (value === "h3") return t("editor.heading", { level: 3 });
63
+ if (value === "bulletList") return t("editor.unorderedList");
64
+ if (value === "orderedList") return t("editor.orderedList");
65
+ return t("editor.quote");
66
+ }
67
+ function setCurrentBlockValue(editor, value) {
68
+ const chain = editor.chain().focus();
69
+ if (value === "paragraph") {
70
+ chain.setParagraph().run();
71
+ return;
72
+ }
73
+ if (value === "h1" || value === "h2" || value === "h3") {
74
+ chain.toggleHeading({ level: Number(value.replace("h", "")) }).run();
75
+ return;
76
+ }
77
+ if (value === "bulletList") {
78
+ chain.toggleBulletList().run();
79
+ return;
80
+ }
81
+ if (value === "orderedList") {
82
+ chain.toggleOrderedList().run();
83
+ return;
84
+ }
85
+ if (value === "blockquote") chain.toggleBlockquote().run();
86
+ }
87
+ /**
10
88
  * Bubble menu that appears on text selection
11
89
  */
12
90
  function RichTextBubbleMenu(t0) {
13
- const $ = c(27);
14
- const { editor, features, disabled, onLinkClick } = t0;
91
+ const $ = c(45);
92
+ const { editor, features, disabled, linkOpen, onImageClick, onLinkOpenChange, showFormatting: t1 } = t0;
93
+ const showFormatting = t1 === void 0 ? true : t1;
15
94
  const { t } = useTranslation();
95
+ const [linkUrl, setLinkUrl] = React.useState("");
96
+ const linkInputRef = React.useRef(null);
16
97
  const isEditable = !disabled;
17
- let t1;
18
- if ($[0] !== editor || $[1] !== features.bold || $[2] !== isEditable || $[3] !== t) {
19
- t1 = features.bold && /* @__PURE__ */ jsx(ToolbarButton, {
20
- icon: EDITOR_ICONS.bold,
21
- active: editor.isActive("bold"),
22
- disabled: !isEditable,
23
- title: t("editor.bold"),
24
- shortcut: "⌘B",
25
- onClick: () => editor.chain().focus().toggleBold().run()
26
- });
27
- $[0] = editor;
28
- $[1] = features.bold;
29
- $[2] = isEditable;
30
- $[3] = t;
31
- $[4] = t1;
32
- } else t1 = $[4];
98
+ let currentBlockValue;
33
99
  let t2;
34
- if ($[5] !== editor || $[6] !== features.italic || $[7] !== isEditable || $[8] !== t) {
35
- t2 = features.italic && /* @__PURE__ */ jsx(ToolbarButton, {
36
- icon: EDITOR_ICONS.italic,
37
- active: editor.isActive("italic"),
38
- disabled: !isEditable,
39
- title: t("editor.italic"),
40
- shortcut: "⌘I",
41
- onClick: () => editor.chain().focus().toggleItalic().run()
42
- });
43
- $[5] = editor;
44
- $[6] = features.italic;
45
- $[7] = isEditable;
46
- $[8] = t;
47
- $[9] = t2;
48
- } else t2 = $[9];
100
+ if ($[0] !== editor || $[1] !== t) {
101
+ currentBlockValue = getCurrentBlockValue(editor);
102
+ t2 = BLOCK_OPTIONS.find((option) => option.value === currentBlockValue)?.value ? getBlockOptionLabel(currentBlockValue, t) : t("editor.paragraph");
103
+ $[0] = editor;
104
+ $[1] = t;
105
+ $[2] = currentBlockValue;
106
+ $[3] = t2;
107
+ } else {
108
+ currentBlockValue = $[2];
109
+ t2 = $[3];
110
+ }
111
+ const currentBlockLabel = t2;
49
112
  let t3;
50
- if ($[10] !== editor || $[11] !== features.underline || $[12] !== isEditable || $[13] !== t) {
51
- t3 = features.underline && /* @__PURE__ */ jsx(ToolbarButton, {
52
- icon: EDITOR_ICONS.underline,
53
- active: editor.isActive("underline"),
54
- disabled: !isEditable,
55
- title: t("editor.underline"),
56
- shortcut: "⌘U",
57
- onClick: () => editor.chain().focus().toggleUnderline().run()
58
- });
59
- $[10] = editor;
60
- $[11] = features.underline;
61
- $[12] = isEditable;
62
- $[13] = t;
63
- $[14] = t3;
64
- } else t3 = $[14];
113
+ if ($[4] !== isEditable || $[5] !== linkOpen || $[6] !== showFormatting) {
114
+ t3 = (t4$1) => {
115
+ const { editor: currentEditor, from, to } = t4$1;
116
+ if (!isEditable) return false;
117
+ if (linkOpen) return true;
118
+ if (!showFormatting) return false;
119
+ if (from === to) return false;
120
+ return !currentEditor.isActive("image");
121
+ };
122
+ $[4] = isEditable;
123
+ $[5] = linkOpen;
124
+ $[6] = showFormatting;
125
+ $[7] = t3;
126
+ } else t3 = $[7];
127
+ const shouldShow = t3;
65
128
  let t4;
66
- if ($[15] !== editor || $[16] !== features.link || $[17] !== isEditable || $[18] !== onLinkClick || $[19] !== t) {
67
- t4 = features.link && /* @__PURE__ */ jsx(ToolbarButton, {
68
- icon: EDITOR_ICONS.link,
69
- active: editor.isActive("link"),
70
- disabled: !isEditable,
71
- title: t("editor.link"),
72
- shortcut: "⌘K",
73
- onClick: onLinkClick
74
- });
75
- $[15] = editor;
76
- $[16] = features.link;
77
- $[17] = isEditable;
78
- $[18] = onLinkClick;
79
- $[19] = t;
80
- $[20] = t4;
81
- } else t4 = $[20];
129
+ if ($[8] !== editor || $[9] !== onLinkOpenChange) {
130
+ t4 = () => {
131
+ const currentLink = editor.getAttributes("link").href;
132
+ setLinkUrl(currentLink || "");
133
+ onLinkOpenChange(true);
134
+ };
135
+ $[8] = editor;
136
+ $[9] = onLinkOpenChange;
137
+ $[10] = t4;
138
+ } else t4 = $[10];
139
+ const openLinkMode = t4;
82
140
  let t5;
83
- if ($[21] !== editor || $[22] !== t1 || $[23] !== t2 || $[24] !== t3 || $[25] !== t4) {
84
- t5 = /* @__PURE__ */ jsxs(BubbleMenu, {
85
- editor,
86
- className: "bg-background flex items-center gap-1 border p-1 shadow-lg",
141
+ if ($[11] !== editor || $[12] !== onLinkOpenChange) {
142
+ t5 = () => {
143
+ onLinkOpenChange(false);
144
+ setLinkUrl("");
145
+ editor.chain().focus().run();
146
+ };
147
+ $[11] = editor;
148
+ $[12] = onLinkOpenChange;
149
+ $[13] = t5;
150
+ } else t5 = $[13];
151
+ const closeLinkMode = t5;
152
+ let t6;
153
+ if ($[14] !== closeLinkMode || $[15] !== editor || $[16] !== linkUrl) {
154
+ t6 = () => {
155
+ const trimmedUrl = linkUrl.trim();
156
+ if (!trimmedUrl) {
157
+ editor.chain().focus().extendMarkRange("link").unsetLink().run();
158
+ closeLinkMode();
159
+ return;
160
+ }
161
+ const attrs = createLinkAttributes(trimmedUrl);
162
+ if (editor.state.selection.empty && !editor.isActive("link")) editor.chain().focus().insertContent({
163
+ type: "text",
164
+ text: attrs.href,
165
+ marks: [{
166
+ type: "link",
167
+ attrs
168
+ }]
169
+ }).run();
170
+ else editor.chain().focus().extendMarkRange("link").setLink(attrs).run();
171
+ closeLinkMode();
172
+ };
173
+ $[14] = closeLinkMode;
174
+ $[15] = editor;
175
+ $[16] = linkUrl;
176
+ $[17] = t6;
177
+ } else t6 = $[17];
178
+ const applyLink = t6;
179
+ let t7;
180
+ if ($[18] !== closeLinkMode || $[19] !== editor) {
181
+ t7 = () => {
182
+ editor.chain().focus().extendMarkRange("link").unsetLink().run();
183
+ closeLinkMode();
184
+ };
185
+ $[18] = closeLinkMode;
186
+ $[19] = editor;
187
+ $[20] = t7;
188
+ } else t7 = $[20];
189
+ const removeLink = t7;
190
+ let t8;
191
+ let t9;
192
+ if ($[21] !== editor || $[22] !== linkOpen) {
193
+ t8 = () => {
194
+ if (!linkOpen) return;
195
+ const currentLink_0 = editor.getAttributes("link").href;
196
+ setLinkUrl(currentLink_0 || "");
197
+ window.requestAnimationFrame(() => {
198
+ linkInputRef.current?.focus();
199
+ linkInputRef.current?.select();
200
+ });
201
+ };
202
+ t9 = [editor, linkOpen];
203
+ $[21] = editor;
204
+ $[22] = linkOpen;
205
+ $[23] = t8;
206
+ $[24] = t9;
207
+ } else {
208
+ t8 = $[23];
209
+ t9 = $[24];
210
+ }
211
+ React.useEffect(t8, t9);
212
+ let t10;
213
+ if ($[25] === Symbol.for("react.memo_cache_sentinel")) {
214
+ t10 = [120, 90];
215
+ $[25] = t10;
216
+ } else t10 = $[25];
217
+ let t11;
218
+ if ($[26] === Symbol.for("react.memo_cache_sentinel")) {
219
+ t11 = {
220
+ duration: t10,
221
+ interactive: true,
222
+ maxWidth: "none",
223
+ offset: [0, 8],
224
+ placement: "top"
225
+ };
226
+ $[26] = t11;
227
+ } else t11 = $[26];
228
+ let t12;
229
+ if ($[27] !== applyLink || $[28] !== closeLinkMode || $[29] !== currentBlockLabel || $[30] !== currentBlockValue || $[31] !== editor || $[32] !== features || $[33] !== isEditable || $[34] !== linkOpen || $[35] !== linkUrl || $[36] !== onImageClick || $[37] !== openLinkMode || $[38] !== removeLink || $[39] !== t) {
230
+ t12 = linkOpen ? /* @__PURE__ */ jsxs("form", {
231
+ className: "qp-rich-text-editor__link-form",
232
+ onSubmit: (event) => {
233
+ event.preventDefault();
234
+ applyLink();
235
+ },
236
+ onKeyDown: (event_0) => {
237
+ event_0.stopPropagation();
238
+ if (event_0.key === "Escape") {
239
+ event_0.preventDefault();
240
+ closeLinkMode();
241
+ }
242
+ },
87
243
  children: [
88
- t1,
89
- t2,
90
- t3,
91
- t4
244
+ /* @__PURE__ */ jsx(Icon, {
245
+ "aria-hidden": "true",
246
+ className: "text-muted-foreground shrink-0",
247
+ icon: "ph:link",
248
+ width: 16,
249
+ height: 16
250
+ }),
251
+ /* @__PURE__ */ jsx(Input, {
252
+ ref: linkInputRef,
253
+ "aria-label": t("editor.link"),
254
+ autoComplete: "off",
255
+ className: "qp-rich-text-editor__link-input",
256
+ inputMode: "url",
257
+ name: "rich-text-inline-link-url",
258
+ placeholder: t("editor.pasteOrTypeLink"),
259
+ type: "text",
260
+ value: linkUrl,
261
+ onChange: (event_1) => setLinkUrl(event_1.target.value),
262
+ disabled: !isEditable
263
+ }),
264
+ /* @__PURE__ */ jsx(Button, {
265
+ type: "submit",
266
+ size: "icon-xs",
267
+ "aria-label": t("common.apply"),
268
+ disabled: !isEditable || !linkUrl.trim(),
269
+ children: /* @__PURE__ */ jsx(Icon, {
270
+ "aria-hidden": "true",
271
+ icon: "ph:check"
272
+ })
273
+ }),
274
+ /* @__PURE__ */ jsx(Button, {
275
+ type: "button",
276
+ size: "icon-xs",
277
+ variant: "ghost",
278
+ "aria-label": t("common.remove"),
279
+ onClick: removeLink,
280
+ disabled: !isEditable || !editor.isActive("link"),
281
+ children: /* @__PURE__ */ jsx(Icon, {
282
+ "aria-hidden": "true",
283
+ icon: "ph:link-break"
284
+ })
285
+ })
92
286
  ]
287
+ }) : /* @__PURE__ */ jsxs(Fragment, { children: [
288
+ features.heading && /* @__PURE__ */ jsxs(Select, {
289
+ value: currentBlockValue,
290
+ disabled: !isEditable,
291
+ onValueChange: (value) => {
292
+ if (typeof value === "string") setCurrentBlockValue(editor, value);
293
+ },
294
+ children: [/* @__PURE__ */ jsx(SelectTrigger, {
295
+ "aria-label": t("editor.selectionBlockType"),
296
+ className: "qp-rich-text-editor__bubble-block h-8 min-w-[116px] px-2.5 text-xs",
297
+ size: "sm",
298
+ children: /* @__PURE__ */ jsx(SelectValue, { children: currentBlockLabel })
299
+ }), /* @__PURE__ */ jsxs(SelectContent, {
300
+ align: "start",
301
+ className: "min-w-[148px]",
302
+ children: [
303
+ /* @__PURE__ */ jsxs(SelectGroup, { children: [/* @__PURE__ */ jsx(SelectLabel, { children: t("editor.textBlocks") }), /* @__PURE__ */ jsx(SelectItem, {
304
+ value: "paragraph",
305
+ children: t("editor.paragraph")
306
+ })] }),
307
+ /* @__PURE__ */ jsx(SelectSeparator, {}),
308
+ /* @__PURE__ */ jsxs(SelectGroup, { children: [/* @__PURE__ */ jsx(SelectLabel, { children: t("editor.headings") }), BLOCK_OPTIONS.filter(_temp).map((option_1) => /* @__PURE__ */ jsx(SelectItem, {
309
+ value: option_1.value,
310
+ children: getBlockOptionLabel(option_1.value, t)
311
+ }, option_1.value))] }),
312
+ /* @__PURE__ */ jsx(SelectSeparator, {}),
313
+ /* @__PURE__ */ jsxs(SelectGroup, { children: [/* @__PURE__ */ jsx(SelectLabel, { children: t("editor.list") }), BLOCK_OPTIONS.filter(_temp2).map((option_3) => /* @__PURE__ */ jsx(SelectItem, {
314
+ value: option_3.value,
315
+ children: getBlockOptionLabel(option_3.value, t)
316
+ }, option_3.value))] }),
317
+ /* @__PURE__ */ jsx(SelectSeparator, {}),
318
+ /* @__PURE__ */ jsxs(SelectGroup, { children: [/* @__PURE__ */ jsx(SelectLabel, { children: t("editor.blocks") }), /* @__PURE__ */ jsx(SelectItem, {
319
+ value: "blockquote",
320
+ children: t("editor.quote")
321
+ })] })
322
+ ]
323
+ })]
324
+ }),
325
+ /* @__PURE__ */ jsx("span", {
326
+ className: "qp-rich-text-editor__bubble-separator",
327
+ "aria-hidden": "true"
328
+ }),
329
+ features.bold && /* @__PURE__ */ jsx(ToolbarButton, {
330
+ icon: EDITOR_ICONS.bold,
331
+ active: editor.isActive("bold"),
332
+ disabled: !isEditable,
333
+ title: t("editor.bold"),
334
+ shortcut: "⌘B",
335
+ onClick: () => editor.chain().focus().toggleBold().run()
336
+ }),
337
+ features.italic && /* @__PURE__ */ jsx(ToolbarButton, {
338
+ icon: EDITOR_ICONS.italic,
339
+ active: editor.isActive("italic"),
340
+ disabled: !isEditable,
341
+ title: t("editor.italic"),
342
+ shortcut: "⌘I",
343
+ onClick: () => editor.chain().focus().toggleItalic().run()
344
+ }),
345
+ features.underline && /* @__PURE__ */ jsx(ToolbarButton, {
346
+ icon: EDITOR_ICONS.underline,
347
+ active: editor.isActive("underline"),
348
+ disabled: !isEditable,
349
+ title: t("editor.underline"),
350
+ shortcut: "⌘U",
351
+ onClick: () => editor.chain().focus().toggleUnderline().run()
352
+ }),
353
+ features.code && /* @__PURE__ */ jsx(ToolbarButton, {
354
+ icon: EDITOR_ICONS.code,
355
+ active: editor.isActive("code"),
356
+ disabled: !isEditable,
357
+ title: t("editor.code"),
358
+ shortcut: "⌘E",
359
+ onClick: () => editor.chain().focus().toggleCode().run()
360
+ }),
361
+ features.link && /* @__PURE__ */ jsx(ToolbarButton, {
362
+ icon: EDITOR_ICONS.link,
363
+ active: editor.isActive("link"),
364
+ disabled: !isEditable,
365
+ title: t("editor.link"),
366
+ shortcut: "⌘K",
367
+ onClick: openLinkMode
368
+ }),
369
+ features.image && onImageClick && /* @__PURE__ */ jsx(ToolbarButton, {
370
+ icon: EDITOR_ICONS.image,
371
+ disabled: !isEditable,
372
+ title: t("editor.image"),
373
+ onClick: onImageClick
374
+ })
375
+ ] });
376
+ $[27] = applyLink;
377
+ $[28] = closeLinkMode;
378
+ $[29] = currentBlockLabel;
379
+ $[30] = currentBlockValue;
380
+ $[31] = editor;
381
+ $[32] = features;
382
+ $[33] = isEditable;
383
+ $[34] = linkOpen;
384
+ $[35] = linkUrl;
385
+ $[36] = onImageClick;
386
+ $[37] = openLinkMode;
387
+ $[38] = removeLink;
388
+ $[39] = t;
389
+ $[40] = t12;
390
+ } else t12 = $[40];
391
+ let t13;
392
+ if ($[41] !== editor || $[42] !== shouldShow || $[43] !== t12) {
393
+ t13 = /* @__PURE__ */ jsx(BubbleMenu, {
394
+ editor,
395
+ shouldShow,
396
+ tippyOptions: t11,
397
+ className: "qp-rich-text-editor__bubble floating-surface text-popover-foreground",
398
+ children: t12
93
399
  });
94
- $[21] = editor;
95
- $[22] = t1;
96
- $[23] = t2;
97
- $[24] = t3;
98
- $[25] = t4;
99
- $[26] = t5;
100
- } else t5 = $[26];
101
- return t5;
400
+ $[41] = editor;
401
+ $[42] = shouldShow;
402
+ $[43] = t12;
403
+ $[44] = t13;
404
+ } else t13 = $[44];
405
+ return t13;
406
+ }
407
+ function _temp2(option_2) {
408
+ return option_2.group === "list";
409
+ }
410
+ function _temp(option_0) {
411
+ return option_0.group === "heading";
102
412
  }
103
413
 
104
414
  //#endregion