attempting to add a theme w/ burnettk cullerton

This commit is contained in:
jasquat 2022-11-16 13:35:55 -05:00
parent f838e11759
commit 2c3e9760a6
54 changed files with 1238 additions and 1 deletions

View File

@ -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",

View File

@ -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",

View File

@ -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';

View File

@ -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;

View File

@ -0,0 +1,2 @@
export { default } from "./AddButton";
export * from "./AddButton";

View File

@ -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;

View File

@ -0,0 +1,2 @@
export { default } from "./ArrayFieldItemTemplate";
export * from "./ArrayFieldItemTemplate";

View File

@ -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;

View File

@ -0,0 +1,2 @@
export { default } from "./ArrayFieldTemplate";
export * from "./ArrayFieldTemplate";

View File

@ -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;

View File

@ -0,0 +1,2 @@
export { default } from "./BaseInputTemplate";
export * from "./BaseInputTemplate";

View File

@ -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;

View File

@ -0,0 +1,2 @@
export { default } from "./CheckboxWidget";
export * from "./CheckboxWidget";

View File

@ -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;

View File

@ -0,0 +1,2 @@
export { default } from "./CheckboxesWidget";
export * from "./CheckboxesWidget";

View File

@ -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;

View File

@ -0,0 +1,2 @@
export { default } from "./DescriptionField";
export * from "./DescriptionField";

View File

@ -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;

View File

@ -0,0 +1,2 @@
export { default } from "./ErrorList";
export * from "./ErrorList";

View File

@ -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>
);
}

View File

@ -0,0 +1,2 @@
export { default } from "./FieldErrorTemplate";
export * from "./FieldErrorTemplate";

View File

@ -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>
);
}

View File

@ -0,0 +1,2 @@
export { default } from "./FieldHelpTemplate";
export * from "./FieldHelpTemplate";

View File

@ -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;

View File

@ -0,0 +1,2 @@
export { default } from "./FieldTemplate";
export * from "./FieldTemplate";

View File

@ -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;

View File

@ -0,0 +1,2 @@
export { default } from "./FileWidget";
export * from "./FileWidget";

View File

@ -0,0 +1,7 @@
import { withTheme, FormProps } from "@rjsf/core";
import Theme from "../Theme";
const Form: React.ComponentType<FormProps> = withTheme(Theme);
export default Form;

View File

@ -0,0 +1,2 @@
export { default } from "./Form";
export * from "./Form";

View File

@ -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 />}
/>
);
}

View File

@ -0,0 +1,2 @@
export { default } from "./IconButton";
export * from "./IconButton";

View File

@ -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;

View File

@ -0,0 +1,2 @@
export { default } from "./ObjectFieldTemplate";
export * from "./ObjectFieldTemplate";

View File

@ -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;

View File

@ -0,0 +1,2 @@
export { default } from "./RadioWidget";
export * from "./RadioWidget";

View File

@ -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;

View File

@ -0,0 +1,2 @@
export { default } from "./RangeWidget";
export * from "./RangeWidget";

View File

@ -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;

View File

@ -0,0 +1,2 @@
export { default } from "./SelectWidget";
export * from "./SelectWidget";

View File

@ -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;

View File

@ -0,0 +1,2 @@
export { default } from "./SubmitButton";
export * from "./SubmitButton";

View File

@ -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,
};

View File

@ -0,0 +1,2 @@
export { default } from "./Templates";
export * from "./Templates";

View File

@ -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;

View File

@ -0,0 +1,2 @@
export { default } from "./TextareaWidget";
export * from "./TextareaWidget";

View File

@ -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;

View File

@ -0,0 +1,2 @@
export { default } from "./Theme";
export * from "./Theme";

View File

@ -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;

View File

@ -0,0 +1,2 @@
export { default } from "./TitleField";
export * from "./TitleField";

View File

@ -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,
};

View File

@ -0,0 +1,2 @@
export { default } from "./Widgets";
export * from "./Widgets";

View File

@ -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;

View File

@ -0,0 +1,2 @@
export { default } from "./WrapIfAdditionalTemplate";
export * from "./WrapIfAdditionalTemplate";

View File

@ -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;