feat: finishes tabs field

This commit is contained in:
James
2022-07-15 18:40:31 -07:00
parent 735e385537
commit 68e7c41fdc
8 changed files with 157 additions and 21 deletions

4
.vscode/launch.json vendored
View File

@@ -31,7 +31,7 @@
"env": { "env": {
"BABEL_ENV": "development" "BABEL_ENV": "development"
}, },
"program": "${workspaceFolder}/test/dev/index.js", "program": "${workspaceFolder}/test/dev.js",
"skipFiles": [ "skipFiles": [
"<node_internals>/**" "<node_internals>/**"
], ],
@@ -39,7 +39,7 @@
"--nolazy" "--nolazy"
], ],
"args": [ "args": [
"e2e/fields" "fields"
] ]
}, },
] ]

View File

@@ -2,8 +2,11 @@ import React from 'react';
import { Props, isComponent } from './types'; import { Props, isComponent } from './types';
import './index.scss'; import './index.scss';
const baseClass = 'field-description';
const FieldDescription: React.FC<Props> = (props) => { const FieldDescription: React.FC<Props> = (props) => {
const { const {
className,
description, description,
value, value,
} = props; } = props;
@@ -17,7 +20,10 @@ const FieldDescription: React.FC<Props> = (props) => {
if (description) { if (description) {
return ( return (
<div <div
className="field-description" className={[
baseClass,
className,
].filter(Boolean).join(' ')}
> >
{typeof description === 'function' ? description({ value }) : description} {typeof description === 'function' ? description({ value }) : description}
</div> </div>

View File

@@ -9,6 +9,7 @@ export type Description = string | DescriptionFunction | DescriptionComponent
export type Props = { export type Props = {
description?: Description description?: Description
value?: unknown; value?: unknown;
className?: string
} }
export function isComponent(description: Description): description is DescriptionComponent { export function isComponent(description: Description): description is DescriptionComponent {

View File

@@ -0,0 +1,91 @@
@import '../../../../scss/styles.scss';
.tabs-field {
margin-left: calc(var(--gutter-h) * -1);
margin-right: calc(var(--gutter-h) * -1);
margin-bottom: base(2);
&__tabs,
&__content-wrap {
padding-left: var(--gutter-h);
padding-right: var(--gutter-h);
}
&--within-collapsible {
margin-left: calc(#{$baseline} * -1);
margin-right: calc(#{$baseline} * -1);
margin-bottom: 0;
.tabs-field__tabs,
.tabs-field__content-wrap {
padding-left: $baseline;
padding-right: $baseline;
}
}
&__tabs {
border-bottom: 1px solid var(--theme-elevation-100);
margin-bottom: $baseline;
}
&__tab-button {
@extend %btn-reset;
@extend %h4;
padding-bottom: base(.5);
margin: 0 $baseline 0 0;
cursor: pointer;
opacity: .5;
position: relative;
&:last-child {
margin: 0;
}
&:after {
content: ' ';
position: absolute;
right: 0;
bottom: -1px;
left: 0;
height: 1px;
background: var(--theme-elevation-800);
opacity: 0;
}
&:hover {
opacity: .75;
&:after {
opacity: .2;
}
}
}
&__tab-button--active {
opacity: 1 !important;
&:after {
opacity: 1 !important;
height: 2px;
}
}
&__description {
margin-bottom: $baseline;
}
@include small-break {
&--within-collapsible {
margin-left: calc(var(--gutter-h) * -1);
margin-right: calc(var(--gutter-h) * -1);
}
&__tab-button {
margin: 0 base(.75) 0 0;
&:last-child {
margin: 0;
}
}
}
}

View File

@@ -5,6 +5,7 @@ import { Props } from './types';
import { fieldAffectsData } from '../../../../../fields/config/types'; import { fieldAffectsData } from '../../../../../fields/config/types';
import FieldDescription from '../../FieldDescription'; import FieldDescription from '../../FieldDescription';
import toKebabCase from '../../../../../utilities/toKebabCase'; import toKebabCase from '../../../../../utilities/toKebabCase';
import { useCollapsible } from '../../../elements/Collapsible/provider';
import './index.scss'; import './index.scss';
@@ -22,6 +23,7 @@ const TabsField: React.FC<Props> = (props) => {
}, },
} = props; } = props;
const isWithinCollapsible = useCollapsible();
const [active, setActive] = useState(0); const [active, setActive] = useState(0);
const activeTab = tabs[active]; const activeTab = tabs[active];
@@ -30,6 +32,7 @@ const TabsField: React.FC<Props> = (props) => {
<div className={[ <div className={[
className, className,
baseClass, baseClass,
isWithinCollapsible && `${baseClass}--within-collapsible`,
].filter(Boolean).join(' ')} ].filter(Boolean).join(' ')}
> >
<div className={`${baseClass}__tabs`}> <div className={`${baseClass}__tabs`}>
@@ -38,7 +41,10 @@ const TabsField: React.FC<Props> = (props) => {
<button <button
key={i} key={i}
type="button" type="button"
className={`${baseClass}__tab`} className={[
`${baseClass}__tab-button`,
active === i && `${baseClass}__tab-button--active`,
].filter(Boolean).join(' ')}
onClick={() => setActive(i)} onClick={() => setActive(i)}
> >
{tab.label} {tab.label}
@@ -54,6 +60,7 @@ const TabsField: React.FC<Props> = (props) => {
].join(' ')} ].join(' ')}
> >
<FieldDescription <FieldDescription
className={`${baseClass}__description`}
description={activeTab.description} description={activeTab.description}
/> />
<RenderFields <RenderFields

View File

@@ -62,6 +62,7 @@
margin: 0 0 $baseline; margin: 0 0 $baseline;
font-size: base(.75); font-size: base(.75);
line-height: 1.5; line-height: 1.5;
letter-spacing: -.375px;
} }
%h5 { %h5 {

View File

@@ -304,48 +304,44 @@ 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 }; let newFields = { ...fields };
field.fields.forEach((subField: Field) => { field.fields.forEach((subField: Field) => {
const fieldSchemaMap: FieldSchemaGenerator = fieldToSchemaMap[subField.type]; const fieldSchema: FieldSchemaGenerator = fieldToSchemaMap[subField.type];
if (fieldSchemaMap && fieldAffectsData(subField)) { if (fieldSchema) {
const fieldSchema = fieldSchemaMap(subField, fields, config, buildSchemaOptions); newFields = fieldSchema(subField, newFields, config, buildSchemaOptions);
newFields[subField.name] = fieldSchema[subField.name];
} }
}); });
return newFields; return newFields;
}, },
collapsible: (field: CollapsibleField, fields: SchemaDefinition, config: SanitizedConfig, buildSchemaOptions: BuildSchemaOptions): SchemaDefinition => { collapsible: (field: CollapsibleField, fields: SchemaDefinition, config: SanitizedConfig, buildSchemaOptions: BuildSchemaOptions): SchemaDefinition => {
const newFields = { ...fields }; let newFields = { ...fields };
field.fields.forEach((subField: Field) => { field.fields.forEach((subField: Field) => {
const fieldSchemaMap: FieldSchemaGenerator = fieldToSchemaMap[subField.type]; const fieldSchema: FieldSchemaGenerator = fieldToSchemaMap[subField.type];
if (fieldSchemaMap && fieldAffectsData(subField)) { if (fieldSchema) {
const fieldSchema = fieldSchemaMap(subField, fields, config, buildSchemaOptions); newFields = fieldSchema(subField, newFields, config, buildSchemaOptions);
newFields[subField.name] = fieldSchema[subField.name];
} }
}); });
return newFields; return newFields;
}, },
tabs: (field: TabsField, fields: SchemaDefinition, config: SanitizedConfig, buildSchemaOptions: BuildSchemaOptions): SchemaDefinition => { tabs: (field: TabsField, fields: SchemaDefinition, config: SanitizedConfig, buildSchemaOptions: BuildSchemaOptions): SchemaDefinition => {
const newFields = { ...fields }; let newFields = { ...fields };
field.tabs.forEach((tab) => { field.tabs.forEach((tab) => {
tab.fields.forEach((subField: Field) => { tab.fields.forEach((subField: Field) => {
const fieldSchemaMap: FieldSchemaGenerator = fieldToSchemaMap[subField.type]; const fieldSchema: FieldSchemaGenerator = fieldToSchemaMap[subField.type];
if (fieldSchemaMap && fieldAffectsData(subField)) { if (fieldSchema) {
const fieldSchema = fieldSchemaMap(subField, fields, config, buildSchemaOptions); newFields = fieldSchema(subField, newFields, config, buildSchemaOptions);
newFields[subField.name] = fieldSchema[subField.name];
} }
}); });
}); });
return newFields; return newFields;
}, },
array: (field: ArrayField, fields: SchemaDefinition, config: SanitizedConfig, buildSchemaOptions: BuildSchemaOptions) => { array: (field: ArrayField, fields: SchemaDefinition, config: SanitizedConfig, buildSchemaOptions: BuildSchemaOptions) => {

View File

@@ -49,6 +49,38 @@ const TabsFields: CollectionConfig = {
}, },
], ],
}, },
{
type: 'collapsible',
label: 'Tabs within Collapsible',
fields: [
{
type: 'tabs',
tabs: [
{
label: 'Nested Tab One',
description: 'Here is a description for a nested tab',
fields: [
{
name: 'textarea',
type: 'textarea',
},
],
},
{
label: 'Nested Tab Two',
description: 'Description for tab two',
fields: [
{
name: 'anotherText',
type: 'text',
required: true,
},
],
},
],
},
],
},
], ],
}; };
@@ -66,6 +98,8 @@ export const tabsDoc = {
], ],
text: 'This text will show up in the second tab input', text: 'This text will show up in the second tab input',
number: 12, number: 12,
textarea: 'Here is some text that goes in a textarea',
anotherText: 'Super tired of writing this text',
}; };
export default TabsFields; export default TabsFields;