Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/fds 116 - Set up onAction function for feature parity with Table #141

Merged
merged 9 commits into from
Feb 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,10 @@
"statusBarItem.hoverBackground": "#b4104a",
"titleBar.activeBackground": "#850c37",
"titleBar.activeForeground": "#e7e7e7",
"titleBar.inactiveBackground": "#90023A99",
"titleBar.inactiveBackground": "#850c3799",
"titleBar.inactiveForeground": "#e7e7e799",
"sideBarSectionHeader.background": "#90023A",
"sideBarSectionHeader.foreground": "#e7e7e7"
}
},
"peacock.color": "#850c37"
}
2 changes: 2 additions & 0 deletions docs/src/lib/MDX_COMPONENTS.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
Button,
Chat,
Dashboard,
Form,
JsonPlaceholder,
Table,
} from '@espressive/cascara';
Expand Down Expand Up @@ -48,6 +49,7 @@ const MDX_COMPONENTS = {
</ChatProvider>
),
Dashboard: (props) => <Dashboard {...props} />,
Form: (props) => <Form {...props} />,
JsonPlaceholder: (props) => <JsonPlaceholder {...props} />,
Table: (props) => <Table {...props} />,

Expand Down
3 changes: 2 additions & 1 deletion docs/src/pages/docs/[[...mdx]].js
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ export const getStaticProps = async ({ params }) => {

// We need to make sure this is only actual files and not a directory
// so we are filtering it to make sure the size of the file is not zero.
const mdxDirFiles = mdxDir.filter((file) => file.size > 0 && file);
const mdxDirFiles = mdxDir.filter(({ type }) => type !== 'directory');

// This needs to be async or it will blow up since `next-mdx-remote` is
// asyncrhonously getting all MDX files and rendering them to string.
Expand All @@ -160,6 +160,7 @@ export const getStaticProps = async ({ params }) => {
const mdxDirSource = await Promise.all(
mdxDirFiles.map(async (file) => {
const filePath = path.join(process.cwd(), file.path);

const { data, content } = matter(fs.readFileSync(filePath, 'utf8'));

const fileSource = await renderToString(content, {
Expand Down
4 changes: 2 additions & 2 deletions packages/cascara/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import JsonPlaceholder from './placeholders/JsonPlaceholder';
import Button from './ui/Button';
import Chat from './ui/Chat';
import Dashboard from './ui/Dashboard';
// import Form from './ui/Form';
import Form from './ui/Form';
import Table from './ui/Table';

export {
Expand All @@ -18,7 +18,7 @@ export {
Button,
Chat,
Dashboard,
// Form,
Form,
JsonPlaceholder,
Table,
};
17 changes: 14 additions & 3 deletions packages/cascara/src/modules/ActionButton/ActionButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,21 @@ const ActionButton = ({
label = 'ActionButton',
...rest
}) => {
const { isEditing, onAction, record } = useContext(ModuleContext);
const { data, isEditing, onAction, record } = useContext(ModuleContext);
const dataOrRecord = record || data;

const handleClick = ({ currentTarget }) => {
onAction(currentTarget, record);
const handleClick = (e) => {
e.preventDefault();
const {
currentTarget: { name },
} = e;

onAction(
{
name,
},
dataOrRecord
);
};

return isEditing ? null : (
Expand Down
6 changes: 4 additions & 2 deletions packages/cascara/src/modules/AllModules.fixture.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import FormProvider from '../ui/Form/context/FormProvider';
import tableStyles from '../ui/Table/Table.module.scss';
import {
ActionButton,
ActionEdit,
DataCheckbox,
DataEmail,
DataNumber,
Expand All @@ -15,6 +14,9 @@ import {
DataTextArea,
} from './';

import FormActionEdit from '../ui/Form/modules/ActionEdit';
// import TableActionEdit from '../ui/Table/modules/ActionEdit';

const lorem =
'Lorem ipsum dolor sit amet consectetur adipisicing elit. Autem hic mollitia, fuga ex architecto cumque accusamus tenetur qui odio quam tempora aliquam minima ipsum laborum?';

Expand Down Expand Up @@ -132,7 +134,7 @@ const AllModules = ({ data, dataConfig }) => {
<FormProvider>
<h2>Action Modules</h2>
<ActionButton />
<ActionEdit />
<FormActionEdit />
</FormProvider>

<h2>Table Presentation</h2>
Expand Down
3 changes: 2 additions & 1 deletion packages/cascara/src/modules/DataText/DataText.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const DataText = ({
attribute,
isEditable = true,
isLabeled = true,
isSecure,
label,
value,
...rest
Expand All @@ -41,7 +42,7 @@ const DataText = ({
id={label}
name={attribute || label}
ref={formMethods?.register}
type='text'
type={'text'}
/>
</label>
);
Expand Down
2 changes: 1 addition & 1 deletion packages/cascara/src/modules/ModuleError/ModuleError.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const ModuleError = ({ moduleName, moduleOptions }) => {
', '
)}]`;
// eslint-disable-next-line no-console
console.error(message);
// console.error(message);

return (
<div className={styles.Error} data-testid={'module-error'}>
Expand Down
4 changes: 0 additions & 4 deletions packages/cascara/src/modules/ModuleKeys.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
// Action Modules
import ActionButton from './ActionButton';
// import DownloadButton from './DownloadButton'
import ActionEdit from './ActionEdit';

// Data Modules
import DataCheckbox from './DataCheckbox';
Expand All @@ -14,8 +12,6 @@ import DataTextArea from './DataTextArea';

const actionModules = {
button: ActionButton,
// download: DownloadButton,
edit: ActionEdit,
};

const dataModules = {
Expand Down
2 changes: 0 additions & 2 deletions packages/cascara/src/modules/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { ModuleContext, ModuleProvider } from './context';

import ActionButton from './ActionButton';
import ActionEdit from './ActionEdit';
import DataCheckbox from './DataCheckbox';
import DataEmail from './DataEmail';
import DataNumber from './DataNumber';
Expand All @@ -13,7 +12,6 @@ import ModuleError from './ModuleError';

export {
ActionButton,
ActionEdit,
DataCheckbox,
DataEmail,
DataNumber,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@
import React from 'react';
import DataText from '../DataText';
import ActionButton from '../ActionButton';
import ActionEdit from '../ActionEdit';
import { Divider } from 'semantic-ui-react';
import AreaPlaceholder from '../../placeholders/AreaPlaceholder';
import FormProvider from '../../ui/Form/context/FormProvider';
import RowProvider from '../../ui/Table/context/RowProvider';
import TableProvider from '../../ui/Table/context/TableProvider';

import FormActionEdit from '../../ui/Form/modules/ActionEdit';
import TableActionEdit from '../../ui/Table/modules/ActionEdit';

const fakeTableData = [
{
defaultValue: 'green',
Expand All @@ -35,7 +37,7 @@ const FakeRow = ({ defaultValue, label, ...rest }) => (
>
<AreaPlaceholder color='green' label='RowProvider'>
<DataText label={label} value={defaultValue} />
<ActionEdit />
<TableActionEdit />
</AreaPlaceholder>
</RowProvider>
);
Expand Down Expand Up @@ -97,7 +99,7 @@ const ContextComposableActions = ({ data, dataConfig }) => {
}}
>
<ActionButton />
<ActionEdit />
<FormActionEdit />
<Divider clearing fitted hidden />
</div>
</AreaPlaceholder>
Expand All @@ -113,7 +115,7 @@ const ContextComposableActions = ({ data, dataConfig }) => {
>
<AreaPlaceholder color='pink' label='TableProvider'>
<DataText label='Table Level Module' value='Table' />
<ActionEdit />
<TableActionEdit />
{fakeTableData.map((row, i) => (
<FakeRow {...row} />
))}
Expand Down
4 changes: 2 additions & 2 deletions packages/cascara/src/private.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import {
ActionButton,
ActionEdit,
DataCheckbox,
DataEmail,
DataNumber,
Expand All @@ -13,10 +12,11 @@ import {
} from './modules';

import { ChatProvider } from './ui/Chat';
import ActionEdit from './ui/Table/modules/ActionEdit';

export {
ActionButton,
ActionEdit,
ActionButton,
ChatProvider,
DataCheckbox,
DataEmail,
Expand Down
79 changes: 68 additions & 11 deletions packages/cascara/src/ui/Form/Form.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, { useState } from 'react';
import pt from 'prop-types';
// import styles from './Form.module.scss';

Expand All @@ -7,10 +7,18 @@ import FormProvider from './context/FormProvider';
import ModuleError from '../../modules/ModuleError';

import { actionModules, dataModules } from '../../modules/ModuleKeys';
import { formModules } from './modules';
import { formActionModules, formModules } from './modules';
import ActionBar from './atoms/ActionBar';

const formDataModules = { ...formModules, ...dataModules };
const actionModuleOptions = Object.keys(actionModules);
const bundledActionModules = {
...actionModules,
...formActionModules, // Spread our component specific modules last just in case there is a conflict from globals
};
const formDataModules = {
...dataModules,
...formModules, // Spread our component specific modules last just in case there is a conflict from globals
};
const actionModuleOptions = Object.keys(bundledActionModules);
const dataModuleOptions = Object.keys(formDataModules);

const propTypes = {
Expand Down Expand Up @@ -55,9 +63,10 @@ const formFields = (display, data) => {
const { module, label, ...rest } = field;
const Module = dataModules[module];
const moduleValue = data[field.attribute];
const key = `${module}.${field.attribute}.${moduleValue}`;

return Module ? (
<Module {...rest} key={label} label={label} value={moduleValue} />
<Module {...rest} key={key} label={label} value={moduleValue} />
) : (
<ModuleError moduleName={module} moduleOptions={dataModuleOptions} />
);
Expand All @@ -66,15 +75,19 @@ const formFields = (display, data) => {
const renderFields = (fields) => fields.map((field) => renderField(field));

return display.map((field, i) => {
const { module } = field;
const { attribute, module, fields = [] } = field;

// Check to see if we have a form module, which will probably only be a FormRow
const FormModule = formModules[module];

const key = fields.reduce(
(key, { attribute }) => `${key}.${i}.${attribute}`,
`${attribute ? `field.${module}.${attribute}` : 'row'}`
);

return (
<ErrorBoundary>
<ErrorBoundary key={key}>
{Boolean(FormModule) ? (
// TODO: We should concat the form ID with this row index for a more robust key value
<FormModule {...field}>{renderFields(field.fields)}</FormModule>
) : (
renderField(field)
Expand All @@ -84,28 +97,72 @@ const formFields = (display, data) => {
});
};

const renderActions = (actions) =>
actions.map((action, id) => {
const { module, ...rest } = action;
const Action = bundledActionModules[module];

/**
* In certain predefined-action modules in which a label is not required, e.g. `edit`,
* the following unique key generation fails, as it relies on the label (content). */
const key = `${id}.${module}.${rest.label || module}`;

return Action ? (
<Action key={key} {...rest} />
) : (
<ModuleError
key={key}
moduleName={module}
moduleOptions={actionModuleOptions}
/>
);
});

const Form = ({
data,
dataConfig,
onAction,
onAction = () => {},
uniqueIdAttribute,
isEditable: incomingIsEditable,
isInitialEditing = false,
...rest
}) => {
const { display } = dataConfig;
const { actions = [], display } = dataConfig;
const renderedActions = renderActions(actions);
const isEditable =
typeof incomingIsEditable === 'undefined'
? Boolean(dataConfig?.actions?.find((action) => action.module === 'edit'))
: incomingIsEditable;

const [isEditing, setIsEtiding] = useState(() =>
!isEditable ? false : isInitialEditing
);

function enterEditMode(recordId) {
setIsEtiding(true);
}

function exitEditMode() {
setIsEtiding(false);
}

return (
<ErrorBoundary>
<FormProvider
value={{
data,
dataConfig,
isEditing: isInitialEditing,
enterEditMode,
exitEditMode,
isEditable,
isEditing,
onAction,
uniqueIdAttribute,
}}
{...rest}
>
{formFields(display, data)}
<ActionBar actions={renderedActions} />
</FormProvider>
</ErrorBoundary>
);
Expand Down
9 changes: 9 additions & 0 deletions packages/cascara/src/ui/Form/Form.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,15 @@
}
}

.FormActionBar {
margin: 0;
display: contents;

& > * {
margin-bottom: 1em;
}
}

// Need to standardize these breakpoints
@media (min-width: 720px) {
.FormRow {
Expand Down
Loading