v5.0.0 and v6.0.0 Release Target
Due to the already large size of the v4.0.0 release, I'm going to move some of the targeted changes for the v5.0.0 release target instead.
v5.0.0 Release Target
Improved @react-md/menu API
A new and improved @react-md/menu API. Instead of passing a list of items, directly use the <MenuItem> components within the children.
function Example() {
return (
- <DropdownMenu
- id="dropdown-menu-1"
- items={[
- 'Item 1',
- null,
- 0,
- 1,
- 'separator',
- { children: 'Item 2' },
- { role: 'separator', inset: true },
- { rightAddon: <HomeSVGIcon />, children: 'Home' },
- {
- leftAddon: <InfoOutlineSVGIcon />,
- children: <span>Custom content</span>,
- },
- { href: '#', children: 'Link' },
- <MenuItem>Custom item</MenuItem>,
- <MenuItemLink href="#">Link</MenuItemLink>,
- ]}
- >
- Options...
+ <DropdownMenu id="dropdown-menu-1" buttonChildren="Options...">
+ <MenuItem>Item 1</MenuItem>
+ {someBoolean && <MenuItem>Conditional Item</MenuItem>}
+ <MenuItem>0</MenuItem>
+ <MenuItem>1</MenuItem>
+ <Divider />
+ <MenuItem>Item 2</MenuItem>
+ <Divider inset />
+ <MenuItem rightAddon={<HomeSVGIcon />}>Home</MenuItem>
+ <MenuItem leftAddon={<InfoOutlineSVGIcon />}>
+ <span>Custom content</span>
+ </MenuItem>
+ <MenuItemLink href="#">Link</MenuItemLink>
+ <MenuItem>Custom item</MenuItem>
+ <MenuItemLink href="#">Link</MenuItemLink>
</DropdownMenu>
);
}
These changes make it so that you can now create resuable components to handle specific actions. i.e.
function CreateNewFolder(): ReactElement {
return <MenuItem onClick={() => /* some click behavior */}>Folder</MenuItem>;
}
function Example(): ReactElement {
return (
<DropdownMenu id="some-menu-id" buttonChildren="New">
<CreateNewFolder />
<AnotherAction />
<AndAnotherAction />
</DropdownMenu>
);
}
Additional changes:
- There will be some new hooks to handle creating custom menus
- Support hover mode by default
v6.0.0 Release Target
Improved Select API and Behavior
What I'm mostly trying to accomplish with these changes are:
- fix the terrible typescript types so that you don't need to do:
onChange={(value) => setValue(value as SomeTypeUnion)} - Allow the
Selectto handle validation like theTextFieldandTextAreacomponents- mostly want the
requiredbehavior to start working
- mostly want the
The Select component will now render an invisible <select> element and all the <option>s instead of using an <input type="hidden" value={CURRENT_VALUE} />. This change makes it so that the Select component can now correctly handle form validation.
I'm still working out the API, but I think it'll mimic the new Menu API since it follows how you'd use a native <select> and allows for elements to be rendered without first creating a list of options:
<Select {...props}>
{options.map(({ label, value }) => <Option value={value}>{label}</Option>
</Select>
const [value, setValue] = useState("");
<Select {...props}>
<OptGroup label="A">
// the `label` might be optional since I can automatically pull the text content via refs
<Option label="Alabama" value="AL" />
<Option value="AK"><strong>Alaska</strong></Option>
</OptGroup>
<Divider />
<OptGroup label={<span>C</span>}>
<Option label="California" value="CA" disabled />
</OptGroup>
<Option label="Delaware" value="DE" />
</Select>
Another alternative is something like this (less preferred now):
interface SearchableListboxOption {
label: string;
value: string;
// this would be rendered instead of the `label` if exists. The `label` string is required since this is how the "type to focus" behavior is implemented to mimic the native `<select>` element
children?: ReactNode;
disabled?: boolean;
// Like other places if any of these keys are part of the `ListItemProps`, they will be passed correctly and rendered (like addons, secondaryText, etc)
[key: string]: unknown;
}
type IgnoredListboxOption = Record<string, unknown> | ReactElement;
type ListboxOption = SearchableListboxOption | IgnoredListboxOption;
const options: readonly ListboxOption[] = [
{ label: "Some label", value: "a" },
{ label: "Another Label', value: "b" },
<Divider key="divider-1" />,
{ label: "Final Label", value: "c", disabled: true },
];
const [value, setValue] = useState("");
<Select
id="some-select-id"
options={options}
label="Some label"
value={value}
setValue={setValue}
required
// this is optional (ha) if the default behavior doesn't work for your use-case. I
renderOptions={(option) => {
// this will pretty much be the default implementation
return <Option {...option}>{option.children ?? option.label}</Option>
}}
/>
Quick video example of changes:
https://user-images.githubusercontent.com/3920850/143302148-9a37f442-7e3d-4ebc-a9b1-1f91632047fb.mov
Remove @react-md/autocomplete package
With all the new Select changes listed above, I think it would be better just to integrate the AutoComplete component into the @react-md/form package with a new useAutoComplete hook and AutoComplete component.