@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,87 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
5
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
7
|
+
*
|
|
8
|
+
* Copyright (c) Infonomic Company Limited
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { useTranslation } from '@byline/i18n/react'
|
|
12
|
+
import {
|
|
13
|
+
DeleteIcon,
|
|
14
|
+
Dropdown as DropdownMenu,
|
|
15
|
+
EllipsisIcon,
|
|
16
|
+
IconButton,
|
|
17
|
+
PlusIcon,
|
|
18
|
+
} from '@byline/ui/react'
|
|
19
|
+
import cx from 'classnames'
|
|
20
|
+
|
|
21
|
+
import styles from './draggable-context-menu.module.css'
|
|
22
|
+
|
|
23
|
+
interface DraggableContextMenuProps {
|
|
24
|
+
onAddBelow?: () => void
|
|
25
|
+
onRemove?: () => void
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function DraggableContextMenu({
|
|
29
|
+
onAddBelow,
|
|
30
|
+
onRemove,
|
|
31
|
+
}: DraggableContextMenuProps): React.JSX.Element {
|
|
32
|
+
const { t } = useTranslation('byline-admin')
|
|
33
|
+
const itemClass = cx('byline-draggable-menu-item', styles.item)
|
|
34
|
+
const rowClass = cx('byline-draggable-menu-row', styles.row)
|
|
35
|
+
const iconSlotClass = cx('byline-draggable-menu-icon-slot', styles['icon-slot'])
|
|
36
|
+
const labelClass = cx('byline-draggable-menu-label', styles.label)
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<DropdownMenu.Root modal={false}>
|
|
40
|
+
<DropdownMenu.Trigger render={<IconButton variant="text" size="sm" />}>
|
|
41
|
+
<EllipsisIcon width="16px" height="16px" />
|
|
42
|
+
</DropdownMenu.Trigger>
|
|
43
|
+
|
|
44
|
+
<DropdownMenu.Portal>
|
|
45
|
+
<DropdownMenu.Content
|
|
46
|
+
align="end"
|
|
47
|
+
sideOffset={0}
|
|
48
|
+
className={cx('byline-draggable-menu', styles.menu)}
|
|
49
|
+
>
|
|
50
|
+
<DropdownMenu.Item className={itemClass} onClick={onAddBelow}>
|
|
51
|
+
<div className={rowClass}>
|
|
52
|
+
<span className={iconSlotClass}>
|
|
53
|
+
<PlusIcon width="18px" height="18px" />
|
|
54
|
+
</span>
|
|
55
|
+
<span className={labelClass}>{t('fields.draggableMenu.addBelow')}</span>
|
|
56
|
+
</div>
|
|
57
|
+
</DropdownMenu.Item>
|
|
58
|
+
<DropdownMenu.Separator
|
|
59
|
+
className={cx('byline-draggable-menu-separator', styles.separator)}
|
|
60
|
+
/>
|
|
61
|
+
<DropdownMenu.Item className={itemClass} onClick={onRemove}>
|
|
62
|
+
<div className={rowClass}>
|
|
63
|
+
<div className={rowClass}>
|
|
64
|
+
<span className={iconSlotClass}>
|
|
65
|
+
<DeleteIcon
|
|
66
|
+
width="18px"
|
|
67
|
+
height="18px"
|
|
68
|
+
svgClassName={cx('byline-draggable-menu-delete-icon', styles['delete-icon'])}
|
|
69
|
+
/>
|
|
70
|
+
</span>
|
|
71
|
+
<span
|
|
72
|
+
className={cx(
|
|
73
|
+
'byline-draggable-menu-label byline-draggable-menu-label-danger',
|
|
74
|
+
styles.label,
|
|
75
|
+
styles['label-danger']
|
|
76
|
+
)}
|
|
77
|
+
>
|
|
78
|
+
{t('fields.draggableMenu.remove')}
|
|
79
|
+
</span>
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
</DropdownMenu.Item>
|
|
83
|
+
</DropdownMenu.Content>
|
|
84
|
+
</DropdownMenu.Portal>
|
|
85
|
+
</DropdownMenu.Root>
|
|
86
|
+
)
|
|
87
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
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
|
+
|
|
9
|
+
import type { Field } from '@byline/core'
|
|
10
|
+
import { resolveFieldDefaultValue } from '@byline/core'
|
|
11
|
+
|
|
12
|
+
export const placeholderStoredFileValue = {
|
|
13
|
+
fileId: crypto.randomUUID(),
|
|
14
|
+
filename: 'placeholder',
|
|
15
|
+
originalFilename: 'placeholder',
|
|
16
|
+
mimeType: 'application/octet-stream',
|
|
17
|
+
fileSize: 0,
|
|
18
|
+
storageProvider: 'placeholder',
|
|
19
|
+
storagePath: 'pending',
|
|
20
|
+
storageUrl: null,
|
|
21
|
+
fileHash: null,
|
|
22
|
+
imageWidth: null,
|
|
23
|
+
imageHeight: null,
|
|
24
|
+
imageFormat: null,
|
|
25
|
+
processingStatus: 'pending',
|
|
26
|
+
thumbnailGenerated: false,
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const placeholderForField = (f: Field): any => {
|
|
30
|
+
switch (f.type) {
|
|
31
|
+
case 'text':
|
|
32
|
+
case 'textArea':
|
|
33
|
+
return ''
|
|
34
|
+
case 'checkbox':
|
|
35
|
+
return false
|
|
36
|
+
case 'integer':
|
|
37
|
+
return 0
|
|
38
|
+
case 'counter':
|
|
39
|
+
// Allocator-assigned in the lifecycle layer; absent at form-init time.
|
|
40
|
+
return undefined
|
|
41
|
+
case 'richText':
|
|
42
|
+
case 'datetime':
|
|
43
|
+
return undefined
|
|
44
|
+
case 'select':
|
|
45
|
+
return ''
|
|
46
|
+
case 'file':
|
|
47
|
+
case 'image':
|
|
48
|
+
return placeholderStoredFileValue
|
|
49
|
+
default:
|
|
50
|
+
return null
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export const defaultScalarForField = async (
|
|
55
|
+
f: Field,
|
|
56
|
+
getFieldValues: () => Record<string, any>
|
|
57
|
+
): Promise<any> => {
|
|
58
|
+
const schemaDefault = await resolveFieldDefaultValue(f, {
|
|
59
|
+
data: getFieldValues(),
|
|
60
|
+
now: () => new Date(),
|
|
61
|
+
uuid: () => crypto.randomUUID(),
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
if (schemaDefault !== undefined) {
|
|
65
|
+
return schemaDefault
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return placeholderForField(f)
|
|
69
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FieldRenderer — main field-type switch wrapper.
|
|
3
|
+
*
|
|
4
|
+
* Override handles:
|
|
5
|
+
* .byline-field-localized-wrap — wrapper added when a non-self-badging
|
|
6
|
+
* field needs an absolutely-positioned
|
|
7
|
+
* locale badge in the corner
|
|
8
|
+
* .byline-field-localized-badge — the absolutely-positioned badge slot
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
.localized-wrap,
|
|
12
|
+
:global(.byline-field-localized-wrap) {
|
|
13
|
+
position: relative;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.localized-badge,
|
|
17
|
+
:global(.byline-field-localized-badge) {
|
|
18
|
+
position: absolute;
|
|
19
|
+
top: 0;
|
|
20
|
+
right: 0;
|
|
21
|
+
line-height: 1;
|
|
22
|
+
}
|
|
@@ -0,0 +1,288 @@
|
|
|
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
|
+
|
|
9
|
+
import type {
|
|
10
|
+
ArrayField as ArrayFieldType,
|
|
11
|
+
BlocksField as BlocksFieldType,
|
|
12
|
+
Field,
|
|
13
|
+
FieldComponentSlots,
|
|
14
|
+
GroupField as GroupFieldType,
|
|
15
|
+
RichTextEditorComponent,
|
|
16
|
+
} from '@byline/core'
|
|
17
|
+
import { getClientConfig } from '@byline/core'
|
|
18
|
+
import cx from 'classnames'
|
|
19
|
+
|
|
20
|
+
import { ArrayField } from './array/array-field'
|
|
21
|
+
import { BlocksField } from './blocks/blocks-field'
|
|
22
|
+
import { CheckboxField } from './checkbox/checkbox-field'
|
|
23
|
+
import { DateTimeField } from './datetime/datetime-field'
|
|
24
|
+
import styles from './field-renderer.module.css'
|
|
25
|
+
import { FileField } from './file/file-field'
|
|
26
|
+
import { GroupField } from './group/group-field'
|
|
27
|
+
import { ImageField } from './image/image-field'
|
|
28
|
+
import { LocaleBadge } from './locale-badge'
|
|
29
|
+
import { NumericalField } from './numerical/numerical-field'
|
|
30
|
+
import { RelationField } from './relation/relation-field'
|
|
31
|
+
import { SelectField } from './select/select-field'
|
|
32
|
+
import { TextField } from './text/text-field'
|
|
33
|
+
import { TextAreaField } from './text-area/text-area-field'
|
|
34
|
+
import { useFieldChangeHandler } from './use-field-change-handler'
|
|
35
|
+
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
// FieldRenderer — the main field type switch. Delegates to the appropriate
|
|
38
|
+
// field widget based on `field.type`.
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
|
|
41
|
+
interface FieldRendererProps {
|
|
42
|
+
field: Field
|
|
43
|
+
defaultValue?: any
|
|
44
|
+
basePath?: string
|
|
45
|
+
disableSorting?: boolean
|
|
46
|
+
hideLabel?: boolean
|
|
47
|
+
/** Collection path (e.g. `'media'`) forwarded to upload-capable fields. */
|
|
48
|
+
collectionPath?: string
|
|
49
|
+
/**
|
|
50
|
+
* The active content locale (e.g. `'en'`, `'fr'`). When provided and
|
|
51
|
+
* `field.localized === true`, a small locale badge is shown so the editor
|
|
52
|
+
* knows they are working on a localised field in the current language.
|
|
53
|
+
*/
|
|
54
|
+
contentLocale?: string
|
|
55
|
+
/**
|
|
56
|
+
* Optional UI component slot overrides from the admin config.
|
|
57
|
+
* Forwarded to value-field widgets that support custom slots.
|
|
58
|
+
*/
|
|
59
|
+
components?: FieldComponentSlots
|
|
60
|
+
/**
|
|
61
|
+
* Per-field rich-text editor component override from the admin config.
|
|
62
|
+
* Takes precedence over the globally registered
|
|
63
|
+
* `ClientConfig.fields.richText.editor` for this single field.
|
|
64
|
+
* Ignored when `field.type !== 'richText'`.
|
|
65
|
+
*/
|
|
66
|
+
editor?: RichTextEditorComponent
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export const FieldRenderer = ({
|
|
70
|
+
field,
|
|
71
|
+
defaultValue,
|
|
72
|
+
basePath,
|
|
73
|
+
disableSorting,
|
|
74
|
+
hideLabel,
|
|
75
|
+
collectionPath,
|
|
76
|
+
contentLocale,
|
|
77
|
+
components,
|
|
78
|
+
editor,
|
|
79
|
+
}: FieldRendererProps) => {
|
|
80
|
+
const path = basePath ? `${basePath}.${field.name}` : field.name
|
|
81
|
+
const htmlId = path.replace(/[[\].]/g, '-')
|
|
82
|
+
|
|
83
|
+
const handleChange = useFieldChangeHandler(field, path)
|
|
84
|
+
|
|
85
|
+
// When a locale is active and the field is localised, inject a badge into
|
|
86
|
+
// the field label so the editor knows they are editing locale-specific content.
|
|
87
|
+
const isLocalised = (field as any).localized === true
|
|
88
|
+
|
|
89
|
+
const badge =
|
|
90
|
+
isLocalised && contentLocale && !hideLabel ? <LocaleBadge locale={contentLocale} /> : null
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Render the underlying field widget. If the field is localised, we wrap it
|
|
94
|
+
* so we can append the locale badge after the label.
|
|
95
|
+
*/
|
|
96
|
+
const renderField = () => {
|
|
97
|
+
switch (field.type) {
|
|
98
|
+
case 'text':
|
|
99
|
+
return (
|
|
100
|
+
<TextField
|
|
101
|
+
field={hideLabel ? { ...field, label: undefined } : field}
|
|
102
|
+
defaultValue={defaultValue}
|
|
103
|
+
onChange={handleChange}
|
|
104
|
+
path={path}
|
|
105
|
+
id={htmlId}
|
|
106
|
+
locale={isLocalised ? contentLocale : undefined}
|
|
107
|
+
components={components}
|
|
108
|
+
/>
|
|
109
|
+
)
|
|
110
|
+
case 'textArea':
|
|
111
|
+
return (
|
|
112
|
+
<TextAreaField
|
|
113
|
+
field={hideLabel ? { ...field, label: undefined } : field}
|
|
114
|
+
defaultValue={defaultValue}
|
|
115
|
+
onChange={handleChange}
|
|
116
|
+
path={path}
|
|
117
|
+
id={htmlId}
|
|
118
|
+
locale={isLocalised ? contentLocale : undefined}
|
|
119
|
+
components={components}
|
|
120
|
+
/>
|
|
121
|
+
)
|
|
122
|
+
case 'checkbox':
|
|
123
|
+
return (
|
|
124
|
+
<CheckboxField
|
|
125
|
+
field={hideLabel ? { ...field, label: undefined } : field}
|
|
126
|
+
defaultValue={defaultValue}
|
|
127
|
+
onChange={handleChange}
|
|
128
|
+
path={path}
|
|
129
|
+
id={htmlId}
|
|
130
|
+
/>
|
|
131
|
+
)
|
|
132
|
+
case 'select':
|
|
133
|
+
return (
|
|
134
|
+
<SelectField
|
|
135
|
+
field={hideLabel ? { ...field, label: undefined } : field}
|
|
136
|
+
defaultValue={defaultValue}
|
|
137
|
+
onChange={handleChange}
|
|
138
|
+
path={path}
|
|
139
|
+
id={htmlId}
|
|
140
|
+
/>
|
|
141
|
+
)
|
|
142
|
+
case 'richText': {
|
|
143
|
+
// Admin-side per-field override takes precedence over the globally
|
|
144
|
+
// registered editor (`ClientConfig.fields.richText.editor`). The
|
|
145
|
+
// override travels via `FieldAdminConfig.fields.<name>.editor` —
|
|
146
|
+
// see admin-types — so React component references stay out of the
|
|
147
|
+
// schema graph that's loaded by the server bootstrap.
|
|
148
|
+
const RichTextEditor = editor ?? getClientConfig().fields?.richText?.editor
|
|
149
|
+
if (!RichTextEditor) {
|
|
150
|
+
throw new Error(
|
|
151
|
+
'No richText editor registered. Install @byline/richtext-lexical and set ' +
|
|
152
|
+
'`fields.richText.editor` in your admin config.'
|
|
153
|
+
)
|
|
154
|
+
}
|
|
155
|
+
return (
|
|
156
|
+
<RichTextEditor
|
|
157
|
+
field={hideLabel ? { ...field, label: undefined } : field}
|
|
158
|
+
defaultValue={defaultValue}
|
|
159
|
+
onChange={handleChange}
|
|
160
|
+
path={path}
|
|
161
|
+
instanceKey={htmlId}
|
|
162
|
+
locale={isLocalised ? contentLocale : undefined}
|
|
163
|
+
/>
|
|
164
|
+
)
|
|
165
|
+
}
|
|
166
|
+
case 'datetime':
|
|
167
|
+
return (
|
|
168
|
+
<DateTimeField
|
|
169
|
+
field={hideLabel ? { ...field, label: undefined } : field}
|
|
170
|
+
defaultValue={defaultValue}
|
|
171
|
+
onChange={handleChange}
|
|
172
|
+
path={path}
|
|
173
|
+
id={htmlId}
|
|
174
|
+
/>
|
|
175
|
+
)
|
|
176
|
+
case 'integer':
|
|
177
|
+
return (
|
|
178
|
+
<NumericalField
|
|
179
|
+
field={hideLabel ? { ...field, label: undefined } : field}
|
|
180
|
+
defaultValue={defaultValue}
|
|
181
|
+
onChange={handleChange}
|
|
182
|
+
path={path}
|
|
183
|
+
id={htmlId}
|
|
184
|
+
components={components}
|
|
185
|
+
/>
|
|
186
|
+
)
|
|
187
|
+
case 'counter':
|
|
188
|
+
// Counter values are allocator-assigned; force readOnly at the
|
|
189
|
+
// renderer level so the widget is always non-editable regardless
|
|
190
|
+
// of whether the developer set `field.readOnly` explicitly.
|
|
191
|
+
return (
|
|
192
|
+
<NumericalField
|
|
193
|
+
field={
|
|
194
|
+
hideLabel
|
|
195
|
+
? { ...field, label: undefined, readOnly: true }
|
|
196
|
+
: { ...field, readOnly: true }
|
|
197
|
+
}
|
|
198
|
+
defaultValue={defaultValue}
|
|
199
|
+
onChange={handleChange}
|
|
200
|
+
path={path}
|
|
201
|
+
id={htmlId}
|
|
202
|
+
components={components}
|
|
203
|
+
/>
|
|
204
|
+
)
|
|
205
|
+
case 'file':
|
|
206
|
+
return (
|
|
207
|
+
<FileField
|
|
208
|
+
field={hideLabel ? { ...field, label: undefined } : field}
|
|
209
|
+
defaultValue={defaultValue}
|
|
210
|
+
onChange={handleChange}
|
|
211
|
+
path={path}
|
|
212
|
+
collectionPath={collectionPath}
|
|
213
|
+
/>
|
|
214
|
+
)
|
|
215
|
+
case 'image':
|
|
216
|
+
return (
|
|
217
|
+
<ImageField
|
|
218
|
+
field={hideLabel ? { ...field, label: undefined } : field}
|
|
219
|
+
defaultValue={defaultValue}
|
|
220
|
+
onChange={handleChange}
|
|
221
|
+
path={path}
|
|
222
|
+
collectionPath={collectionPath}
|
|
223
|
+
/>
|
|
224
|
+
)
|
|
225
|
+
case 'relation':
|
|
226
|
+
return (
|
|
227
|
+
<RelationField
|
|
228
|
+
field={hideLabel ? { ...field, label: undefined } : field}
|
|
229
|
+
defaultValue={defaultValue}
|
|
230
|
+
onChange={handleChange}
|
|
231
|
+
path={path}
|
|
232
|
+
id={htmlId}
|
|
233
|
+
/>
|
|
234
|
+
)
|
|
235
|
+
case 'group':
|
|
236
|
+
// Render a group field as a fixed-order inline field group.
|
|
237
|
+
return (
|
|
238
|
+
<GroupField
|
|
239
|
+
field={
|
|
240
|
+
hideLabel
|
|
241
|
+
? ({ ...field, label: undefined } as unknown as GroupFieldType)
|
|
242
|
+
: (field as unknown as GroupFieldType)
|
|
243
|
+
}
|
|
244
|
+
defaultValue={defaultValue}
|
|
245
|
+
path={path}
|
|
246
|
+
/>
|
|
247
|
+
)
|
|
248
|
+
case 'blocks':
|
|
249
|
+
if (!field.blocks) return null
|
|
250
|
+
return (
|
|
251
|
+
<BlocksField
|
|
252
|
+
field={field as unknown as BlocksFieldType}
|
|
253
|
+
defaultValue={defaultValue}
|
|
254
|
+
path={path}
|
|
255
|
+
/>
|
|
256
|
+
)
|
|
257
|
+
case 'array':
|
|
258
|
+
if (!field.fields) return null
|
|
259
|
+
return (
|
|
260
|
+
<ArrayField
|
|
261
|
+
field={field as unknown as ArrayFieldType}
|
|
262
|
+
defaultValue={defaultValue}
|
|
263
|
+
path={path}
|
|
264
|
+
disableSorting={disableSorting}
|
|
265
|
+
/>
|
|
266
|
+
)
|
|
267
|
+
default:
|
|
268
|
+
return null
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// text and textArea render the badge inside their own Label row;
|
|
273
|
+
// the outer wrapper is only needed for other field types.
|
|
274
|
+
const selfBadge = field.type === 'text' || field.type === 'textArea' || field.type === 'richText'
|
|
275
|
+
|
|
276
|
+
if (badge && !selfBadge) {
|
|
277
|
+
return (
|
|
278
|
+
<div className={cx('byline-field-localized-wrap', styles['localized-wrap'])}>
|
|
279
|
+
{renderField()}
|
|
280
|
+
<span className={cx('byline-field-localized-badge', styles['localized-badge'])}>
|
|
281
|
+
{badge}
|
|
282
|
+
</span>
|
|
283
|
+
</div>
|
|
284
|
+
)
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
return renderField()
|
|
288
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
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
|
+
|
|
9
|
+
import { createContext, type ReactNode, useContext } from 'react'
|
|
10
|
+
|
|
11
|
+
import type { BylineFieldServices } from './field-services-types'
|
|
12
|
+
|
|
13
|
+
const FieldServicesContext = createContext<BylineFieldServices | null>(null)
|
|
14
|
+
|
|
15
|
+
interface BylineFieldServicesProviderProps {
|
|
16
|
+
services: BylineFieldServices
|
|
17
|
+
children: ReactNode
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const BylineFieldServicesProvider = ({
|
|
21
|
+
services,
|
|
22
|
+
children,
|
|
23
|
+
}: BylineFieldServicesProviderProps) => (
|
|
24
|
+
<FieldServicesContext.Provider value={services}>{children}</FieldServicesContext.Provider>
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
export const useBylineFieldServices = (): BylineFieldServices => {
|
|
28
|
+
const ctx = useContext(FieldServicesContext)
|
|
29
|
+
if (!ctx) {
|
|
30
|
+
throw new Error(
|
|
31
|
+
'@byline/ui: BylineFieldServicesProvider missing. Wrap your admin tree with <BylineFieldServicesProvider services={…} />.'
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
return ctx
|
|
35
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
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
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Framework-neutral function contracts that field/form components in
|
|
11
|
+
* `@byline/ui` need from the host application. The host wires concrete
|
|
12
|
+
* implementations via `BylineFieldServicesProvider` — typically thin
|
|
13
|
+
* adapters around TanStack Start server functions, Next.js server
|
|
14
|
+
* actions, or any other RPC-style transport.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import type { StoredFileValue } from '@byline/core'
|
|
18
|
+
|
|
19
|
+
export interface CollectionListParams {
|
|
20
|
+
page?: number
|
|
21
|
+
page_size?: number
|
|
22
|
+
order?: string
|
|
23
|
+
desc?: boolean
|
|
24
|
+
query?: string
|
|
25
|
+
locale?: string
|
|
26
|
+
status?: string
|
|
27
|
+
fields?: string[]
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface CollectionListDoc {
|
|
31
|
+
id: string
|
|
32
|
+
path?: string
|
|
33
|
+
[field: string]: unknown
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface CollectionListResponse {
|
|
37
|
+
docs: CollectionListDoc[]
|
|
38
|
+
meta: { totalPages?: number; [k: string]: unknown }
|
|
39
|
+
included: { collection: { id: string; [k: string]: unknown } }
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export type GetCollectionDocumentsFn = (input: {
|
|
43
|
+
collection: string
|
|
44
|
+
params: CollectionListParams
|
|
45
|
+
}) => Promise<CollectionListResponse>
|
|
46
|
+
|
|
47
|
+
export interface UploadedFileResult {
|
|
48
|
+
documentId?: string
|
|
49
|
+
documentVersionId?: string
|
|
50
|
+
/**
|
|
51
|
+
* The persisted file value, including the `variants` array with
|
|
52
|
+
* `storagePath`, `storageUrl`, `width`, `height`, and `format` for each
|
|
53
|
+
* generated derivative. Single source of truth — the legacy top-level
|
|
54
|
+
* `variants: { name, url }[]` is gone.
|
|
55
|
+
*/
|
|
56
|
+
storedFile: StoredFileValue
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export type UploadFieldFn = (
|
|
60
|
+
collection: string,
|
|
61
|
+
formData: FormData,
|
|
62
|
+
createDocument?: boolean
|
|
63
|
+
) => Promise<UploadedFileResult>
|
|
64
|
+
|
|
65
|
+
export interface BylineFieldServices {
|
|
66
|
+
getCollectionDocuments: GetCollectionDocumentsFn
|
|
67
|
+
uploadField: UploadFieldFn
|
|
68
|
+
}
|