feat: ensures groups within blocks render properly
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "payload",
|
||||
"version": "0.20.5-beta.0",
|
||||
"version": "0.20.7-beta.0",
|
||||
"description": "Node, React and MongoDB Headless CMS and Application Framework",
|
||||
"license": "MIT",
|
||||
"author": {
|
||||
|
||||
@@ -286,6 +286,7 @@ const ArrayFieldType: React.FC<Props> = (props) => {
|
||||
value={row.id}
|
||||
/>
|
||||
<RenderFields
|
||||
className={`${baseClass}__fields`}
|
||||
forceRender
|
||||
readOnly={readOnly}
|
||||
fieldTypes={fieldTypes}
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.field-type:last-child {
|
||||
&__fields>.field-type:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,6 +336,7 @@ const Blocks: React.FC<Props> = (props) => {
|
||||
value={row.id}
|
||||
/>
|
||||
<RenderFields
|
||||
className={`${baseClass}__fields`}
|
||||
forceRender
|
||||
readOnly={readOnly}
|
||||
fieldTypes={fieldTypes}
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.field-type:last-child {
|
||||
&__fields>.field-type:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,18 @@
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
&--within-tab:first-child {
|
||||
margin-top: 0;
|
||||
border-top: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
&--within-tab:last-child {
|
||||
margin-bottom: 0;
|
||||
border-bottom: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
&--gutter {
|
||||
border-left: 1px solid var(--theme-elevation-100);
|
||||
padding: 0 0 0 $baseline;
|
||||
|
||||
@@ -8,6 +8,7 @@ import { useCollapsible } from '../../../elements/Collapsible/provider';
|
||||
|
||||
import './index.scss';
|
||||
import { GroupProvider, useGroup } from './provider';
|
||||
import { useTabs } from '../Tabs/provider';
|
||||
|
||||
const baseClass = 'group-field';
|
||||
|
||||
@@ -31,6 +32,7 @@ const Group: React.FC<Props> = (props) => {
|
||||
|
||||
const isWithinCollapsible = useCollapsible();
|
||||
const isWithinGroup = useGroup();
|
||||
const isWithinTab = useTabs();
|
||||
|
||||
const path = pathFromProps || name;
|
||||
|
||||
@@ -42,6 +44,7 @@ const Group: React.FC<Props> = (props) => {
|
||||
baseClass,
|
||||
isWithinCollapsible && `${baseClass}--within-collapsible`,
|
||||
isWithinGroup && `${baseClass}--within-group`,
|
||||
isWithinTab && `${baseClass}--within-tab`,
|
||||
(!hideGutter && isWithinGroup) && `${baseClass}--gutter`,
|
||||
className,
|
||||
].filter(Boolean).join(' ')}
|
||||
|
||||
@@ -6,6 +6,7 @@ import { fieldAffectsData } from '../../../../../fields/config/types';
|
||||
import FieldDescription from '../../FieldDescription';
|
||||
import toKebabCase from '../../../../../utilities/toKebabCase';
|
||||
import { useCollapsible } from '../../../elements/Collapsible/provider';
|
||||
import { TabsProvider } from './provider';
|
||||
|
||||
import './index.scss';
|
||||
|
||||
@@ -35,25 +36,26 @@ const TabsField: React.FC<Props> = (props) => {
|
||||
isWithinCollapsible && `${baseClass}--within-collapsible`,
|
||||
].filter(Boolean).join(' ')}
|
||||
>
|
||||
<div className={`${baseClass}__tabs`}>
|
||||
{tabs.map((tab, i) => {
|
||||
return (
|
||||
<button
|
||||
key={i}
|
||||
type="button"
|
||||
className={[
|
||||
`${baseClass}__tab-button`,
|
||||
active === i && `${baseClass}__tab-button--active`,
|
||||
].filter(Boolean).join(' ')}
|
||||
onClick={() => setActive(i)}
|
||||
>
|
||||
{tab.label}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div className={`${baseClass}__content-wrap`}>
|
||||
{activeTab && (
|
||||
<TabsProvider>
|
||||
<div className={`${baseClass}__tabs`}>
|
||||
{tabs.map((tab, i) => {
|
||||
return (
|
||||
<button
|
||||
key={i}
|
||||
type="button"
|
||||
className={[
|
||||
`${baseClass}__tab-button`,
|
||||
active === i && `${baseClass}__tab-button--active`,
|
||||
].filter(Boolean).join(' ')}
|
||||
onClick={() => setActive(i)}
|
||||
>
|
||||
{tab.label}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div className={`${baseClass}__content-wrap`}>
|
||||
{activeTab && (
|
||||
<div className={[
|
||||
`${baseClass}__tab`,
|
||||
`${baseClass}__tab-${toKebabCase(activeTab.label)}`,
|
||||
@@ -74,8 +76,9 @@ const TabsField: React.FC<Props> = (props) => {
|
||||
}))}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</TabsProvider>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
17
src/admin/components/forms/field-types/Tabs/provider.tsx
Normal file
17
src/admin/components/forms/field-types/Tabs/provider.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import React, {
|
||||
createContext, useContext,
|
||||
} from 'react';
|
||||
|
||||
const Context = createContext(false);
|
||||
|
||||
export const TabsProvider: React.FC<{ children?: React.ReactNode, withinTab?: boolean }> = ({ children, withinTab = true }) => {
|
||||
return (
|
||||
<Context.Provider value={withinTab}>
|
||||
{children}
|
||||
</Context.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useTabs = (): boolean => useContext(Context);
|
||||
|
||||
export default Context;
|
||||
@@ -1,4 +1,5 @@
|
||||
@import 'vars';
|
||||
@import 'z-index';
|
||||
|
||||
//////////////////////////////
|
||||
// IMPORT OVERRIDES
|
||||
|
||||
@@ -22,14 +22,14 @@ $baseline : math.div($baseline-px, $baseline-body-size)+rem;
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
// FONTS (LEGACY - DO NOT USE. PREFER CSS VARIABLES)
|
||||
// FONTS (DEPRECATED. DO NOT USE. PREFER CSS VARIABLES)
|
||||
//////////////////////////////
|
||||
|
||||
$font-body : 'Suisse Intl' !default;
|
||||
$font-mono : monospace !default;
|
||||
|
||||
//////////////////////////////
|
||||
// COLORS (LEGACY - DO NOT USE. PREFER CSS VARIABLES)
|
||||
// COLORS (DEPRECATED. DO NOT USE. PREFER CSS VARIABLES)
|
||||
//////////////////////////////
|
||||
|
||||
$color-dark-gray : #333333 !default;
|
||||
|
||||
9
src/admin/scss/z-index.scss
Normal file
9
src/admin/scss/z-index.scss
Normal file
@@ -0,0 +1,9 @@
|
||||
/////////////////////////////
|
||||
// Z-INDEX CHART (DEPRECATED. DO NOT USE. PREFER CSS VARIABLES)
|
||||
/////////////////////////////
|
||||
|
||||
$z-page: 20;
|
||||
$z-page-content: 30;
|
||||
$z-nav: 40;
|
||||
$z-modal: 50;
|
||||
$z-status: 60;
|
||||
@@ -1,59 +1,55 @@
|
||||
import type { CollectionConfig } from '../../../../src/collections/config/types';
|
||||
import { Field } from '../../../../src/fields/config/types';
|
||||
|
||||
const BlockFields: CollectionConfig = {
|
||||
slug: 'block-fields',
|
||||
fields: [
|
||||
export const blocksField: Field = {
|
||||
name: 'blocks',
|
||||
type: 'blocks',
|
||||
required: true,
|
||||
blocks: [
|
||||
{
|
||||
name: 'blocks',
|
||||
type: 'blocks',
|
||||
required: true,
|
||||
blocks: [
|
||||
slug: 'text',
|
||||
fields: [
|
||||
{
|
||||
slug: 'text',
|
||||
fields: [
|
||||
{
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
slug: 'number',
|
||||
fields: [
|
||||
{
|
||||
slug: 'number',
|
||||
fields: [
|
||||
{
|
||||
name: 'number',
|
||||
type: 'number',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
name: 'number',
|
||||
type: 'number',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
slug: 'subBlocks',
|
||||
fields: [
|
||||
{
|
||||
slug: 'subBlocks',
|
||||
fields: [
|
||||
name: 'subBlocks',
|
||||
type: 'blocks',
|
||||
blocks: [
|
||||
{
|
||||
name: 'subBlocks',
|
||||
type: 'blocks',
|
||||
blocks: [
|
||||
slug: 'text',
|
||||
fields: [
|
||||
{
|
||||
slug: 'text',
|
||||
fields: [
|
||||
{
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
slug: 'number',
|
||||
fields: [
|
||||
{
|
||||
slug: 'number',
|
||||
fields: [
|
||||
{
|
||||
name: 'number',
|
||||
type: 'number',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
name: 'number',
|
||||
type: 'number',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -64,35 +60,44 @@ const BlockFields: CollectionConfig = {
|
||||
],
|
||||
};
|
||||
|
||||
export const blocksDoc = {
|
||||
blocks: [
|
||||
{
|
||||
blockName: 'First block',
|
||||
blockType: 'text',
|
||||
text: 'first block',
|
||||
},
|
||||
{
|
||||
blockName: 'Second block',
|
||||
blockType: 'number',
|
||||
number: 342,
|
||||
},
|
||||
{
|
||||
blockName: 'Sub-block demonstration',
|
||||
blockType: 'subBlocks',
|
||||
subBlocks: [
|
||||
{
|
||||
blockName: 'First sub block',
|
||||
blockType: 'number',
|
||||
number: 123,
|
||||
},
|
||||
{
|
||||
blockName: 'Second sub block',
|
||||
blockType: 'text',
|
||||
text: 'second sub block',
|
||||
},
|
||||
],
|
||||
},
|
||||
const BlockFields: CollectionConfig = {
|
||||
slug: 'block-fields',
|
||||
fields: [
|
||||
blocksField,
|
||||
],
|
||||
};
|
||||
|
||||
export const blocksFieldSeedData = [
|
||||
{
|
||||
blockName: 'First block',
|
||||
blockType: 'text',
|
||||
text: 'first block',
|
||||
},
|
||||
{
|
||||
blockName: 'Second block',
|
||||
blockType: 'number',
|
||||
number: 342,
|
||||
},
|
||||
{
|
||||
blockName: 'Sub-block demonstration',
|
||||
blockType: 'subBlocks',
|
||||
subBlocks: [
|
||||
{
|
||||
blockName: 'First sub block',
|
||||
blockType: 'number',
|
||||
number: 123,
|
||||
},
|
||||
{
|
||||
blockName: 'Second sub block',
|
||||
blockType: 'text',
|
||||
text: 'second sub block',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export const blocksDoc = {
|
||||
blocks: blocksFieldSeedData,
|
||||
};
|
||||
|
||||
export default BlockFields;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { CollectionConfig } from '../../../../src/collections/config/types';
|
||||
import { blocksField, blocksFieldSeedData } from '../Blocks';
|
||||
|
||||
const TabsFields: CollectionConfig = {
|
||||
slug: 'tabs-fields',
|
||||
@@ -8,8 +9,8 @@ const TabsFields: CollectionConfig = {
|
||||
type: 'tabs',
|
||||
tabs: [
|
||||
{
|
||||
label: 'Tab One',
|
||||
description: 'Here is a description for tab one',
|
||||
label: 'Tab with Array',
|
||||
description: 'This tab has an array.',
|
||||
fields: [
|
||||
{
|
||||
name: 'array',
|
||||
@@ -30,24 +31,27 @@ const TabsFields: CollectionConfig = {
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Tab Two',
|
||||
description: 'Description for tab two',
|
||||
label: 'Tab with Blocks',
|
||||
description: 'Blocks are rendered here to ensure they populate and render correctly.',
|
||||
fields: [
|
||||
{
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
blocksField,
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Tab Three',
|
||||
description: 'Description for tab three',
|
||||
label: 'Tab with Group',
|
||||
description: 'This tab has a group, which should not render its top border or margin.',
|
||||
fields: [
|
||||
{
|
||||
name: 'number',
|
||||
type: 'number',
|
||||
required: true,
|
||||
name: 'group',
|
||||
type: 'group',
|
||||
label: 'Group',
|
||||
fields: [
|
||||
{
|
||||
name: 'number',
|
||||
type: 'number',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -100,8 +104,10 @@ export const tabsDoc = {
|
||||
text: 'Here is some data for the third row',
|
||||
},
|
||||
],
|
||||
text: 'This text will show up in the second tab input',
|
||||
number: 12,
|
||||
blocks: blocksFieldSeedData,
|
||||
group: {
|
||||
number: 12,
|
||||
},
|
||||
textarea: 'Here is some text that goes in a textarea',
|
||||
anotherText: 'Super tired of writing this text',
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user