attempting to add a theme w/ burnettk cullerton
This commit is contained in:
parent
f838e11759
commit
2c3e9760a6
|
@ -19,6 +19,7 @@
|
|||
"@ginkgo-bioworks/react-json-schema-form-builder": "^2.9.0",
|
||||
"@monaco-editor/react": "^4.4.5",
|
||||
"@rjsf/core": "^4.2.0",
|
||||
"@rjsf/utils": "^5.0.0-beta.13",
|
||||
"@tanstack/react-table": "^8.2.2",
|
||||
"@testing-library/jest-dom": "^5.16.4",
|
||||
"@testing-library/react": "^13.3.0",
|
||||
|
@ -4551,6 +4552,42 @@
|
|||
"react": ">=16 || >=17"
|
||||
}
|
||||
},
|
||||
"node_modules/@rjsf/utils": {
|
||||
"version": "5.0.0-beta.13",
|
||||
"resolved": "https://registry.npmjs.org/@rjsf/utils/-/utils-5.0.0-beta.13.tgz",
|
||||
"integrity": "sha512-hWWWFD2ifjSOhqWueML4OHrZe2HW5pE2nfKGhCObFbwtggHoQlj64xDBsJ1qfUG8DGvCHztJQ/sKIaOvXnpt7w==",
|
||||
"dependencies": {
|
||||
"json-schema-merge-allof": "^0.8.1",
|
||||
"jsonpointer": "^5.0.1",
|
||||
"lodash": "^4.17.15",
|
||||
"lodash-es": "^4.17.15",
|
||||
"react-is": "^18.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.14.0 || >=17"
|
||||
}
|
||||
},
|
||||
"node_modules/@rjsf/utils/node_modules/json-schema-merge-allof": {
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-merge-allof/-/json-schema-merge-allof-0.8.1.tgz",
|
||||
"integrity": "sha512-CTUKmIlPJbsWfzRRnOXz+0MjIqvnleIXwFTzz+t9T86HnYX/Rozria6ZVGLktAU9e+NygNljveP+yxqtQp/Q4w==",
|
||||
"dependencies": {
|
||||
"compute-lcm": "^1.1.2",
|
||||
"json-schema-compare": "^0.2.2",
|
||||
"lodash": "^4.17.20"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@rjsf/utils/node_modules/react-is": {
|
||||
"version": "18.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
|
||||
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
|
||||
},
|
||||
"node_modules/@rollup/plugin-babel": {
|
||||
"version": "5.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
|
||||
|
@ -34221,6 +34258,35 @@
|
|||
"react-is": "16.9.0"
|
||||
}
|
||||
},
|
||||
"@rjsf/utils": {
|
||||
"version": "5.0.0-beta.13",
|
||||
"resolved": "https://registry.npmjs.org/@rjsf/utils/-/utils-5.0.0-beta.13.tgz",
|
||||
"integrity": "sha512-hWWWFD2ifjSOhqWueML4OHrZe2HW5pE2nfKGhCObFbwtggHoQlj64xDBsJ1qfUG8DGvCHztJQ/sKIaOvXnpt7w==",
|
||||
"requires": {
|
||||
"json-schema-merge-allof": "^0.8.1",
|
||||
"jsonpointer": "^5.0.1",
|
||||
"lodash": "^4.17.15",
|
||||
"lodash-es": "^4.17.15",
|
||||
"react-is": "^18.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"json-schema-merge-allof": {
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-merge-allof/-/json-schema-merge-allof-0.8.1.tgz",
|
||||
"integrity": "sha512-CTUKmIlPJbsWfzRRnOXz+0MjIqvnleIXwFTzz+t9T86HnYX/Rozria6ZVGLktAU9e+NygNljveP+yxqtQp/Q4w==",
|
||||
"requires": {
|
||||
"compute-lcm": "^1.1.2",
|
||||
"json-schema-compare": "^0.2.2",
|
||||
"lodash": "^4.17.20"
|
||||
}
|
||||
},
|
||||
"react-is": {
|
||||
"version": "18.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
|
||||
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@rollup/plugin-babel": {
|
||||
"version": "5.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
"@ginkgo-bioworks/react-json-schema-form-builder": "^2.9.0",
|
||||
"@monaco-editor/react": "^4.4.5",
|
||||
"@rjsf/core": "^4.2.0",
|
||||
"@rjsf/utils": "^5.0.0-beta.13",
|
||||
"@tanstack/react-table": "^8.2.2",
|
||||
"@testing-library/jest-dom": "^5.16.4",
|
||||
"@testing-library/react": "^13.3.0",
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import { useContext, useEffect, useState } from 'react';
|
||||
import { Link, useNavigate, useParams } from 'react-router-dom';
|
||||
import Form from '@rjsf/core';
|
||||
// import Form from '@rjsf/core';
|
||||
// @ts-ignore
|
||||
import { Button, Stack } from '@carbon/react';
|
||||
|
||||
import ReactMarkdown from 'react-markdown';
|
||||
import remarkGfm from 'remark-gfm';
|
||||
import Form from '../themes';
|
||||
import HttpService from '../services/HttpService';
|
||||
import ErrorContext from '../contexts/ErrorContext';
|
||||
import { modifyProcessModelPath } from '../helpers';
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
import React from "react";
|
||||
import { IconButtonProps } from "@rjsf/utils";
|
||||
import Button from "react-bootstrap/Button";
|
||||
import { BsPlus } from "@react-icons/all-files/bs/BsPlus";
|
||||
|
||||
const AddButton: React.ComponentType<IconButtonProps> = ({
|
||||
uiSchema,
|
||||
...props
|
||||
}) => (
|
||||
<Button
|
||||
{...props}
|
||||
style={{ width: "100%" }}
|
||||
className={`ml-1 ${props.className}`}
|
||||
title="Add Item"
|
||||
>
|
||||
<BsPlus />
|
||||
</Button>
|
||||
);
|
||||
|
||||
export default AddButton;
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from "./AddButton";
|
||||
export * from "./AddButton";
|
|
@ -0,0 +1,77 @@
|
|||
import React, { CSSProperties } from "react";
|
||||
import Row from "react-bootstrap/Row";
|
||||
import Col from "react-bootstrap/Col";
|
||||
import { ArrayFieldTemplateItemType } from "@rjsf/utils";
|
||||
|
||||
const ArrayFieldItemTemplate = (props: ArrayFieldTemplateItemType) => {
|
||||
const {
|
||||
children,
|
||||
disabled,
|
||||
hasToolbar,
|
||||
hasMoveDown,
|
||||
hasMoveUp,
|
||||
hasRemove,
|
||||
index,
|
||||
onDropIndexClick,
|
||||
onReorderClick,
|
||||
readonly,
|
||||
registry,
|
||||
uiSchema,
|
||||
} = props;
|
||||
const { MoveDownButton, MoveUpButton, RemoveButton } =
|
||||
registry.templates.ButtonTemplates;
|
||||
const btnStyle: CSSProperties = {
|
||||
flex: 1,
|
||||
paddingLeft: 6,
|
||||
paddingRight: 6,
|
||||
fontWeight: "bold",
|
||||
};
|
||||
return (
|
||||
<div>
|
||||
<Row className="mb-2 d-flex align-items-center">
|
||||
<Col xs="9" lg="9">
|
||||
{children}
|
||||
</Col>
|
||||
<Col xs="3" lg="3" className="py-4">
|
||||
{hasToolbar && (
|
||||
<div className="d-flex flex-row">
|
||||
{(hasMoveUp || hasMoveDown) && (
|
||||
<div className="m-0 p-0">
|
||||
<MoveUpButton
|
||||
className="array-item-move-up"
|
||||
style={btnStyle}
|
||||
disabled={disabled || readonly || !hasMoveUp}
|
||||
onClick={onReorderClick(index, index - 1)}
|
||||
uiSchema={uiSchema}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{(hasMoveUp || hasMoveDown) && (
|
||||
<div className="m-0 p-0">
|
||||
<MoveDownButton
|
||||
style={btnStyle}
|
||||
disabled={disabled || readonly || !hasMoveDown}
|
||||
onClick={onReorderClick(index, index + 1)}
|
||||
uiSchema={uiSchema}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{hasRemove && (
|
||||
<div className="m-0 p-0">
|
||||
<RemoveButton
|
||||
style={btnStyle}
|
||||
disabled={disabled || readonly}
|
||||
onClick={onDropIndexClick(index)}
|
||||
uiSchema={uiSchema}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ArrayFieldItemTemplate;
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from "./ArrayFieldItemTemplate";
|
||||
export * from "./ArrayFieldItemTemplate";
|
|
@ -0,0 +1,97 @@
|
|||
import React from "react";
|
||||
import Row from "react-bootstrap/Row";
|
||||
import Col from "react-bootstrap/Col";
|
||||
import Container from "react-bootstrap/Container";
|
||||
import {
|
||||
ArrayFieldTemplateItemType,
|
||||
ArrayFieldTemplateProps,
|
||||
getTemplate,
|
||||
getUiOptions,
|
||||
} from "@rjsf/utils";
|
||||
|
||||
const ArrayFieldTemplate = (props: ArrayFieldTemplateProps) => {
|
||||
const {
|
||||
canAdd,
|
||||
disabled,
|
||||
idSchema,
|
||||
uiSchema,
|
||||
items,
|
||||
onAddClick,
|
||||
readonly,
|
||||
registry,
|
||||
required,
|
||||
schema,
|
||||
title,
|
||||
} = props;
|
||||
const uiOptions = getUiOptions(uiSchema);
|
||||
const ArrayFieldDescriptionTemplate =
|
||||
getTemplate<"ArrayFieldDescriptionTemplate">(
|
||||
"ArrayFieldDescriptionTemplate",
|
||||
registry,
|
||||
uiOptions
|
||||
);
|
||||
const ArrayFieldItemTemplate = getTemplate<"ArrayFieldItemTemplate">(
|
||||
"ArrayFieldItemTemplate",
|
||||
registry,
|
||||
uiOptions
|
||||
);
|
||||
const ArrayFieldTitleTemplate = getTemplate<"ArrayFieldTitleTemplate">(
|
||||
"ArrayFieldTitleTemplate",
|
||||
registry,
|
||||
uiOptions
|
||||
);
|
||||
// Button templates are not overridden in the uiSchema
|
||||
const {
|
||||
ButtonTemplates: { AddButton },
|
||||
} = registry.templates;
|
||||
return (
|
||||
<div>
|
||||
<Row className="p-0 m-0">
|
||||
<Col className="p-0 m-0">
|
||||
<ArrayFieldTitleTemplate
|
||||
idSchema={idSchema}
|
||||
title={uiOptions.title || title}
|
||||
schema={schema}
|
||||
uiSchema={uiSchema}
|
||||
required={required}
|
||||
registry={registry}
|
||||
/>
|
||||
<ArrayFieldDescriptionTemplate
|
||||
idSchema={idSchema}
|
||||
description={uiOptions.description || schema.description}
|
||||
schema={schema}
|
||||
uiSchema={uiSchema}
|
||||
registry={registry}
|
||||
/>
|
||||
<Container
|
||||
fluid
|
||||
key={`array-item-list-${idSchema.$id}`}
|
||||
className="p-0 m-0"
|
||||
>
|
||||
{items &&
|
||||
items.map(({ key, ...itemProps }: ArrayFieldTemplateItemType) => (
|
||||
<ArrayFieldItemTemplate key={key} {...itemProps} />
|
||||
))}
|
||||
{canAdd && (
|
||||
<Container className="">
|
||||
<Row className="mt-2">
|
||||
<Col xs={9}></Col>
|
||||
<Col xs={3} className="py-4 col-lg-3 col-3">
|
||||
<AddButton
|
||||
className="array-item-add"
|
||||
onClick={onAddClick}
|
||||
disabled={disabled || readonly}
|
||||
uiSchema={uiSchema}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
</Container>
|
||||
)}
|
||||
</Container>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ArrayFieldTemplate;
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from "./ArrayFieldTemplate";
|
||||
export * from "./ArrayFieldTemplate";
|
|
@ -0,0 +1,67 @@
|
|||
import React from "react";
|
||||
import Form from "react-bootstrap/Form";
|
||||
import { getInputProps, WidgetProps } from "@rjsf/utils";
|
||||
|
||||
const BaseInputTemplate = ({
|
||||
id,
|
||||
placeholder,
|
||||
required,
|
||||
readonly,
|
||||
disabled,
|
||||
type,
|
||||
value,
|
||||
onChange,
|
||||
onBlur,
|
||||
onFocus,
|
||||
autofocus,
|
||||
options,
|
||||
schema,
|
||||
rawErrors = [],
|
||||
children,
|
||||
extraProps,
|
||||
}: WidgetProps) => {
|
||||
const inputProps = { ...extraProps, ...getInputProps(schema, type, options) };
|
||||
const _onChange = ({
|
||||
target: { value },
|
||||
}: React.ChangeEvent<HTMLInputElement>) =>
|
||||
onChange(value === "" ? options.emptyValue : value);
|
||||
const _onBlur = ({ target: { value } }: React.FocusEvent<HTMLInputElement>) =>
|
||||
onBlur(id, value);
|
||||
const _onFocus = ({
|
||||
target: { value },
|
||||
}: React.FocusEvent<HTMLInputElement>) => onFocus(id, value);
|
||||
|
||||
// const classNames = [rawErrors.length > 0 ? "is-invalid" : "", type === 'file' ? 'custom-file-label': ""]
|
||||
return (
|
||||
<>
|
||||
<Form.Control
|
||||
id={id}
|
||||
name={id}
|
||||
placeholder={placeholder}
|
||||
autoFocus={autofocus}
|
||||
required={required}
|
||||
disabled={disabled}
|
||||
readOnly={readonly}
|
||||
className={rawErrors.length > 0 ? "is-invalid" : ""}
|
||||
list={schema.examples ? `examples_${id}` : undefined}
|
||||
{...inputProps}
|
||||
value={value || value === 0 ? value : ""}
|
||||
onChange={_onChange}
|
||||
onBlur={_onBlur}
|
||||
onFocus={_onFocus}
|
||||
/>
|
||||
{children}
|
||||
{schema.examples ? (
|
||||
<datalist id={`examples_${id}`}>
|
||||
{(schema.examples as string[])
|
||||
.concat(schema.default ? ([schema.default] as string[]) : [])
|
||||
.map((example: any) => {
|
||||
return <option key={example} value={example} />;
|
||||
})}
|
||||
</datalist>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default BaseInputTemplate;
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from "./BaseInputTemplate";
|
||||
export * from "./BaseInputTemplate";
|
|
@ -0,0 +1,53 @@
|
|||
import React from "react";
|
||||
|
||||
import { WidgetProps } from "@rjsf/utils";
|
||||
import Form from "react-bootstrap/Form";
|
||||
|
||||
const CheckboxWidget = (props: WidgetProps) => {
|
||||
const {
|
||||
id,
|
||||
value,
|
||||
required,
|
||||
disabled,
|
||||
readonly,
|
||||
label,
|
||||
schema,
|
||||
autofocus,
|
||||
onChange,
|
||||
onBlur,
|
||||
onFocus,
|
||||
} = props;
|
||||
|
||||
const _onChange = ({
|
||||
target: { checked },
|
||||
}: React.FocusEvent<HTMLInputElement>) => onChange(checked);
|
||||
const _onBlur = ({
|
||||
target: { checked },
|
||||
}: React.FocusEvent<HTMLInputElement>) => onBlur(id, checked);
|
||||
const _onFocus = ({
|
||||
target: { checked },
|
||||
}: React.FocusEvent<HTMLInputElement>) => onFocus(id, checked);
|
||||
|
||||
const desc = label || schema.description;
|
||||
return (
|
||||
<Form.Group
|
||||
className={`checkbox ${disabled || readonly ? "disabled" : ""}`}
|
||||
>
|
||||
<Form.Check
|
||||
id={id}
|
||||
name={id}
|
||||
label={desc}
|
||||
checked={typeof value === "undefined" ? false : value}
|
||||
required={required}
|
||||
disabled={disabled || readonly}
|
||||
autoFocus={autofocus}
|
||||
onChange={_onChange}
|
||||
type="checkbox"
|
||||
onBlur={_onBlur}
|
||||
onFocus={_onFocus}
|
||||
/>
|
||||
</Form.Group>
|
||||
);
|
||||
};
|
||||
|
||||
export default CheckboxWidget;
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from "./CheckboxWidget";
|
||||
export * from "./CheckboxWidget";
|
|
@ -0,0 +1,83 @@
|
|||
import React from "react";
|
||||
import Form from "react-bootstrap/Form";
|
||||
import { WidgetProps } from "@rjsf/utils";
|
||||
|
||||
const selectValue = (value: any, selected: any, all: any) => {
|
||||
const at = all.indexOf(value);
|
||||
const updated = selected.slice(0, at).concat(value, selected.slice(at));
|
||||
|
||||
// As inserting values at predefined index positions doesn't work with empty
|
||||
// arrays, we need to reorder the updated selection to match the initial order
|
||||
return updated.sort((a: any, b: any) => all.indexOf(a) > all.indexOf(b));
|
||||
};
|
||||
|
||||
const deselectValue = (value: any, selected: any) => {
|
||||
return selected.filter((v: any) => v !== value);
|
||||
};
|
||||
|
||||
const CheckboxesWidget = ({
|
||||
id,
|
||||
disabled,
|
||||
options,
|
||||
value,
|
||||
autofocus,
|
||||
readonly,
|
||||
required,
|
||||
onChange,
|
||||
onBlur,
|
||||
onFocus,
|
||||
}: WidgetProps) => {
|
||||
const { enumOptions, enumDisabled, inline } = options;
|
||||
|
||||
const _onChange =
|
||||
(option: any) =>
|
||||
({ target: { checked } }: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const all = (enumOptions as any).map(({ value }: any) => value);
|
||||
|
||||
if (checked) {
|
||||
onChange(selectValue(option.value, value, all));
|
||||
} else {
|
||||
onChange(deselectValue(option.value, value));
|
||||
}
|
||||
};
|
||||
|
||||
const _onBlur = ({ target: { value } }: React.FocusEvent<HTMLInputElement>) =>
|
||||
onBlur(id, value);
|
||||
const _onFocus = ({
|
||||
target: { value },
|
||||
}: React.FocusEvent<HTMLInputElement>) => onFocus(id, value);
|
||||
|
||||
return (
|
||||
<Form.Group>
|
||||
{Array.isArray(enumOptions) &&
|
||||
enumOptions.map((option, index: number) => {
|
||||
const checked = value.indexOf(option.value) !== -1;
|
||||
const itemDisabled =
|
||||
Array.isArray(enumDisabled) &&
|
||||
enumDisabled.indexOf(option.value) !== -1;
|
||||
|
||||
return (
|
||||
<Form.Check
|
||||
key={option.value}
|
||||
inline={inline}
|
||||
custom
|
||||
required={required}
|
||||
checked={checked}
|
||||
className="bg-transparent border-0"
|
||||
type={"checkbox"}
|
||||
id={`${id}-${option.value}`}
|
||||
name={id}
|
||||
label={option.label}
|
||||
autoFocus={autofocus && index === 0}
|
||||
onChange={_onChange(option)}
|
||||
onBlur={_onBlur}
|
||||
onFocus={_onFocus}
|
||||
disabled={disabled || itemDisabled || readonly}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Form.Group>
|
||||
);
|
||||
};
|
||||
|
||||
export default CheckboxesWidget;
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from "./CheckboxesWidget";
|
||||
export * from "./CheckboxesWidget";
|
|
@ -0,0 +1,18 @@
|
|||
import React from "react";
|
||||
import { DescriptionFieldProps } from "@rjsf/utils";
|
||||
|
||||
const DescriptionField = ({ id, description }: DescriptionFieldProps) => {
|
||||
if (description) {
|
||||
return (
|
||||
<div>
|
||||
<div id={id} className="mb-3">
|
||||
{description}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
export default DescriptionField;
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from "./DescriptionField";
|
||||
export * from "./DescriptionField";
|
|
@ -0,0 +1,25 @@
|
|||
import React from "react";
|
||||
|
||||
import Card from "react-bootstrap/Card";
|
||||
import ListGroup from "react-bootstrap/ListGroup";
|
||||
|
||||
import { ErrorListProps } from "@rjsf/utils";
|
||||
|
||||
const ErrorList = ({ errors }: ErrorListProps) => (
|
||||
<Card border="danger" className="mb-4">
|
||||
<Card.Header className="alert-danger">Errors</Card.Header>
|
||||
<Card.Body className="p-0">
|
||||
<ListGroup>
|
||||
{errors.map((error, i: number) => {
|
||||
return (
|
||||
<ListGroup.Item key={i} className="border-0">
|
||||
<span>{error.stack}</span>
|
||||
</ListGroup.Item>
|
||||
);
|
||||
})}
|
||||
</ListGroup>
|
||||
</Card.Body>
|
||||
</Card>
|
||||
);
|
||||
|
||||
export default ErrorList;
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from "./ErrorList";
|
||||
export * from "./ErrorList";
|
|
@ -0,0 +1,27 @@
|
|||
import React from "react";
|
||||
import { FieldErrorProps } from "@rjsf/utils";
|
||||
import ListGroup from "react-bootstrap/ListGroup";
|
||||
|
||||
/** The `FieldErrorTemplate` component renders the errors local to the particular field
|
||||
*
|
||||
* @param props - The `FieldErrorProps` for the errors being rendered
|
||||
*/
|
||||
export default function FieldErrorTemplate(props: FieldErrorProps) {
|
||||
const { errors = [], idSchema } = props;
|
||||
if (errors.length === 0) {
|
||||
return null;
|
||||
}
|
||||
const id = `${idSchema.$id}__error`;
|
||||
|
||||
return (
|
||||
<ListGroup as="ul" id={id}>
|
||||
{errors.map((error, i) => {
|
||||
return (
|
||||
<ListGroup.Item as="li" key={i} className="border-0 m-0 p-0">
|
||||
<small className="m-0 text-danger">{error}</small>
|
||||
</ListGroup.Item>
|
||||
);
|
||||
})}
|
||||
</ListGroup>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from "./FieldErrorTemplate";
|
||||
export * from "./FieldErrorTemplate";
|
|
@ -0,0 +1,20 @@
|
|||
import React from "react";
|
||||
import { FieldHelpProps } from "@rjsf/utils";
|
||||
import Form from "react-bootstrap/Form";
|
||||
|
||||
/** The `FieldHelpTemplate` component renders any help desired for a field
|
||||
*
|
||||
* @param props - The `FieldHelpProps` to be rendered
|
||||
*/
|
||||
export default function FieldHelpTemplate(props: FieldHelpProps) {
|
||||
const { idSchema, help, hasErrors } = props;
|
||||
if (!help) {
|
||||
return null;
|
||||
}
|
||||
const id = `${idSchema.$id}__help`;
|
||||
return (
|
||||
<Form.Text className={hasErrors ? "text-danger" : "text-muted"} id={id}>
|
||||
{help}
|
||||
</Form.Text>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from "./FieldHelpTemplate";
|
||||
export * from "./FieldHelpTemplate";
|
|
@ -0,0 +1,73 @@
|
|||
import React from "react";
|
||||
import { FieldTemplateProps, getTemplate, getUiOptions } from "@rjsf/utils";
|
||||
import Form from "react-bootstrap/Form";
|
||||
|
||||
const FieldTemplate = ({
|
||||
id,
|
||||
children,
|
||||
displayLabel,
|
||||
rawErrors = [],
|
||||
errors,
|
||||
help,
|
||||
rawDescription,
|
||||
classNames,
|
||||
disabled,
|
||||
label,
|
||||
hidden,
|
||||
onDropPropertyClick,
|
||||
onKeyChange,
|
||||
readonly,
|
||||
required,
|
||||
schema,
|
||||
uiSchema,
|
||||
registry,
|
||||
}: FieldTemplateProps) => {
|
||||
const uiOptions = getUiOptions(uiSchema);
|
||||
const WrapIfAdditionalTemplate = getTemplate<"WrapIfAdditionalTemplate">(
|
||||
"WrapIfAdditionalTemplate",
|
||||
registry,
|
||||
uiOptions
|
||||
);
|
||||
if (hidden) {
|
||||
return <div className="hidden">{children}</div>;
|
||||
}
|
||||
return (
|
||||
<WrapIfAdditionalTemplate
|
||||
classNames={classNames}
|
||||
disabled={disabled}
|
||||
id={id}
|
||||
label={label}
|
||||
onDropPropertyClick={onDropPropertyClick}
|
||||
onKeyChange={onKeyChange}
|
||||
readonly={readonly}
|
||||
required={required}
|
||||
schema={schema}
|
||||
uiSchema={uiSchema}
|
||||
registry={registry}
|
||||
>
|
||||
<Form.Group>
|
||||
{displayLabel && (
|
||||
<Form.Label
|
||||
htmlFor={id}
|
||||
className={rawErrors.length > 0 ? "text-danger" : ""}
|
||||
>
|
||||
{label}
|
||||
{required ? "*" : null}
|
||||
</Form.Label>
|
||||
)}
|
||||
{children}
|
||||
{displayLabel && rawDescription && (
|
||||
<Form.Text
|
||||
className={rawErrors.length > 0 ? "text-danger" : "text-muted"}
|
||||
>
|
||||
{rawDescription}
|
||||
</Form.Text>
|
||||
)}
|
||||
{errors}
|
||||
{help}
|
||||
</Form.Group>
|
||||
</WrapIfAdditionalTemplate>
|
||||
);
|
||||
};
|
||||
|
||||
export default FieldTemplate;
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from "./FieldTemplate";
|
||||
export * from "./FieldTemplate";
|
|
@ -0,0 +1,14 @@
|
|||
import React from "react";
|
||||
import { getTemplate, WidgetProps } from "@rjsf/utils";
|
||||
|
||||
const FileWidget = (props: WidgetProps) => {
|
||||
const { options, registry } = props;
|
||||
const BaseInputTemplate = getTemplate<"BaseInputTemplate">(
|
||||
"BaseInputTemplate",
|
||||
registry,
|
||||
options
|
||||
);
|
||||
return <BaseInputTemplate {...props} type="file" />;
|
||||
};
|
||||
|
||||
export default FileWidget;
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from "./FileWidget";
|
||||
export * from "./FileWidget";
|
|
@ -0,0 +1,7 @@
|
|||
import { withTheme, FormProps } from "@rjsf/core";
|
||||
|
||||
import Theme from "../Theme";
|
||||
|
||||
const Form: React.ComponentType<FormProps> = withTheme(Theme);
|
||||
|
||||
export default Form;
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from "./Form";
|
||||
export * from "./Form";
|
|
@ -0,0 +1,43 @@
|
|||
import React from "react";
|
||||
import { IconButtonProps } from "@rjsf/utils";
|
||||
import Button, { ButtonProps } from "react-bootstrap/Button";
|
||||
import { IoIosRemove } from "@react-icons/all-files/io/IoIosRemove";
|
||||
import { AiOutlineArrowUp } from "@react-icons/all-files/ai/AiOutlineArrowUp";
|
||||
import { AiOutlineArrowDown } from "@react-icons/all-files/ai/AiOutlineArrowDown";
|
||||
|
||||
const IconButton = (props: IconButtonProps & ButtonProps) => {
|
||||
const { icon, iconType, className, uiSchema, ...otherProps } = props;
|
||||
return (
|
||||
<Button
|
||||
block={iconType === "block"}
|
||||
{...otherProps}
|
||||
variant={props.variant || "light"}
|
||||
size="sm"
|
||||
>
|
||||
{icon}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export default IconButton;
|
||||
|
||||
export function MoveDownButton(props: IconButtonProps) {
|
||||
return (
|
||||
<IconButton title="Move down" {...props} icon={<AiOutlineArrowDown />} />
|
||||
);
|
||||
}
|
||||
|
||||
export function MoveUpButton(props: IconButtonProps) {
|
||||
return <IconButton title="Move up" {...props} icon={<AiOutlineArrowUp />} />;
|
||||
}
|
||||
|
||||
export function RemoveButton(props: IconButtonProps) {
|
||||
return (
|
||||
<IconButton
|
||||
title="Remove"
|
||||
{...props}
|
||||
variant="danger"
|
||||
icon={<IoIosRemove />}
|
||||
/>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from "./IconButton";
|
||||
export * from "./IconButton";
|
|
@ -0,0 +1,91 @@
|
|||
import React from "react";
|
||||
|
||||
import Row from "react-bootstrap/Row";
|
||||
import Col from "react-bootstrap/Col";
|
||||
import Container from "react-bootstrap/Container";
|
||||
|
||||
import {
|
||||
canExpand,
|
||||
getTemplate,
|
||||
getUiOptions,
|
||||
ObjectFieldTemplateProps,
|
||||
} from "@rjsf/utils";
|
||||
|
||||
const ObjectFieldTemplate = ({
|
||||
description,
|
||||
title,
|
||||
properties,
|
||||
required,
|
||||
uiSchema,
|
||||
idSchema,
|
||||
schema,
|
||||
formData,
|
||||
onAddClick,
|
||||
disabled,
|
||||
readonly,
|
||||
registry,
|
||||
}: ObjectFieldTemplateProps) => {
|
||||
const uiOptions = getUiOptions(uiSchema);
|
||||
const TitleFieldTemplate = getTemplate<"TitleFieldTemplate">(
|
||||
"TitleFieldTemplate",
|
||||
registry,
|
||||
uiOptions
|
||||
);
|
||||
const DescriptionFieldTemplate = getTemplate<"DescriptionFieldTemplate">(
|
||||
"DescriptionFieldTemplate",
|
||||
registry,
|
||||
uiOptions
|
||||
);
|
||||
// Button templates are not overridden in the uiSchema
|
||||
const {
|
||||
ButtonTemplates: { AddButton },
|
||||
} = registry.templates;
|
||||
return (
|
||||
<>
|
||||
{(uiOptions.title || title) && (
|
||||
<TitleFieldTemplate
|
||||
id={`${idSchema.$id}-title`}
|
||||
title={uiOptions.title || title}
|
||||
required={required}
|
||||
schema={schema}
|
||||
uiSchema={uiSchema}
|
||||
registry={registry}
|
||||
/>
|
||||
)}
|
||||
{(uiOptions.description || description) && (
|
||||
<DescriptionFieldTemplate
|
||||
id={`${idSchema.$id}-description`}
|
||||
description={uiOptions.description || description!}
|
||||
schema={schema}
|
||||
uiSchema={uiSchema}
|
||||
registry={registry}
|
||||
/>
|
||||
)}
|
||||
<Container fluid className="p-0">
|
||||
{properties.map((element: any, index: number) => (
|
||||
<Row
|
||||
key={index}
|
||||
style={{ marginBottom: "10px" }}
|
||||
className={element.hidden ? "d-none" : undefined}
|
||||
>
|
||||
<Col xs={12}> {element.content}</Col>
|
||||
</Row>
|
||||
))}
|
||||
{canExpand(schema, uiSchema, formData) ? (
|
||||
<Row>
|
||||
<Col xs={{ offset: 9, span: 3 }} className="py-4">
|
||||
<AddButton
|
||||
onClick={onAddClick(schema)}
|
||||
disabled={disabled || readonly}
|
||||
className="object-property-expand"
|
||||
uiSchema={uiSchema}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
) : null}
|
||||
</Container>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ObjectFieldTemplate;
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from "./ObjectFieldTemplate";
|
||||
export * from "./ObjectFieldTemplate";
|
|
@ -0,0 +1,65 @@
|
|||
import React from "react";
|
||||
|
||||
import Form from "react-bootstrap/Form";
|
||||
|
||||
import { WidgetProps } from "@rjsf/utils";
|
||||
|
||||
const RadioWidget = ({
|
||||
id,
|
||||
schema,
|
||||
options,
|
||||
value,
|
||||
required,
|
||||
disabled,
|
||||
readonly,
|
||||
onChange,
|
||||
onBlur,
|
||||
onFocus,
|
||||
}: WidgetProps) => {
|
||||
const { enumOptions, enumDisabled } = options;
|
||||
|
||||
const _onChange = ({
|
||||
target: { value },
|
||||
}: React.ChangeEvent<HTMLInputElement>) =>
|
||||
onChange(schema.type == "boolean" ? value !== "false" : value);
|
||||
const _onBlur = ({ target: { value } }: React.FocusEvent<HTMLInputElement>) =>
|
||||
onBlur(id, value);
|
||||
const _onFocus = ({
|
||||
target: { value },
|
||||
}: React.FocusEvent<HTMLInputElement>) => onFocus(id, value);
|
||||
|
||||
const inline = Boolean(options && options.inline);
|
||||
|
||||
return (
|
||||
<Form.Group className="mb-0">
|
||||
{Array.isArray(enumOptions) &&
|
||||
enumOptions.map((option) => {
|
||||
const itemDisabled =
|
||||
Array.isArray(enumDisabled) &&
|
||||
enumDisabled.indexOf(option.value) !== -1;
|
||||
const checked = option.value == value;
|
||||
|
||||
const radio = (
|
||||
<Form.Check
|
||||
inline={inline}
|
||||
label={option.label}
|
||||
id={`${id}-${option.value}`}
|
||||
key={option.value}
|
||||
name={id}
|
||||
type="radio"
|
||||
disabled={disabled || itemDisabled || readonly}
|
||||
checked={checked}
|
||||
required={required}
|
||||
value={option.value}
|
||||
onChange={_onChange}
|
||||
onBlur={_onBlur}
|
||||
onFocus={_onFocus}
|
||||
/>
|
||||
);
|
||||
return radio;
|
||||
})}
|
||||
</Form.Group>
|
||||
);
|
||||
};
|
||||
|
||||
export default RadioWidget;
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from "./RadioWidget";
|
||||
export * from "./RadioWidget";
|
|
@ -0,0 +1,18 @@
|
|||
import React from "react";
|
||||
import { getTemplate, WidgetProps } from "@rjsf/utils";
|
||||
|
||||
const RangeWidget = (props: WidgetProps) => {
|
||||
const { value, label, options, registry } = props;
|
||||
const BaseInputTemplate = getTemplate<"BaseInputTemplate">(
|
||||
"BaseInputTemplate",
|
||||
registry,
|
||||
options
|
||||
);
|
||||
return (
|
||||
<BaseInputTemplate {...props} extraProps={label}>
|
||||
<span className="range-view">{value}</span>
|
||||
</BaseInputTemplate>
|
||||
);
|
||||
};
|
||||
|
||||
export default RangeWidget;
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from "./RangeWidget";
|
||||
export * from "./RangeWidget";
|
|
@ -0,0 +1,89 @@
|
|||
import React from "react";
|
||||
|
||||
import Form from "react-bootstrap/Form";
|
||||
|
||||
import { processSelectValue, WidgetProps } from "@rjsf/utils";
|
||||
|
||||
const SelectWidget = ({
|
||||
schema,
|
||||
id,
|
||||
options,
|
||||
required,
|
||||
disabled,
|
||||
readonly,
|
||||
value,
|
||||
multiple,
|
||||
autofocus,
|
||||
onChange,
|
||||
onBlur,
|
||||
onFocus,
|
||||
placeholder,
|
||||
rawErrors = [],
|
||||
}: WidgetProps) => {
|
||||
const { enumOptions, enumDisabled } = options;
|
||||
|
||||
const emptyValue = multiple ? [] : "";
|
||||
|
||||
function getValue(
|
||||
event: React.FocusEvent | React.ChangeEvent | any,
|
||||
multiple?: boolean
|
||||
) {
|
||||
if (multiple) {
|
||||
return [].slice
|
||||
.call(event.target.options as any)
|
||||
.filter((o: any) => o.selected)
|
||||
.map((o: any) => o.value);
|
||||
} else {
|
||||
return event.target.value;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Form.Control
|
||||
as="select"
|
||||
bsPrefix="custom-select"
|
||||
id={id}
|
||||
name={id}
|
||||
value={typeof value === "undefined" ? emptyValue : value}
|
||||
required={required}
|
||||
multiple={multiple}
|
||||
disabled={disabled || readonly}
|
||||
autoFocus={autofocus}
|
||||
className={rawErrors.length > 0 ? "is-invalid" : ""}
|
||||
onBlur={
|
||||
onBlur &&
|
||||
((event: React.FocusEvent) => {
|
||||
const newValue = getValue(event, multiple);
|
||||
onBlur(id, processSelectValue(schema, newValue, options));
|
||||
})
|
||||
}
|
||||
onFocus={
|
||||
onFocus &&
|
||||
((event: React.FocusEvent) => {
|
||||
const newValue = getValue(event, multiple);
|
||||
onFocus(id, processSelectValue(schema, newValue, options));
|
||||
})
|
||||
}
|
||||
onChange={(event: React.ChangeEvent) => {
|
||||
const newValue = getValue(event, multiple);
|
||||
onChange(processSelectValue(schema, newValue, options));
|
||||
}}
|
||||
>
|
||||
{!multiple && schema.default === undefined && (
|
||||
<option value="">{placeholder}</option>
|
||||
)}
|
||||
{(enumOptions as any).map(({ value, label }: any, i: number) => {
|
||||
const disabled: any =
|
||||
Array.isArray(enumDisabled) &&
|
||||
(enumDisabled as any).indexOf(value) != -1;
|
||||
return (
|
||||
<option key={i} id={label} value={value} disabled={disabled}>
|
||||
{label}
|
||||
</option>
|
||||
);
|
||||
})}
|
||||
</Form.Control>
|
||||
);
|
||||
};
|
||||
|
||||
export default SelectWidget;
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from "./SelectWidget";
|
||||
export * from "./SelectWidget";
|
|
@ -0,0 +1,23 @@
|
|||
import React from "react";
|
||||
import Button from "react-bootstrap/Button";
|
||||
import { getSubmitButtonOptions, SubmitButtonProps } from "@rjsf/utils";
|
||||
|
||||
const SubmitButton: React.ComponentType<SubmitButtonProps> = (props) => {
|
||||
const {
|
||||
submitText,
|
||||
norender,
|
||||
props: submitButtonProps,
|
||||
} = getSubmitButtonOptions(props.uiSchema);
|
||||
if (norender) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<Button variant="primary" type="submit" {...submitButtonProps}>
|
||||
{submitText}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SubmitButton;
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from "./SubmitButton";
|
||||
export * from "./SubmitButton";
|
|
@ -0,0 +1,35 @@
|
|||
import AddButton from "../AddButton";
|
||||
import ArrayFieldItemTemplate from "../ArrayFieldItemTemplate";
|
||||
import ArrayFieldTemplate from "../ArrayFieldTemplate";
|
||||
import BaseInputTemplate from "../BaseInputTemplate/BaseInputTemplate";
|
||||
import DescriptionField from "../DescriptionField";
|
||||
import ErrorList from "../ErrorList";
|
||||
import { MoveDownButton, MoveUpButton, RemoveButton } from "../IconButton";
|
||||
import FieldErrorTemplate from "../FieldErrorTemplate";
|
||||
import FieldHelpTemplate from "../FieldHelpTemplate";
|
||||
import FieldTemplate from "../FieldTemplate";
|
||||
import ObjectFieldTemplate from "../ObjectFieldTemplate";
|
||||
import SubmitButton from "../SubmitButton";
|
||||
import TitleField from "../TitleField";
|
||||
import WrapIfAdditionalTemplate from "../WrapIfAdditionalTemplate";
|
||||
|
||||
export default {
|
||||
ArrayFieldItemTemplate,
|
||||
ArrayFieldTemplate,
|
||||
BaseInputTemplate,
|
||||
ButtonTemplates: {
|
||||
AddButton,
|
||||
MoveDownButton,
|
||||
MoveUpButton,
|
||||
RemoveButton,
|
||||
SubmitButton,
|
||||
},
|
||||
DescriptionFieldTemplate: DescriptionField,
|
||||
ErrorListTemplate: ErrorList,
|
||||
FieldErrorTemplate,
|
||||
FieldHelpTemplate,
|
||||
FieldTemplate,
|
||||
ObjectFieldTemplate,
|
||||
TitleFieldTemplate: TitleField,
|
||||
WrapIfAdditionalTemplate,
|
||||
};
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from "./Templates";
|
||||
export * from "./Templates";
|
|
@ -0,0 +1,56 @@
|
|||
import React from "react";
|
||||
|
||||
import { WidgetProps } from "@rjsf/utils";
|
||||
import FormControl from "react-bootstrap/FormControl";
|
||||
import InputGroup from "react-bootstrap/InputGroup";
|
||||
|
||||
type CustomWidgetProps = WidgetProps & {
|
||||
options: any;
|
||||
};
|
||||
|
||||
const TextareaWidget = ({
|
||||
id,
|
||||
placeholder,
|
||||
value,
|
||||
required,
|
||||
disabled,
|
||||
autofocus,
|
||||
readonly,
|
||||
onBlur,
|
||||
onFocus,
|
||||
onChange,
|
||||
options,
|
||||
}: CustomWidgetProps) => {
|
||||
const _onChange = ({
|
||||
target: { value },
|
||||
}: React.ChangeEvent<HTMLTextAreaElement>) =>
|
||||
onChange(value === "" ? options.emptyValue : value);
|
||||
const _onBlur = ({
|
||||
target: { value },
|
||||
}: React.FocusEvent<HTMLTextAreaElement>) => onBlur(id, value);
|
||||
const _onFocus = ({
|
||||
target: { value },
|
||||
}: React.FocusEvent<HTMLTextAreaElement>) => onFocus(id, value);
|
||||
|
||||
return (
|
||||
<InputGroup>
|
||||
<FormControl
|
||||
id={id}
|
||||
name={id}
|
||||
as="textarea"
|
||||
placeholder={placeholder}
|
||||
disabled={disabled}
|
||||
readOnly={readonly}
|
||||
value={value}
|
||||
required={required}
|
||||
autoFocus={autofocus}
|
||||
rows={options.rows || 5}
|
||||
onChange={_onChange}
|
||||
onBlur={_onBlur}
|
||||
onFocus={_onFocus}
|
||||
/>
|
||||
</InputGroup>
|
||||
);
|
||||
};
|
||||
|
||||
export default TextareaWidget;
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from "./TextareaWidget";
|
||||
export * from "./TextareaWidget";
|
|
@ -0,0 +1,11 @@
|
|||
import { ThemeProps } from "@rjsf/core";
|
||||
|
||||
import Templates from "../Templates";
|
||||
import Widgets from "../Widgets";
|
||||
|
||||
const Theme: ThemeProps = {
|
||||
templates: Templates,
|
||||
widgets: Widgets,
|
||||
};
|
||||
|
||||
export default Theme;
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from "./Theme";
|
||||
export * from "./Theme";
|
|
@ -0,0 +1,13 @@
|
|||
import React from "react";
|
||||
import { TitleFieldProps } from "@rjsf/utils";
|
||||
|
||||
const TitleField = ({ id, title, uiSchema }: TitleFieldProps) => (
|
||||
<>
|
||||
<div id={id} className="my-1">
|
||||
<h5>{(uiSchema && uiSchema["ui:title"]) || title}</h5>
|
||||
<hr className="border-0 bg-secondary" style={{ height: "1px" }} />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
export default TitleField;
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from "./TitleField";
|
||||
export * from "./TitleField";
|
|
@ -0,0 +1,17 @@
|
|||
import CheckboxWidget from "../CheckboxWidget/CheckboxWidget";
|
||||
import CheckboxesWidget from "../CheckboxesWidget/CheckboxesWidget";
|
||||
import RadioWidget from "../RadioWidget/RadioWidget";
|
||||
import RangeWidget from "../RangeWidget/RangeWidget";
|
||||
import SelectWidget from "../SelectWidget/SelectWidget";
|
||||
import TextareaWidget from "../TextareaWidget/TextareaWidget";
|
||||
import FileWidget from "../FileWidget/FileWidget";
|
||||
|
||||
export default {
|
||||
CheckboxWidget,
|
||||
CheckboxesWidget,
|
||||
RadioWidget,
|
||||
RangeWidget,
|
||||
SelectWidget,
|
||||
TextareaWidget,
|
||||
FileWidget,
|
||||
};
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from "./Widgets";
|
||||
export * from "./Widgets";
|
|
@ -0,0 +1,69 @@
|
|||
import React from "react";
|
||||
|
||||
import {
|
||||
ADDITIONAL_PROPERTY_FLAG,
|
||||
WrapIfAdditionalTemplateProps,
|
||||
} from "@rjsf/utils";
|
||||
|
||||
import Row from "react-bootstrap/Row";
|
||||
import Col from "react-bootstrap/Col";
|
||||
import Form from "react-bootstrap/Form";
|
||||
|
||||
const WrapIfAdditionalTemplate = ({
|
||||
classNames,
|
||||
children,
|
||||
disabled,
|
||||
id,
|
||||
label,
|
||||
onDropPropertyClick,
|
||||
onKeyChange,
|
||||
readonly,
|
||||
required,
|
||||
schema,
|
||||
uiSchema,
|
||||
registry,
|
||||
}: WrapIfAdditionalTemplateProps) => {
|
||||
// Button templates are not overridden in the uiSchema
|
||||
const { RemoveButton } = registry.templates.ButtonTemplates;
|
||||
const keyLabel = `${label} Key`; // i18n ?
|
||||
const additional = ADDITIONAL_PROPERTY_FLAG in schema;
|
||||
|
||||
if (!additional) {
|
||||
return <div className={classNames}>{children}</div>;
|
||||
}
|
||||
|
||||
const handleBlur = ({ target }: React.FocusEvent<HTMLInputElement>) =>
|
||||
onKeyChange(target.value);
|
||||
const keyId = `${id}-key`;
|
||||
|
||||
return (
|
||||
<Row className={classNames} key={keyId}>
|
||||
<Col xs={5}>
|
||||
<Form.Group>
|
||||
<Form.Label htmlFor={keyId}>{keyLabel}</Form.Label>
|
||||
<Form.Control
|
||||
required={required}
|
||||
defaultValue={label}
|
||||
disabled={disabled || readonly}
|
||||
id={keyId}
|
||||
name={keyId}
|
||||
onBlur={!readonly ? handleBlur : undefined}
|
||||
type="text"
|
||||
/>
|
||||
</Form.Group>
|
||||
</Col>
|
||||
<Col xs={5}>{children}</Col>
|
||||
<Col xs={2} className="py-4">
|
||||
<RemoveButton
|
||||
iconType="block"
|
||||
className="w-100"
|
||||
disabled={disabled || readonly}
|
||||
onClick={onDropPropertyClick(label)}
|
||||
uiSchema={uiSchema}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
};
|
||||
|
||||
export default WrapIfAdditionalTemplate;
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from "./WrapIfAdditionalTemplate";
|
||||
export * from "./WrapIfAdditionalTemplate";
|
|
@ -0,0 +1,8 @@
|
|||
import Form from './Form/Form';
|
||||
|
||||
export { default as Form } from './Form';
|
||||
export { default as Templates } from './Templates';
|
||||
export { default as Theme } from './Theme';
|
||||
export { default as Widgets } from './Widgets';
|
||||
|
||||
export default Form;
|
Loading…
Reference in New Issue