Skip to content

Commit 63da6cb

Browse files
jeffibmjeffbonson
authored andcommitted
Basic drag and drop implementation
1 parent f9d74a6 commit 63da6cb

File tree

17 files changed

+1246
-2
lines changed

17 files changed

+1246
-2
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import React from 'react';
2+
import {
3+
CheckboxChecked32, RadioButtonChecked32, Time32, StringText32, TextSmallCaps32, CaretDown32, Tag32, Calendar32,
4+
} from '@carbon/icons-react';
5+
6+
export const dragItems = {
7+
COMPONENT: 'component',
8+
SECTION: 'section',
9+
FIELD: 'field',
10+
};
11+
12+
/** Data needed to render the dynamic components on the left hand side of the form. */
13+
export const dynamicComponents = [
14+
{ id: 1, title: 'Text Box', icon: <StringText32 /> },
15+
{ id: 2, title: 'Text Area', icon: <TextSmallCaps32 /> },
16+
{ id: 3, title: 'Check Box', icon: <CheckboxChecked32 /> },
17+
{ id: 4, title: 'Dropdown', icon: <CaretDown32 /> },
18+
{ id: 5, title: 'Radio Button', icon: <RadioButtonChecked32 /> },
19+
{ id: 6, title: 'Datepicker', icon: <Calendar32 /> },
20+
{ id: 7, title: 'Timepicker', icon: <Time32 /> },
21+
{ id: 8, title: 'Tag Control', icon: <Tag32 /> },
22+
];
23+
24+
/** Function which returens the default data for a section under a tab. */
25+
export const defaultSectionContents = (tabId, sectionId) => ({
26+
tabId,
27+
sectionId,
28+
title: 'New Section',
29+
fields: [],
30+
order: 0,
31+
});
32+
33+
/** Function which returns the default data for a tab with default section. */
34+
export const defaultTabContents = (tabId) => ({
35+
tabId,
36+
name: tabId === 0 ? __('New Tab') : __(`New Tab ${tabId}`),
37+
sections: [defaultSectionContents(tabId, 0)],
38+
});
39+
40+
/** Function to create a dummy tab for creating new tabs. */
41+
export const createNewTab = () => ({
42+
tabId: 'new',
43+
name: 'Create Tab',
44+
sections: [],
45+
});
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
import { dragItems } from './data';
4+
5+
/** Component to render the components list vertically on left side.
6+
* Components can be used to drag and drop into the tab Contents */
7+
const DynamicComponentChooser = ({ list, onDragStartComponent }) => (
8+
<div className="components-list-wrapper">
9+
{
10+
list.map((item, index) => (
11+
<div
12+
title={`Drag and Drop a ${item.title.toLowerCase()} to any section`}
13+
id={item.id}
14+
className="component-item-wrapper"
15+
draggable="true"
16+
onDragStart={(event) => onDragStartComponent(event, dragItems.COMPONENT)}
17+
key={index.toString()}
18+
>
19+
<div className="component-item">
20+
{item.icon}
21+
{item.title}
22+
</div>
23+
</div>
24+
))
25+
}
26+
</div>
27+
);
28+
29+
DynamicComponentChooser.propTypes = {
30+
list: PropTypes.arrayOf(PropTypes.any).isRequired,
31+
onDragStartComponent: PropTypes.func.isRequired,
32+
};
33+
34+
export default DynamicComponentChooser;
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import React, { useState } from 'react';
2+
import PropTypes from 'prop-types';
3+
import { Button } from 'carbon-components-react';
4+
import { Close16, Edit16 } from '@carbon/icons-react';
5+
import { SD_ACTIONS } from './helper';
6+
import EditFieldModal from './edit-field-modal';
7+
8+
/** Component to render a Field. */
9+
const DynamicFieldActions = ({ componentId, dynamicFieldAction, fieldConfiguration }) => {
10+
const [{ showModal }, setState] = useState({ showModal: false });
11+
12+
const onModalHide = () => setState((state) => ({ ...state, showModal: false }));
13+
const onModalShow = () => setState((state) => ({ ...state, showModal: true }));
14+
const onModalApply = () => setState((state) => ({ ...state, showModal: false }));
15+
16+
const renderEditButton = () => (
17+
<Button
18+
renderIcon={Edit16}
19+
kind="ghost"
20+
iconDescription={__('Edit')}
21+
onClick={onModalShow}
22+
onKeyPress={(event) => dynamicFieldAction(SD_ACTIONS.field.edit, event)}
23+
title={__('Edit field')}
24+
/>
25+
);
26+
27+
const renderRemoveButton = () => (
28+
<Button
29+
renderIcon={Close16}
30+
kind="ghost"
31+
iconDescription={__('Remove')}
32+
onClick={(event) => dynamicFieldAction(SD_ACTIONS.field.delete, event)}
33+
onKeyPress={(event) => dynamicFieldAction(SD_ACTIONS.field.delete, event)}
34+
title={__('Remove field')}
35+
/>
36+
);
37+
38+
const renderEditFieldModal = () => (
39+
showModal && (
40+
<EditFieldModal
41+
componentId={componentId}
42+
fieldConfiguration={fieldConfiguration}
43+
showModal={showModal}
44+
onModalHide={onModalHide}
45+
onModalApply={onModalApply}
46+
/>
47+
)
48+
);
49+
50+
return (
51+
<div className="dynamic-form-field-actions">
52+
{renderEditButton()}
53+
{renderRemoveButton()}
54+
{renderEditFieldModal()}
55+
</div>
56+
);
57+
};
58+
59+
DynamicFieldActions.propTypes = {
60+
componentId: PropTypes.number.isRequired,
61+
dynamicFieldAction: PropTypes.func.isRequired,
62+
fieldConfiguration: PropTypes.arrayOf(PropTypes.any).isRequired,
63+
};
64+
65+
export default DynamicFieldActions;
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
import DynamicTextInput from './dynamic-fields/dynamic-text-input';
4+
import DynamicTextArea from './dynamic-fields/dynamic-text-area';
5+
import { dynamicFieldDataProps } from './helper';
6+
/** Component to render a Field. */
7+
const DynamicField = ({ fieldData, onFieldAction }) => {
8+
const fieldSelector = (fieldData) => {
9+
switch (fieldData.field.componentId) {
10+
case 1:
11+
return <DynamicTextInput dynamicFieldData={fieldData} onFieldAction={(newFieldData) => onFieldAction(newFieldData)} />;
12+
case 2:
13+
return <DynamicTextArea dynamicFieldData={fieldData} onFieldAction={(newFieldData) => onFieldAction(newFieldData)} />;
14+
case 3:
15+
return fieldData.field.componentId;
16+
case 4:
17+
return fieldData.field.componentId;
18+
case 5:
19+
return fieldData.field.componentId;
20+
case 6:
21+
return fieldData.field.componentId;
22+
case 7:
23+
return fieldData.field.componentId;
24+
case 8:
25+
return fieldData.field.componentId;
26+
case 9:
27+
return fieldData.field.componentId;
28+
default:
29+
return <DynamicTextInput dynamicFieldData={fieldData} onFieldAction={(newFieldData) => onFieldAction(newFieldData)} />;
30+
}
31+
};
32+
33+
return (
34+
<>
35+
{
36+
fieldSelector(fieldData)
37+
}
38+
</>
39+
);
40+
};
41+
42+
DynamicField.propTypes = {
43+
fieldData: dynamicFieldDataProps.isRequired,
44+
onFieldAction: PropTypes.func.isRequired,
45+
};
46+
47+
export default DynamicField;
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { componentTypes } from '@data-driven-forms/react-form-renderer';
2+
3+
export const dynamicFields = {
4+
defaultValue: { label: __('Default value'), field: componentTypes.TEXT_FIELD },
5+
dynamic: { label: __('Dynamic'), field: componentTypes.SWITCH },
6+
entries: { label: __('Entries'), field: 'component', component: componentTypes.SELECT },
7+
entryPoint: { label: __('Entry point'), field: componentTypes.SELECT },
8+
fieldsToRefresh: { label: __('Fields to refresh'), field: componentTypes.SELECT },
9+
help: { label: __('Help'), field: componentTypes.TEXTAREA },
10+
label: { label: __('Label'), field: componentTypes.TEXT_FIELD },
11+
loadOnInit: { label: __('Load values on init'), field: componentTypes.SWITCH },
12+
multiselect: { label: __('Multiselect'), field: componentTypes.SWITCH },
13+
name: { label: __('Name'), field: componentTypes.TEXT_FIELD },
14+
protected: { label: __('Protected'), field: componentTypes.SWITCH },
15+
reconfigurable: { label: __('Reconfigurable'), field: componentTypes.SWITCH },
16+
required: { label: __('Required'), field: componentTypes.SWITCH },
17+
readOnly: { label: __('Read only'), field: componentTypes.SWITCH },
18+
showRefresh: { label: __('Show refresh button'), field: componentTypes.SWITCH },
19+
sortBy: { label: __('Sort by'), field: componentTypes.SELECT },
20+
sortOrder: { label: __('Sort order'), field: componentTypes.SELECT },
21+
showPastDates: { label: __('Show Past Dates'), field: componentTypes.SWITCH },
22+
singleValue: { label: __('Single value'), field: componentTypes.SWITCH },
23+
visible: { label: __('Visible'), field: componentTypes.SWITCH },
24+
valueType: { label: __('Value type'), field: componentTypes.SELECT },
25+
validation: { label: __('Validation'), field: componentTypes.SWITCH },
26+
validator: { label: __('Validator'), field: componentTypes.TEXT_FIELD },
27+
};
28+
29+
export const fieldTab = {
30+
fieldInformation: __('Field Information'),
31+
options: __('Options'),
32+
advanced: __('Advanced'),
33+
overridableOptions: __('Overridable Options'),
34+
};
35+
36+
export const fieldInformation = () => ({
37+
name: fieldTab.fieldInformation,
38+
fields: [
39+
dynamicFields.label,
40+
dynamicFields.name,
41+
dynamicFields.help,
42+
dynamicFields.dynamic, // not there for tag control.
43+
],
44+
});
45+
46+
export const advanced = () => ({
47+
name: fieldTab.advanced,
48+
fields: [dynamicFields.reconfigurable],
49+
});
50+
51+
export const overridableOptions = () => ({
52+
name: fieldTab.overridableOptions,
53+
fields: [
54+
dynamicFields.readOnly,
55+
dynamicFields.visible,
56+
dynamicFields.defaultValue,
57+
],
58+
});
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
import { TextArea, FormLabel } from 'carbon-components-react';
4+
import { dynamicFieldDataProps, SD_ACTIONS } from '../helper';
5+
import DynamicFieldActions from '../dynamic-field-actions';
6+
import {
7+
fieldInformation, advanced, overridableOptions, fieldTab, dynamicFields,
8+
} from './dynamic-field-configuration';
9+
10+
/** Component to render a Field. */
11+
const DynamicTextArea = ({ dynamicFieldData: { section, field, fieldPosition }, onFieldAction }) => {
12+
const { tabId, sectionId } = section;
13+
const fieldActions = (event, type) => onFieldAction({
14+
event,
15+
fieldPosition,
16+
type,
17+
});
18+
19+
const ordinaryTextAreaOptions = () => ([
20+
dynamicFields.defaultValue,
21+
dynamicFields.required,
22+
dynamicFields.readOnly,
23+
dynamicFields.visible,
24+
dynamicFields.validation,
25+
dynamicFields.validator,
26+
dynamicFields.fieldsToRefresh,
27+
]);
28+
29+
const dynamicTextAreaOptions = () => ([
30+
dynamicFields.entryPoint,
31+
dynamicFields.showRefresh,
32+
dynamicFields.loadOnInit,
33+
dynamicFields.required,
34+
dynamicFields.validation,
35+
dynamicFields.validator,
36+
dynamicFields.fieldsToRefresh,
37+
]);
38+
39+
const textAreaOptions = (dynamic) => ({
40+
name: fieldTab.options,
41+
fields: dynamic ? dynamicTextAreaOptions() : ordinaryTextAreaOptions(),
42+
});
43+
44+
const textAreaEditFields = (dynamic) => {
45+
const tabs = [
46+
fieldInformation(),
47+
textAreaOptions(dynamic),
48+
advanced(),
49+
];
50+
if (dynamic) {
51+
tabs.push(overridableOptions());
52+
}
53+
return tabs;
54+
};
55+
56+
return (
57+
<div className="dynamic-form-field">
58+
<div className="dynamic-form-field-item">
59+
<FormLabel>
60+
Text Area
61+
</FormLabel>
62+
<TextArea
63+
id={`tab-${tabId}-section-${sectionId}-field-${fieldPosition}-text-area`}
64+
labelText={__('Text Area')}
65+
hideLabel
66+
placeholder={__('Text Area')}
67+
name={`tab-${tabId}-section-${sectionId}-field-${fieldPosition}-text-area`}
68+
value="default text area value"
69+
title={__('Text Area')}
70+
onChange={(event) => fieldActions(event, SD_ACTIONS.textAreaOnChange)}
71+
/>
72+
</div>
73+
<DynamicFieldActions
74+
componentId={field.componentId}
75+
dynamicFieldAction={(action) => console.log(action)}
76+
fieldConfiguration={textAreaEditFields(false)}
77+
/>
78+
</div>
79+
);
80+
};
81+
82+
DynamicTextArea.propTypes = {
83+
dynamicFieldData: dynamicFieldDataProps.isRequired,
84+
onFieldAction: PropTypes.func.isRequired,
85+
};
86+
87+
export default DynamicTextArea;

0 commit comments

Comments
 (0)