Skip to content
Snippets Groups Projects
Unverified Commit ec997484 authored by Ryan Laurie's avatar Ryan Laurie Committed by GitHub
Browse files

:seedling: Remove `/_internal` Directory (#29463)

* remove _internal pages and resources

* remove internal jest config
parent bb807af8
No related branches found
No related tags found
No related merge requests found
Showing
with 1 addition and 940 deletions
......@@ -55,7 +55,7 @@ Features that are ready for design are tagged [Design Needed](https://github.com
Once a feature is tagged [Help Wanted](https://github.com/metabase/metabase/labels/.Help%20Wanted), it is considered ready to be built. A core team member (or you, awesomely helpful person that you are) can start working on it.
If you're building something that users will see in Metabase, please refer to the Style Guide (found at `https://localhost:3000/_internal` while running the development environment to learn how and when to use various Metabase UI elements.
If you're building something that users will see in Metabase, please refer to the Style Guide (found at `https://storybook.metabase.com`) to learn how and when to use various Metabase UI elements.
Once one or more people have started to work on a feature, it should be marked [In Progress](https://github.com/metabase/metabase/labels/.In%20Progress). Once there is a branch+some code, a pull request is opened, linked to the feature + any issues that were pulled together to inform the feature.
......
import React from "react";
import Breadcrumbs from "metabase/components/Breadcrumbs";
export const component = Breadcrumbs;
export const category = "navigation";
export const description = `
Breadcrumbs to help user get know where they are and to parent pages.
`;
const crumbs = [
["Hello", () => alert("action can be a function")],
["World", "/or a url"],
["Foo"],
];
export const examples = {
default: <Breadcrumbs crumbs={crumbs} />,
"sidebar variant": <Breadcrumbs crumbs={crumbs} inSidebar />,
};
import React from "react";
import ButtonBar from "metabase/components/ButtonBar";
import Button from "metabase/core/components/Button";
export const component = ButtonBar;
export const category = "layout";
export const description = `
ButtonBar is a layout with left, right, and center sections
`;
export const examples = {
default: (
<ButtonBar>
<Button>Button</Button>
</ButtonBar>
),
"left and right": (
<ButtonBar left={<Button>Left</Button>} right={<Button>Right</Button>} />
),
"left, right, and center": (
<ButtonBar
left={<Button>Left</Button>}
center={<Button>Center</Button>}
right={<Button>Right</Button>}
/>
),
};
import React from "react";
import moment from "moment-timezone";
import Calendar from "./Calendar";
export const component = Calendar;
export const category = "pickers";
export const description = `For when gregorian time is your need, a calendar is your friend indeed`;
const onChange = () => ({});
export const examples = {
default: <Calendar onChange={onChange} />,
"With a selected date": <Calendar onChange={onChange} selected={moment()} />,
"With a date range": (
<Calendar
selected={moment()}
selectedEnd={moment().add(10, "days")}
onChange={onChange}
/>
),
};
import React from "react";
import Card from "metabase/components/Card";
export const component = Card;
export const category = "layout";
export const description = `
A generic card component.
`;
const DemoContent = () => <div className="p4">Look, a card!</div>;
export const examples = {
normal: (
<Card>
<DemoContent />
</Card>
),
dark: (
<Card dark>
<DemoContent />
</Card>
),
hoverable: (
<Card hoverable>
<DemoContent />
</Card>
),
};
import React from "react";
import ClampedText from "metabase/components/ClampedText";
export const component = ClampedText;
export const category = "display";
export const description = `
Shows a set number of lines for a variable-length string
`;
const text =
"Lorem ipsum \n \n dolor sit amet, consectetur adipiscing elit. Cras sit amet sagittis dui. Morbi in odio laoreet, finibus erat vitae, sagittis dui. Ut at mauris eget ligula volutpat pellentesque. Integer non faucibus urna. Maecenas faucibus ornare gravida. Aliquam orci tortor, ullamcorper et vehicula accumsan, malesuada in ipsum. Nullam auctor, justo et mattis fringilla, enim ipsum aliquet nunc, quis posuere odio erat in nulla. Suspendisse elementum, est et rutrum volutpat, purus mi placerat odio, sit amet blandit nulla diam at lectus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Ut ultricies placerat mollis. Curabitur vestibulum semper turpis, id cursus ex dignissim id. Cras efficitur sed ligula ac dictum. Curabitur hendrerit metus eget vestibulum bibendum. Cras nulla arcu, condimentum in rhoncus eu, interdum ut sapien. Cras sed molestie tellus, quis aliquet nunc. Nulla nec est eu est condimentum facilisis sit amet et ex.";
export const examples = {
Default: <ClampedText text={text} visibleLines={3} />,
"No 'See more' button when all text visible": (
<React.Fragment>
<strong>A single line of text:</strong>
<ClampedText text="foo" visibleLines={3} />
<br />
<strong>Many lines of text, but an unset `visibleLines` prop:</strong>
<ClampedText text={text} />
</React.Fragment>
),
};
import React from "react";
import CollapseSection from "metabase/components/CollapseSection";
import Icon from "metabase/components/Icon";
export const component = CollapseSection;
export const category = "layout";
export const description = `
A collapsible section with a clickable header.
`;
export const examples = {
"Collapsed by default": (
<CollapseSection header="Section header">
foo foo foo foo foo foo foo foo
</CollapseSection>
),
"Settable collpased/expanded initial state": (
<CollapseSection initialState="expanded" header="Foo">
foo foo foo foo foo
</CollapseSection>
),
"Up-down icon variant": (
<CollapseSection
initialState="collapsed"
header="Foo"
iconVariant="up-down"
>
foo foo foo foo foo
</CollapseSection>
),
"Icon on the right": (
<CollapseSection initialState="collapsed" header="Foo" iconPosition="right">
foo foo foo foo foo
</CollapseSection>
),
"Components in header": (
<CollapseSection
header={
<div>
<Icon className="mr1" name="folder" size={12} />
Component header
</div>
}
>
foo foo foo foo foo
</CollapseSection>
),
"Header and body classes": (
<CollapseSection
initialState="expanded"
header="Section header"
headerClass="text-brand flex-reverse justify-between p1 border-bottom"
bodyClass="p2"
>
<div>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus neque
tellus, mattis ut felis non, tempus mollis lacus. Vivamus nulla massa,
accumsan non ligula eu, dapibus volutpat libero. Mauris sollicitudin
dolor et ipsum fringilla auctor. Praesent et diam non nisi consequat
ornare. Aenean et risus vel dolor maximus dapibus a id massa. Nam
finibus quis libero eu finibus. Sed vehicula ac enim pellentesque
luctus. Phasellus vehicula et ipsum porttitor mollis. Fusce blandit
lacus a elit pretium, vestibulum porta nisi vehicula. Aliquam vel ligula
enim. Orci varius natoque penatibus et magnis dis parturient montes,
nascetur ridiculus mus. Pellentesque eget porta mi. Duis et lectus eget
dolor convallis mollis. Sed commodo nec urna eget egestas.
<br />
<br />
Mauris in ante sit amet ipsum tempus consequat. Curabitur auctor massa
vitae dui auctor scelerisque. Donec in leo a libero commodo sodales.
Integer egestas lacinia elit, vitae cursus sem mollis ut. Proin ut
dapibus metus, vel accumsan justo. Pellentesque eget finibus elit, ut
commodo felis. Ut non lacinia metus. Maecenas eget bibendum nisl.
</div>
</CollapseSection>
),
};
import React from "react";
import DateTime, { DATE_TIME_UNITS } from "./DateTime";
export const component = DateTime;
export const description = `
Formats date and time strings according to Metabase settings (/admin/settings/localization)
`;
export const category = "display";
const now = new Date();
export const examples = Object.fromEntries(
DATE_TIME_UNITS.map(unit => [
unit,
<DateTime key={unit} value={now} unit={unit} />,
]),
);
/* eslint-disable react/prop-types */
import React from "react";
import { t } from "ttag";
import EntityMenu from "metabase/components/EntityMenu";
export const component = EntityMenu;
export const category = "navigation";
export const description = `
A menu with various entity related options grouped by context.
`;
const DemoAlignRight = ({ children }) => (
<div className="flex flex-full">
<div className="flex align-center ml-auto">{children}</div>
</div>
);
export const examples = {
"Edit menu": (
<DemoAlignRight>
<EntityMenu
triggerIcon="pencil"
items={[
{
title: t`Edit this question`,
icon: "edit_document",
action: () => alert(t`Action type`),
},
{ title: t`View revision history`, icon: "history", link: "/derp" },
{ title: t`Move`, icon: "move", action: () => alert(t`Move action`) },
{
title: t`Archive`,
icon: "archive",
action: () => alert(t`Archive action`),
},
]}
/>
</DemoAlignRight>
),
"Share menu": (
<DemoAlignRight>
<EntityMenu
triggerIcon="share"
items={[
{
title: t`Add to dashboard`,
icon: "add_to_dash",
action: () => alert(t`Action type`),
},
{ title: t`Download results`, icon: "download", link: "/download" },
{
title: t`Sharing and embedding`,
icon: "embed",
action: () => alert(t`Another action type`),
},
]}
/>
</DemoAlignRight>
),
"More menu": (
<DemoAlignRight>
<EntityMenu
triggerIcon="burger"
items={[
{
title: t`Get alerts about this`,
icon: "alert",
action: () => alert(t`Get alerts about this`),
},
{ title: t`View the SQL`, icon: "sql", link: "/download" },
]}
/>
</DemoAlignRight>
),
"Multiple menus": (
<DemoAlignRight>
<EntityMenu
triggerIcon="pencil"
items={[
{
title: t`Edit this question`,
icon: "edit_document",
action: () => alert(t`Action type`),
},
{ title: t`View revision history`, icon: "history", link: "/derp" },
{ title: t`Move`, icon: "move", action: () => alert(t`Move action`) },
{
title: t`Archive`,
icon: "archive",
action: () => alert(t`Archive action`),
},
]}
/>
<EntityMenu
triggerIcon="share"
items={[
{
title: t`Add to dashboard`,
icon: "add_to_dash",
action: () => alert(t`Action type`),
},
{ title: t`Download results`, icon: "download", link: "/download" },
{
title: t`Sharing and embedding`,
icon: "embed",
action: () => alert(t`Another action type`),
},
]}
/>
<EntityMenu
triggerIcon="burger"
items={[
{
title: t`Get alerts about this`,
icon: "alert",
action: () => alert(t`Get alerts about this`),
},
{ title: t`View the SQL`, icon: "sql", link: "/download" },
]}
/>
</DemoAlignRight>
),
};
import React from "react";
import {
PRODUCTS,
ORDERS,
metadata,
} from "__support__/sample_database_fixture";
import Card from "metabase/components/Card";
import PopoverWithTrigger from "metabase/components/PopoverWithTrigger";
import Button from "metabase/core/components/Button";
import Dimension from "metabase-lib/Dimension";
import DimensionInfo from "./DimensionInfo";
const fieldDimension = Dimension.parseMBQL(
["field", PRODUCTS.CATEGORY.id, null],
metadata,
);
fieldDimension.field().fingerprint = {
global: {
"distinct-count": 5,
},
};
const numberDimension = Dimension.parseMBQL(
["field", ORDERS.TOTAL.id, null],
metadata,
);
numberDimension.field().fingerprint = {
type: {
"type/Number": {
avg: 3.5,
min: 2,
max: 5,
},
},
};
const dateDimension = Dimension.parseMBQL(
["field", PRODUCTS.CREATED_AT.id, null],
metadata,
);
dateDimension.field().table = {
database: {
timezone: "America/Los_Angeles",
},
};
dateDimension.field().fingerprint = {
type: {
"type/DateTime": {
earliest: "2021-11-09T04:43:33.667Z",
latest: "2021-12-09T04:43:33.667Z",
},
},
};
const expressionDimension = Dimension.parseMBQL(
["expression", Array(15).fill("Long display name").join(" -- ")],
metadata,
);
const longDescriptionDimension = {
displayName: () => "Foo",
icon: () => "string",
field: () => ({
description: Array(50)
.fill("Long description Long description")
.join("\n "),
}),
};
export const component = DimensionInfo;
export const description =
"A selection of information from a given Dimension instance, for use in some containing component";
export const examples = {
"with description": <DimensionInfo dimension={fieldDimension} />,
"without description": <DimensionInfo dimension={expressionDimension} />,
"long description": <DimensionInfo dimension={longDescriptionDimension} />,
"in a card": (
<Card>
<DimensionInfo dimension={fieldDimension} />
</Card>
),
"in a popoover": (
<PopoverWithTrigger triggerElement={<Button>click me</Button>}>
<DimensionInfo dimension={longDescriptionDimension} />
</PopoverWithTrigger>
),
"with number fingerprint": (
<Card>
<DimensionInfo dimension={numberDimension} />
</Card>
),
"with date fingerprint": (
<Card>
<DimensionInfo dimension={dateDimension} />
</Card>
),
};
import React from "react";
import styled from "@emotion/styled";
import { PRODUCTS, metadata } from "__support__/sample_database_fixture";
import Dimension from "metabase-lib/Dimension";
import DimensionSemanticTypeLabel from "./DimensionSemanticTypeLabel";
const fieldDimension = Dimension.parseMBQL(
["field", PRODUCTS.CATEGORY.id, null],
metadata,
);
const BiggerDimensionSemanticTypeLabel = styled(DimensionSemanticTypeLabel)`
font-size: 32px;
`;
export const component = DimensionSemanticTypeLabel;
export const description = "A label for instances of Dimension";
export const examples = {
DimensionSemanticTypeLabel: (
<DimensionSemanticTypeLabel dimension={fieldDimension} />
),
"Bigger DimensionSemanticTypeLabel": (
<BiggerDimensionSemanticTypeLabel dimension={fieldDimension} />
),
};
import React from "react";
import { PRODUCTS } from "__support__/sample_database_fixture";
import Card from "metabase/components/Card";
import PopoverWithTrigger from "metabase/components/PopoverWithTrigger";
import Button from "metabase/core/components/Button";
import Table from "metabase-lib/metadata/Table";
import TableInfo from "./TableInfo";
const table = new Table(PRODUCTS);
const tableNoDescription = new Table({ id: 123, display_name: "Foo" });
export const component = TableInfo;
export const description =
"A selection of information from a given Table instance, for use in some containing component";
export const examples = {
"with description": <TableInfo table={table} />,
"without description": <TableInfo table={tableNoDescription} />,
"in a card": (
<Card>
<TableInfo table={table} />
</Card>
),
"in a popoover": (
<PopoverWithTrigger triggerElement={<Button>click me</Button>}>
<TableInfo table={table} />
</PopoverWithTrigger>
),
};
import React from "react";
import styled from "@emotion/styled";
import { PRODUCTS } from "__support__/sample_database_fixture";
import Table from "metabase-lib/metadata/Table";
import TableLabel from "./TableLabel";
const table = new Table({
...PRODUCTS,
});
const BiggerTableLabel = styled(TableLabel)`
font-size: 32px;
`;
export const component = TableLabel;
export const description = "A label for instances of Table";
export const examples = {
TableLabel: <TableLabel table={table} />,
"Bigger TableLabel": <BiggerTableLabel table={table} />,
};
/* eslint-disable react/prop-types */
import React from "react";
import ModalContent from "metabase/components/ModalContent";
import Button from "metabase/core/components/Button";
export const component = ModalContent;
export const category = "modal";
export const description = `
A standard modal content layout, including header with title and close button, body, and footer.
`;
const Modal = ({ children }) => (
<div className="rounded bordered">{children}</div>
);
export const examples = {
default: (
<Modal>
<ModalContent
title="Do something crazy?"
onClose={() => alert("close!")}
footer={<Button danger>Ok</Button>}
>
Are you sure?
</ModalContent>
</Modal>
),
};
import React from "react";
import styled from "@emotion/styled";
import TippyPopover from "./TippyPopover";
export const component = TippyPopover;
export const description = "Wrapper around react-popper";
const Base = styled.div`
border: 1px solid black;
display: flex;
align-items: center;
justify-content: center;
`;
const PopoverBody = styled(Base)`
border: none;
height: 200px;
width: 200px;
`;
const LongPopoverBody = styled(PopoverBody)`
height: 600px;
`;
const LazyPopoverBody = styled(Base)`
border: none;
height: 200px;
width: 200px;
transition: opacity 1s;
opacity: ${props => props.opacity};
`;
const PopoverTarget = styled(Base)`
height: 100px;
width: 100px;
`;
const content = <PopoverBody>popover body</PopoverBody>;
const longContent = <LongPopoverBody>long popover body</LongPopoverBody>;
const target = <PopoverTarget>popover target</PopoverTarget>;
function LazyContentExample() {
const [opacity, setOpacity] = React.useState(0.1);
const timeout = React.useRef();
React.useEffect(() => {
timeout.current = setTimeout(() => {
setOpacity(1);
}, 1000);
return () => {
clearTimeout(timeout.current);
};
}, [opacity]);
return <LazyPopoverBody opacity={opacity}>popover content</LazyPopoverBody>;
}
function VisiblePropExample() {
const [visible, setVisible] = React.useState(true);
return (
<TippyPopover
visible={visible}
onHide={() => {
setVisible(false);
}}
placement="left-end"
content={content}
>
<div onClick={() => setVisible(true)}>{target}</div>
</TippyPopover>
);
}
export const examples = {
"vertical placement": (
<TippyPopover placement="top-start" content={content}>
{target}
</TippyPopover>
),
"horizontal placement": (
<TippyPopover placement="left-end" content={content}>
{target}
</TippyPopover>
),
"lazy content rendering": (
<React.Fragment>
<TippyPopover placement="left-end" content={<LazyContentExample />}>
<PopoverTarget>lazy target</PopoverTarget>
</TippyPopover>
<TippyPopover
lazy={false}
placement="left-end"
content={<LazyContentExample />}
>
<PopoverTarget>not lazy target</PopoverTarget>
</TippyPopover>
</React.Fragment>
),
"interactive disabled": (
<TippyPopover interactive={false} placement="left-end" content={content}>
{target}
</TippyPopover>
),
"control mode + handling of Esc press": <VisiblePropExample />,
"flip disabled": (
<TippyPopover flip={false} placement="bottom-start" content={content}>
{target}
</TippyPopover>
),
sizeToFit: (
<TippyPopover
sizeToFit
placement="bottom-start"
visible
content={longContent}
>
{target}
</TippyPopover>
),
extra_space: <div style={{ height: 400 }} />,
};
import React from "react";
import ProgressBar from "metabase/components/ProgressBar";
export const component = ProgressBar;
export const category = "feedback";
export const description = `
Progress bar.
`;
export const examples = {
Default: <ProgressBar percentage={0.75} />,
Animated: <ProgressBar percentage={0.35} animated />,
};
import React from "react";
import { t } from "ttag";
import _ from "underscore";
import Select from "metabase/core/components/Select";
export const component = Select;
export const category = "input";
export const description = t`
A component used to make a selection
`;
import { field_semantic_types } from "metabase/lib/core";
const EXAMPLE_SECTIONS = _.chain(field_semantic_types)
.first(10)
.groupBy("section")
.pairs()
.map(([section, items]) => ({
name: section,
items: items.map(item => ({
name: item.name,
value: item.id,
icon:
item.id === "type/FK"
? "connections"
: item.id === "type/Name"
? "string"
: item.id === "type/PK"
? "unknown"
: null,
description: item.description,
})),
}))
.value();
const EXAMPLE_OPTIONS = EXAMPLE_SECTIONS.map(section => section.items).flat();
export const examples = {
default: (
<Select defaultValue={EXAMPLE_OPTIONS[0].value} options={EXAMPLE_OPTIONS} />
),
search: (
<Select
defaultValue={EXAMPLE_OPTIONS[0].value}
options={EXAMPLE_OPTIONS}
searchProp="name"
/>
),
sections: (
<Select
defaultValue={EXAMPLE_OPTIONS[0].value}
sections={EXAMPLE_SECTIONS}
/>
),
multiple: (
<Select
defaultValue={[EXAMPLE_OPTIONS[0].value, EXAMPLE_OPTIONS[3].value]}
options={EXAMPLE_OPTIONS}
multiple
/>
),
kitchen_sink: (
<Select
defaultValue={[EXAMPLE_OPTIONS[0].value, EXAMPLE_OPTIONS[3].value]}
sections={EXAMPLE_SECTIONS}
multiple
searchProp="name"
/>
),
};
/* eslint-disable react/prop-types */
import React, { useState } from "react";
import StackedCheckBox from "metabase/components/StackedCheckBox";
export const component = StackedCheckBox;
export const category = "input";
export const description = `
A stacked checkbox, representing "all" items.
`;
function StackedCheckBoxDemo({
checked: isCheckedInitially = false,
...props
}) {
const [checked, setChecked] = useState(isCheckedInitially);
return (
<StackedCheckBox
{...props}
checked={checked}
onChange={e => setChecked(e.target.checked)}
/>
);
}
const rowStyle = {
display: "flex",
alignItems: "center",
justifyContent: "space-around",
};
export const examples = {
Default: <StackedCheckBoxDemo />,
Label: (
<div>
<StackedCheckBoxDemo label="Confirm Stuff" />
<br />
<StackedCheckBoxDemo label={<h3>Custom element label</h3>} />
</div>
),
Disabled: (
<div>
<StackedCheckBoxDemo disabled />
<br />
<StackedCheckBoxDemo label="Confirm Stuff" disabled checked />
</div>
),
Sizing: (
<div style={rowStyle}>
{[10, 12, 14, 16, 18, 20, 24].map(size => (
<StackedCheckBoxDemo key={size} checked size={size} />
))}
</div>
),
Colors: (
<div style={rowStyle}>
{["accent1", "accent2", "accent3", "accent4"].map(color => (
<StackedCheckBoxDemo key={color} checked checkedColor={color} />
))}
</div>
),
};
import React from "react";
import moment from "moment-timezone";
import styled from "@emotion/styled";
import Timeline from "metabase/components/Timeline";
import { color } from "metabase/lib/colors";
export const component = Timeline;
export const category = "display";
export const description = `
A component for showing events in descending order.
`;
const Container = styled.div`
line-height: 1.5;
width: 350px;
border: 1px dashed ${color("bg-dark")};
border-radius: 0.5rem;
padding: 1rem;
`;
const items = [
{
icon: "verified",
title: "John Someone verified this",
description: "idk lol",
timestamp: moment().subtract(1, "day").valueOf(),
numComments: 5,
},
{
icon: "pencil",
title: "Foo edited this",
description: "Did a thing.",
timestamp: moment().subtract(1, "week").valueOf(),
},
{
icon: "warning_colorized",
title: "Someone McSomeone thinks something looks wrong",
description:
"Uh oh that's not correct. Uh oh that's not correct. Uh oh that's not correct. Uh oh that's not correct. Uh oh that's not correct. Uh oh that's not correct. Uh oh that's not correct. Uh oh that's not correct. Uh oh that's not correct. \nUh oh that's not correct. \nUh oh that's not correct. \nUh oh that's not correct. \nUh oh that's not correct. \nUh oh that's not correct. \nUh oh that's not correct. \nUh oh that's not correct. \nUh oh that's not correct. \nUh oh that's not correct. Uh oh that's not correct. Uh oh that's not correct. Uh oh that's not correct. Uh oh that's not",
timestamp: moment().subtract(2, "month").valueOf(),
},
{
icon: "clarification",
title: "Someone is confused",
description:
"Something something something something something something something something something something something something?",
timestamp: moment().subtract(1, "year").valueOf(),
numComments: 123,
},
];
function renderFooter(item) {
return item.numComments ? (
<a
href="/_internal/components/timeline"
className="text-underline"
>{`${item.numComments} comments`}</a>
) : (
""
);
}
export const examples = {
"Constrained width": (
<Container>
<Timeline items={items} />
</Container>
),
"Optional footer": <Timeline items={items} renderFooter={renderFooter} />,
};
/* eslint-disable react/prop-types */
import React from "react";
import TokenField from "metabase/components/TokenField";
export const component = TokenField;
export const category = "pickers";
export const description = `
Token field picker with searching
`;
class TokenFieldWithStateAndDefaults extends React.Component {
constructor(props) {
super(props);
this.state = {
value: props.value || [],
};
}
render() {
return (
<TokenField
value={this.state.value}
options={[]}
onChange={value => this.setState({ value })}
multi
valueKey={option => option}
labelKey={option => option}
layoutRenderer={({ valuesList, optionsList }) => (
<div>
{valuesList}
{optionsList}
</div>
)}
{...this.props}
/>
);
}
}
export const examples = {
"": (
<TokenFieldWithStateAndDefaults
options={["Doohickey", "Gadget", "Gizmo", "Widget"]}
/>
),
updateOnInputChange: (
<TokenFieldWithStateAndDefaults
options={["Doohickey", "Gadget", "Gizmo", "Widget"]}
updateOnInputChange
parseFreeformValue={value => value}
/>
),
};
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment