@questpie/admin 3.5.2 → 3.5.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.
- package/README.md +8 -0
- package/dist/client/blocks/block-renderer.d.mts +2 -2
- package/dist/client/builder/index.d.mts +1 -1
- package/dist/client/builder/types/collection-types.d.mts +89 -5
- package/dist/client/builder/types/common.d.mts +5 -0
- package/dist/client/builder/types/field-types.d.mts +41 -1
- package/dist/client/builder/view/view.d.mts +3 -2
- package/dist/client/components/actions/action-dialog.mjs +5 -0
- package/dist/client/components/admin-link.d.mts +2 -2
- package/dist/client/components/fields/boolean-field.mjs +2 -1
- package/dist/client/components/fields/date-field.mjs +2 -1
- package/dist/client/components/fields/datetime-field.mjs +2 -1
- package/dist/client/components/fields/email-field.mjs +2 -1
- package/dist/client/components/fields/field-utils.d.mts +11 -0
- package/dist/client/components/fields/field-utils.mjs +3 -1
- package/dist/client/components/fields/field-wrapper.mjs +3 -3
- package/dist/client/components/fields/number-field.mjs +2 -1
- package/dist/client/components/fields/object-field.mjs +2 -1
- package/dist/client/components/fields/relation/displays/types.mjs +3 -3
- package/dist/client/components/fields/rich-text-editor/bubble-menu.mjs +7 -0
- package/dist/client/components/fields/rich-text-editor/extensions.mjs +19 -2
- package/dist/client/components/fields/rich-text-editor/image-popover.mjs +6 -2
- package/dist/client/components/fields/rich-text-editor/image-upload.mjs +2 -1
- package/dist/client/components/fields/rich-text-editor/index.d.mts +5 -3
- package/dist/client/components/fields/rich-text-editor/index.mjs +38 -76
- package/dist/client/components/fields/rich-text-editor/slash-commands.mjs +30 -7
- package/dist/client/components/fields/rich-text-editor/toolbar.mjs +1 -312
- package/dist/client/components/fields/rich-text-editor/types.d.mts +4 -0
- package/dist/client/components/fields/rich-text-editor/types.mjs +1 -1
- package/dist/client/components/fields/rich-text-editor/utils.mjs +6 -12
- package/dist/client/components/fields/select-field.mjs +2 -1
- package/dist/client/components/fields/text-field.mjs +2 -1
- package/dist/client/components/fields/textarea-field.mjs +2 -1
- package/dist/client/components/fields/time-field.mjs +2 -1
- package/dist/client/components/filter-builder/filter-builder-sheet.mjs +75 -22
- package/dist/client/components/layout/field-layout-renderer.mjs +4 -4
- package/dist/client/components/media/media-grid.mjs +2 -1
- package/dist/client/components/primitives/asset-preview.mjs +4 -2
- package/dist/client/components/primitives/dropzone.d.mts +100 -0
- package/dist/client/components/primitives/field-select-control.mjs +2 -1
- package/dist/client/components/ui/button.d.mts +23 -0
- package/dist/client/components/ui/button.mjs +2 -2
- package/dist/client/components/ui/dropdown-menu.d.mts +49 -0
- package/dist/client/components/ui/dropdown-menu.mjs +7 -19
- package/dist/client/components/ui/popover.mjs +1 -1
- package/dist/client/components/ui/search-input.d.mts +56 -0
- package/dist/client/components/ui/select.mjs +2 -2
- package/dist/client/components/ui/sheet.d.mts +40 -0
- package/dist/client/components/ui/table.d.mts +49 -0
- package/dist/client/components/ui/table.mjs +15 -1
- package/dist/client/components/ui/tooltip.d.mts +21 -0
- package/dist/client/contexts/focus-context.d.mts +2 -2
- package/dist/client/hooks/query-access.d.mts +9 -0
- package/dist/client/hooks/query-access.mjs +20 -0
- package/dist/client/hooks/typed-hooks.d.mts +4 -2
- package/dist/client/hooks/typed-hooks.mjs +30 -29
- package/dist/client/hooks/use-admin-config.mjs +20 -1
- package/dist/client/hooks/use-autosave.mjs +91 -0
- package/dist/client/hooks/use-collection.mjs +65 -23
- package/dist/client/hooks/use-reactive-fields.d.mts +1 -0
- package/dist/client/hooks/use-reactive-fields.mjs +16 -1
- package/dist/client/hooks/use-server-actions.mjs +12 -1
- package/dist/client/hooks/use-upload.d.mts +40 -0
- package/dist/client/hooks/use-upload.mjs +4 -2
- package/dist/client/hooks/use-view-state.mjs +15 -7
- package/dist/client/i18n/hooks.d.mts +20 -0
- package/dist/client/lib/utils.d.mts +6 -0
- package/dist/client/lib/view-filter-utils.mjs +30 -0
- package/dist/client/preview/block-scope-context.d.mts +2 -2
- package/dist/client/preview/preview-banner.d.mts +2 -2
- package/dist/client/preview/preview-field.d.mts +4 -4
- package/dist/client/runtime/provider.mjs +22 -3
- package/dist/client/scope/picker.d.mts +2 -2
- package/dist/client/scope/provider.d.mts +2 -2
- package/dist/client/styles/base.css +75 -79
- package/dist/client/utils/asset-url.mjs +27 -0
- package/dist/client/utils/build-field-definitions-from-schema.mjs +1 -0
- package/dist/client/views/auth/accept-invite-form.d.mts +2 -2
- package/dist/client/views/auth/auth-layout.d.mts +3 -3
- package/dist/client/views/auth/forgot-password-form.d.mts +2 -2
- package/dist/client/views/auth/login-form.d.mts +2 -2
- package/dist/client/views/auth/reset-password-form.d.mts +2 -2
- package/dist/client/views/auth/setup-form.d.mts +2 -2
- package/dist/client/views/collection/auto-form-fields.mjs +7 -6
- package/dist/client/views/collection/cells/primitive-cells.mjs +9 -6
- package/dist/client/views/collection/cells/shared/asset-thumbnail.d.mts +7 -0
- package/dist/client/views/collection/cells/shared/asset-thumbnail.mjs +3 -2
- package/dist/client/views/collection/cells/shared/cell-helpers.mjs +3 -2
- package/dist/client/views/collection/cells/upload-cells.mjs +2 -1
- package/dist/client/views/collection/columns/build-columns.mjs +3 -1
- package/dist/client/views/collection/document-view.d.mts +30 -0
- package/dist/client/views/collection/document-view.mjs +377 -0
- package/dist/client/views/collection/field-context.mjs +3 -2
- package/dist/client/views/collection/field-renderer.mjs +13 -5
- package/dist/client/views/collection/form-view.mjs +221 -282
- package/dist/client/views/collection/list-view.mjs +592 -190
- package/dist/client/views/collection/outline.mjs +44 -19
- package/dist/client/views/collection/quick-filter-bar.mjs +45 -0
- package/dist/client/views/collection/table-view.mjs +61 -17
- package/dist/client/views/globals/global-form-view.mjs +12 -9
- package/dist/client/views/layout/admin-layout-provider.mjs +4 -3
- package/dist/client/views/layout/admin-layout.mjs +108 -21
- package/dist/client/views/layout/admin-router.mjs +19 -3
- package/dist/client/views/layout/admin-sidebar.mjs +70 -20
- package/dist/client/views/layout/admin-theme.mjs +5 -4
- package/dist/client/views/layout/admin-view-layout.d.mts +36 -0
- package/dist/client/views/pages/accept-invite-page.d.mts +2 -2
- package/dist/client/views/pages/dashboard-page.d.mts +2 -2
- package/dist/client/views/pages/forgot-password-page.d.mts +2 -2
- package/dist/client/views/pages/invite-page.d.mts +2 -2
- package/dist/client/views/pages/login-page.d.mts +2 -2
- package/dist/client/views/pages/reset-password-page.d.mts +2 -2
- package/dist/client/views/pages/setup-page.d.mts +2 -2
- package/dist/client.d.mts +17 -2
- package/dist/client.mjs +17 -2
- package/dist/components/rich-text/rich-text-renderer.d.mts +5 -5
- package/dist/components/rich-text/rich-text-renderer.mjs +5 -2
- package/dist/factories.d.mts +4 -2
- package/dist/factories.mjs +2 -2
- package/dist/index.d.mts +17 -3
- package/dist/index.mjs +17 -2
- package/dist/modules/admin.d.mts +1 -1
- package/dist/server/adapters/index.d.mts +2 -0
- package/dist/server/adapters/nextjs.d.mts +1 -0
- package/dist/server/augmentation/actions.d.mts +9 -3
- package/dist/server/augmentation/dashboard.d.mts +11 -11
- package/dist/server/augmentation/form-layout.d.mts +16 -6
- package/dist/server/augmentation/index.d.mts +7 -0
- package/dist/server/augmentation/sidebar.d.mts +8 -8
- package/dist/server/augmentation/views.d.mts +4 -1
- package/dist/server/auth-helpers.d.mts +1 -0
- package/dist/server/codegen/admin-client-template.mjs +7 -6
- package/dist/server/fields/blocks.mjs +4 -1
- package/dist/server/fields/index.d.mts +1 -1
- package/dist/server/fields/reactive-runtime.mjs +3 -0
- package/dist/server/fields/rich-text.d.mts +16 -17
- package/dist/server/fields/rich-text.mjs +18 -7
- package/dist/server/i18n/messages/cs.mjs +2 -0
- package/dist/server/i18n/messages/de.mjs +2 -0
- package/dist/server/i18n/messages/en.mjs +4 -0
- package/dist/server/i18n/messages/es.mjs +2 -0
- package/dist/server/i18n/messages/fr.mjs +2 -0
- package/dist/server/i18n/messages/pl.mjs +2 -0
- package/dist/server/i18n/messages/pt.mjs +2 -0
- package/dist/server/i18n/messages/sk.mjs +2 -0
- package/dist/server/modules/admin/.generated/module.d.mts +1 -1
- package/dist/server/modules/admin/auth-helpers.mjs +7 -1
- package/dist/server/modules/admin/block/block-builder.d.mts +0 -8
- package/dist/server/modules/admin/block/introspection.d.mts +2 -2
- package/dist/server/modules/admin/block/introspection.mjs +28 -4
- package/dist/server/modules/admin/block/prefetch.d.mts +11 -0
- package/dist/server/modules/admin/block/prefetch.mjs +108 -27
- package/dist/server/modules/admin/client/.generated/module.d.mts +68 -67
- package/dist/server/modules/admin/client/.generated/module.mjs +2 -0
- package/dist/server/modules/admin/client/views/collection-document.d.mts +6 -0
- package/dist/server/modules/admin/client/views/collection-document.mjs +10 -0
- package/dist/server/modules/admin/collections/account.d.mts +53 -52
- package/dist/server/modules/admin/collections/admin-locks.d.mts +57 -56
- package/dist/server/modules/admin/collections/admin-preferences.d.mts +38 -37
- package/dist/server/modules/admin/collections/admin-saved-views.d.mts +50 -49
- package/dist/server/modules/admin/collections/apikey.d.mts +76 -67
- package/dist/server/modules/admin/collections/assets.d.mts +37 -36
- package/dist/server/modules/admin/collections/session.d.mts +42 -41
- package/dist/server/modules/admin/collections/user.d.mts +57 -56
- package/dist/server/modules/admin/collections/verification.d.mts +34 -33
- package/dist/server/modules/admin/dto/admin-config.dto.mjs +34 -4
- package/dist/server/modules/admin/factories.mjs +4 -34
- package/dist/server/modules/admin/index.d.mts +3 -3
- package/dist/server/modules/admin/routes/admin-config.d.mts +4 -2
- package/dist/server/modules/admin/routes/admin-config.mjs +56 -24
- package/dist/server/modules/admin/routes/execute-action.d.mts +9 -9
- package/dist/server/modules/admin/routes/execute-action.mjs +35 -9
- package/dist/server/modules/admin/routes/locales.mjs +1 -1
- package/dist/server/modules/admin/routes/preview.d.mts +11 -11
- package/dist/server/modules/admin/routes/preview.mjs +6 -5
- package/dist/server/modules/admin/routes/reactive.d.mts +9 -9
- package/dist/server/modules/admin/routes/reactive.mjs +2 -2
- package/dist/server/modules/admin/routes/route-helpers.d.mts +11 -7
- package/dist/server/modules/admin/routes/route-helpers.mjs +1 -1
- package/dist/server/modules/admin/routes/setup.d.mts +7 -7
- package/dist/server/modules/admin/routes/translations.d.mts +4 -4
- package/dist/server/modules/admin/routes/widget-data.d.mts +5 -5
- package/dist/server/modules/admin/routes/widget-data.mjs +12 -4
- package/dist/server/modules/admin-preferences/collections/saved-views.d.mts +45 -45
- package/dist/server/modules/audit/.generated/module.d.mts +6 -6
- package/dist/server/modules/audit/collections/audit-log.d.mts +81 -80
- package/dist/server/modules/audit/jobs/audit-cleanup.d.mts +2 -2
- package/dist/server/plugin.mjs +10 -5
- package/dist/server/proxy-factories.d.mts +8 -1
- package/dist/server/proxy-factories.mjs +33 -1
- package/dist/server.d.mts +3 -1
- package/dist/shared/types/index.d.mts +1 -0
- package/dist/shared/types/saved-views.types.d.mts +14 -7
- package/dist/shared.d.mts +3 -2
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -65,6 +65,14 @@ export default adminConfig({
|
|
|
65
65
|
|
|
66
66
|
Collections, globals, routes, and jobs are auto-discovered via file convention. Codegen produces a `.generated/index.ts` with the fully-typed `App` and runtime `app` instance.
|
|
67
67
|
|
|
68
|
+
### Admin Auth Contract
|
|
69
|
+
|
|
70
|
+
`@questpie/admin` expects the app to use `adminModule`'s starter Better Auth model, or an equivalent auth setup that exposes `session.user.role` on the active session.
|
|
71
|
+
|
|
72
|
+
Access to the admin panel and admin RPC routes is granted only when `session.user.role === "admin"`. This includes admin config, content locale callbacks, preview URL/token generation, actions, widgets, and reactive field handlers. Authenticated users with `role: "user"` or a missing role are not admin users. The built-in setup route uses the same contract when checking for and creating the first admin user with `role = "admin"`.
|
|
73
|
+
|
|
74
|
+
If you extend the Better Auth `user` collection, merge the starter user collection instead of replacing it from scratch. Custom user collections must preserve the role field and session role propagation used by the admin guard.
|
|
75
|
+
|
|
68
76
|
### Collection Admin Config
|
|
69
77
|
|
|
70
78
|
Admin metadata, list views, and form views are defined on the collection itself:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BlockContent } from "./types.mjs";
|
|
2
2
|
import * as React from "react";
|
|
3
|
-
import * as
|
|
3
|
+
import * as react_jsx_runtime54 from "react/jsx-runtime";
|
|
4
4
|
|
|
5
5
|
//#region src/client/blocks/block-renderer.d.ts
|
|
6
6
|
|
|
@@ -50,6 +50,6 @@ declare function BlockRenderer({
|
|
|
50
50
|
onBlockClick,
|
|
51
51
|
onBlockInsert,
|
|
52
52
|
className
|
|
53
|
-
}: BlockRendererProps):
|
|
53
|
+
}: BlockRendererProps): react_jsx_runtime54.JSX.Element | null;
|
|
54
54
|
//#endregion
|
|
55
55
|
export { BlockRenderer, BlockRendererProps };
|
|
@@ -4,7 +4,7 @@ import { AnyWidgetConfig, WidgetAction, WidgetCardVariant, WidgetComponentProps,
|
|
|
4
4
|
import { DashboardAction, DashboardConfig, DashboardLayoutItem, DashboardSection, DashboardTabConfig, DashboardTabs } from "./types/ui-config.mjs";
|
|
5
5
|
import { AdminState } from "./admin-types.mjs";
|
|
6
6
|
import { Admin, AppAdmin, InferAdminCMS } from "./admin.mjs";
|
|
7
|
-
import { ComponentRegistry, FieldComponentProps, FieldLayoutItem, FormSidebarConfig, FormViewConfig, SectionLayout, TabConfig, TabsLayout } from "./types/field-types.mjs";
|
|
7
|
+
import { ComponentRegistry, DocumentViewConfig, FieldComponentProps, FieldLayoutItem, FormSidebarConfig, FormViewConfig, SectionLayout, TabConfig, TabsLayout } from "./types/field-types.mjs";
|
|
8
8
|
import { QuestpieApp, QuestpieClient } from "questpie/client";
|
|
9
9
|
import { CollectionInfer } from "questpie";
|
|
10
10
|
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import "../../i18n/types.mjs";
|
|
2
|
-
import { MaybeLazyComponent } from "./common.mjs";
|
|
1
|
+
import { I18nText } from "../../i18n/types.mjs";
|
|
2
|
+
import { IconComponent, MaybeLazyComponent } from "./common.mjs";
|
|
3
|
+
import { ComponentReference } from "../../../server/augmentation/common.mjs";
|
|
4
|
+
import { FilterRule, QuickFilterConfig } from "../../../shared/types/saved-views.types.mjs";
|
|
3
5
|
import "../../../server/augmentation.mjs";
|
|
4
|
-
import "../field/field.mjs";
|
|
5
|
-
import "../admin.mjs";
|
|
6
|
+
import { FieldDefinition } from "../field/field.mjs";
|
|
7
|
+
import { Admin } from "../admin.mjs";
|
|
6
8
|
import { ActionsConfig } from "./action-types.mjs";
|
|
7
9
|
|
|
8
10
|
//#region src/client/builder/types/collection-types.d.ts
|
|
@@ -124,6 +126,14 @@ interface ListViewConfig<TFieldNames extends string = string> {
|
|
|
124
126
|
field: TFieldNames;
|
|
125
127
|
direction: "asc" | "desc";
|
|
126
128
|
};
|
|
129
|
+
/**
|
|
130
|
+
* Initial filters used when the user has no saved view state.
|
|
131
|
+
*/
|
|
132
|
+
defaultFilters?: FilterRule[];
|
|
133
|
+
/**
|
|
134
|
+
* Header-level quick filter presets.
|
|
135
|
+
*/
|
|
136
|
+
quickFilters?: QuickFilterConfig[];
|
|
127
137
|
/**
|
|
128
138
|
* Enables reorder mode for this list.
|
|
129
139
|
* Requires a numeric field named `order` on the collection.
|
|
@@ -193,5 +203,79 @@ interface ListViewConfig<TFieldNames extends string = string> {
|
|
|
193
203
|
*/
|
|
194
204
|
actions?: ActionsConfig;
|
|
195
205
|
}
|
|
206
|
+
/**
|
|
207
|
+
* Preview configuration for live preview in form view
|
|
208
|
+
*/
|
|
209
|
+
interface PreviewConfig {
|
|
210
|
+
/**
|
|
211
|
+
* URL builder function that returns preview URL for current form values
|
|
212
|
+
* @param values - Current form values
|
|
213
|
+
* @param locale - Current content locale
|
|
214
|
+
* @returns Preview URL string
|
|
215
|
+
*/
|
|
216
|
+
url: (values: Record<string, unknown>, locale: string) => string;
|
|
217
|
+
/**
|
|
218
|
+
* Whether preview is enabled (default: true)
|
|
219
|
+
*/
|
|
220
|
+
enabled?: boolean;
|
|
221
|
+
/**
|
|
222
|
+
* Position of the preview panel (default: "right")
|
|
223
|
+
*/
|
|
224
|
+
position?: "right" | "bottom";
|
|
225
|
+
/**
|
|
226
|
+
* Default width/height percentage of preview panel (default: 50)
|
|
227
|
+
*/
|
|
228
|
+
defaultWidth?: number;
|
|
229
|
+
/**
|
|
230
|
+
* Minimum width/height percentage (default: 30)
|
|
231
|
+
*/
|
|
232
|
+
minWidth?: number;
|
|
233
|
+
/**
|
|
234
|
+
* Maximum width/height percentage (default: 70)
|
|
235
|
+
*/
|
|
236
|
+
maxWidth?: number;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Autosave configuration for form view
|
|
240
|
+
*/
|
|
241
|
+
interface AutoSaveConfig {
|
|
242
|
+
/**
|
|
243
|
+
* Whether autosave is enabled
|
|
244
|
+
* @default false
|
|
245
|
+
*/
|
|
246
|
+
enabled?: boolean;
|
|
247
|
+
/**
|
|
248
|
+
* Debounce delay in milliseconds before autosave triggers
|
|
249
|
+
* @default 500 (0.5s as specified)
|
|
250
|
+
*/
|
|
251
|
+
debounce?: number;
|
|
252
|
+
/**
|
|
253
|
+
* Show autosave status indicator in form header
|
|
254
|
+
* @default true
|
|
255
|
+
*/
|
|
256
|
+
indicator?: boolean;
|
|
257
|
+
/**
|
|
258
|
+
* Warn user before navigating away with unsaved changes
|
|
259
|
+
* @default true
|
|
260
|
+
*/
|
|
261
|
+
preventNavigation?: boolean;
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Collection builder state - internal state during building
|
|
265
|
+
*/
|
|
266
|
+
interface CollectionBuilderState<TAdminApp extends Admin<any> = Admin<any>> {
|
|
267
|
+
readonly name: string;
|
|
268
|
+
readonly "~adminApp": TAdminApp;
|
|
269
|
+
/** Display label - supports inline translations */
|
|
270
|
+
readonly label?: I18nText;
|
|
271
|
+
/** Description - supports inline translations */
|
|
272
|
+
readonly description?: I18nText;
|
|
273
|
+
readonly icon?: IconComponent | ComponentReference;
|
|
274
|
+
readonly fields?: Record<string, FieldDefinition>;
|
|
275
|
+
readonly list?: any;
|
|
276
|
+
readonly form?: any;
|
|
277
|
+
readonly preview?: PreviewConfig;
|
|
278
|
+
readonly autoSave?: AutoSaveConfig;
|
|
279
|
+
}
|
|
196
280
|
//#endregion
|
|
197
|
-
export { ListViewConfig };
|
|
281
|
+
export { CollectionBuilderState, ListViewConfig };
|
|
@@ -39,6 +39,11 @@ type BaseFieldProps = {
|
|
|
39
39
|
required?: boolean;
|
|
40
40
|
localized?: boolean;
|
|
41
41
|
locale?: string;
|
|
42
|
+
/**
|
|
43
|
+
* Render the control WITHOUT its own label/description. Used by compact
|
|
44
|
+
* layouts (e.g. Notion-style property rows) that supply the label themselves.
|
|
45
|
+
*/
|
|
46
|
+
hideLabel?: boolean;
|
|
42
47
|
control?: any;
|
|
43
48
|
className?: string;
|
|
44
49
|
};
|
|
@@ -578,6 +578,46 @@ interface FormViewActionsConfig<TItem = any> {
|
|
|
578
578
|
/** Actions shown in dropdown menu (...) */
|
|
579
579
|
secondary?: ActionDefinition<TItem>[];
|
|
580
580
|
}
|
|
581
|
+
/**
|
|
582
|
+
* Document view configuration — a Notion-style page with a dominant rich-text
|
|
583
|
+
* body and inline-editable property rows.
|
|
584
|
+
*
|
|
585
|
+
* No hardcoded field names: the consumer declares which field is the body, the
|
|
586
|
+
* (optional) title field, and which fields appear as properties. Defaults are
|
|
587
|
+
* data-driven (`properties: "auto"` derives from the schema).
|
|
588
|
+
*
|
|
589
|
+
* @example
|
|
590
|
+
* ```ts
|
|
591
|
+
* .form(({ v, f }) => v.collectionDocument({
|
|
592
|
+
* document: {
|
|
593
|
+
* body: f.body,
|
|
594
|
+
* title: f.name,
|
|
595
|
+
* properties: [f.scopeType, f.path, f.createdAt],
|
|
596
|
+
* save: "autosave",
|
|
597
|
+
* },
|
|
598
|
+
* }))
|
|
599
|
+
* ```
|
|
600
|
+
*/
|
|
601
|
+
interface DocumentViewConfig {
|
|
602
|
+
document: {
|
|
603
|
+
/** The dominant long-form field, rendered with the rich-text editor. */
|
|
604
|
+
body: string;
|
|
605
|
+
/**
|
|
606
|
+
* Property fields shown as inline-editable rows.
|
|
607
|
+
* - `"auto"` (default): all schema fields except body/title, in schema order.
|
|
608
|
+
* - `string[]`: an explicit, ordered list.
|
|
609
|
+
*/
|
|
610
|
+
properties?: "auto" | string[];
|
|
611
|
+
/**
|
|
612
|
+
* Save behavior.
|
|
613
|
+
* - `"autosave"` (default): debounced autosave with a "Saved"/"Saving" indicator.
|
|
614
|
+
* - `"manual"`: a Save affordance with dirty tracking.
|
|
615
|
+
*/
|
|
616
|
+
save?: "autosave" | "manual";
|
|
617
|
+
/** Optional page-title field; falls back to the record id/path. */
|
|
618
|
+
title?: string;
|
|
619
|
+
};
|
|
620
|
+
}
|
|
581
621
|
/**
|
|
582
622
|
* Registry for custom field and widget components
|
|
583
623
|
*/
|
|
@@ -596,4 +636,4 @@ interface ComponentRegistry {
|
|
|
596
636
|
custom?: Record<string, MaybeLazyComponent<any>>;
|
|
597
637
|
}
|
|
598
638
|
//#endregion
|
|
599
|
-
export { ComponentRegistry, FieldComponentProps, FieldLayoutItem, FormSidebarConfig, FormViewConfig, SectionLayout, TabConfig, TabsLayout };
|
|
639
|
+
export { ComponentRegistry, DocumentViewConfig, FieldComponentProps, FieldLayoutItem, FormSidebarConfig, FormViewConfig, SectionLayout, TabConfig, TabsLayout };
|
|
@@ -3,9 +3,10 @@ import { MaybeLazyComponent } from "../types/common.mjs";
|
|
|
3
3
|
//#region src/client/builder/view/view.d.ts
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* View kind discriminant — "list" for collection list pages, "form" for edit/create pages
|
|
6
|
+
* View kind discriminant — "list" for collection list pages, "form" for edit/create pages,
|
|
7
|
+
* "document" for Notion-style document pages (dominant rich-text body + property rows).
|
|
7
8
|
*/
|
|
8
|
-
type ViewKind = "list" | "form";
|
|
9
|
+
type ViewKind = "list" | "form" | "document";
|
|
9
10
|
/**
|
|
10
11
|
* View definition — a registry entry mapping a view name to its component.
|
|
11
12
|
*
|
|
@@ -92,6 +92,11 @@ function FormDialogContent({ action, ctx, onClose }) {
|
|
|
92
92
|
return message || t("toast.actionSuccess");
|
|
93
93
|
},
|
|
94
94
|
error: (error) => {
|
|
95
|
+
const validationError = error;
|
|
96
|
+
if (validationError.fieldErrors) for (const [field, message] of Object.entries(validationError.fieldErrors)) form.setError(field, {
|
|
97
|
+
type: "server",
|
|
98
|
+
message
|
|
99
|
+
});
|
|
95
100
|
return error instanceof Error ? error.message : t("toast.actionFailed");
|
|
96
101
|
},
|
|
97
102
|
finally: () => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CollectionNames, GlobalNames } from "../builder/index.mjs";
|
|
2
2
|
import * as React from "react";
|
|
3
|
-
import * as
|
|
3
|
+
import * as react_jsx_runtime48 from "react/jsx-runtime";
|
|
4
4
|
import { QuestpieApp } from "questpie/client";
|
|
5
5
|
|
|
6
6
|
//#region src/client/components/admin-link.d.ts
|
|
@@ -61,6 +61,6 @@ declare function AdminLink<TApp extends QuestpieApp>({
|
|
|
61
61
|
children,
|
|
62
62
|
onClick,
|
|
63
63
|
...rest
|
|
64
|
-
}: AdminLinkProps<TApp>):
|
|
64
|
+
}: AdminLinkProps<TApp>): react_jsx_runtime48.JSX.Element;
|
|
65
65
|
//#endregion
|
|
66
66
|
export { AdminLink };
|
|
@@ -11,7 +11,7 @@ import { Controller } from "react-hook-form";
|
|
|
11
11
|
* Unified boolean field component.
|
|
12
12
|
* Renders as checkbox (default) or switch based on `displayAs` prop.
|
|
13
13
|
*/
|
|
14
|
-
function BooleanField({ name, label, description, required, disabled, localized, locale, control, className, displayAs = "checkbox" }) {
|
|
14
|
+
function BooleanField({ name, label, description, required, disabled, localized, locale, hideLabel, control, className, displayAs = "checkbox" }) {
|
|
15
15
|
return /* @__PURE__ */ jsx(Controller, {
|
|
16
16
|
name,
|
|
17
17
|
control: useResolvedControl(control),
|
|
@@ -23,6 +23,7 @@ function BooleanField({ name, label, description, required, disabled, localized,
|
|
|
23
23
|
disabled,
|
|
24
24
|
localized,
|
|
25
25
|
locale,
|
|
26
|
+
hideLabel,
|
|
26
27
|
error: fieldState.error?.message,
|
|
27
28
|
children: displayAs === "switch" ? /* @__PURE__ */ jsx(ToggleInput, {
|
|
28
29
|
id: name,
|
|
@@ -11,7 +11,7 @@ function parseDateFieldValue(value) {
|
|
|
11
11
|
const date = value instanceof Date ? value : new Date(String(value));
|
|
12
12
|
return Number.isNaN(date.getTime()) ? null : date;
|
|
13
13
|
}
|
|
14
|
-
function DateField({ name, label, description, placeholder, required, disabled, localized, locale, control, className, minDate, maxDate, format }) {
|
|
14
|
+
function DateField({ name, label, description, placeholder, required, disabled, localized, locale, hideLabel, control, className, minDate, maxDate, format }) {
|
|
15
15
|
return /* @__PURE__ */ jsx(Controller, {
|
|
16
16
|
name,
|
|
17
17
|
control: useResolvedControl(control),
|
|
@@ -25,6 +25,7 @@ function DateField({ name, label, description, placeholder, required, disabled,
|
|
|
25
25
|
disabled,
|
|
26
26
|
localized,
|
|
27
27
|
locale,
|
|
28
|
+
hideLabel,
|
|
28
29
|
error: fieldState.error?.message,
|
|
29
30
|
children: /* @__PURE__ */ jsx(DateInput, {
|
|
30
31
|
id: name,
|
|
@@ -11,7 +11,7 @@ function parseDateTimeFieldValue(value) {
|
|
|
11
11
|
const date = value instanceof Date ? value : new Date(String(value));
|
|
12
12
|
return Number.isNaN(date.getTime()) ? null : date;
|
|
13
13
|
}
|
|
14
|
-
function DatetimeField({ name, label, description, placeholder, required, disabled, localized, locale, control, className, minDate, maxDate, format, precision }) {
|
|
14
|
+
function DatetimeField({ name, label, description, placeholder, required, disabled, localized, locale, hideLabel, control, className, minDate, maxDate, format, precision }) {
|
|
15
15
|
return /* @__PURE__ */ jsx(Controller, {
|
|
16
16
|
name,
|
|
17
17
|
control: useResolvedControl(control),
|
|
@@ -25,6 +25,7 @@ function DatetimeField({ name, label, description, placeholder, required, disabl
|
|
|
25
25
|
disabled,
|
|
26
26
|
localized,
|
|
27
27
|
locale,
|
|
28
|
+
hideLabel,
|
|
28
29
|
error: fieldState.error?.message,
|
|
29
30
|
children: /* @__PURE__ */ jsx(DateTimeInput, {
|
|
30
31
|
id: name,
|
|
@@ -6,7 +6,7 @@ import { jsx } from "react/jsx-runtime";
|
|
|
6
6
|
import { Controller } from "react-hook-form";
|
|
7
7
|
|
|
8
8
|
//#region src/client/components/fields/email-field.tsx
|
|
9
|
-
function EmailField({ name, label, description, placeholder, required, disabled, localized, locale, control, className }) {
|
|
9
|
+
function EmailField({ name, label, description, placeholder, required, disabled, localized, locale, hideLabel, control, className }) {
|
|
10
10
|
return /* @__PURE__ */ jsx(Controller, {
|
|
11
11
|
name,
|
|
12
12
|
control: useResolvedControl(control),
|
|
@@ -18,6 +18,7 @@ function EmailField({ name, label, description, placeholder, required, disabled,
|
|
|
18
18
|
disabled,
|
|
19
19
|
localized,
|
|
20
20
|
locale,
|
|
21
|
+
hideLabel,
|
|
21
22
|
error: fieldState.error?.message,
|
|
22
23
|
children: /* @__PURE__ */ jsx(TextInput, {
|
|
23
24
|
id: name,
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import "react-hook-form";
|
|
2
|
+
|
|
3
|
+
//#region src/client/components/fields/field-utils.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Sanitize filename for safe storage.
|
|
7
|
+
* Removes special characters, replaces spaces with hyphens.
|
|
8
|
+
*/
|
|
9
|
+
declare function sanitizeFilename(filename: string): string;
|
|
10
|
+
//#endregion
|
|
11
|
+
export { sanitizeFilename };
|
|
@@ -12,7 +12,9 @@ function useResolvedControl(control) {
|
|
|
12
12
|
function sanitizeFilename(filename) {
|
|
13
13
|
const lastDot = filename.lastIndexOf(".");
|
|
14
14
|
const ext = lastDot > 0 ? filename.slice(lastDot) : "";
|
|
15
|
-
|
|
15
|
+
const sanitized = (lastDot > 0 ? filename.slice(0, lastDot) : filename).normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/\s+/g, "-").replace(/[^a-zA-Z0-9._-]/g, "").replace(/-+/g, "-").replace(/^-|-$/g, "").toLowerCase();
|
|
16
|
+
const safeExt = ext.toLowerCase().replace(/[^a-z0-9.]/g, "");
|
|
17
|
+
return (sanitized || "file") + safeExt;
|
|
16
18
|
}
|
|
17
19
|
/**
|
|
18
20
|
* Extract columns from collection list config.
|
|
@@ -36,10 +36,10 @@ function FieldLocaleIndicator({ localized, locale }) {
|
|
|
36
36
|
showFlag: false
|
|
37
37
|
});
|
|
38
38
|
}
|
|
39
|
-
function FieldWrapper({ name, label, description, labelAccessory, required, disabled, readOnly, error, localized, locale, children, fieldPath }) {
|
|
39
|
+
function FieldWrapper({ name, label, description, labelAccessory, required, disabled, readOnly, error, localized, locale, hideLabel, children, fieldPath }) {
|
|
40
40
|
const resolveText = useResolveText();
|
|
41
|
-
const resolvedLabel = label ? resolveText(label)
|
|
42
|
-
const resolvedDescription = description ? resolveText(description)
|
|
41
|
+
const resolvedLabel = hideLabel || !label ? void 0 : resolveText(label);
|
|
42
|
+
const resolvedDescription = hideLabel || !description ? void 0 : resolveText(description);
|
|
43
43
|
return /* @__PURE__ */ jsx(Field, {
|
|
44
44
|
"data-disabled": disabled,
|
|
45
45
|
"data-readonly": !disabled && readOnly,
|
|
@@ -6,7 +6,7 @@ import { jsx } from "react/jsx-runtime";
|
|
|
6
6
|
import { Controller } from "react-hook-form";
|
|
7
7
|
|
|
8
8
|
//#region src/client/components/fields/number-field.tsx
|
|
9
|
-
function NumberField({ name, label, description, placeholder, required, disabled, localized, locale, control, className, min, max, step, showButtons }) {
|
|
9
|
+
function NumberField({ name, label, description, placeholder, required, disabled, localized, locale, hideLabel, control, className, min, max, step, showButtons }) {
|
|
10
10
|
return /* @__PURE__ */ jsx(Controller, {
|
|
11
11
|
name,
|
|
12
12
|
control: useResolvedControl(control),
|
|
@@ -18,6 +18,7 @@ function NumberField({ name, label, description, placeholder, required, disabled
|
|
|
18
18
|
disabled,
|
|
19
19
|
localized,
|
|
20
20
|
locale,
|
|
21
|
+
hideLabel,
|
|
21
22
|
error: fieldState.error?.message,
|
|
22
23
|
children: /* @__PURE__ */ jsx(NumberInput, {
|
|
23
24
|
id: name,
|
|
@@ -26,7 +26,8 @@ function ObjectFieldPanel({ name, label, description, required, disabled, locali
|
|
|
26
26
|
type: "button",
|
|
27
27
|
variant: "ghost",
|
|
28
28
|
onClick: onToggle,
|
|
29
|
-
className: "h-auto min-h-
|
|
29
|
+
className: "hover:bg-surface-low aria-expanded:bg-surface-low h-auto min-h-12 w-full justify-between rounded-none px-4 py-3 text-left",
|
|
30
|
+
"aria-expanded": !isCollapsed,
|
|
30
31
|
disabled,
|
|
31
32
|
children: [/* @__PURE__ */ jsxs("span", {
|
|
32
33
|
className: "flex min-w-0 items-center gap-2",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { formatLabel } from "../../../../lib/utils.mjs";
|
|
2
|
+
import { resolveAssetUrl } from "../../../../utils/asset-url.mjs";
|
|
2
3
|
import { DefaultCell } from "../../../../views/collection/cells/primitive-cells.mjs";
|
|
3
4
|
|
|
4
5
|
//#region src/client/components/fields/relation/displays/types.ts
|
|
@@ -31,9 +32,8 @@ function formatCellValue(value) {
|
|
|
31
32
|
function getImageUrl(item, imageField) {
|
|
32
33
|
if (!imageField) return null;
|
|
33
34
|
const imageValue = item[imageField];
|
|
34
|
-
if (typeof imageValue === "string") return imageValue;
|
|
35
|
-
if (imageValue?.url) return imageValue.url;
|
|
36
|
-
if (imageValue?.key) return imageValue.key;
|
|
35
|
+
if (typeof imageValue === "string") return resolveAssetUrl(imageValue) ?? null;
|
|
36
|
+
if (imageValue?.url) return resolveAssetUrl(imageValue.url) ?? null;
|
|
37
37
|
return null;
|
|
38
38
|
}
|
|
39
39
|
/**
|
|
@@ -283,6 +283,13 @@ function RichTextBubbleMenu({ editor, features, disabled, linkOpen, onImageClick
|
|
|
283
283
|
shortcut: "⌘U",
|
|
284
284
|
onClick: () => editor.chain().focus().toggleUnderline().run()
|
|
285
285
|
}),
|
|
286
|
+
features.strike && /* @__PURE__ */ jsx(ToolbarButton, {
|
|
287
|
+
icon: EDITOR_ICONS.strikethrough,
|
|
288
|
+
active: editor.isActive("strike"),
|
|
289
|
+
disabled: !isEditable,
|
|
290
|
+
title: t("editor.strikethrough"),
|
|
291
|
+
onClick: () => editor.chain().focus().toggleStrike().run()
|
|
292
|
+
}),
|
|
286
293
|
features.code && /* @__PURE__ */ jsx(ToolbarButton, {
|
|
287
294
|
icon: EDITOR_ICONS.code,
|
|
288
295
|
active: editor.isActive("code"),
|
|
@@ -10,6 +10,7 @@ import TableRow from "@tiptap/extension-table-row";
|
|
|
10
10
|
import TextAlign from "@tiptap/extension-text-align";
|
|
11
11
|
import Underline from "@tiptap/extension-underline";
|
|
12
12
|
import StarterKit from "@tiptap/starter-kit";
|
|
13
|
+
import { Markdown } from "tiptap-markdown";
|
|
13
14
|
|
|
14
15
|
//#region src/client/components/fields/rich-text-editor/extensions.tsx
|
|
15
16
|
let codeBlockExtension = null;
|
|
@@ -54,12 +55,13 @@ const defaultLabels = {
|
|
|
54
55
|
* (i.e. codeBlock disabled, or lowlight already cached). Only returns a
|
|
55
56
|
* `Promise` on the first build that includes codeBlock.
|
|
56
57
|
*/
|
|
57
|
-
function buildExtensions({ features, labels, placeholder, maxCharacters, customExtensions }) {
|
|
58
|
+
function buildExtensions({ features, labels, placeholder, maxCharacters, outputMode, customExtensions }) {
|
|
58
59
|
const base = buildBaseExtensions({
|
|
59
60
|
features,
|
|
60
61
|
labels,
|
|
61
62
|
placeholder,
|
|
62
63
|
maxCharacters,
|
|
64
|
+
outputMode,
|
|
63
65
|
customExtensions
|
|
64
66
|
});
|
|
65
67
|
if (!features.codeBlock) return base;
|
|
@@ -67,7 +69,7 @@ function buildExtensions({ features, labels, placeholder, maxCharacters, customE
|
|
|
67
69
|
if (!(codeBlock instanceof Promise)) return [...base, codeBlock];
|
|
68
70
|
return codeBlock.then((ext) => [...base, ext]);
|
|
69
71
|
}
|
|
70
|
-
function buildBaseExtensions({ features, labels = defaultLabels, placeholder, maxCharacters, customExtensions }) {
|
|
72
|
+
function buildBaseExtensions({ features, labels = defaultLabels, placeholder, maxCharacters, outputMode, customExtensions }) {
|
|
71
73
|
const starterKitConfig = { codeBlock: false };
|
|
72
74
|
if (!features.bold) starterKitConfig.bold = false;
|
|
73
75
|
if (!features.italic) starterKitConfig.italic = false;
|
|
@@ -97,18 +99,21 @@ function buildBaseExtensions({ features, labels = defaultLabels, placeholder, ma
|
|
|
97
99
|
title: labels.heading(1),
|
|
98
100
|
description: labels.heading1Description,
|
|
99
101
|
icon: "ph:text-h-one",
|
|
102
|
+
group: "Headings",
|
|
100
103
|
keywords: ["h1"],
|
|
101
104
|
command: (cmdEditor) => cmdEditor.chain().focus().toggleHeading({ level: 1 }).run()
|
|
102
105
|
}, {
|
|
103
106
|
title: labels.heading(2),
|
|
104
107
|
description: labels.heading2Description,
|
|
105
108
|
icon: "ph:text-h-two",
|
|
109
|
+
group: "Headings",
|
|
106
110
|
keywords: ["h2"],
|
|
107
111
|
command: (cmdEditor) => cmdEditor.chain().focus().toggleHeading({ level: 2 }).run()
|
|
108
112
|
}, {
|
|
109
113
|
title: labels.heading(3),
|
|
110
114
|
description: labels.heading3Description,
|
|
111
115
|
icon: "ph:text-h-three",
|
|
116
|
+
group: "Headings",
|
|
112
117
|
keywords: ["h3"],
|
|
113
118
|
command: (cmdEditor) => cmdEditor.chain().focus().toggleHeading({ level: 3 }).run()
|
|
114
119
|
});
|
|
@@ -116,6 +121,7 @@ function buildBaseExtensions({ features, labels = defaultLabels, placeholder, ma
|
|
|
116
121
|
title: labels.paragraph,
|
|
117
122
|
description: labels.paragraphDescription,
|
|
118
123
|
icon: "ph:text-align-left",
|
|
124
|
+
group: "Text",
|
|
119
125
|
keywords: ["text"],
|
|
120
126
|
command: (cmdEditor) => cmdEditor.chain().focus().setParagraph().run()
|
|
121
127
|
});
|
|
@@ -123,6 +129,7 @@ function buildBaseExtensions({ features, labels = defaultLabels, placeholder, ma
|
|
|
123
129
|
title: labels.bulletList,
|
|
124
130
|
description: labels.bulletListDescription,
|
|
125
131
|
icon: "ph:list-bullets",
|
|
132
|
+
group: "Lists",
|
|
126
133
|
keywords: ["list", "ul"],
|
|
127
134
|
command: (cmdEditor) => cmdEditor.chain().focus().toggleBulletList().run()
|
|
128
135
|
});
|
|
@@ -130,6 +137,7 @@ function buildBaseExtensions({ features, labels = defaultLabels, placeholder, ma
|
|
|
130
137
|
title: labels.orderedList,
|
|
131
138
|
description: labels.orderedListDescription,
|
|
132
139
|
icon: "ph:list-numbers",
|
|
140
|
+
group: "Lists",
|
|
133
141
|
keywords: ["list", "ol"],
|
|
134
142
|
command: (cmdEditor) => cmdEditor.chain().focus().toggleOrderedList().run()
|
|
135
143
|
});
|
|
@@ -137,6 +145,7 @@ function buildBaseExtensions({ features, labels = defaultLabels, placeholder, ma
|
|
|
137
145
|
title: labels.quote,
|
|
138
146
|
description: labels.quoteDescription,
|
|
139
147
|
icon: "ph:quotes",
|
|
148
|
+
group: "Blocks",
|
|
140
149
|
keywords: ["blockquote"],
|
|
141
150
|
command: (cmdEditor) => cmdEditor.chain().focus().toggleBlockquote().run()
|
|
142
151
|
});
|
|
@@ -144,6 +153,7 @@ function buildBaseExtensions({ features, labels = defaultLabels, placeholder, ma
|
|
|
144
153
|
title: labels.codeBlock,
|
|
145
154
|
description: labels.codeBlockDescription,
|
|
146
155
|
icon: "ph:code-block",
|
|
156
|
+
group: "Blocks",
|
|
147
157
|
keywords: ["code"],
|
|
148
158
|
command: (cmdEditor) => cmdEditor.chain().focus().toggleCodeBlock().run()
|
|
149
159
|
});
|
|
@@ -151,6 +161,7 @@ function buildBaseExtensions({ features, labels = defaultLabels, placeholder, ma
|
|
|
151
161
|
title: labels.divider,
|
|
152
162
|
description: labels.dividerDescription,
|
|
153
163
|
icon: "ph:minus",
|
|
164
|
+
group: "Blocks",
|
|
154
165
|
keywords: ["hr"],
|
|
155
166
|
command: (cmdEditor) => cmdEditor.chain().focus().setHorizontalRule().run()
|
|
156
167
|
});
|
|
@@ -158,6 +169,7 @@ function buildBaseExtensions({ features, labels = defaultLabels, placeholder, ma
|
|
|
158
169
|
title: labels.table,
|
|
159
170
|
description: labels.tableDescription,
|
|
160
171
|
icon: "ph:table",
|
|
172
|
+
group: "Blocks",
|
|
161
173
|
keywords: ["grid"],
|
|
162
174
|
command: (cmdEditor) => cmdEditor.chain().focus().insertTable({
|
|
163
175
|
rows: 3,
|
|
@@ -167,6 +179,11 @@ function buildBaseExtensions({ features, labels = defaultLabels, placeholder, ma
|
|
|
167
179
|
});
|
|
168
180
|
return commands;
|
|
169
181
|
}));
|
|
182
|
+
if (outputMode === "markdown") extensions.push(Markdown.configure({
|
|
183
|
+
html: true,
|
|
184
|
+
transformCopiedText: true,
|
|
185
|
+
transformPastedText: true
|
|
186
|
+
}));
|
|
170
187
|
if (customExtensions?.length) extensions.push(...customExtensions);
|
|
171
188
|
return extensions;
|
|
172
189
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useTranslation } from "../../../i18n/hooks.mjs";
|
|
2
2
|
import { Button } from "../../ui/button.mjs";
|
|
3
3
|
import { Input } from "../../ui/input.mjs";
|
|
4
|
+
import { resolveAssetUrl } from "../../../utils/asset-url.mjs";
|
|
4
5
|
import { Popover, PopoverContent, PopoverHeader, PopoverTitle, PopoverTrigger } from "../../ui/popover.mjs";
|
|
5
6
|
import { MediaPickerDialog } from "../../media/media-picker-dialog.mjs";
|
|
6
7
|
import { useRichTextImageUpload } from "./image-upload.mjs";
|
|
@@ -76,7 +77,7 @@ function ImagePopover({ editor, open, onOpenChange, disabled, onImageUpload, ima
|
|
|
76
77
|
return;
|
|
77
78
|
}
|
|
78
79
|
editor.chain().focus().setImage({
|
|
79
|
-
src: asset.url,
|
|
80
|
+
src: resolveAssetUrl(asset.url) ?? asset.url,
|
|
80
81
|
alt: imageAlt || asset.alt || void 0
|
|
81
82
|
}).run();
|
|
82
83
|
setImageUrl("");
|
|
@@ -95,7 +96,10 @@ function ImagePopover({ editor, open, onOpenChange, disabled, onImageUpload, ima
|
|
|
95
96
|
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs(Popover, {
|
|
96
97
|
open,
|
|
97
98
|
onOpenChange,
|
|
98
|
-
children: [/* @__PURE__ */ jsx(PopoverTrigger, {
|
|
99
|
+
children: [/* @__PURE__ */ jsx(PopoverTrigger, {
|
|
100
|
+
nativeButton: false,
|
|
101
|
+
render: /* @__PURE__ */ jsx("div", { className: "sr-only" })
|
|
102
|
+
}), /* @__PURE__ */ jsxs(PopoverContent, {
|
|
99
103
|
className: "w-80",
|
|
100
104
|
children: [/* @__PURE__ */ jsx(PopoverHeader, { children: /* @__PURE__ */ jsx(PopoverTitle, { children: t("editor.image") }) }), /* @__PURE__ */ jsxs("div", {
|
|
101
105
|
className: "space-y-3",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useTranslation } from "../../../i18n/hooks.mjs";
|
|
2
2
|
import { sanitizeFilename } from "../field-utils.mjs";
|
|
3
|
+
import { resolveAssetUrl } from "../../../utils/asset-url.mjs";
|
|
3
4
|
import { useUploadCollection } from "../../../hooks/use-upload-collection.mjs";
|
|
4
5
|
import { useUpload } from "../../../hooks/use-upload.mjs";
|
|
5
6
|
import * as React from "react";
|
|
@@ -35,7 +36,7 @@ function useRichTextImageUpload({ imageCollection, onImageUpload }) {
|
|
|
35
36
|
const sanitizedName = sanitizeFilename(file.name);
|
|
36
37
|
const uploadedAsset = await upload(sanitizedName === file.name ? file : new File([file], sanitizedName, { type: file.type }), { to: collection });
|
|
37
38
|
if (!uploadedAsset?.url) throw new Error(t("upload.error"));
|
|
38
|
-
return uploadedAsset.url;
|
|
39
|
+
return resolveAssetUrl(uploadedAsset.url) ?? uploadedAsset.url;
|
|
39
40
|
}, [
|
|
40
41
|
collection,
|
|
41
42
|
collections,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RichTextEditorProps } from "./types.mjs";
|
|
2
|
-
import * as
|
|
2
|
+
import * as react_jsx_runtime33 from "react/jsx-runtime";
|
|
3
3
|
|
|
4
4
|
//#region src/client/components/fields/rich-text-editor/index.d.ts
|
|
5
5
|
|
|
@@ -24,6 +24,7 @@ declare function RichTextEditor({
|
|
|
24
24
|
error,
|
|
25
25
|
localized,
|
|
26
26
|
locale,
|
|
27
|
+
hideLabel,
|
|
27
28
|
extensions,
|
|
28
29
|
preset,
|
|
29
30
|
features,
|
|
@@ -32,7 +33,8 @@ declare function RichTextEditor({
|
|
|
32
33
|
enableImages,
|
|
33
34
|
onImageUpload,
|
|
34
35
|
imageCollection,
|
|
35
|
-
enableMediaLibrary
|
|
36
|
-
|
|
36
|
+
enableMediaLibrary,
|
|
37
|
+
outputMode
|
|
38
|
+
}: RichTextEditorProps): react_jsx_runtime33.JSX.Element;
|
|
37
39
|
//#endregion
|
|
38
40
|
export { RichTextEditor };
|