@atlaskit/editor-plugin-extension
Version:
editor-plugin-extension plugin for @atlaskit/editor-core
252 lines (250 loc) • 8.86 kB
JavaScript
import _extends from "@babel/runtime/helpers/extends";
import _defineProperty from "@babel/runtime/helpers/defineProperty";
/**
* @jsxRuntime classic
* @jsx jsx
*/
import React, { Fragment } from 'react';
// eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
import { css, jsx } from '@emotion/react';
import { injectIntl } from 'react-intl';
import Button from '@atlaskit/button/new';
import { configPanelMessages as messages } from '@atlaskit/editor-common/extensions';
import Heading from '@atlaskit/heading';
import AddCircleIcon from '@atlaskit/icon/core/add';
// eslint-disable-next-line @atlaskit/design-system/no-emotion-primitives -- to be migrated to @atlaskit/primitives/compiled – go/akcss
import { Box, Text, xcss } from '@atlaskit/primitives';
import SectionMessage from '@atlaskit/section-message';
import Select from '@atlaskit/select';
import { getNameFromDuplicateField, isDuplicateField } from '../utils';
const actionsWrapperStyles = css({
borderTop: `${"var(--ds-border-width, 1px)"} solid ${"var(--ds-border, #0B120E24)"}`,
marginTop: "var(--ds-space-200, 16px)",
paddingTop: "var(--ds-space-200, 16px)"
});
const populateFromParameters = (parameters, fields) => {
if (Object.keys(parameters).length) {
const keys = Object.keys(parameters);
const existingFieldKeys = keys.filter(key => fields.find(field => field.name === getNameFromDuplicateField(key)));
if (existingFieldKeys.length > 0) {
return existingFieldKeys;
}
}
};
const populateFromRequired = fields => {
return fields.filter(field => field.isRequired).map(field => field.name);
};
const getInitialFields = (parameters = {}, fields, isDynamic) => {
if (!isDynamic) {
return new Set(fields.map(field => field.name));
}
const dynamicFields = [];
const fromRequired = populateFromRequired(fields);
if (fromRequired) {
dynamicFields.push(...fromRequired);
}
const fromParameters = populateFromParameters(parameters, fields);
if (fromParameters) {
dynamicFields.push(...fromParameters);
}
if (dynamicFields.length === 0 && Array.isArray(fields) && fields.length > 0) {
dynamicFields.push(fields[0].name);
}
return new Set(dynamicFields);
};
// eslint-disable-next-line @repo/internal/react/no-class-components
class FieldsetField extends React.Component {
constructor(props) {
super(props);
_defineProperty(this, "getSelectedFields", visibleFields => {
const {
field
} = this.props;
return [...visibleFields].map(fieldName => {
const originalFieldDef = field.fields.find(field => field.name === getNameFromDuplicateField(fieldName));
const fieldDef = {
...originalFieldDef,
name: fieldName
};
// for duplicate fields we only want the first one to actually be required
if (originalFieldDef.name !== fieldName && fieldDef.isRequired === true) {
fieldDef.isRequired = false;
}
return fieldDef;
});
});
_defineProperty(this, "getSelectOptions", visibleFields => {
const {
field
} = this.props;
return field.fields.filter(field => field.allowDuplicates || !visibleFields.has(field.name)).map(field => ({
value: field.name,
label: field.label
}));
});
_defineProperty(this, "setIsAdding", value => {
this.setState(state => ({
...state,
isAdding: value
}));
});
_defineProperty(this, "setCurrentParameters", parameters => {
this.setState(state => ({
...state,
currentParameters: parameters
}),
// callback required so autosave can be triggered on
// the right moment if fields are being removed
() => this.props.onFieldChange(this.props.field.name, true));
});
_defineProperty(this, "setVisibleFields", fields => {
this.setState(state => ({
...state,
visibleFields: fields,
selectedFields: this.getSelectedFields(fields),
selectOptions: this.getSelectOptions(fields)
}));
});
_defineProperty(this, "onSelectItem", option => {
const {
visibleFields
} = this.state;
let newItem = option.value;
const duplicates = [...visibleFields].filter(field => getNameFromDuplicateField(field) === newItem);
if (duplicates.length > 0) {
newItem += `:${duplicates.length}`;
}
this.setVisibleFields(new Set([...visibleFields, newItem]));
this.setIsAdding(false);
});
_defineProperty(this, "onClickRemove", fieldName => {
const {
visibleFields,
currentParameters
} = this.state;
visibleFields.delete(fieldName);
this.setVisibleFields(new Set(visibleFields));
const newParameters = {
...currentParameters
};
delete newParameters[fieldName];
// if any there are duplicate fields that come after the one removed, we want to reduce their
// duplicate index eg. label:2 -> label:1
if (isDuplicateField(fieldName)) {
const [key, idx] = fieldName.split(':');
let currentIdx = +idx;
while (currentParameters[`${key}:${currentIdx + 1}`]) {
newParameters[`${key}:${currentIdx}`] = currentParameters[`${key}:${currentIdx + 1}`];
currentIdx++;
}
delete newParameters[`${key}:${currentIdx}`];
}
this.setCurrentParameters(newParameters);
});
_defineProperty(this, "renderActions", () => {
const {
intl
} = this.props;
const {
selectOptions,
isAdding
} = this.state;
if (selectOptions.length === 0) {
return null;
}
return jsx(React.Fragment, null, isAdding ? jsx(Select, {
testId: "field-picker",
defaultMenuIsOpen: true,
autoFocus: true,
placeholder: intl.formatMessage(messages.addField),
options: selectOptions
// eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
,
onChange: option => {
if (option) {
this.onSelectItem(option);
}
}
}) : jsx(Button, {
testId: "add-more",
appearance: "subtle"
// eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
,
iconBefore: iconProps => jsx(AddCircleIcon
// Ignored via go/ees005
// eslint-disable-next-line react/jsx-props-no-spreading
, _extends({}, iconProps, {
spacing: "none",
label: intl.formatMessage(messages.addField)
}))
// eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
,
onClick: () => this.setIsAdding(true)
}, intl.formatMessage(messages.addField)));
});
const initialFields = getInitialFields(props.parameters, props.field.fields, props.field.options.isDynamic);
this.state = {
isAdding: false,
currentParameters: props.parameters || {},
visibleFields: initialFields,
selectedFields: this.getSelectedFields(initialFields),
selectOptions: this.getSelectOptions(initialFields)
};
}
render() {
const {
name,
field,
extensionManifest,
onFieldChange,
firstVisibleFieldName,
error,
formComponent: FormComponent
} = this.props;
const {
label,
options
} = field;
const {
selectedFields,
currentParameters,
visibleFields
} = this.state;
const children = this.renderActions();
return jsx(Fragment, null, error && jsx(FieldsetError, {
message: error
}), jsx("div", null, (options === null || options === void 0 ? void 0 : options.showTitle) && jsx(Heading, {
size: "xsmall"
}, label), jsx(FormComponent, {
fields: selectedFields,
parentName: name,
extensionManifest: extensionManifest,
parameters: currentParameters,
canRemoveFields: field.options.isDynamic && visibleFields.size > 1,
onClickRemove: this.onClickRemove,
onFieldChange: onFieldChange,
firstVisibleFieldName: firstVisibleFieldName,
isDisabled: field.isDisabled
}), children && jsx("div", {
css: actionsWrapperStyles,
"data-testId": "fieldset-actions"
}, children)));
}
}
function FieldsetError({
message
}) {
return jsx(Box, {
xcss: sectionMessageWrapperStyles
}, jsx(SectionMessage, {
appearance: "error"
}, jsx(Text, {
as: "p"
}, message)));
}
const sectionMessageWrapperStyles = xcss({
marginBottom: 'space.300'
});
// eslint-disable-next-line @typescript-eslint/ban-types
const _default_1 = injectIntl(FieldsetField);
export default _default_1;