Skip to content

Commit

Permalink
Add FocusableItem example and documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
szhsin committed Oct 3, 2020
1 parent 0be753c commit 4508b0b
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 1 deletion.
27 changes: 27 additions & 0 deletions example/src/components/Usage.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
Menu,
MenuItem,
MenuButton,
FocusableItem,
SubMenu,
MenuRadioGroup,
MenuHeader,
Expand Down Expand Up @@ -43,6 +44,7 @@ export const Usage = React.memo(function Usage() {
<LinkAndDisabledExample />
<IconAndImageExample />
<HoverAndActiveExample />
<FocusableItemExample />

<GroupingSection data={codeExamples.menuButton} />
<OpenStateExample />
Expand Down Expand Up @@ -356,6 +358,31 @@ function HoverAndActiveExample() {
);
}

function FocusableItemExample() {
const [filter, setFilter] = useState('');

return (
<Example data={codeExamples.focusableItem} >
<Menu menuButton={<MenuButton>Open menu</MenuButton>}
align="center" onChange={e => e.open && setFilter('')}>
<FocusableItem>
{({ ref }) => (
<input ref={ref} className="form-control" type="text"
placeholder="Type to filter" value={filter}
onChange={e => setFilter(e.target.value)} />
)}
</FocusableItem>
{
['Apple', 'Banana', 'Blueberry', 'Cherry', 'Strawberry']
.filter(fruit => fruit.toUpperCase()
.includes(filter.trim().toUpperCase()))
.map(fruit => <MenuItem key={fruit}>{fruit}</MenuItem>)
}
</Menu>
</Example>
);
}

function OpenStateExample() {

return (
Expand Down
71 changes: 70 additions & 1 deletion example/src/data/codeExamples.js
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,74 @@ export default function Example() {
}`
};

export const focusableItem = {
id: 'focusable-item',
title: 'Focusable item',
desc:
<>
<p><code>FocusableItem</code> is a special menu item. It's used to wrap elements
which are able to receive focus, such as input or button.</p>
<p>It receives a render prop as children and passes down a <code>ref</code> and
several other states. This example demonstrates how to use an input element to filter
menu items.</p>
</>,

source:
`const [filter, setFilter] = useState('');
<Menu menuButton={<MenuButton>Open menu</MenuButton>}
onChange={e => e.open && setFilter('')}>
<FocusableItem>
{({ ref }) => (
<input ref={ref} className="form-control" type="text"
placeholder="Type to filter" value={filter}
onChange={e => setFilter(e.target.value)} />
)}
</FocusableItem>
{
['Apple', 'Banana', 'Blueberry', 'Cherry', 'Strawberry']
.filter(fruit => fruit.toUpperCase()
.includes(filter.trim().toUpperCase()))
.map(fruit => <MenuItem key={fruit}>{fruit}</MenuItem>)
}
</Menu>`,

fullSource:
`import React, { useState } from 'react';
import {
Menu,
MenuItem,
FocusableItem,
MenuButton
} from '@szhsin/react-menu';
import '@szhsin/react-menu/dist/index.css';
export default function Example() {
const [filter, setFilter] = useState('');
return (
<Menu menuButton={<MenuButton>Open menu</MenuButton>}
onChange={e => e.open && setFilter('')}>
<FocusableItem>
{({ ref }) => (
<input ref={ref} className="form-control" type="text"
placeholder="Type to filter" value={filter}
onChange={e => setFilter(e.target.value)} />
)}
</FocusableItem>
{
['Apple', 'Banana', 'Blueberry', 'Cherry', 'Strawberry']
.filter(fruit => fruit.toUpperCase()
.includes(filter.trim().toUpperCase()))
.map(fruit => <MenuItem key={fruit}>{fruit}</MenuItem>)
}
</Menu>
);
}`
};


export const hoverAndActive = {
id: 'hover-active',

Expand Down Expand Up @@ -1179,7 +1247,8 @@ export const menuItem = {
list: [
linkAndDisabled,
iconAndImage,
hoverAndActive
hoverAndActive,
focusableItem
]
};

Expand Down
49 changes: 49 additions & 0 deletions example/src/data/documentation.js
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,54 @@ const menuRadioGroup = {
]
};

const focusableItem = {
id: 'focusable-item',
title: 'FocusableItem',
desc: <p><code>FocusableItem</code> can be used to wrap focusable element (input, button) in a
menu item. It manages focus automatically among other menu items during mouse and keyboard
interactions.</p>,
rows: [
...styleProps('focusable item', (
<ul>
<li><code>focusable: bool</code> always <code>true</code> for a focusable item.</li>
<li><code>hover: bool</code> indicates if the focusable item is being hovered.</li>
<li><code>disabled: bool</code> indicates if the focusable item is disabled.</li>
</ul>
)),
{
name: 'disabled',
type: 'boolean',
desc:
<>
<p>Set <code>true</code> to disabled the item.</p>
<p>Please note this prop only removes the current item from mouse and keyboard
interaction sequences. You still need to disable any focusable element
which you have supplied in its children. This prop is passed to the
children render function.</p>
</>
},
{
name: 'children',
type: 'function',
desc:
<>
<p>A function which returns what to be rendered. It will be called by passing an
object with the following properties:</p>
<ul>
<li><code>hover: bool</code> indicates if the focusable item is being hovered.</li>
<li><code>disabled: bool</code> indicates if the focusable item is disabled.</li>
<li><code>ref: object</code> A ref to be attached to the element which should receive
focus when this focusable item is hovered. <br />If you render a React component,
it needs to expose a <code>focus</code> method or supports ref forwarding.</li>
<li><code>closeMenu: func</code> A function that requests to close the root menu.
You could optionally pass a <code>keyCode</code> parameter to indicate which key
initiates the close request.</li>
</ul>
</>
},
]
};

const controlledMenu = {
id: 'controlled-menu',
title: 'ControlledMenu',
Expand Down Expand Up @@ -632,6 +680,7 @@ const components = {
menu,
menuItem,
menuButton,
focusableItem,
submenu,
menuRadioGroup,
menuHeader,
Expand Down

0 comments on commit 4508b0b

Please sign in to comment.