@byline/admin 2.5.2 → 2.6.0
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/dist/fields/array/array-field.d.ts +14 -0
- package/dist/fields/array/array-field.js +177 -0
- package/dist/fields/array/array-field.module.js +11 -0
- package/dist/fields/array/array-field_module.css +32 -0
- package/dist/fields/blocks/blocks-field.d.ts +13 -0
- package/dist/fields/blocks/blocks-field.js +245 -0
- package/dist/fields/blocks/blocks-field.module.js +26 -0
- package/dist/fields/blocks/blocks-field_module.css +107 -0
- package/dist/fields/checkbox/checkbox-field.d.ts +16 -0
- package/dist/fields/checkbox/checkbox-field.js +28 -0
- package/dist/fields/checkbox/checkbox-field.module.js +6 -0
- package/dist/fields/checkbox/checkbox-field_module.css +4 -0
- package/dist/fields/column-formatter.d.ts +20 -0
- package/dist/fields/column-formatter.js +15 -0
- package/dist/fields/date-time-formatter.d.ts +16 -0
- package/dist/fields/date-time-formatter.js +8 -0
- package/dist/fields/datetime/datetime-field.d.ts +16 -0
- package/dist/fields/datetime/datetime-field.js +37 -0
- package/dist/fields/datetime/datetime-field.module.js +5 -0
- package/dist/fields/datetime/datetime-field_module.css +4 -0
- package/dist/fields/draggable-context-menu.d.ts +6 -0
- package/dist/fields/draggable-context-menu.js +85 -0
- package/dist/fields/draggable-context-menu.module.js +15 -0
- package/dist/fields/draggable-context-menu_module.css +91 -0
- package/dist/fields/field-helpers.d.ts +26 -0
- package/dist/fields/field-helpers.js +50 -0
- package/dist/fields/field-renderer.d.ts +37 -0
- package/dist/fields/field-renderer.js +206 -0
- package/dist/fields/field-renderer.module.js +8 -0
- package/dist/fields/field-renderer_module.css +11 -0
- package/dist/fields/field-services-context.d.ts +16 -0
- package/dist/fields/field-services-context.js +13 -0
- package/dist/fields/field-services-types.d.ts +63 -0
- package/dist/fields/field-services-types.js +1 -0
- package/dist/fields/file/file-field.d.ts +19 -0
- package/dist/fields/file/file-field.js +225 -0
- package/dist/fields/file/file-field.module.js +18 -0
- package/dist/fields/file/file-field_module.css +131 -0
- package/dist/fields/file/file-upload-field.d.ts +21 -0
- package/dist/fields/file/file-upload-field.js +130 -0
- package/dist/fields/file/file-upload-field.module.js +15 -0
- package/dist/fields/file/file-upload-field_module.css +74 -0
- package/dist/fields/group/group-field.d.ts +15 -0
- package/dist/fields/group/group-field.js +59 -0
- package/dist/fields/group/group-field.module.js +9 -0
- package/dist/fields/group/group-field_module.css +27 -0
- package/dist/fields/image/image-field.d.ts +19 -0
- package/dist/fields/image/image-field.js +241 -0
- package/dist/fields/image/image-field.module.js +22 -0
- package/dist/fields/image/image-field_module.css +121 -0
- package/dist/fields/image/image-upload-field.d.ts +21 -0
- package/dist/fields/image/image-upload-field.js +190 -0
- package/dist/fields/image/image-upload-field.module.js +19 -0
- package/dist/fields/image/image-upload-field_module.css +92 -0
- package/dist/fields/local-date-time.d.ts +27 -0
- package/dist/fields/local-date-time.js +49 -0
- package/dist/fields/locale-badge.d.ts +18 -0
- package/dist/fields/locale-badge.js +10 -0
- package/dist/fields/locale-badge.module.js +5 -0
- package/dist/fields/locale-badge_module.css +27 -0
- package/dist/fields/numerical/numerical-field.d.ts +18 -0
- package/dist/fields/numerical/numerical-field.js +74 -0
- package/dist/fields/relation/relation-display.d.ts +40 -0
- package/dist/fields/relation/relation-display.js +58 -0
- package/dist/fields/relation/relation-display.module.js +9 -0
- package/dist/fields/relation/relation-display_module.css +21 -0
- package/dist/fields/relation/relation-field.d.ts +18 -0
- package/dist/fields/relation/relation-field.js +138 -0
- package/dist/fields/relation/relation-field.module.js +13 -0
- package/dist/fields/relation/relation-field_module.css +62 -0
- package/dist/fields/relation/relation-picker.d.ts +49 -0
- package/dist/fields/relation/relation-picker.js +236 -0
- package/dist/fields/relation/relation-picker.module.js +26 -0
- package/dist/fields/relation/relation-picker_module.css +124 -0
- package/dist/fields/relation/relation-summary.d.ts +31 -0
- package/dist/fields/relation/relation-summary.js +50 -0
- package/dist/fields/relation/relation-summary.module.js +11 -0
- package/dist/fields/relation/relation-summary_module.css +37 -0
- package/dist/fields/select/select-field.d.ts +16 -0
- package/dist/fields/select/select-field.js +50 -0
- package/dist/fields/select/select-field.module.js +5 -0
- package/dist/fields/select/select-field_module.css +4 -0
- package/dist/fields/sortable-item.d.ts +15 -0
- package/dist/fields/sortable-item.js +81 -0
- package/dist/fields/sortable-item.module.js +22 -0
- package/dist/fields/sortable-item_module.css +124 -0
- package/dist/fields/text/text-field.d.ts +20 -0
- package/dist/fields/text/text-field.js +104 -0
- package/dist/fields/text/text-field.module.js +6 -0
- package/dist/fields/text/text-field_module.css +5 -0
- package/dist/fields/text-area/text-area-field.d.ts +20 -0
- package/dist/fields/text-area/text-area-field.js +105 -0
- package/dist/fields/text-area/text-area-field.module.js +6 -0
- package/dist/fields/text-area/text-area-field_module.css +5 -0
- package/dist/fields/use-field-change-handler.d.ts +23 -0
- package/dist/fields/use-field-change-handler.js +52 -0
- package/dist/forms/document-actions.d.ts +48 -0
- package/dist/forms/document-actions.js +475 -0
- package/dist/forms/document-actions.module.js +34 -0
- package/dist/forms/document-actions_module.css +118 -0
- package/dist/forms/form-context.d.ts +89 -0
- package/dist/forms/form-context.js +466 -0
- package/dist/forms/form-renderer.d.ts +98 -0
- package/dist/forms/form-renderer.js +597 -0
- package/dist/forms/form-renderer.module.js +46 -0
- package/dist/forms/form-renderer_module.css +245 -0
- package/dist/forms/navigation-guard.d.ts +54 -0
- package/dist/forms/navigation-guard.js +22 -0
- package/dist/forms/path-widget.d.ts +36 -0
- package/dist/forms/path-widget.js +116 -0
- package/dist/forms/path-widget.module.js +8 -0
- package/dist/forms/path-widget_module.css +29 -0
- package/dist/forms/upload-executor.d.ts +57 -0
- package/dist/forms/upload-executor.js +94 -0
- package/dist/lib/translate-validation-error.d.ts +36 -0
- package/dist/lib/translate-validation-error.js +11 -0
- package/dist/modules/admin-account/commands.d.ts +2 -1
- package/dist/modules/admin-account/commands.js +13 -2
- package/dist/modules/admin-account/components/change-password.js +45 -36
- package/dist/modules/admin-account/components/container.js +185 -134
- package/dist/modules/admin-account/components/preferences.d.ts +8 -0
- package/dist/modules/admin-account/components/preferences.js +152 -0
- package/dist/modules/admin-account/components/preferences.module.js +11 -0
- package/dist/modules/admin-account/components/preferences_module.css +41 -0
- package/dist/modules/admin-account/components/update.js +50 -31
- package/dist/modules/admin-account/index.d.ts +3 -3
- package/dist/modules/admin-account/index.js +2 -2
- package/dist/modules/admin-account/schemas.d.ts +4 -0
- package/dist/modules/admin-account/schemas.js +4 -1
- package/dist/modules/admin-account/service.d.ts +1 -0
- package/dist/modules/admin-account/service.js +8 -0
- package/dist/modules/admin-permissions/components/inspector.js +31 -41
- package/dist/modules/admin-roles/components/create.js +43 -26
- package/dist/modules/admin-roles/components/permissions.js +26 -35
- package/dist/modules/admin-roles/components/update.js +26 -16
- package/dist/modules/admin-users/components/create.js +60 -40
- package/dist/modules/admin-users/components/roles.js +9 -15
- package/dist/modules/admin-users/components/set-password.js +30 -31
- package/dist/modules/admin-users/components/update.js +58 -39
- package/dist/modules/admin-users/dto.js +1 -0
- package/dist/modules/admin-users/repository.d.ts +17 -0
- package/dist/modules/admin-users/schemas.d.ts +4 -0
- package/dist/modules/admin-users/schemas.js +6 -2
- package/dist/modules/auth/components/sign-in-form.js +10 -8
- package/dist/presentation/group.d.ts +27 -0
- package/dist/presentation/group.js +14 -0
- package/dist/presentation/group.module.js +6 -0
- package/dist/presentation/group_module.css +19 -0
- package/dist/presentation/row.d.ts +25 -0
- package/dist/presentation/row.js +8 -0
- package/dist/presentation/row.module.js +5 -0
- package/dist/presentation/row_module.css +18 -0
- package/dist/presentation/tabs.d.ts +25 -0
- package/dist/presentation/tabs.js +39 -0
- package/dist/presentation/tabs.module.js +10 -0
- package/dist/presentation/tabs_module.css +68 -0
- package/dist/react.d.ts +66 -0
- package/dist/react.js +36 -0
- package/dist/services/admin-services-types.d.ts +16 -0
- package/dist/widgets/diff-viewer/diff-modal.d.ts +22 -0
- package/dist/widgets/diff-viewer/diff-modal.js +149 -0
- package/dist/widgets/diff-viewer/diff-modal.module.js +14 -0
- package/dist/widgets/diff-viewer/diff-modal_module.css +56 -0
- package/dist/widgets/status-badge/status-badge.d.ts +25 -0
- package/dist/widgets/status-badge/status-badge.js +37 -0
- package/dist/widgets/status-badge/status-badge.module.js +7 -0
- package/dist/widgets/status-badge/status-badge_module.css +20 -0
- package/package.json +14 -4
- package/src/fields/array/array-field.module.css +48 -0
- package/src/fields/array/array-field.tsx +267 -0
- package/src/fields/blocks/blocks-field.module.css +148 -0
- package/src/fields/blocks/blocks-field.tsx +323 -0
- package/src/fields/checkbox/checkbox-field.module.css +4 -0
- package/src/fields/checkbox/checkbox-field.tsx +54 -0
- package/src/fields/column-formatter.tsx +31 -0
- package/src/fields/date-time-formatter.tsx +22 -0
- package/src/fields/datetime/datetime-field.module.css +13 -0
- package/src/fields/datetime/datetime-field.tsx +54 -0
- package/src/fields/draggable-context-menu.module.css +127 -0
- package/src/fields/draggable-context-menu.tsx +87 -0
- package/src/fields/field-helpers.ts +69 -0
- package/src/fields/field-renderer.module.css +22 -0
- package/src/fields/field-renderer.tsx +288 -0
- package/src/fields/field-services-context.tsx +35 -0
- package/src/fields/field-services-types.ts +68 -0
- package/src/fields/file/file-field.module.css +153 -0
- package/src/fields/file/file-field.tsx +286 -0
- package/src/fields/file/file-upload-field.module.css +101 -0
- package/src/fields/file/file-upload-field.tsx +187 -0
- package/src/fields/group/group-field.module.css +43 -0
- package/src/fields/group/group-field.tsx +84 -0
- package/src/fields/image/image-field.module.css +155 -0
- package/src/fields/image/image-field.tsx +306 -0
- package/src/fields/image/image-upload-field.module.css +123 -0
- package/src/fields/image/image-upload-field.tsx +276 -0
- package/src/fields/local-date-time.tsx +88 -0
- package/src/fields/locale-badge.module.css +37 -0
- package/src/fields/locale-badge.tsx +32 -0
- package/src/fields/numerical/numerical-field.tsx +114 -0
- package/src/fields/relation/relation-display.module.css +36 -0
- package/src/fields/relation/relation-display.tsx +130 -0
- package/src/fields/relation/relation-field.module.css +83 -0
- package/src/fields/relation/relation-field.tsx +211 -0
- package/src/fields/relation/relation-picker.module.css +168 -0
- package/src/fields/relation/relation-picker.tsx +326 -0
- package/src/fields/relation/relation-summary.module.css +55 -0
- package/src/fields/relation/relation-summary.tsx +123 -0
- package/src/fields/select/select-field.module.css +13 -0
- package/src/fields/select/select-field.tsx +61 -0
- package/src/fields/sortable-item.module.css +167 -0
- package/src/fields/sortable-item.tsx +106 -0
- package/src/fields/text/text-field.module.css +13 -0
- package/src/fields/text/text-field.tsx +146 -0
- package/src/fields/text-area/text-area-field.module.css +13 -0
- package/src/fields/text-area/text-area-field.tsx +147 -0
- package/src/fields/use-field-change-handler.ts +112 -0
- package/src/forms/document-actions.module.css +160 -0
- package/src/forms/document-actions.tsx +482 -0
- package/src/forms/form-context.tsx +704 -0
- package/src/forms/form-renderer.module.css +321 -0
- package/src/forms/form-renderer.tsx +891 -0
- package/src/forms/navigation-guard.tsx +98 -0
- package/src/forms/path-widget.module.css +41 -0
- package/src/forms/path-widget.test.tsx +217 -0
- package/src/forms/path-widget.tsx +183 -0
- package/src/forms/upload-executor.ts +192 -0
- package/src/lib/translate-validation-error.ts +56 -0
- package/src/modules/admin-account/commands.ts +13 -0
- package/src/modules/admin-account/components/change-password.tsx +46 -31
- package/src/modules/admin-account/components/container.tsx +83 -38
- package/src/modules/admin-account/components/preferences.module.css +60 -0
- package/src/modules/admin-account/components/preferences.tsx +203 -0
- package/src/modules/admin-account/components/update.tsx +53 -27
- package/src/modules/admin-account/index.ts +3 -0
- package/src/modules/admin-account/schemas.ts +13 -0
- package/src/modules/admin-account/service.ts +12 -0
- package/src/modules/admin-permissions/components/inspector.tsx +22 -14
- package/src/modules/admin-roles/components/create.tsx +51 -23
- package/src/modules/admin-roles/components/permissions.tsx +25 -21
- package/src/modules/admin-roles/components/update.tsx +37 -19
- package/src/modules/admin-users/components/create.tsx +63 -34
- package/src/modules/admin-users/components/roles.tsx +9 -8
- package/src/modules/admin-users/components/set-password.tsx +34 -28
- package/src/modules/admin-users/components/update.tsx +58 -36
- package/src/modules/admin-users/dto.ts +1 -0
- package/src/modules/admin-users/repository.ts +17 -0
- package/src/modules/admin-users/schemas.ts +12 -0
- package/src/modules/auth/components/sign-in-form.tsx +14 -8
- package/src/presentation/group.module.css +41 -0
- package/src/presentation/group.tsx +40 -0
- package/src/presentation/row.module.css +32 -0
- package/src/presentation/row.tsx +33 -0
- package/src/presentation/tabs.module.css +107 -0
- package/src/presentation/tabs.tsx +84 -0
- package/src/react.ts +84 -0
- package/src/services/admin-services-types.ts +18 -0
- package/src/widgets/diff-viewer/diff-modal.module.css +79 -0
- package/src/widgets/diff-viewer/diff-modal.tsx +186 -0
- package/src/widgets/status-badge/status-badge.module.css +31 -0
- package/src/widgets/status-badge/status-badge.tsx +71 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) Infonomic Company Limited
|
|
7
|
+
*/
|
|
8
|
+
import type React from 'react';
|
|
9
|
+
import type { Field } from '@byline/core';
|
|
10
|
+
import type { DocumentPatch } from '@byline/core/patches';
|
|
11
|
+
interface FormError {
|
|
12
|
+
field: string;
|
|
13
|
+
message: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Represents a file that has been selected but not yet uploaded.
|
|
17
|
+
* The file is held locally until form submission.
|
|
18
|
+
*/
|
|
19
|
+
export interface PendingUpload {
|
|
20
|
+
/** The actual File object to upload */
|
|
21
|
+
file: File;
|
|
22
|
+
/** Blob URL for local preview (must be revoked on cleanup) */
|
|
23
|
+
previewUrl: string;
|
|
24
|
+
/** The collection path for the upload endpoint */
|
|
25
|
+
collectionPath: string;
|
|
26
|
+
}
|
|
27
|
+
type FieldListener = (value: any) => void;
|
|
28
|
+
type ErrorsListener = (errors: FormError[]) => void;
|
|
29
|
+
type MetaListener = () => void;
|
|
30
|
+
type SystemPathListener = (value: string | null) => void;
|
|
31
|
+
type FieldUploadingListener = (uploading: boolean) => void;
|
|
32
|
+
interface FormContextType {
|
|
33
|
+
setFieldValue: (name: string, value: any) => void;
|
|
34
|
+
setFieldStore: (name: string, value: any) => void;
|
|
35
|
+
getFieldValue: (name: string) => any;
|
|
36
|
+
getFieldValues: () => Record<string, any>;
|
|
37
|
+
getPatches: () => DocumentPatch[];
|
|
38
|
+
appendPatch: (patch: DocumentPatch) => void;
|
|
39
|
+
resetPatches: () => void;
|
|
40
|
+
hasChanges: () => boolean;
|
|
41
|
+
resetHasChanges: () => void;
|
|
42
|
+
runFieldHooks: (fields: Field[]) => Promise<FormError[]>;
|
|
43
|
+
validateForm: (fields: Field[]) => FormError[];
|
|
44
|
+
errors: FormError[];
|
|
45
|
+
getErrors: () => FormError[];
|
|
46
|
+
clearErrors: () => void;
|
|
47
|
+
setFieldError: (field: string, message: string) => void;
|
|
48
|
+
clearFieldError: (field: string) => void;
|
|
49
|
+
isDirty: (fieldName: string) => boolean;
|
|
50
|
+
subscribeField: (name: string, listener: FieldListener) => () => void;
|
|
51
|
+
subscribeErrors: (listener: ErrorsListener) => () => void;
|
|
52
|
+
subscribeMeta: (listener: MetaListener) => () => void;
|
|
53
|
+
addPendingUpload: (fieldPath: string, upload: PendingUpload) => void;
|
|
54
|
+
removePendingUpload: (fieldPath: string) => void;
|
|
55
|
+
getPendingUploads: () => Map<string, PendingUpload>;
|
|
56
|
+
hasPendingUploads: () => boolean;
|
|
57
|
+
clearPendingUploads: () => void;
|
|
58
|
+
setFieldUploading: (fieldPath: string, uploading: boolean) => void;
|
|
59
|
+
getIsFieldUploading: (fieldPath: string) => boolean;
|
|
60
|
+
subscribeFieldUploading: (fieldPath: string, listener: FieldUploadingListener) => () => void;
|
|
61
|
+
getSystemPath: () => string | null;
|
|
62
|
+
setSystemPath: (value: string | null) => void;
|
|
63
|
+
subscribeSystemPath: (listener: SystemPathListener) => () => void;
|
|
64
|
+
}
|
|
65
|
+
export declare const useFormContext: () => FormContextType;
|
|
66
|
+
export declare const FormProvider: ({ children, initialData, }: {
|
|
67
|
+
children: React.ReactNode;
|
|
68
|
+
initialData?: Record<string, any>;
|
|
69
|
+
}) => React.JSX.Element;
|
|
70
|
+
/**
|
|
71
|
+
* Subscribe to the system `path` slot edited by the path widget.
|
|
72
|
+
* Returns the current value (or `null` when no override is set).
|
|
73
|
+
*/
|
|
74
|
+
export declare const useSystemPath: () => string | null;
|
|
75
|
+
export declare const useFormStore: () => FormContextType;
|
|
76
|
+
export declare const useFieldError: (name: string) => string | undefined;
|
|
77
|
+
export declare const useFormMeta: () => {
|
|
78
|
+
hasChanges: boolean;
|
|
79
|
+
};
|
|
80
|
+
export declare const useIsDirty: (name: string) => boolean;
|
|
81
|
+
export declare const useFieldValue: <T = any>(name: string) => T | undefined;
|
|
82
|
+
/**
|
|
83
|
+
* Subscribe to a single field's upload-in-flight state. Returns `true` while
|
|
84
|
+
* the form orchestrator is actively transporting this field's pending upload
|
|
85
|
+
* (between the `setFieldUploading(path, true)` and the matching `false`
|
|
86
|
+
* emitted by the upload executor's progress callback).
|
|
87
|
+
*/
|
|
88
|
+
export declare const useIsFieldUploading: (fieldPath: string) => boolean;
|
|
89
|
+
export {};
|
|
@@ -0,0 +1,466 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { createContext, useCallback, useContext, useEffect, useRef, useState } from "react";
|
|
4
|
+
import { normalizeHooks } from "@byline/core";
|
|
5
|
+
import { get, set as external_lodash_es_set } from "lodash-es";
|
|
6
|
+
const FormContext = /*#__PURE__*/ createContext(null);
|
|
7
|
+
const useFormContext = ()=>{
|
|
8
|
+
const context = useContext(FormContext);
|
|
9
|
+
if (null == context) throw new Error('useFormContext must be used within a FormProvider');
|
|
10
|
+
return context;
|
|
11
|
+
};
|
|
12
|
+
const FormProvider = ({ children, initialData = {} })=>{
|
|
13
|
+
const fieldValues = useRef(JSON.parse(JSON.stringify(initialData?.fields ?? initialData)));
|
|
14
|
+
const initialValues = useRef(initialData?.fields ?? initialData);
|
|
15
|
+
const errorsRef = useRef([]);
|
|
16
|
+
const dirtyFields = useRef(new Set());
|
|
17
|
+
const patchesRef = useRef([]);
|
|
18
|
+
const pendingUploadsRef = useRef(new Map());
|
|
19
|
+
const uploadingFieldsRef = useRef(new Set());
|
|
20
|
+
const uploadingListenersRef = useRef(new Map());
|
|
21
|
+
const fieldListeners = useRef(new Map());
|
|
22
|
+
const errorListeners = useRef(new Set());
|
|
23
|
+
const metaListeners = useRef(new Set());
|
|
24
|
+
const systemPathRef = useRef('string' == typeof initialData?.path && initialData.path.length > 0 ? initialData.path : null);
|
|
25
|
+
const initialSystemPath = useRef(systemPathRef.current);
|
|
26
|
+
const systemPathListeners = useRef(new Set());
|
|
27
|
+
const subscribeField = useCallback((name, listener)=>{
|
|
28
|
+
if (!fieldListeners.current.has(name)) fieldListeners.current.set(name, new Set());
|
|
29
|
+
fieldListeners.current.get(name)?.add(listener);
|
|
30
|
+
return ()=>{
|
|
31
|
+
const listeners = fieldListeners.current.get(name);
|
|
32
|
+
if (listeners) {
|
|
33
|
+
listeners.delete(listener);
|
|
34
|
+
if (0 === listeners.size) fieldListeners.current.delete(name);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
}, []);
|
|
38
|
+
const subscribeErrors = useCallback((listener)=>{
|
|
39
|
+
errorListeners.current.add(listener);
|
|
40
|
+
return ()=>{
|
|
41
|
+
errorListeners.current.delete(listener);
|
|
42
|
+
};
|
|
43
|
+
}, []);
|
|
44
|
+
const subscribeMeta = useCallback((listener)=>{
|
|
45
|
+
metaListeners.current.add(listener);
|
|
46
|
+
return ()=>{
|
|
47
|
+
metaListeners.current.delete(listener);
|
|
48
|
+
};
|
|
49
|
+
}, []);
|
|
50
|
+
const notifyFieldListeners = useCallback((name, value)=>{
|
|
51
|
+
const listeners = fieldListeners.current.get(name);
|
|
52
|
+
if (listeners) listeners.forEach((listener)=>{
|
|
53
|
+
listener(value);
|
|
54
|
+
});
|
|
55
|
+
}, []);
|
|
56
|
+
const notifyErrorListeners = useCallback(()=>{
|
|
57
|
+
errorListeners.current.forEach((listener)=>{
|
|
58
|
+
listener(errorsRef.current);
|
|
59
|
+
});
|
|
60
|
+
}, []);
|
|
61
|
+
const notifyMetaListeners = useCallback(()=>{
|
|
62
|
+
metaListeners.current.forEach((listener)=>{
|
|
63
|
+
listener();
|
|
64
|
+
});
|
|
65
|
+
}, []);
|
|
66
|
+
const updateFieldStoreInternal = useCallback((name, value)=>{
|
|
67
|
+
const newFieldValues = {
|
|
68
|
+
...fieldValues.current
|
|
69
|
+
};
|
|
70
|
+
external_lodash_es_set(newFieldValues, name, value);
|
|
71
|
+
fieldValues.current = newFieldValues;
|
|
72
|
+
dirtyFields.current.add(name);
|
|
73
|
+
notifyFieldListeners(name, value);
|
|
74
|
+
notifyMetaListeners();
|
|
75
|
+
}, [
|
|
76
|
+
notifyFieldListeners,
|
|
77
|
+
notifyMetaListeners
|
|
78
|
+
]);
|
|
79
|
+
const setFieldStore = useCallback((name, value)=>{
|
|
80
|
+
updateFieldStoreInternal(name, value);
|
|
81
|
+
}, [
|
|
82
|
+
updateFieldStoreInternal
|
|
83
|
+
]);
|
|
84
|
+
const setFieldValue = useCallback((name, value)=>{
|
|
85
|
+
updateFieldStoreInternal(name, value);
|
|
86
|
+
const patch = {
|
|
87
|
+
kind: 'field.set',
|
|
88
|
+
path: name,
|
|
89
|
+
value
|
|
90
|
+
};
|
|
91
|
+
const lastPatch = patchesRef.current[patchesRef.current.length - 1];
|
|
92
|
+
if (lastPatch && 'field.set' === lastPatch.kind && lastPatch.path === name) {
|
|
93
|
+
const newPatches = [
|
|
94
|
+
...patchesRef.current
|
|
95
|
+
];
|
|
96
|
+
newPatches[newPatches.length - 1] = patch;
|
|
97
|
+
patchesRef.current = newPatches;
|
|
98
|
+
} else patchesRef.current = [
|
|
99
|
+
...patchesRef.current,
|
|
100
|
+
patch
|
|
101
|
+
];
|
|
102
|
+
if (errorsRef.current.some((error)=>error.field === name)) {
|
|
103
|
+
errorsRef.current = errorsRef.current.filter((error)=>error.field !== name);
|
|
104
|
+
notifyErrorListeners();
|
|
105
|
+
}
|
|
106
|
+
}, [
|
|
107
|
+
updateFieldStoreInternal,
|
|
108
|
+
notifyErrorListeners
|
|
109
|
+
]);
|
|
110
|
+
const getFieldValues = useCallback(()=>fieldValues.current, []);
|
|
111
|
+
const getPatches = useCallback(()=>patchesRef.current, []);
|
|
112
|
+
const appendPatch = useCallback((patch)=>{
|
|
113
|
+
patchesRef.current = [
|
|
114
|
+
...patchesRef.current,
|
|
115
|
+
patch
|
|
116
|
+
];
|
|
117
|
+
dirtyFields.current.add('__patch__');
|
|
118
|
+
notifyMetaListeners();
|
|
119
|
+
if ('production' !== process.env.NODE_ENV) console.debug('FormContext.appendPatch', {
|
|
120
|
+
patch,
|
|
121
|
+
dirtyCount: dirtyFields.current.size
|
|
122
|
+
});
|
|
123
|
+
}, [
|
|
124
|
+
notifyMetaListeners
|
|
125
|
+
]);
|
|
126
|
+
const getFieldValue = useCallback((name)=>{
|
|
127
|
+
const dirty = dirtyFields.current.has(name);
|
|
128
|
+
const currentValue = get(fieldValues.current, name);
|
|
129
|
+
if (void 0 !== currentValue) return currentValue;
|
|
130
|
+
if (!dirty) return get(initialValues.current, name);
|
|
131
|
+
}, []);
|
|
132
|
+
const hasChanges = useCallback(()=>dirtyFields.current.size > 0, []);
|
|
133
|
+
const resetHasChanges = useCallback(()=>{
|
|
134
|
+
dirtyFields.current.clear();
|
|
135
|
+
patchesRef.current = [];
|
|
136
|
+
initialSystemPath.current = systemPathRef.current;
|
|
137
|
+
notifyMetaListeners();
|
|
138
|
+
}, [
|
|
139
|
+
notifyMetaListeners
|
|
140
|
+
]);
|
|
141
|
+
const isDirty = useCallback((fieldName)=>dirtyFields.current.has(fieldName), []);
|
|
142
|
+
const getSystemPath = useCallback(()=>systemPathRef.current, []);
|
|
143
|
+
const setSystemPath = useCallback((value)=>{
|
|
144
|
+
systemPathRef.current = value;
|
|
145
|
+
if (value !== initialSystemPath.current) dirtyFields.current.add('__systemPath__');
|
|
146
|
+
else dirtyFields.current.delete('__systemPath__');
|
|
147
|
+
systemPathListeners.current.forEach((listener)=>{
|
|
148
|
+
listener(value);
|
|
149
|
+
});
|
|
150
|
+
notifyMetaListeners();
|
|
151
|
+
}, [
|
|
152
|
+
notifyMetaListeners
|
|
153
|
+
]);
|
|
154
|
+
const subscribeSystemPath = useCallback((listener)=>{
|
|
155
|
+
systemPathListeners.current.add(listener);
|
|
156
|
+
return ()=>{
|
|
157
|
+
systemPathListeners.current.delete(listener);
|
|
158
|
+
};
|
|
159
|
+
}, []);
|
|
160
|
+
const addPendingUpload = useCallback((fieldPath, upload)=>{
|
|
161
|
+
const existing = pendingUploadsRef.current.get(fieldPath);
|
|
162
|
+
if (existing) URL.revokeObjectURL(existing.previewUrl);
|
|
163
|
+
pendingUploadsRef.current.set(fieldPath, upload);
|
|
164
|
+
dirtyFields.current.add(fieldPath);
|
|
165
|
+
notifyMetaListeners();
|
|
166
|
+
}, [
|
|
167
|
+
notifyMetaListeners
|
|
168
|
+
]);
|
|
169
|
+
const removePendingUpload = useCallback((fieldPath)=>{
|
|
170
|
+
const existing = pendingUploadsRef.current.get(fieldPath);
|
|
171
|
+
if (existing) {
|
|
172
|
+
URL.revokeObjectURL(existing.previewUrl);
|
|
173
|
+
pendingUploadsRef.current.delete(fieldPath);
|
|
174
|
+
notifyMetaListeners();
|
|
175
|
+
}
|
|
176
|
+
}, [
|
|
177
|
+
notifyMetaListeners
|
|
178
|
+
]);
|
|
179
|
+
const getPendingUploads = useCallback(()=>new Map(pendingUploadsRef.current), []);
|
|
180
|
+
const hasPendingUploads = useCallback(()=>pendingUploadsRef.current.size > 0, []);
|
|
181
|
+
const clearPendingUploads = useCallback(()=>{
|
|
182
|
+
for (const upload of pendingUploadsRef.current.values())URL.revokeObjectURL(upload.previewUrl);
|
|
183
|
+
pendingUploadsRef.current.clear();
|
|
184
|
+
}, []);
|
|
185
|
+
const setFieldUploading = useCallback((fieldPath, uploading)=>{
|
|
186
|
+
if (uploading) {
|
|
187
|
+
if (uploadingFieldsRef.current.has(fieldPath)) return;
|
|
188
|
+
uploadingFieldsRef.current.add(fieldPath);
|
|
189
|
+
} else {
|
|
190
|
+
if (!uploadingFieldsRef.current.has(fieldPath)) return;
|
|
191
|
+
uploadingFieldsRef.current.delete(fieldPath);
|
|
192
|
+
}
|
|
193
|
+
uploadingListenersRef.current.get(fieldPath)?.forEach((listener)=>{
|
|
194
|
+
listener(uploading);
|
|
195
|
+
});
|
|
196
|
+
}, []);
|
|
197
|
+
const getIsFieldUploading = useCallback((fieldPath)=>uploadingFieldsRef.current.has(fieldPath), []);
|
|
198
|
+
const subscribeFieldUploading = useCallback((fieldPath, listener)=>{
|
|
199
|
+
let listeners = uploadingListenersRef.current.get(fieldPath);
|
|
200
|
+
if (!listeners) {
|
|
201
|
+
listeners = new Set();
|
|
202
|
+
uploadingListenersRef.current.set(fieldPath, listeners);
|
|
203
|
+
}
|
|
204
|
+
listeners.add(listener);
|
|
205
|
+
return ()=>{
|
|
206
|
+
const set = uploadingListenersRef.current.get(fieldPath);
|
|
207
|
+
if (set) {
|
|
208
|
+
set.delete(listener);
|
|
209
|
+
if (0 === set.size) uploadingListenersRef.current.delete(fieldPath);
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
}, []);
|
|
213
|
+
useEffect(()=>()=>{
|
|
214
|
+
for (const upload of pendingUploadsRef.current.values())URL.revokeObjectURL(upload.previewUrl);
|
|
215
|
+
}, []);
|
|
216
|
+
const validateForm = useCallback((fields)=>{
|
|
217
|
+
const formErrors = [];
|
|
218
|
+
const data = getFieldValues();
|
|
219
|
+
for (const field of fields){
|
|
220
|
+
const value = getFieldValue(field.name);
|
|
221
|
+
if (!field.optional && (null == value || '' === value)) formErrors.push({
|
|
222
|
+
field: field.name,
|
|
223
|
+
message: `${field.label} is required`
|
|
224
|
+
});
|
|
225
|
+
if (null != value && '' !== value) switch(field.type){
|
|
226
|
+
case 'text':
|
|
227
|
+
if ('string' != typeof value) formErrors.push({
|
|
228
|
+
field: field.name,
|
|
229
|
+
message: `${field.label} must be text`
|
|
230
|
+
});
|
|
231
|
+
break;
|
|
232
|
+
case 'checkbox':
|
|
233
|
+
if ('boolean' != typeof value) formErrors.push({
|
|
234
|
+
field: field.name,
|
|
235
|
+
message: `${field.label} must be true or false`
|
|
236
|
+
});
|
|
237
|
+
break;
|
|
238
|
+
case 'select':
|
|
239
|
+
if ('options' in field && field.options) {
|
|
240
|
+
const validValues = field.options.map((opt)=>opt.value);
|
|
241
|
+
if (!validValues.includes(value)) formErrors.push({
|
|
242
|
+
field: field.name,
|
|
243
|
+
message: `${field.label} must be one of: ${validValues.join(', ')}`
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
break;
|
|
247
|
+
case 'datetime':
|
|
248
|
+
if (value instanceof Date === false && 'string' != typeof value) formErrors.push({
|
|
249
|
+
field: field.name,
|
|
250
|
+
message: `${field.label} must be a valid date`
|
|
251
|
+
});
|
|
252
|
+
break;
|
|
253
|
+
}
|
|
254
|
+
if (field.validate) {
|
|
255
|
+
const error = field.validate(value, data);
|
|
256
|
+
if (error) formErrors.push({
|
|
257
|
+
field: field.name,
|
|
258
|
+
message: error
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
errorsRef.current = formErrors;
|
|
263
|
+
notifyErrorListeners();
|
|
264
|
+
return formErrors;
|
|
265
|
+
}, [
|
|
266
|
+
getFieldValue,
|
|
267
|
+
getFieldValues,
|
|
268
|
+
notifyErrorListeners
|
|
269
|
+
]);
|
|
270
|
+
const clearErrors = useCallback(()=>{
|
|
271
|
+
errorsRef.current = [];
|
|
272
|
+
notifyErrorListeners();
|
|
273
|
+
}, [
|
|
274
|
+
notifyErrorListeners
|
|
275
|
+
]);
|
|
276
|
+
const setFieldError = useCallback((field, message)=>{
|
|
277
|
+
const filtered = errorsRef.current.filter((e)=>e.field !== field);
|
|
278
|
+
filtered.push({
|
|
279
|
+
field,
|
|
280
|
+
message
|
|
281
|
+
});
|
|
282
|
+
errorsRef.current = filtered;
|
|
283
|
+
notifyErrorListeners();
|
|
284
|
+
}, [
|
|
285
|
+
notifyErrorListeners
|
|
286
|
+
]);
|
|
287
|
+
const clearFieldError = useCallback((field)=>{
|
|
288
|
+
if (errorsRef.current.some((e)=>e.field === field)) {
|
|
289
|
+
errorsRef.current = errorsRef.current.filter((e)=>e.field !== field);
|
|
290
|
+
notifyErrorListeners();
|
|
291
|
+
}
|
|
292
|
+
}, [
|
|
293
|
+
notifyErrorListeners
|
|
294
|
+
]);
|
|
295
|
+
const runFieldHooks = useCallback(async (fields)=>{
|
|
296
|
+
const hookErrors = [];
|
|
297
|
+
const data = {
|
|
298
|
+
...fieldValues.current
|
|
299
|
+
};
|
|
300
|
+
for (const field of fields){
|
|
301
|
+
const fns = normalizeHooks(field.hooks?.beforeValidate);
|
|
302
|
+
if (0 === fns.length) continue;
|
|
303
|
+
const path = field.name;
|
|
304
|
+
const value = getFieldValue(path);
|
|
305
|
+
const ctx = {
|
|
306
|
+
value,
|
|
307
|
+
previousValue: value,
|
|
308
|
+
data,
|
|
309
|
+
path,
|
|
310
|
+
field,
|
|
311
|
+
operation: 'submit'
|
|
312
|
+
};
|
|
313
|
+
try {
|
|
314
|
+
for (const fn of fns){
|
|
315
|
+
const result = await fn(ctx);
|
|
316
|
+
if (result?.error) hookErrors.push({
|
|
317
|
+
field: path,
|
|
318
|
+
message: result.error
|
|
319
|
+
});
|
|
320
|
+
if (result?.value !== void 0) {
|
|
321
|
+
setFieldValue(path, result.value);
|
|
322
|
+
ctx.value = result.value;
|
|
323
|
+
data[path] = result.value;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
} catch (err) {
|
|
327
|
+
const message = err instanceof Error ? err.message : 'Unexpected hook error';
|
|
328
|
+
hookErrors.push({
|
|
329
|
+
field: path,
|
|
330
|
+
message
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
if (hookErrors.length > 0) {
|
|
335
|
+
errorsRef.current = [
|
|
336
|
+
...errorsRef.current,
|
|
337
|
+
...hookErrors
|
|
338
|
+
];
|
|
339
|
+
notifyErrorListeners();
|
|
340
|
+
}
|
|
341
|
+
return hookErrors;
|
|
342
|
+
}, [
|
|
343
|
+
getFieldValue,
|
|
344
|
+
setFieldValue,
|
|
345
|
+
notifyErrorListeners
|
|
346
|
+
]);
|
|
347
|
+
return /*#__PURE__*/ jsx(FormContext.Provider, {
|
|
348
|
+
value: {
|
|
349
|
+
setFieldValue,
|
|
350
|
+
setFieldStore,
|
|
351
|
+
getFieldValue,
|
|
352
|
+
getFieldValues,
|
|
353
|
+
getPatches,
|
|
354
|
+
appendPatch,
|
|
355
|
+
resetPatches: ()=>{
|
|
356
|
+
patchesRef.current = [];
|
|
357
|
+
},
|
|
358
|
+
hasChanges,
|
|
359
|
+
resetHasChanges,
|
|
360
|
+
runFieldHooks,
|
|
361
|
+
validateForm,
|
|
362
|
+
errors: errorsRef.current,
|
|
363
|
+
getErrors: ()=>errorsRef.current,
|
|
364
|
+
clearErrors,
|
|
365
|
+
setFieldError,
|
|
366
|
+
clearFieldError,
|
|
367
|
+
isDirty,
|
|
368
|
+
subscribeField,
|
|
369
|
+
subscribeErrors,
|
|
370
|
+
subscribeMeta,
|
|
371
|
+
addPendingUpload,
|
|
372
|
+
removePendingUpload,
|
|
373
|
+
getPendingUploads,
|
|
374
|
+
hasPendingUploads,
|
|
375
|
+
clearPendingUploads,
|
|
376
|
+
setFieldUploading,
|
|
377
|
+
getIsFieldUploading,
|
|
378
|
+
subscribeFieldUploading,
|
|
379
|
+
getSystemPath,
|
|
380
|
+
setSystemPath,
|
|
381
|
+
subscribeSystemPath
|
|
382
|
+
},
|
|
383
|
+
children: children
|
|
384
|
+
});
|
|
385
|
+
};
|
|
386
|
+
const useSystemPath = ()=>{
|
|
387
|
+
const { getSystemPath, subscribeSystemPath } = useFormContext();
|
|
388
|
+
const [value, setValue] = useState(()=>getSystemPath());
|
|
389
|
+
useEffect(()=>subscribeSystemPath((next)=>setValue(next)), [
|
|
390
|
+
subscribeSystemPath
|
|
391
|
+
]);
|
|
392
|
+
return value;
|
|
393
|
+
};
|
|
394
|
+
const useFormStore = ()=>useFormContext();
|
|
395
|
+
const useFieldError = (name)=>{
|
|
396
|
+
const { getErrors, subscribeErrors } = useFormContext();
|
|
397
|
+
const [error, setError] = useState(()=>getErrors().find((e)=>e.field === name)?.message);
|
|
398
|
+
useEffect(()=>{
|
|
399
|
+
const unsubscribe = subscribeErrors((currentErrors)=>{
|
|
400
|
+
const fieldError = currentErrors.find((e)=>e.field === name);
|
|
401
|
+
setError(fieldError?.message);
|
|
402
|
+
});
|
|
403
|
+
return unsubscribe;
|
|
404
|
+
}, [
|
|
405
|
+
subscribeErrors,
|
|
406
|
+
name
|
|
407
|
+
]);
|
|
408
|
+
return error;
|
|
409
|
+
};
|
|
410
|
+
const useFormMeta = ()=>{
|
|
411
|
+
const { hasChanges, subscribeMeta } = useFormContext();
|
|
412
|
+
const [hasChangesValue, setHasChangesValue] = useState(hasChanges());
|
|
413
|
+
useEffect(()=>{
|
|
414
|
+
const unsubscribe = subscribeMeta(()=>{
|
|
415
|
+
setHasChangesValue(hasChanges());
|
|
416
|
+
});
|
|
417
|
+
return unsubscribe;
|
|
418
|
+
}, [
|
|
419
|
+
subscribeMeta,
|
|
420
|
+
hasChanges
|
|
421
|
+
]);
|
|
422
|
+
return {
|
|
423
|
+
hasChanges: hasChangesValue
|
|
424
|
+
};
|
|
425
|
+
};
|
|
426
|
+
const useIsDirty = (name)=>{
|
|
427
|
+
const { isDirty, subscribeMeta } = useFormContext();
|
|
428
|
+
const [dirty, setDirty] = useState(isDirty(name));
|
|
429
|
+
useEffect(()=>{
|
|
430
|
+
const unsubscribe = subscribeMeta(()=>{
|
|
431
|
+
setDirty(isDirty(name));
|
|
432
|
+
});
|
|
433
|
+
return unsubscribe;
|
|
434
|
+
}, [
|
|
435
|
+
subscribeMeta,
|
|
436
|
+
isDirty,
|
|
437
|
+
name
|
|
438
|
+
]);
|
|
439
|
+
return dirty;
|
|
440
|
+
};
|
|
441
|
+
const useFieldValue = (name)=>{
|
|
442
|
+
const { getFieldValue, subscribeField } = useFormContext();
|
|
443
|
+
const [value, setValue] = useState(()=>getFieldValue(name));
|
|
444
|
+
useEffect(()=>{
|
|
445
|
+
const unsubscribe = subscribeField(name, (nextValue)=>{
|
|
446
|
+
setValue(nextValue);
|
|
447
|
+
});
|
|
448
|
+
return unsubscribe;
|
|
449
|
+
}, [
|
|
450
|
+
subscribeField,
|
|
451
|
+
name
|
|
452
|
+
]);
|
|
453
|
+
return value;
|
|
454
|
+
};
|
|
455
|
+
const useIsFieldUploading = (fieldPath)=>{
|
|
456
|
+
const { getIsFieldUploading, subscribeFieldUploading } = useFormContext();
|
|
457
|
+
const [uploading, setUploading] = useState(()=>getIsFieldUploading(fieldPath));
|
|
458
|
+
useEffect(()=>subscribeFieldUploading(fieldPath, (next)=>{
|
|
459
|
+
setUploading(next);
|
|
460
|
+
}), [
|
|
461
|
+
subscribeFieldUploading,
|
|
462
|
+
fieldPath
|
|
463
|
+
]);
|
|
464
|
+
return uploading;
|
|
465
|
+
};
|
|
466
|
+
export { FormProvider, useFieldError, useFieldValue, useFormContext, useFormMeta, useFormStore, useIsDirty, useIsFieldUploading, useSystemPath };
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) Infonomic Company Limited
|
|
7
|
+
*/
|
|
8
|
+
import { type ReactNode } from 'react';
|
|
9
|
+
import type { CollectionAdminConfig, Field, WorkflowStatus } from '@byline/core';
|
|
10
|
+
import { type DocumentActionsLocaleOption } from './document-actions';
|
|
11
|
+
import type { UseNavigationGuard } from './navigation-guard';
|
|
12
|
+
/** Metadata about a previously published version that is still live. */
|
|
13
|
+
export interface PublishedVersionInfo {
|
|
14
|
+
id: string;
|
|
15
|
+
versionId: string;
|
|
16
|
+
status: string;
|
|
17
|
+
createdAt: string | Date;
|
|
18
|
+
updatedAt: string | Date;
|
|
19
|
+
}
|
|
20
|
+
/** Props shared by both the public FormRenderer and its internal FormContent component. */
|
|
21
|
+
export interface FormRendererProps {
|
|
22
|
+
mode: 'create' | 'edit';
|
|
23
|
+
fields: Field[];
|
|
24
|
+
onSubmit: (data: any) => void;
|
|
25
|
+
onCancel: () => void;
|
|
26
|
+
onStatusChange?: (nextStatus: string) => Promise<void>;
|
|
27
|
+
onUnpublish?: () => Promise<void>;
|
|
28
|
+
onDelete?: () => Promise<void>;
|
|
29
|
+
/**
|
|
30
|
+
* Called when the editor confirms the duplicate modal in
|
|
31
|
+
* `DocumentActions`. Edit views provide a handler that invokes the
|
|
32
|
+
* `duplicateCollectionDocument` server fn and navigates to the new doc.
|
|
33
|
+
* When omitted, the Duplicate menu item is hidden.
|
|
34
|
+
*/
|
|
35
|
+
onDuplicate?: () => Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* Called when the editor confirms the Copy-to-Locale modal in
|
|
38
|
+
* `DocumentActions`. Edit views provide a handler that invokes the
|
|
39
|
+
* `copyDocumentToLocale` server fn and navigates to the target-locale
|
|
40
|
+
* view. When omitted (or when fewer than two `contentLocales` are
|
|
41
|
+
* configured), the Copy-to-Locale menu item is hidden.
|
|
42
|
+
*/
|
|
43
|
+
onCopyToLocale?: (args: {
|
|
44
|
+
targetLocale: string;
|
|
45
|
+
overwrite: boolean;
|
|
46
|
+
}) => Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* All configured content locales (code + display label) — required for
|
|
49
|
+
* the Copy-to-Locale modal's target Select. Threaded as an opaque list
|
|
50
|
+
* through to `DocumentActions`.
|
|
51
|
+
*/
|
|
52
|
+
contentLocales?: ReadonlyArray<DocumentActionsLocaleOption>;
|
|
53
|
+
nextStatus?: WorkflowStatus;
|
|
54
|
+
workflowStatuses?: WorkflowStatus[];
|
|
55
|
+
publishedVersion?: PublishedVersionInfo | null;
|
|
56
|
+
initialData?: Record<string, any>;
|
|
57
|
+
adminConfig?: CollectionAdminConfig;
|
|
58
|
+
/**
|
|
59
|
+
* Name of the schema field to render as the live form heading.
|
|
60
|
+
* Sourced from `CollectionDefinition.useAsTitle` by the caller.
|
|
61
|
+
*/
|
|
62
|
+
useAsTitle?: string;
|
|
63
|
+
/**
|
|
64
|
+
* Name of the schema field that initialises the system path.
|
|
65
|
+
* Sourced from `CollectionDefinition.useAsPath` by the caller. When
|
|
66
|
+
* present the path widget renders in the sidebar.
|
|
67
|
+
*/
|
|
68
|
+
useAsPath?: string;
|
|
69
|
+
headingLabel?: string;
|
|
70
|
+
headerSlot?: ReactNode;
|
|
71
|
+
/** Collection path forwarded to upload-capable fields (e.g. `'media'`). */
|
|
72
|
+
collectionPath?: string;
|
|
73
|
+
/** The active content locale — initialised from the route query string. */
|
|
74
|
+
initialLocale?: string;
|
|
75
|
+
/** Called when the user picks a different content locale. */
|
|
76
|
+
onLocaleChange?: (locale: string) => void;
|
|
77
|
+
/**
|
|
78
|
+
* Schema-mismatch warnings produced by a "best-effort" reconstruction
|
|
79
|
+
* of the document (`findById({ lenient: true })`). When present, the
|
|
80
|
+
* form renders an inline Alert telling the editor that fields from a
|
|
81
|
+
* previous schema have been dropped — saving the form will overwrite
|
|
82
|
+
* them with the new shape.
|
|
83
|
+
*/
|
|
84
|
+
restoreWarnings?: string[];
|
|
85
|
+
/**
|
|
86
|
+
* Default content locale used when no `initialLocale` is supplied and as the
|
|
87
|
+
* fallback inside `PathWidget`. Hosts typically pass their app-wide
|
|
88
|
+
* `i18n.content.defaultLocale`. Defaults to `'en'`.
|
|
89
|
+
*/
|
|
90
|
+
defaultLocale?: string;
|
|
91
|
+
/**
|
|
92
|
+
* Framework-specific navigation guard hook.
|
|
93
|
+
* When provided, this overrides the adapter from `NavigationGuardProvider` context.
|
|
94
|
+
* If neither is set, a no-op `beforeunload`-only guard is used.
|
|
95
|
+
*/
|
|
96
|
+
useNavigationGuard?: UseNavigationGuard;
|
|
97
|
+
}
|
|
98
|
+
export declare const FormRenderer: ({ mode, fields, onSubmit, onCancel, onStatusChange, onUnpublish, onDelete, onDuplicate, onCopyToLocale, contentLocales, nextStatus, workflowStatuses, publishedVersion, initialData, adminConfig, useAsTitle, useAsPath, headingLabel, headerSlot, collectionPath, initialLocale, onLocaleChange, defaultLocale, useNavigationGuard, restoreWarnings, }: FormRendererProps) => import("react").JSX.Element;
|