feat: adds collapsible field type
This commit is contained in:
@@ -0,0 +1,49 @@
|
|||||||
|
@import '../../../scss/styles.scss';
|
||||||
|
|
||||||
|
.collapsible {
|
||||||
|
border: 1px solid var(--theme-elevation-200);
|
||||||
|
border-radius: $style-radius-m;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border: 1px solid var(--theme-elevation-300);
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
position: relative;
|
||||||
|
background: var(--theme-elevation-100);
|
||||||
|
border-top-right-radius: $style-radius-s;
|
||||||
|
border-top-left-radius: $style-radius-s;
|
||||||
|
display: flex;
|
||||||
|
padding: base(.75) base(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
&--collapsed {
|
||||||
|
header {
|
||||||
|
border-bottom-right-radius: $style-radius-s;
|
||||||
|
border-bottom-left-radius: $style-radius-s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__toggle {
|
||||||
|
margin: 0 0 0 auto;
|
||||||
|
transform: rotate(.5turn);
|
||||||
|
|
||||||
|
.btn__icon {
|
||||||
|
background-color: var(--theme-elevation-0);
|
||||||
|
}
|
||||||
|
|
||||||
|
&--collapsed {
|
||||||
|
transform: rotate(0turn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__content {
|
||||||
|
padding: $baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include small-break {
|
||||||
|
header {
|
||||||
|
padding: base(.75) var(--gutter-h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,14 +1,52 @@
|
|||||||
import React from 'react';
|
import React, { useState } from 'react';
|
||||||
|
import AnimateHeight from 'react-animate-height';
|
||||||
|
import Button from '../Button';
|
||||||
import { Props } from './types';
|
import { Props } from './types';
|
||||||
|
import { CollapsibleProvider, useCollapsible } from './provider';
|
||||||
|
|
||||||
import './index.scss';
|
import './index.scss';
|
||||||
|
|
||||||
const baseClass = 'collapsible';
|
const baseClass = 'collapsible';
|
||||||
|
|
||||||
export const Collapsible: React.FC<Props> = ({ children }) => {
|
export const Collapsible: React.FC<Props> = ({ children, onToggle, className, header }) => {
|
||||||
|
const [collapsed, setCollapsed] = useState(false);
|
||||||
|
const isNested = useCollapsible();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={baseClass}>
|
<div className={[
|
||||||
|
baseClass,
|
||||||
|
className,
|
||||||
|
collapsed && `${baseClass}--collapsed`,
|
||||||
|
isNested && `${baseClass}--nested`,
|
||||||
|
].filter(Boolean).join(' ')}
|
||||||
|
>
|
||||||
|
<CollapsibleProvider withinCollapsible>
|
||||||
|
<header>
|
||||||
|
{header && (
|
||||||
|
<div className={`${baseClass}__header-wrap`}>
|
||||||
|
{header}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<Button
|
||||||
|
icon="chevron"
|
||||||
|
onClick={() => {
|
||||||
|
if (typeof onToggle === 'function') onToggle(!collapsed);
|
||||||
|
setCollapsed(!collapsed);
|
||||||
|
}}
|
||||||
|
buttonStyle="icon-label"
|
||||||
|
className={`${baseClass}__toggle ${baseClass}__toggle--${collapsed ? 'collapsed' : 'open'}`}
|
||||||
|
round
|
||||||
|
/>
|
||||||
|
</header>
|
||||||
|
<AnimateHeight
|
||||||
|
height={collapsed ? 0 : 'auto'}
|
||||||
|
duration={200}
|
||||||
|
>
|
||||||
|
<div className={`${baseClass}__content`}>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
|
</AnimateHeight>
|
||||||
|
</CollapsibleProvider>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
17
src/admin/components/elements/Collapsible/provider.tsx
Normal file
17
src/admin/components/elements/Collapsible/provider.tsx
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import React, {
|
||||||
|
createContext, useContext,
|
||||||
|
} from 'react';
|
||||||
|
|
||||||
|
const Context = createContext(false);
|
||||||
|
|
||||||
|
export const CollapsibleProvider: React.FC<{ children?: React.ReactNode, withinCollapsible: boolean }> = ({ children, withinCollapsible }) => {
|
||||||
|
return (
|
||||||
|
<Context.Provider value={withinCollapsible}>
|
||||||
|
{children}
|
||||||
|
</Context.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useCollapsible = (): boolean => useContext(Context);
|
||||||
|
|
||||||
|
export default Context;
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
export type Props = {
|
export type Props = {
|
||||||
|
className?: string
|
||||||
|
header?: React.ReactNode
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
|
onToggle?: (collapsed: boolean) => void
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,19 +26,6 @@
|
|||||||
margin-left: - base(.75);
|
margin-left: - base(.75);
|
||||||
margin-right: - base(.75);
|
margin-right: - base(.75);
|
||||||
width: calc(100% + #{base(1.5)});
|
width: calc(100% + #{base(1.5)});
|
||||||
|
|
||||||
.toggle-collapse {
|
|
||||||
margin: 0 0 0 auto;
|
|
||||||
transform: rotate(.5turn);
|
|
||||||
|
|
||||||
.btn__icon {
|
|
||||||
background-color: var(--theme-elevation-0);
|
|
||||||
}
|
|
||||||
|
|
||||||
&--is-collapsed {
|
|
||||||
transform: rotate(0turn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__render-fields-wrapper {
|
&__render-fields-wrapper {
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
@import '../../../../scss/styles.scss';
|
||||||
|
|
||||||
|
.collapsible-field {
|
||||||
|
&__label {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-type:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
49
src/admin/components/forms/field-types/Collapsible/index.tsx
Normal file
49
src/admin/components/forms/field-types/Collapsible/index.tsx
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import RenderFields from '../../RenderFields';
|
||||||
|
import withCondition from '../../withCondition';
|
||||||
|
import { Props } from './types';
|
||||||
|
import { fieldAffectsData } from '../../../../../fields/config/types';
|
||||||
|
import { Collapsible } from '../../../elements/Collapsible';
|
||||||
|
|
||||||
|
import './index.scss';
|
||||||
|
|
||||||
|
const baseClass = 'collapsible-field';
|
||||||
|
|
||||||
|
const CollapsibleField: React.FC<Props> = (props) => {
|
||||||
|
const {
|
||||||
|
label,
|
||||||
|
fields,
|
||||||
|
fieldTypes,
|
||||||
|
path,
|
||||||
|
permissions,
|
||||||
|
admin: {
|
||||||
|
readOnly,
|
||||||
|
className,
|
||||||
|
},
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
const classes = [
|
||||||
|
'field-type',
|
||||||
|
baseClass,
|
||||||
|
className,
|
||||||
|
].filter(Boolean).join(' ');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Collapsible
|
||||||
|
className={classes}
|
||||||
|
header={<div className={`${baseClass}__label`}>{label}</div>}
|
||||||
|
>
|
||||||
|
<RenderFields
|
||||||
|
readOnly={readOnly}
|
||||||
|
permissions={permissions?.fields}
|
||||||
|
fieldTypes={fieldTypes}
|
||||||
|
fieldSchema={fields.map((field) => ({
|
||||||
|
...field,
|
||||||
|
path: `${path ? `${path}.` : ''}${fieldAffectsData(field) ? field.name : ''}`,
|
||||||
|
}))}
|
||||||
|
/>
|
||||||
|
</Collapsible>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default withCondition(CollapsibleField);
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { CollapsibleField } from '../../../../../fields/config/types';
|
||||||
|
import { FieldTypes } from '..';
|
||||||
|
import { FieldPermissions } from '../../../../../auth/types';
|
||||||
|
|
||||||
|
export type Props = Omit<CollapsibleField, 'type'> & {
|
||||||
|
path?: string
|
||||||
|
fieldTypes: FieldTypes
|
||||||
|
permissions: FieldPermissions
|
||||||
|
}
|
||||||
@@ -19,6 +19,7 @@ import blocks from './Blocks';
|
|||||||
import group from './Group';
|
import group from './Group';
|
||||||
import array from './Array';
|
import array from './Array';
|
||||||
import row from './Row';
|
import row from './Row';
|
||||||
|
import collapsible from './Collapsible';
|
||||||
import upload from './Upload';
|
import upload from './Upload';
|
||||||
import ui from './UI';
|
import ui from './UI';
|
||||||
|
|
||||||
@@ -42,6 +43,7 @@ export type FieldTypes = {
|
|||||||
group: React.ComponentType
|
group: React.ComponentType
|
||||||
array: React.ComponentType
|
array: React.ComponentType
|
||||||
row: React.ComponentType
|
row: React.ComponentType
|
||||||
|
collapsible: React.ComponentType
|
||||||
upload: React.ComponentType
|
upload: React.ComponentType
|
||||||
ui: React.ComponentType
|
ui: React.ComponentType
|
||||||
}
|
}
|
||||||
@@ -66,6 +68,7 @@ const fieldTypes: FieldTypes = {
|
|||||||
group,
|
group,
|
||||||
array,
|
array,
|
||||||
row,
|
row,
|
||||||
|
collapsible,
|
||||||
upload,
|
upload,
|
||||||
ui,
|
ui,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ export default {
|
|||||||
checkbox: Text,
|
checkbox: Text,
|
||||||
radio: Text,
|
radio: Text,
|
||||||
row: Nested,
|
row: Nested,
|
||||||
|
collapsible: Nested,
|
||||||
group: Nested,
|
group: Nested,
|
||||||
array: Iterable,
|
array: Iterable,
|
||||||
blocks: Iterable,
|
blocks: Iterable,
|
||||||
|
|||||||
@@ -133,7 +133,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@include small-break {
|
@include small-break {
|
||||||
--gutter-h: #{base(1)};
|
--gutter-h: #{base(.75)};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -175,6 +175,16 @@ export const row = baseField.keys({
|
|||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const collapsible = baseField.keys({
|
||||||
|
label: joi.string().required(),
|
||||||
|
type: joi.string().valid('collapsible').required(),
|
||||||
|
fields: joi.array().items(joi.link('#field')),
|
||||||
|
admin: baseAdminFields.keys({
|
||||||
|
readOnly: joi.forbidden(),
|
||||||
|
hidden: joi.forbidden(),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
export const group = baseField.keys({
|
export const group = baseField.keys({
|
||||||
type: joi.string().valid('group').required(),
|
type: joi.string().valid('group').required(),
|
||||||
name: joi.string().required(),
|
name: joi.string().required(),
|
||||||
@@ -367,6 +377,7 @@ const fieldSchema = joi.alternatives()
|
|||||||
group,
|
group,
|
||||||
array,
|
array,
|
||||||
row,
|
row,
|
||||||
|
collapsible,
|
||||||
radio,
|
radio,
|
||||||
relationship,
|
relationship,
|
||||||
checkbox,
|
checkbox,
|
||||||
|
|||||||
@@ -165,10 +165,7 @@ export type GroupField = FieldBase & {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RowAdmin = Omit<Admin, 'description'> & {
|
export type RowAdmin = Omit<Admin, 'description'>;
|
||||||
readOnly?: false;
|
|
||||||
hidden?: false;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type RowField = Omit<FieldBase, 'admin' | 'name'> & {
|
export type RowField = Omit<FieldBase, 'admin' | 'name'> & {
|
||||||
admin?: RowAdmin;
|
admin?: RowAdmin;
|
||||||
@@ -176,6 +173,12 @@ export type RowField = Omit<FieldBase, 'admin' | 'name'> & {
|
|||||||
fields: Field[];
|
fields: Field[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type CollapsibleField = Omit<FieldBase, 'name'> & {
|
||||||
|
type: 'collapsible';
|
||||||
|
label: string
|
||||||
|
fields: Field[];
|
||||||
|
}
|
||||||
|
|
||||||
export type UIField = {
|
export type UIField = {
|
||||||
name: string
|
name: string
|
||||||
label?: string
|
label?: string
|
||||||
@@ -328,6 +331,7 @@ export type Field =
|
|||||||
| CodeField
|
| CodeField
|
||||||
| PointField
|
| PointField
|
||||||
| RowField
|
| RowField
|
||||||
|
| CollapsibleField
|
||||||
| UIField;
|
| UIField;
|
||||||
|
|
||||||
export type FieldAffectingData =
|
export type FieldAffectingData =
|
||||||
@@ -364,7 +368,8 @@ export type NonPresentationalField = TextField
|
|||||||
| UploadField
|
| UploadField
|
||||||
| CodeField
|
| CodeField
|
||||||
| PointField
|
| PointField
|
||||||
| RowField;
|
| RowField
|
||||||
|
| CollapsibleField;
|
||||||
|
|
||||||
export type FieldWithPath = Field & {
|
export type FieldWithPath = Field & {
|
||||||
path?: string
|
path?: string
|
||||||
@@ -373,7 +378,8 @@ export type FieldWithPath = Field & {
|
|||||||
export type FieldWithSubFields =
|
export type FieldWithSubFields =
|
||||||
GroupField
|
GroupField
|
||||||
| ArrayField
|
| ArrayField
|
||||||
| RowField;
|
| RowField
|
||||||
|
| CollapsibleField;
|
||||||
|
|
||||||
export type FieldPresentationalOnly =
|
export type FieldPresentationalOnly =
|
||||||
UIField;
|
UIField;
|
||||||
@@ -387,7 +393,7 @@ export type FieldWithMaxDepth =
|
|||||||
| RelationshipField
|
| RelationshipField
|
||||||
|
|
||||||
export function fieldHasSubFields(field: Field): field is FieldWithSubFields {
|
export function fieldHasSubFields(field: Field): field is FieldWithSubFields {
|
||||||
return (field.type === 'group' || field.type === 'array' || field.type === 'row');
|
return (field.type === 'group' || field.type === 'array' || field.type === 'row' || field.type === 'collapsible');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fieldIsArrayType(field: Field): field is ArrayField {
|
export function fieldIsArrayType(field: Field): field is ArrayField {
|
||||||
|
|||||||
@@ -111,7 +111,8 @@ export const promise = async ({
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'row': {
|
case 'row':
|
||||||
|
case 'collapsible': {
|
||||||
traverseFields({
|
traverseFields({
|
||||||
data,
|
data,
|
||||||
doc,
|
doc,
|
||||||
|
|||||||
@@ -246,7 +246,8 @@ export const promise = async ({
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'row': {
|
case 'row':
|
||||||
|
case 'collapsible': {
|
||||||
traverseFields({
|
traverseFields({
|
||||||
currentDepth,
|
currentDepth,
|
||||||
depth,
|
depth,
|
||||||
|
|||||||
@@ -259,7 +259,8 @@ export const promise = async ({
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'row': {
|
case 'row':
|
||||||
|
case 'collapsible': {
|
||||||
traverseFields({
|
traverseFields({
|
||||||
data,
|
data,
|
||||||
doc,
|
doc,
|
||||||
|
|||||||
@@ -249,7 +249,8 @@ export const promise = async ({
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'row': {
|
case 'row':
|
||||||
|
case 'collapsible': {
|
||||||
traverseFields({
|
traverseFields({
|
||||||
data,
|
data,
|
||||||
doc,
|
doc,
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import { GraphQLJSON } from 'graphql-type-json';
|
|||||||
import withNullableType from './withNullableType';
|
import withNullableType from './withNullableType';
|
||||||
import formatName from '../utilities/formatName';
|
import formatName from '../utilities/formatName';
|
||||||
import combineParentName from '../utilities/combineParentName';
|
import combineParentName from '../utilities/combineParentName';
|
||||||
import { ArrayField, CodeField, DateField, EmailField, Field, fieldHasSubFields, fieldAffectsData, fieldIsPresentationalOnly, GroupField, NumberField, PointField, RadioField, RelationshipField, RichTextField, RowField, SelectField, TextareaField, TextField, UploadField } from '../../fields/config/types';
|
import { ArrayField, CodeField, DateField, EmailField, Field, fieldHasSubFields, fieldAffectsData, fieldIsPresentationalOnly, GroupField, NumberField, PointField, RadioField, RelationshipField, RichTextField, RowField, SelectField, TextareaField, TextField, UploadField, CollapsibleField } from '../../fields/config/types';
|
||||||
import { toWords } from '../../utilities/formatLabels';
|
import { toWords } from '../../utilities/formatLabels';
|
||||||
import { Payload } from '../../index';
|
import { Payload } from '../../index';
|
||||||
import { SanitizedCollectionConfig } from '../../collections/config/types';
|
import { SanitizedCollectionConfig } from '../../collections/config/types';
|
||||||
@@ -135,6 +135,20 @@ function buildMutationInputType(payload: Payload, name: string, fields: Field[],
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, []),
|
||||||
|
collapsible: (field: CollapsibleField) => field.fields.reduce((acc, collapsibleField: CollapsibleField) => {
|
||||||
|
const getFieldSchema = fieldToSchemaMap[collapsibleField.type];
|
||||||
|
|
||||||
|
if (getFieldSchema) {
|
||||||
|
const fieldSchema = getFieldSchema(collapsibleField);
|
||||||
|
|
||||||
|
return [
|
||||||
|
...acc,
|
||||||
|
fieldSchema,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
return acc;
|
return acc;
|
||||||
}, []),
|
}, []),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -429,6 +429,18 @@ function buildObjectType(payload: Payload, name: string, fields: Field[], parent
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return subFieldSchema;
|
||||||
|
}, {}),
|
||||||
|
collapsible: (field) => field.fields.reduce((subFieldSchema, subField) => {
|
||||||
|
const buildSchemaType = fieldToSchemaMap[subField.type];
|
||||||
|
|
||||||
|
if (!fieldIsPresentationalOnly(subField) && buildSchemaType) {
|
||||||
|
return {
|
||||||
|
...subFieldSchema,
|
||||||
|
[formatName(subField.name)]: buildSchemaType(subField),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
return subFieldSchema;
|
return subFieldSchema;
|
||||||
}, {}),
|
}, {}),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { GraphQLJSON } from 'graphql-type-json';
|
|||||||
import {
|
import {
|
||||||
ArrayField,
|
ArrayField,
|
||||||
CheckboxField,
|
CheckboxField,
|
||||||
CodeField, DateField,
|
CodeField, CollapsibleField, DateField,
|
||||||
EmailField, fieldAffectsData, fieldHasSubFields, GroupField,
|
EmailField, fieldAffectsData, fieldHasSubFields, GroupField,
|
||||||
NumberField, optionIsObject, PointField,
|
NumberField, optionIsObject, PointField,
|
||||||
RadioField, RelationshipField,
|
RadioField, RelationshipField,
|
||||||
@@ -220,24 +220,51 @@ const fieldToSchemaMap: (parentName: string) => any = (parentName: string) => ({
|
|||||||
}),
|
}),
|
||||||
array: (field: ArrayField) => recursivelyBuildNestedPaths(parentName, field),
|
array: (field: ArrayField) => recursivelyBuildNestedPaths(parentName, field),
|
||||||
group: (field: GroupField) => recursivelyBuildNestedPaths(parentName, field),
|
group: (field: GroupField) => recursivelyBuildNestedPaths(parentName, field),
|
||||||
row: (field: RowField) => field.fields.reduce((rowSchema, rowField) => {
|
row: (field: RowField) => field.fields.reduce((rowSchema, subField) => {
|
||||||
const getFieldSchema = fieldToSchemaMap(parentName)[rowField.type];
|
const getFieldSchema = fieldToSchemaMap(parentName)[subField.type];
|
||||||
|
|
||||||
if (getFieldSchema) {
|
if (getFieldSchema) {
|
||||||
const rowFieldSchema = getFieldSchema(rowField);
|
const rowFieldSchema = getFieldSchema(subField);
|
||||||
|
|
||||||
if (fieldHasSubFields(rowField)) {
|
if (fieldHasSubFields(subField)) {
|
||||||
return [
|
return [
|
||||||
...rowSchema,
|
...rowSchema,
|
||||||
...rowFieldSchema,
|
...rowFieldSchema,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fieldAffectsData(rowField)) {
|
if (fieldAffectsData(subField)) {
|
||||||
return [
|
return [
|
||||||
...rowSchema,
|
...rowSchema,
|
||||||
{
|
{
|
||||||
key: rowField.name,
|
key: subField.name,
|
||||||
|
type: rowFieldSchema,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return rowSchema;
|
||||||
|
}, []),
|
||||||
|
collapsible: (field: CollapsibleField) => field.fields.reduce((rowSchema, subField) => {
|
||||||
|
const getFieldSchema = fieldToSchemaMap(parentName)[subField.type];
|
||||||
|
|
||||||
|
if (getFieldSchema) {
|
||||||
|
const rowFieldSchema = getFieldSchema(subField);
|
||||||
|
|
||||||
|
if (fieldHasSubFields(subField)) {
|
||||||
|
return [
|
||||||
|
...rowSchema,
|
||||||
|
...rowFieldSchema,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fieldAffectsData(subField)) {
|
||||||
|
return [
|
||||||
|
...rowSchema,
|
||||||
|
{
|
||||||
|
key: subField.name,
|
||||||
type: rowFieldSchema,
|
type: rowFieldSchema,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
/* eslint-disable no-use-before-define */
|
/* eslint-disable no-use-before-define */
|
||||||
import { Schema, SchemaDefinition, SchemaOptions } from 'mongoose';
|
import { Schema, SchemaDefinition, SchemaOptions } from 'mongoose';
|
||||||
import { SanitizedConfig } from '../config/types';
|
import { SanitizedConfig } from '../config/types';
|
||||||
import { ArrayField, Block, BlockField, CheckboxField, CodeField, DateField, EmailField, Field, fieldAffectsData, GroupField, NumberField, PointField, RadioField, RelationshipField, RichTextField, RowField, SelectField, TextareaField, TextField, UploadField, fieldIsPresentationalOnly, NonPresentationalField } from '../fields/config/types';
|
import { ArrayField, Block, BlockField, CheckboxField, CodeField, DateField, EmailField, Field, fieldAffectsData, GroupField, NumberField, PointField, RadioField, RelationshipField, RichTextField, RowField, SelectField, TextareaField, TextField, UploadField, fieldIsPresentationalOnly, NonPresentationalField, CollapsibleField } from '../fields/config/types';
|
||||||
import sortableFieldTypes from '../fields/sortableFieldTypes';
|
import sortableFieldTypes from '../fields/sortableFieldTypes';
|
||||||
|
|
||||||
export type BuildSchemaOptions = {
|
export type BuildSchemaOptions = {
|
||||||
@@ -306,12 +306,26 @@ const fieldToSchemaMap = {
|
|||||||
row: (field: RowField, fields: SchemaDefinition, config: SanitizedConfig, buildSchemaOptions: BuildSchemaOptions): SchemaDefinition => {
|
row: (field: RowField, fields: SchemaDefinition, config: SanitizedConfig, buildSchemaOptions: BuildSchemaOptions): SchemaDefinition => {
|
||||||
const newFields = { ...fields };
|
const newFields = { ...fields };
|
||||||
|
|
||||||
field.fields.forEach((rowField: Field) => {
|
field.fields.forEach((subField: Field) => {
|
||||||
const fieldSchemaMap: FieldSchemaGenerator = fieldToSchemaMap[rowField.type];
|
const fieldSchemaMap: FieldSchemaGenerator = fieldToSchemaMap[subField.type];
|
||||||
|
|
||||||
if (fieldSchemaMap && fieldAffectsData(rowField)) {
|
if (fieldSchemaMap && fieldAffectsData(subField)) {
|
||||||
const fieldSchema = fieldSchemaMap(rowField, fields, config, buildSchemaOptions);
|
const fieldSchema = fieldSchemaMap(subField, fields, config, buildSchemaOptions);
|
||||||
newFields[rowField.name] = fieldSchema[rowField.name];
|
newFields[subField.name] = fieldSchema[subField.name];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return newFields;
|
||||||
|
},
|
||||||
|
collapsible: (field: CollapsibleField, fields: SchemaDefinition, config: SanitizedConfig, buildSchemaOptions: BuildSchemaOptions): SchemaDefinition => {
|
||||||
|
const newFields = { ...fields };
|
||||||
|
|
||||||
|
field.fields.forEach((subField: Field) => {
|
||||||
|
const fieldSchemaMap: FieldSchemaGenerator = fieldToSchemaMap[subField.type];
|
||||||
|
|
||||||
|
if (fieldSchemaMap && fieldAffectsData(subField)) {
|
||||||
|
const fieldSchema = fieldSchemaMap(subField, fields, config, buildSchemaOptions);
|
||||||
|
newFields[subField.name] = fieldSchema[subField.name];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,74 @@
|
|||||||
import { buildConfig } from '../buildConfig';
|
import { buildConfig } from '../buildConfig';
|
||||||
import { devUser } from '../../credentials';
|
import { devUser } from '../../credentials';
|
||||||
import { textDoc } from './shared';
|
import { arrayDoc, blocksDoc, collapsibleDoc, textDoc } from './shared';
|
||||||
|
|
||||||
export default buildConfig({
|
export default buildConfig({
|
||||||
collections: [
|
collections: [
|
||||||
|
{
|
||||||
|
slug: 'array-fields',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'array',
|
||||||
|
type: 'array',
|
||||||
|
required: true,
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'text',
|
||||||
|
type: 'text',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
slug: 'block-fields',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'blocks',
|
||||||
|
type: 'blocks',
|
||||||
|
required: true,
|
||||||
|
blocks: [
|
||||||
|
{
|
||||||
|
slug: 'text',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'text',
|
||||||
|
type: 'text',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
slug: 'number',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'number',
|
||||||
|
type: 'number',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
slug: 'collapsible-fields',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
label: 'Collapsible Field',
|
||||||
|
type: 'collapsible',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'text',
|
||||||
|
type: 'text',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
slug: 'text-fields',
|
slug: 'text-fields',
|
||||||
admin: {
|
admin: {
|
||||||
@@ -27,6 +92,21 @@ export default buildConfig({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await payload.create({
|
||||||
|
collection: 'array-fields',
|
||||||
|
data: arrayDoc,
|
||||||
|
});
|
||||||
|
|
||||||
|
await payload.create({
|
||||||
|
collection: 'block-fields',
|
||||||
|
data: blocksDoc,
|
||||||
|
});
|
||||||
|
|
||||||
|
await payload.create({
|
||||||
|
collection: 'collapsible-fields',
|
||||||
|
data: collapsibleDoc,
|
||||||
|
});
|
||||||
|
|
||||||
await payload.create({
|
await payload.create({
|
||||||
collection: 'text-fields',
|
collection: 'text-fields',
|
||||||
data: textDoc,
|
data: textDoc,
|
||||||
|
|||||||
@@ -1,3 +1,45 @@
|
|||||||
|
export const arrayDoc = {
|
||||||
|
array: [
|
||||||
|
{
|
||||||
|
text: 'first row',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'second row',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'third row',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'fourth row',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'fifth row',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'sixth row',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const blocksDoc = {
|
||||||
|
blocks: [
|
||||||
|
{
|
||||||
|
blockName: 'First block',
|
||||||
|
blockType: 'text',
|
||||||
|
text: 'first block',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
blockName: 'Second block',
|
||||||
|
blockType: 'number',
|
||||||
|
number: 342,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
export const textDoc = {
|
export const textDoc = {
|
||||||
text: 'Seeded text document',
|
text: 'Seeded text document',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const collapsibleDoc = {
|
||||||
|
text: 'Seeded collapsible doc',
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user