feat: finishes tabs field
This commit is contained in:
4
.vscode/launch.json
vendored
4
.vscode/launch.json
vendored
@@ -31,7 +31,7 @@
|
||||
"env": {
|
||||
"BABEL_ENV": "development"
|
||||
},
|
||||
"program": "${workspaceFolder}/test/dev/index.js",
|
||||
"program": "${workspaceFolder}/test/dev.js",
|
||||
"skipFiles": [
|
||||
"<node_internals>/**"
|
||||
],
|
||||
@@ -39,7 +39,7 @@
|
||||
"--nolazy"
|
||||
],
|
||||
"args": [
|
||||
"e2e/fields"
|
||||
"fields"
|
||||
]
|
||||
},
|
||||
]
|
||||
|
||||
@@ -2,8 +2,11 @@ import React from 'react';
|
||||
import { Props, isComponent } from './types';
|
||||
import './index.scss';
|
||||
|
||||
const baseClass = 'field-description';
|
||||
|
||||
const FieldDescription: React.FC<Props> = (props) => {
|
||||
const {
|
||||
className,
|
||||
description,
|
||||
value,
|
||||
} = props;
|
||||
@@ -17,7 +20,10 @@ const FieldDescription: React.FC<Props> = (props) => {
|
||||
if (description) {
|
||||
return (
|
||||
<div
|
||||
className="field-description"
|
||||
className={[
|
||||
baseClass,
|
||||
className,
|
||||
].filter(Boolean).join(' ')}
|
||||
>
|
||||
{typeof description === 'function' ? description({ value }) : description}
|
||||
</div>
|
||||
|
||||
@@ -9,6 +9,7 @@ export type Description = string | DescriptionFunction | DescriptionComponent
|
||||
export type Props = {
|
||||
description?: Description
|
||||
value?: unknown;
|
||||
className?: string
|
||||
}
|
||||
|
||||
export function isComponent(description: Description): description is DescriptionComponent {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { Props } from './types';
|
||||
import { fieldAffectsData } from '../../../../../fields/config/types';
|
||||
import FieldDescription from '../../FieldDescription';
|
||||
import toKebabCase from '../../../../../utilities/toKebabCase';
|
||||
import { useCollapsible } from '../../../elements/Collapsible/provider';
|
||||
|
||||
import './index.scss';
|
||||
|
||||
@@ -22,6 +23,7 @@ const TabsField: React.FC<Props> = (props) => {
|
||||
},
|
||||
} = props;
|
||||
|
||||
const isWithinCollapsible = useCollapsible();
|
||||
const [active, setActive] = useState(0);
|
||||
|
||||
const activeTab = tabs[active];
|
||||
@@ -30,6 +32,7 @@ const TabsField: React.FC<Props> = (props) => {
|
||||
<div className={[
|
||||
className,
|
||||
baseClass,
|
||||
isWithinCollapsible && `${baseClass}--within-collapsible`,
|
||||
].filter(Boolean).join(' ')}
|
||||
>
|
||||
<div className={`${baseClass}__tabs`}>
|
||||
@@ -38,7 +41,10 @@ const TabsField: React.FC<Props> = (props) => {
|
||||
<button
|
||||
key={i}
|
||||
type="button"
|
||||
className={`${baseClass}__tab`}
|
||||
className={[
|
||||
`${baseClass}__tab-button`,
|
||||
active === i && `${baseClass}__tab-button--active`,
|
||||
].filter(Boolean).join(' ')}
|
||||
onClick={() => setActive(i)}
|
||||
>
|
||||
{tab.label}
|
||||
@@ -54,6 +60,7 @@ const TabsField: React.FC<Props> = (props) => {
|
||||
].join(' ')}
|
||||
>
|
||||
<FieldDescription
|
||||
className={`${baseClass}__description`}
|
||||
description={activeTab.description}
|
||||
/>
|
||||
<RenderFields
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
margin: 0 0 $baseline;
|
||||
font-size: base(.75);
|
||||
line-height: 1.5;
|
||||
letter-spacing: -.375px;
|
||||
}
|
||||
|
||||
%h5 {
|
||||
|
||||
@@ -304,48 +304,44 @@ const fieldToSchemaMap = {
|
||||
};
|
||||
},
|
||||
row: (field: RowField, fields: SchemaDefinition, config: SanitizedConfig, buildSchemaOptions: BuildSchemaOptions): SchemaDefinition => {
|
||||
const newFields = { ...fields };
|
||||
let newFields = { ...fields };
|
||||
|
||||
field.fields.forEach((subField: Field) => {
|
||||
const fieldSchemaMap: FieldSchemaGenerator = fieldToSchemaMap[subField.type];
|
||||
const fieldSchema: FieldSchemaGenerator = fieldToSchemaMap[subField.type];
|
||||
|
||||
if (fieldSchemaMap && fieldAffectsData(subField)) {
|
||||
const fieldSchema = fieldSchemaMap(subField, fields, config, buildSchemaOptions);
|
||||
newFields[subField.name] = fieldSchema[subField.name];
|
||||
if (fieldSchema) {
|
||||
newFields = fieldSchema(subField, newFields, config, buildSchemaOptions);
|
||||
}
|
||||
});
|
||||
|
||||
return newFields;
|
||||
},
|
||||
collapsible: (field: CollapsibleField, fields: SchemaDefinition, config: SanitizedConfig, buildSchemaOptions: BuildSchemaOptions): SchemaDefinition => {
|
||||
const newFields = { ...fields };
|
||||
let newFields = { ...fields };
|
||||
|
||||
field.fields.forEach((subField: Field) => {
|
||||
const fieldSchemaMap: FieldSchemaGenerator = fieldToSchemaMap[subField.type];
|
||||
const fieldSchema: FieldSchemaGenerator = fieldToSchemaMap[subField.type];
|
||||
|
||||
if (fieldSchemaMap && fieldAffectsData(subField)) {
|
||||
const fieldSchema = fieldSchemaMap(subField, fields, config, buildSchemaOptions);
|
||||
newFields[subField.name] = fieldSchema[subField.name];
|
||||
if (fieldSchema) {
|
||||
newFields = fieldSchema(subField, newFields, config, buildSchemaOptions);
|
||||
}
|
||||
});
|
||||
|
||||
return newFields;
|
||||
},
|
||||
tabs: (field: TabsField, fields: SchemaDefinition, config: SanitizedConfig, buildSchemaOptions: BuildSchemaOptions): SchemaDefinition => {
|
||||
const newFields = { ...fields };
|
||||
let newFields = { ...fields };
|
||||
|
||||
field.tabs.forEach((tab) => {
|
||||
tab.fields.forEach((subField: Field) => {
|
||||
const fieldSchemaMap: FieldSchemaGenerator = fieldToSchemaMap[subField.type];
|
||||
const fieldSchema: FieldSchemaGenerator = fieldToSchemaMap[subField.type];
|
||||
|
||||
if (fieldSchemaMap && fieldAffectsData(subField)) {
|
||||
const fieldSchema = fieldSchemaMap(subField, fields, config, buildSchemaOptions);
|
||||
newFields[subField.name] = fieldSchema[subField.name];
|
||||
if (fieldSchema) {
|
||||
newFields = fieldSchema(subField, newFields, config, buildSchemaOptions);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
return newFields;
|
||||
},
|
||||
array: (field: ArrayField, fields: SchemaDefinition, config: SanitizedConfig, buildSchemaOptions: BuildSchemaOptions) => {
|
||||
|
||||
@@ -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',
|
||||
number: 12,
|
||||
textarea: 'Here is some text that goes in a textarea',
|
||||
anotherText: 'Super tired of writing this text',
|
||||
};
|
||||
|
||||
export default TabsFields;
|
||||
|
||||
Reference in New Issue
Block a user