@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,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RelationSummary — selected-value tile for the relation field widget.
|
|
3
|
+
*
|
|
4
|
+
* Override handles:
|
|
5
|
+
* .byline-relation-summary — root container
|
|
6
|
+
* .byline-relation-summary-stack — vertical layout used for label + value
|
|
7
|
+
* .byline-relation-summary-row — horizontal layout used for picker columns
|
|
8
|
+
* .byline-relation-summary-kind — small "type" label above the value
|
|
9
|
+
* .byline-relation-summary-value — primary value text
|
|
10
|
+
* .byline-relation-summary-value-mono — monospace fallback (raw uuid / not-found)
|
|
11
|
+
* .byline-relation-summary-missing — added to the value when target is unresolved
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
.stack,
|
|
15
|
+
:global(.byline-relation-summary-stack) {
|
|
16
|
+
display: flex;
|
|
17
|
+
flex-direction: column;
|
|
18
|
+
gap: 0.125rem;
|
|
19
|
+
min-width: 0;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.row,
|
|
23
|
+
:global(.byline-relation-summary-row) {
|
|
24
|
+
display: flex;
|
|
25
|
+
align-items: center;
|
|
26
|
+
gap: 0.75rem;
|
|
27
|
+
min-width: 0;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.kind,
|
|
31
|
+
:global(.byline-relation-summary-kind) {
|
|
32
|
+
color: var(--gray-500);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.value,
|
|
36
|
+
:global(.byline-relation-summary-value) {
|
|
37
|
+
color: var(--gray-100);
|
|
38
|
+
overflow: hidden;
|
|
39
|
+
text-overflow: ellipsis;
|
|
40
|
+
white-space: nowrap;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.value-mono,
|
|
44
|
+
:global(.byline-relation-summary-value-mono) {
|
|
45
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
46
|
+
overflow: hidden;
|
|
47
|
+
text-overflow: ellipsis;
|
|
48
|
+
white-space: nowrap;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.missing,
|
|
52
|
+
:global(.byline-relation-summary-missing) {
|
|
53
|
+
font-size: var(--font-size-xs);
|
|
54
|
+
color: var(--red-400);
|
|
55
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
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 { CollectionAdminConfig, CollectionDefinition } from '@byline/core'
|
|
10
|
+
import cx from 'classnames'
|
|
11
|
+
|
|
12
|
+
import { PickerCell, resolveFallbackDisplayField, resolveRowLabel } from './relation-display'
|
|
13
|
+
import styles from './relation-summary.module.css'
|
|
14
|
+
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// RelationSummary — selected-value tile for the relation field widget.
|
|
17
|
+
//
|
|
18
|
+
// Rendering priority (mirrors RelationPicker so the tile and picker rows
|
|
19
|
+
// look identical):
|
|
20
|
+
// 1. target `CollectionAdminConfig.picker` columns (full fidelity, with
|
|
21
|
+
// formatters — e.g. MediaThumbnail + title)
|
|
22
|
+
// 2. explicit `displayField` prop (from source schema's RelationField)
|
|
23
|
+
// 3. `CollectionDefinition.useAsTitle`
|
|
24
|
+
// 4. first declared text field on the target
|
|
25
|
+
// 5. target UUID (only when nothing else is available — "resolved but
|
|
26
|
+
// naked" or unpopulated)
|
|
27
|
+
//
|
|
28
|
+
// Value source priority:
|
|
29
|
+
// 1. `populated.document` — a `PopulatedRelationValue` attached by the
|
|
30
|
+
// server-side populate pass on first page load.
|
|
31
|
+
// 2. `cachedRecord` — the raw document the picker just handed us after
|
|
32
|
+
// a fresh pick (no server round trip needed).
|
|
33
|
+
// 3. neither — we have only the stored ref; fall through to UUID.
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
|
|
36
|
+
interface RelationSummaryProps {
|
|
37
|
+
targetDefinition: CollectionDefinition
|
|
38
|
+
targetAdminConfig: CollectionAdminConfig | null
|
|
39
|
+
displayField?: string
|
|
40
|
+
/** The raw relation value from the form. May be a plain ref or a populated envelope. */
|
|
41
|
+
value: {
|
|
42
|
+
targetDocumentId: string
|
|
43
|
+
targetCollectionId: string
|
|
44
|
+
_resolved?: boolean
|
|
45
|
+
_cycle?: boolean
|
|
46
|
+
document?: Record<string, any>
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* A document record cached client-side from a recent picker selection.
|
|
50
|
+
* Used when `value` is a plain ref (post-pick state) but we still want
|
|
51
|
+
* the tile to render real display data without a refetch. Caller is
|
|
52
|
+
* responsible for clearing/replacing this when the value's
|
|
53
|
+
* `targetDocumentId` changes.
|
|
54
|
+
*/
|
|
55
|
+
cachedRecord?: Record<string, any> | null
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function RelationSummary({
|
|
59
|
+
targetDefinition,
|
|
60
|
+
targetAdminConfig,
|
|
61
|
+
displayField,
|
|
62
|
+
value,
|
|
63
|
+
cachedRecord,
|
|
64
|
+
}: RelationSummaryProps) {
|
|
65
|
+
const pickerColumns = targetAdminConfig?.picker
|
|
66
|
+
|
|
67
|
+
// Unresolved (deleted target).
|
|
68
|
+
if (value._resolved === false) {
|
|
69
|
+
return (
|
|
70
|
+
<div className={cx('byline-relation-summary-stack', styles.stack)}>
|
|
71
|
+
<span className={cx('byline-relation-summary-kind', styles.kind)}>
|
|
72
|
+
{targetDefinition.labels.singular}
|
|
73
|
+
</span>
|
|
74
|
+
<span
|
|
75
|
+
className={cx(
|
|
76
|
+
'byline-relation-summary-value-mono byline-relation-summary-missing',
|
|
77
|
+
styles['value-mono'],
|
|
78
|
+
styles.missing
|
|
79
|
+
)}
|
|
80
|
+
>
|
|
81
|
+
(target not found) {value.targetDocumentId}
|
|
82
|
+
</span>
|
|
83
|
+
</div>
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Prefer the populated envelope's document; fall back to the cached
|
|
88
|
+
// picker record; finally fall back to rendering just the raw ref.
|
|
89
|
+
const record: Record<string, any> | null =
|
|
90
|
+
(value._resolved === true && !value._cycle && value.document) || cachedRecord || null
|
|
91
|
+
|
|
92
|
+
if (record && pickerColumns && pickerColumns.length > 0) {
|
|
93
|
+
return (
|
|
94
|
+
<div className={cx('byline-relation-summary-row', styles.row)}>
|
|
95
|
+
{pickerColumns.map((col) => (
|
|
96
|
+
<PickerCell key={String(col.fieldName)} column={col} record={record} />
|
|
97
|
+
))}
|
|
98
|
+
</div>
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const resolvedDisplayField =
|
|
103
|
+
displayField ??
|
|
104
|
+
targetDefinition.useAsTitle ??
|
|
105
|
+
resolveFallbackDisplayField(targetDefinition) ??
|
|
106
|
+
null
|
|
107
|
+
const label = record ? resolveRowLabel(record, resolvedDisplayField) : null
|
|
108
|
+
|
|
109
|
+
return (
|
|
110
|
+
<div className={cx('byline-relation-summary-stack', styles.stack)}>
|
|
111
|
+
<span className={cx('byline-relation-summary-kind', styles.kind)}>
|
|
112
|
+
{targetDefinition.labels.singular}
|
|
113
|
+
</span>
|
|
114
|
+
{label ? (
|
|
115
|
+
<span className={cx('byline-relation-summary-value', styles.value)}>{label}</span>
|
|
116
|
+
) : (
|
|
117
|
+
<span className={cx('byline-relation-summary-value-mono', styles['value-mono'])}>
|
|
118
|
+
{value.targetDocumentId}
|
|
119
|
+
</span>
|
|
120
|
+
)}
|
|
121
|
+
</div>
|
|
122
|
+
)
|
|
123
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SelectField — dropdown form widget.
|
|
3
|
+
*
|
|
4
|
+
* Override handles:
|
|
5
|
+
* .byline-field-select — the wrapper div
|
|
6
|
+
* .byline-field-select-dirty — added to the inner select when the
|
|
7
|
+
* field has unsaved local changes
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
.dirty,
|
|
11
|
+
:global(.byline-field-select-dirty) {
|
|
12
|
+
border-color: var(--blue-300);
|
|
13
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
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 { SelectField as FieldType } from '@byline/core'
|
|
10
|
+
import { ErrorText, Label, Select } from '@byline/ui/react'
|
|
11
|
+
import cx from 'classnames'
|
|
12
|
+
|
|
13
|
+
import { useFieldError, useFieldValue, useIsDirty } from '../../forms/form-context'
|
|
14
|
+
import styles from './select-field.module.css'
|
|
15
|
+
|
|
16
|
+
export const SelectField = ({
|
|
17
|
+
field,
|
|
18
|
+
value,
|
|
19
|
+
defaultValue,
|
|
20
|
+
onChange,
|
|
21
|
+
id,
|
|
22
|
+
path,
|
|
23
|
+
}: {
|
|
24
|
+
field: FieldType
|
|
25
|
+
value?: string
|
|
26
|
+
defaultValue?: string
|
|
27
|
+
onChange?: (value: string) => void
|
|
28
|
+
id?: string
|
|
29
|
+
path?: string
|
|
30
|
+
}) => {
|
|
31
|
+
const fieldPath = path ?? field.name
|
|
32
|
+
const fieldError = useFieldError(fieldPath)
|
|
33
|
+
const isDirty = useIsDirty(fieldPath)
|
|
34
|
+
const fieldValue = useFieldValue<string | undefined>(fieldPath)
|
|
35
|
+
const incomingValue = value ?? fieldValue ?? defaultValue ?? ''
|
|
36
|
+
const htmlId = id ?? fieldPath
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<div className={`byline-field-select ${field.name}`}>
|
|
40
|
+
{field.label && (
|
|
41
|
+
<Label id={htmlId} htmlFor={htmlId} label={field.label} required={!field.optional} />
|
|
42
|
+
)}
|
|
43
|
+
<Select<string>
|
|
44
|
+
size="sm"
|
|
45
|
+
id={htmlId}
|
|
46
|
+
name={field.name}
|
|
47
|
+
placeholder="Select an option"
|
|
48
|
+
required={!field.optional}
|
|
49
|
+
value={incomingValue}
|
|
50
|
+
ariaLabel={field.label}
|
|
51
|
+
helpText={field.helpText}
|
|
52
|
+
items={field.options.map((opt) => ({ value: opt.value, label: opt.label }))}
|
|
53
|
+
onValueChange={(value) => {
|
|
54
|
+
if (value != null) onChange?.(value)
|
|
55
|
+
}}
|
|
56
|
+
className={cx(isDirty && ['byline-field-select-dirty', styles.dirty])}
|
|
57
|
+
/>
|
|
58
|
+
{fieldError && <ErrorText id={`${field.name}-error`} text={fieldError} />}
|
|
59
|
+
</div>
|
|
60
|
+
)
|
|
61
|
+
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SortableItem — drag-card wrapping array/blocks list rows.
|
|
3
|
+
*
|
|
4
|
+
* Override handles:
|
|
5
|
+
* .byline-sortable — root card
|
|
6
|
+
* .byline-sortable-dragging — added while the item is mid-drag
|
|
7
|
+
* .byline-sortable-collapsed — added when content is collapsed
|
|
8
|
+
* .byline-sortable-header — top row (gripper + label + actions)
|
|
9
|
+
* .byline-sortable-header-collapsed — added to header when collapsed
|
|
10
|
+
* .byline-sortable-grip — drag handle button
|
|
11
|
+
* .byline-sortable-grip-icon — drag handle icon
|
|
12
|
+
* .byline-sortable-label — header label text
|
|
13
|
+
* .byline-sortable-toggle — collapse/expand button
|
|
14
|
+
* .byline-sortable-toggle-icon — chevron icon (rotates when collapsed)
|
|
15
|
+
* .byline-sortable-content — body container (children)
|
|
16
|
+
* .byline-sortable-content-hidden — collapsed body state
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
.root,
|
|
20
|
+
:global(.byline-sortable) {
|
|
21
|
+
padding: var(--spacing-16);
|
|
22
|
+
padding-top: var(--spacing-8);
|
|
23
|
+
border: var(--border-width-thin) dashed var(--gray-600);
|
|
24
|
+
border-radius: var(--border-radius-md);
|
|
25
|
+
background-color: oklch(from var(--canvas-50) l c h / 0.5);
|
|
26
|
+
box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.dragging,
|
|
30
|
+
:global(.byline-sortable-dragging) {
|
|
31
|
+
background-color: oklch(from var(--canvas-50) l c h / 0.8);
|
|
32
|
+
box-shadow:
|
|
33
|
+
0 4px 6px -1px rgb(0 0 0 / 0.1),
|
|
34
|
+
0 2px 4px -2px rgb(0 0 0 / 0.1);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.collapsed,
|
|
38
|
+
:global(.byline-sortable-collapsed) {
|
|
39
|
+
padding-top: var(--spacing-8);
|
|
40
|
+
padding-bottom: var(--spacing-8);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.header,
|
|
44
|
+
:global(.byline-sortable-header) {
|
|
45
|
+
display: flex;
|
|
46
|
+
align-items: center;
|
|
47
|
+
gap: var(--spacing-8);
|
|
48
|
+
margin-bottom: 0;
|
|
49
|
+
margin-left: -0.75rem;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.header-expanded,
|
|
53
|
+
:global(.byline-sortable-header-expanded) {
|
|
54
|
+
margin-bottom: var(--spacing-8);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.grip,
|
|
58
|
+
:global(.byline-sortable-grip) {
|
|
59
|
+
display: flex;
|
|
60
|
+
align-items: center;
|
|
61
|
+
justify-content: center;
|
|
62
|
+
padding: 0.25rem;
|
|
63
|
+
border: none;
|
|
64
|
+
background: none;
|
|
65
|
+
border-radius: var(--border-radius-sm);
|
|
66
|
+
color: var(--gray-400);
|
|
67
|
+
cursor: grab;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.grip:hover,
|
|
71
|
+
:global(.byline-sortable-grip):hover {
|
|
72
|
+
background-color: var(--gray-100);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.grip:active,
|
|
76
|
+
:global(.byline-sortable-grip):active {
|
|
77
|
+
cursor: grabbing;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.grip-icon,
|
|
81
|
+
:global(.byline-sortable-grip-icon) {
|
|
82
|
+
width: 1rem;
|
|
83
|
+
height: 1rem;
|
|
84
|
+
color: var(--primary-500);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.label,
|
|
88
|
+
:global(.byline-sortable-label) {
|
|
89
|
+
flex: 1;
|
|
90
|
+
min-width: 0;
|
|
91
|
+
font-size: 1rem;
|
|
92
|
+
font-weight: var(--font-weight-medium);
|
|
93
|
+
overflow: hidden;
|
|
94
|
+
text-overflow: ellipsis;
|
|
95
|
+
white-space: nowrap;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.toggle,
|
|
99
|
+
:global(.byline-sortable-toggle) {
|
|
100
|
+
display: flex;
|
|
101
|
+
align-items: center;
|
|
102
|
+
justify-content: center;
|
|
103
|
+
padding: 0.25rem;
|
|
104
|
+
border: none;
|
|
105
|
+
background: none;
|
|
106
|
+
border-radius: var(--border-radius-sm);
|
|
107
|
+
color: var(--gray-400);
|
|
108
|
+
cursor: pointer;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.toggle:hover,
|
|
112
|
+
:global(.byline-sortable-toggle):hover {
|
|
113
|
+
background-color: var(--gray-800);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.toggle-icon,
|
|
117
|
+
:global(.byline-sortable-toggle-icon) {
|
|
118
|
+
width: 1rem;
|
|
119
|
+
height: 1rem;
|
|
120
|
+
transition: transform 150ms ease;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.toggle-icon-rotated,
|
|
124
|
+
:global(.byline-sortable-toggle-icon-rotated) {
|
|
125
|
+
transform: rotate(180deg);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.content,
|
|
129
|
+
:global(.byline-sortable-content) {
|
|
130
|
+
position: relative;
|
|
131
|
+
display: flex;
|
|
132
|
+
flex-direction: column;
|
|
133
|
+
gap: var(--spacing-16);
|
|
134
|
+
transition: all 200ms ease;
|
|
135
|
+
opacity: 1;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.content-hidden,
|
|
139
|
+
:global(.byline-sortable-content-hidden) {
|
|
140
|
+
max-height: 0;
|
|
141
|
+
opacity: 0;
|
|
142
|
+
z-index: -10;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/* ─── Dark theme variants ───────────────────────────────────── */
|
|
146
|
+
|
|
147
|
+
:is([data-theme="dark"], :global(.dark)) {
|
|
148
|
+
.root,
|
|
149
|
+
:global(.byline-sortable) {
|
|
150
|
+
background-color: var(--canvas-800);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.dragging,
|
|
154
|
+
:global(.byline-sortable-dragging) {
|
|
155
|
+
background-color: oklch(from var(--canvas-700) l c h / 0.3);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.grip:hover,
|
|
159
|
+
:global(.byline-sortable-grip):hover {
|
|
160
|
+
background-color: var(--gray-800);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.grip-icon,
|
|
164
|
+
:global(.byline-sortable-grip-icon) {
|
|
165
|
+
color: var(--primary-200);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
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 ReactNode, useState } from 'react'
|
|
10
|
+
|
|
11
|
+
import { useTranslation } from '@byline/i18n/react'
|
|
12
|
+
import { ChevronDownIcon, GripperVerticalIcon, useSortable } from '@byline/ui/react'
|
|
13
|
+
import cx from 'classnames'
|
|
14
|
+
|
|
15
|
+
import { DraggableContextMenu } from './draggable-context-menu'
|
|
16
|
+
import styles from './sortable-item.module.css'
|
|
17
|
+
|
|
18
|
+
export const SortableItem = ({
|
|
19
|
+
id,
|
|
20
|
+
label,
|
|
21
|
+
children,
|
|
22
|
+
onAddBelow,
|
|
23
|
+
onRemove,
|
|
24
|
+
}: {
|
|
25
|
+
id: string
|
|
26
|
+
label: ReactNode
|
|
27
|
+
children: ReactNode
|
|
28
|
+
onAddBelow?: () => void
|
|
29
|
+
onRemove?: () => void
|
|
30
|
+
}) => {
|
|
31
|
+
const { t } = useTranslation('byline-admin')
|
|
32
|
+
const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
|
|
33
|
+
id,
|
|
34
|
+
transition: {
|
|
35
|
+
duration: 250,
|
|
36
|
+
easing: 'cubic-bezier(0, 0.2, 0.2, 1)',
|
|
37
|
+
},
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
const [collapsed, setCollapsed] = useState(false)
|
|
41
|
+
|
|
42
|
+
const style = {
|
|
43
|
+
transform: transform ? `translate3d(${transform.x}px, ${transform.y}px, 0)` : undefined,
|
|
44
|
+
transition,
|
|
45
|
+
zIndex: isDragging ? 10 : 'auto',
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<div
|
|
50
|
+
ref={setNodeRef}
|
|
51
|
+
style={style}
|
|
52
|
+
className={cx(
|
|
53
|
+
'byline-sortable',
|
|
54
|
+
styles.root,
|
|
55
|
+
isDragging && ['byline-sortable-dragging', styles.dragging],
|
|
56
|
+
collapsed && ['byline-sortable-collapsed', styles.collapsed]
|
|
57
|
+
)}
|
|
58
|
+
>
|
|
59
|
+
<div
|
|
60
|
+
className={cx(
|
|
61
|
+
'byline-sortable-header',
|
|
62
|
+
styles.header,
|
|
63
|
+
!collapsed && ['byline-sortable-header-expanded', styles['header-expanded']]
|
|
64
|
+
)}
|
|
65
|
+
>
|
|
66
|
+
<button
|
|
67
|
+
type="button"
|
|
68
|
+
className={cx('byline-sortable-grip', styles.grip)}
|
|
69
|
+
{...attributes}
|
|
70
|
+
{...listeners}
|
|
71
|
+
>
|
|
72
|
+
<GripperVerticalIcon className={cx('byline-sortable-grip-icon', styles['grip-icon'])} />
|
|
73
|
+
</button>
|
|
74
|
+
<div className={cx('byline-sortable-label', styles.label)}>{label}</div>
|
|
75
|
+
<DraggableContextMenu onAddBelow={onAddBelow} onRemove={onRemove} />
|
|
76
|
+
<button
|
|
77
|
+
type="button"
|
|
78
|
+
className={cx('byline-sortable-toggle', styles.toggle)}
|
|
79
|
+
onClick={() => setCollapsed((prev) => !prev)}
|
|
80
|
+
aria-label={
|
|
81
|
+
collapsed
|
|
82
|
+
? t('fields.sortable.expandAriaLabel')
|
|
83
|
+
: t('fields.sortable.collapseAriaLabel')
|
|
84
|
+
}
|
|
85
|
+
>
|
|
86
|
+
<ChevronDownIcon
|
|
87
|
+
className={cx(
|
|
88
|
+
'byline-sortable-toggle-icon',
|
|
89
|
+
styles['toggle-icon'],
|
|
90
|
+
collapsed && ['byline-sortable-toggle-icon-rotated', styles['toggle-icon-rotated']]
|
|
91
|
+
)}
|
|
92
|
+
/>
|
|
93
|
+
</button>
|
|
94
|
+
</div>
|
|
95
|
+
<div
|
|
96
|
+
className={cx(
|
|
97
|
+
'byline-sortable-content',
|
|
98
|
+
styles.content,
|
|
99
|
+
collapsed && ['byline-sortable-content-hidden', styles['content-hidden']]
|
|
100
|
+
)}
|
|
101
|
+
>
|
|
102
|
+
{children}
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
105
|
+
)
|
|
106
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TextField — single-line text input wrapper.
|
|
3
|
+
*
|
|
4
|
+
* Override handles:
|
|
5
|
+
* .byline-field-text — the wrapper div
|
|
6
|
+
* .byline-field-text-label-row — the label + locale-badge row
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
.label-row,
|
|
10
|
+
:global(.byline-field-text-label-row) {
|
|
11
|
+
display: flex;
|
|
12
|
+
align-items: center;
|
|
13
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
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 { useCallback } from 'react'
|
|
10
|
+
|
|
11
|
+
import type { Field, FieldComponentSlots, TextField as FieldType } from '@byline/core'
|
|
12
|
+
import { Input, Label } from '@byline/ui/react'
|
|
13
|
+
import cx from 'classnames'
|
|
14
|
+
|
|
15
|
+
import { useFieldError, useFieldValue } from '../../forms/form-context'
|
|
16
|
+
import { LocaleBadge } from '../locale-badge'
|
|
17
|
+
import styles from './text-field.module.css'
|
|
18
|
+
|
|
19
|
+
export const TextField = ({
|
|
20
|
+
field,
|
|
21
|
+
value,
|
|
22
|
+
defaultValue,
|
|
23
|
+
onChange,
|
|
24
|
+
id,
|
|
25
|
+
path,
|
|
26
|
+
locale,
|
|
27
|
+
components,
|
|
28
|
+
}: {
|
|
29
|
+
field: FieldType
|
|
30
|
+
value?: string
|
|
31
|
+
defaultValue?: string
|
|
32
|
+
onChange?: (value: string) => void
|
|
33
|
+
id?: string
|
|
34
|
+
path?: string
|
|
35
|
+
/** When provided, renders a LocaleBadge next to the field label. */
|
|
36
|
+
locale?: string
|
|
37
|
+
/** Optional UI component slot overrides from the admin config. */
|
|
38
|
+
components?: FieldComponentSlots
|
|
39
|
+
}) => {
|
|
40
|
+
const fieldPath = path ?? field.name
|
|
41
|
+
const fieldError = useFieldError(fieldPath)
|
|
42
|
+
const fieldValue = useFieldValue<string | undefined>(fieldPath)
|
|
43
|
+
const incomingValue = value ?? fieldValue ?? defaultValue ?? ''
|
|
44
|
+
const htmlId = id ?? fieldPath
|
|
45
|
+
|
|
46
|
+
const handleChange = useCallback(
|
|
47
|
+
(value: string) => {
|
|
48
|
+
if (onChange) {
|
|
49
|
+
onChange(value)
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
[onChange]
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
// Custom component slots (from admin config)
|
|
56
|
+
const slots = components
|
|
57
|
+
const CustomLabel = slots?.Label
|
|
58
|
+
const CustomHelpText = slots?.HelpText
|
|
59
|
+
const CustomField = slots?.Field
|
|
60
|
+
const BeforeField = slots?.beforeField
|
|
61
|
+
const AfterField = slots?.afterField
|
|
62
|
+
|
|
63
|
+
// Shared props available to every slot component
|
|
64
|
+
const slotBaseProps = {
|
|
65
|
+
field: field as Field,
|
|
66
|
+
path: fieldPath,
|
|
67
|
+
value: incomingValue,
|
|
68
|
+
error: fieldError,
|
|
69
|
+
id: htmlId,
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// When a locale is active, render a custom Label+badge and suppress the
|
|
73
|
+
// Input's own label so the locale indicator appears in the label row.
|
|
74
|
+
const showBadge = !!locale && !!field.label
|
|
75
|
+
|
|
76
|
+
// Determine whether the label is handled externally (by a custom slot or
|
|
77
|
+
// the locale badge row) so Input doesn't render its own.
|
|
78
|
+
const hasCustomLabel = !!CustomLabel
|
|
79
|
+
const suppressInputLabel = showBadge || hasCustomLabel
|
|
80
|
+
const suppressInputHelpText = !!CustomHelpText
|
|
81
|
+
|
|
82
|
+
const labelRowClass = cx('byline-field-text-label-row', styles['label-row'])
|
|
83
|
+
|
|
84
|
+
// ── Label rendering ──────────────────────────────────────────
|
|
85
|
+
const renderLabel = () => {
|
|
86
|
+
if (hasCustomLabel) {
|
|
87
|
+
return (
|
|
88
|
+
<div className={labelRowClass}>
|
|
89
|
+
<CustomLabel {...slotBaseProps} label={field.label} required={!field.optional} />
|
|
90
|
+
{showBadge && <LocaleBadge locale={locale!} />}
|
|
91
|
+
</div>
|
|
92
|
+
)
|
|
93
|
+
}
|
|
94
|
+
if (showBadge) {
|
|
95
|
+
return (
|
|
96
|
+
<div className={labelRowClass}>
|
|
97
|
+
<Label
|
|
98
|
+
id={`${htmlId}-label`}
|
|
99
|
+
htmlFor={htmlId}
|
|
100
|
+
label={field.label!}
|
|
101
|
+
required={!field.optional}
|
|
102
|
+
/>
|
|
103
|
+
<LocaleBadge locale={locale!} />
|
|
104
|
+
</div>
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
return null
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// ── Field input rendering ────────────────────────────────────
|
|
111
|
+
const renderInput = () => {
|
|
112
|
+
if (CustomField) {
|
|
113
|
+
return (
|
|
114
|
+
<CustomField
|
|
115
|
+
{...slotBaseProps}
|
|
116
|
+
onChange={handleChange}
|
|
117
|
+
defaultValue={defaultValue}
|
|
118
|
+
placeholder={field.placeholder}
|
|
119
|
+
/>
|
|
120
|
+
)
|
|
121
|
+
}
|
|
122
|
+
return (
|
|
123
|
+
<Input
|
|
124
|
+
id={htmlId}
|
|
125
|
+
name={field.name}
|
|
126
|
+
label={suppressInputLabel ? undefined : field.label}
|
|
127
|
+
required={!field.optional}
|
|
128
|
+
helpText={suppressInputHelpText ? undefined : field.helpText}
|
|
129
|
+
value={incomingValue}
|
|
130
|
+
onChange={(e) => handleChange(e.target.value)}
|
|
131
|
+
error={fieldError != null}
|
|
132
|
+
errorText={fieldError}
|
|
133
|
+
/>
|
|
134
|
+
)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return (
|
|
138
|
+
<div className={`byline-field-text ${field.name}`}>
|
|
139
|
+
{renderLabel()}
|
|
140
|
+
{BeforeField && <BeforeField {...slotBaseProps} />}
|
|
141
|
+
{renderInput()}
|
|
142
|
+
{AfterField && <AfterField {...slotBaseProps} />}
|
|
143
|
+
{CustomHelpText && <CustomHelpText {...slotBaseProps} helpText={field.helpText} />}
|
|
144
|
+
</div>
|
|
145
|
+
)
|
|
146
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TextAreaField — multi-line text input wrapper.
|
|
3
|
+
*
|
|
4
|
+
* Override handles:
|
|
5
|
+
* .byline-field-text-area — the wrapper div
|
|
6
|
+
* .byline-field-text-area-label-row — the label + locale-badge row
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
.label-row,
|
|
10
|
+
:global(.byline-field-text-area-label-row) {
|
|
11
|
+
display: flex;
|
|
12
|
+
align-items: center;
|
|
13
|
+
}
|