Skip to content

Commit 70fbbaa

Browse files
committed
Add some padding to the story
1 parent 1926074 commit 70fbbaa

22 files changed

+2599
-3354
lines changed

package.json

Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,9 @@
6565
"devDependencies": {
6666
"@babel/core": "^7.12.3",
6767
"@emotion/babel-plugin": "^11.2.0",
68-
"@emotion/babel-preset-css-prop": "^10.0.27",
69-
"@emotion/core": "^10.0.35",
70-
"@size-limit/preset-small-lib": "^4.6.2",
68+
"@emotion/babel-preset-css-prop": "10.0.27",
69+
"@emotion/core": "10.0.35",
70+
"@size-limit/preset-small-lib": "^8.1.0",
7171
"@storybook/addon-a11y": "^6.1.21",
7272
"@storybook/addon-essentials": "^6.0.26",
7373
"@storybook/addon-info": "^5.3.21",
@@ -79,14 +79,14 @@
7979
"babel-loader": "^8.1.0",
8080
"babel-plugin-polished": "^1.1.0",
8181
"chromatic": "^6.5.1",
82-
"husky": "^4.3.0",
82+
"husky": "^8.0.1",
8383
"polished": "^4.2.2",
8484
"react": "18",
8585
"react-dom": "18",
8686
"react-hook-form": "^7.27.1",
87-
"react-is": "^17.0.1",
88-
"size-limit": "^4.6.2",
89-
"storybook-addon-designs": "^5.4.5",
87+
"react-is": "^18.2.0",
88+
"size-limit": "^8.1.0",
89+
"storybook-addon-designs": "^6.3.1",
9090
"tslib": "^2.0.3",
9191
"typescript": "^4.0.3"
9292
},
@@ -97,33 +97,34 @@
9797
"**/@typescript-eslint/parser": "^4.1.1"
9898
},
9999
"dependencies": {
100-
"@react-aria/button": "^3.3.1",
101-
"@react-aria/dialog": "^3.1.2",
102-
"@react-aria/focus": "^3.2.3",
103-
"@react-aria/i18n": "^3.5.1",
104-
"@react-aria/interactions": "^3.3.3",
105-
"@react-aria/listbox": "^3.3.1",
106-
"@react-aria/overlays": "^3.6.1",
107-
"@react-aria/radio": "^3.1.3",
108-
"@react-aria/select": "^3.5.0",
109-
"@react-aria/separator": "^3.1.3",
110-
"@react-aria/textfield": "^3.5.2",
111-
"@react-aria/tooltip": "^3.1.1",
112-
"@react-aria/utils": "^3.6.0",
113-
"@react-aria/virtualizer": "^3.3.4",
114-
"@react-aria/visually-hidden": "^3.2.1",
115-
"@react-stately/collections": "^3.3.4",
116-
"@react-stately/layout": "^3.4.2",
117-
"@react-stately/list": "^3.3.0",
118-
"@react-stately/overlays": "^3.1.1",
119-
"@react-stately/radio": "^3.3.0",
120-
"@react-stately/select": "^3.1.3",
121-
"@react-stately/tooltip": "^3.0.3",
122-
"@react-stately/utils": "^3.2.0",
123-
"@react-stately/virtualizer": "^3.1.5",
124-
"@react-types/shared": "^3.5.0",
100+
"@react-aria/button": "^3.6.2",
101+
"@react-aria/dialog": "^3.4.0",
102+
"@react-aria/focus": "^3.9.0",
103+
"@react-aria/i18n": "^3.6.1",
104+
"@react-aria/interactions": "^3.12.0",
105+
"@react-aria/listbox": "^3.7.0",
106+
"@react-aria/overlays": "^3.11.0",
107+
"@react-aria/radio": "^3.4.0",
108+
"@react-aria/select": "^3.8.2",
109+
"@react-aria/separator": "^3.2.4",
110+
"@react-aria/textfield": "^3.7.2",
111+
"@react-aria/tooltip": "^3.3.2",
112+
"@react-aria/utils": "^3.14.0",
113+
"@react-aria/visually-hidden": "^3.5.0",
114+
"@react-stately/collections": "^3.4.4",
115+
"@react-stately/layout": "^3.8.0",
116+
"@react-stately/list": "^3.5.4",
117+
"@react-stately/overlays": "^3.4.2",
118+
"@react-stately/radio": "^3.6.0",
119+
"@react-stately/select": "^3.3.2",
120+
"@react-stately/tooltip": "^3.2.2",
121+
"@react-stately/utils": "^3.5.1",
122+
"@react-stately/virtualizer": "^3.3.1",
123+
"@react-types/shared": "^3.15.0",
125124
"@storybook/addon-measure": "^6.5.10",
126125
"@types/react-transition-group": "^4.4.5",
126+
"@typescript-eslint/eslint-plugin": "^5.39.0",
127+
"@typescript-eslint/parser": "^5.39.0",
127128
"clsx": "^1.1.1",
128129
"react-transition-group": "^4.4.5",
129130
"tsdx": "^0.14.1"

src/button/styles.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export const buttonCSS = css`
99
display: flex;
1010
justify-content: center;
1111
align-items: center;
12-
box-sizing: content-box;
12+
box-sizing: border-box;
1313
border-radius: ${theme.borderRadius.medium}px;
1414
color: ${theme.textColors.white90};
1515
cursor: pointer;

src/icon/Icons.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,3 +476,16 @@ export const CloseCircleOutline = () => (
476476
</g>
477477
</svg>
478478
);
479+
480+
export const MoreHorizontalOutline = () => (
481+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
482+
<g data-name="Layer 2">
483+
<g data-name="more-horizotnal">
484+
<rect width="24" height="24" opacity="0" />
485+
<circle cx="12" cy="12" r="2" />
486+
<circle cx="19" cy="12" r="2" />
487+
<circle cx="5" cy="12" r="2" />
488+
</g>
489+
</g>
490+
</svg>
491+
);

src/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export * from './search';
2222
export * from './overlays';
2323
export * from './dialog';
2424
export * from './view';
25+
export * from './menu';
2526
export { theme } from './theme';
2627
// export interface Props extends HTMLAttributes<HTMLDivElement> {
2728
// /** custom content, defaults to 'the snozzberries taste like snozzberries' */

src/listbox/ListBoxOption.tsx

Lines changed: 3 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { Icon, CheckmarkOutline } from '../icon';
2-
import { css } from '@emotion/core';
32
import { classNames } from '../utils';
43
import { FocusRing } from '@react-aria/focus';
54
import { isFocusVisible, useHover } from '@react-aria/interactions';
@@ -10,7 +9,7 @@ import React, { useContext } from 'react';
109
import { Text } from '../content';
1110
import { useOption } from '@react-aria/listbox';
1211
import { useRef } from 'react';
13-
import theme from '../theme';
12+
import { menuItemCSS } from '../menu/styles';
1413

1514
interface OptionProps<T> {
1615
item: Node<T>;
@@ -19,23 +18,6 @@ interface OptionProps<T> {
1918
shouldUseVirtualFocus?: boolean;
2019
}
2120

22-
const menuItemCSS = css`
23-
&.is-selected {
24-
i {
25-
color: ${theme.colors.arizeLightBlue};
26-
}
27-
}
28-
&.is-hovered,
29-
&.focus-ring {
30-
background-color: ${theme.colors.hoverBgColor};
31-
}
32-
&.is-selectable {
33-
cursor: pointer;
34-
}
35-
/* show focus in other ways */
36-
outline: none;
37-
`;
38-
3921
/** @private */
4022
export function ListBoxOption<T>(props: OptionProps<T>) {
4123
let {
@@ -94,25 +76,8 @@ export function ListBoxOption<T>(props: OptionProps<T>) {
9476
})}
9577
css={menuItemCSS}
9678
>
97-
<div
98-
className="ac-menu-item"
99-
css={css`
100-
display: flex;
101-
justify-content: space-between;
102-
align-items: flex-start;
103-
color: ${theme.textColors.white90};
104-
padding: ${theme.spacing.padding8}px ${theme.spacing.padding16}px;
105-
position: relative;
106-
& > .ac-icon-wrap {
107-
position: absolute;
108-
top: ${theme.spacing.padding8}px;
109-
right: ${theme.spacing.padding8}px;
110-
}
111-
`}
112-
>
113-
{contents}
114-
{isSelected && <Icon svg={<CheckmarkOutline />} />}
115-
</div>
79+
{contents}
80+
{isSelected && <Icon svg={<CheckmarkOutline />} />}
11681
</div>
11782
</FocusRing>
11883
);

src/menu/ActionMenu.tsx

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { Button } from '../button';
2+
import { filterDOMProps } from '@react-aria/utils';
3+
import { FocusableRef } from '@react-types/shared';
4+
import { Menu } from './Menu';
5+
import { MenuTrigger } from './MenuTrigger';
6+
import { Icon, MoreHorizontalOutline } from '../icon';
7+
import React, { forwardRef, ReactElement } from 'react';
8+
import { ActionMenuProps } from '../types';
9+
10+
function ActionMenu<T extends object>(
11+
props: ActionMenuProps<T>,
12+
ref: FocusableRef<HTMLButtonElement>
13+
) {
14+
const { children, buttonText, icon } = props;
15+
const buttonProps = filterDOMProps(props, { labelable: true });
16+
if (buttonProps['aria-label'] === undefined) {
17+
buttonProps['aria-label'] = 'actions';
18+
}
19+
20+
return (
21+
<MenuTrigger
22+
isOpen={props.isOpen}
23+
defaultOpen={props.defaultOpen}
24+
onOpenChange={props.onOpenChange}
25+
align={props.align}
26+
direction={props.direction}
27+
shouldFlip={props.shouldFlip}
28+
>
29+
<Button
30+
variant="default"
31+
icon={icon ?? <Icon svg={<MoreHorizontalOutline />} />}
32+
ref={ref}
33+
{...buttonProps}
34+
children={buttonText}
35+
/>
36+
<Menu
37+
children={children}
38+
items={props.items}
39+
disabledKeys={props.disabledKeys}
40+
onAction={props.onAction}
41+
/>
42+
</MenuTrigger>
43+
);
44+
}
45+
46+
/**
47+
* ActionMenu combines an ActionButton with a Menu for simple "more actions" use cases.
48+
*/
49+
const _ActionMenu = forwardRef(ActionMenu) as <T>(
50+
props: ActionMenuProps<T> & { ref?: FocusableRef<HTMLButtonElement> }
51+
) => ReactElement;
52+
export { _ActionMenu as ActionMenu };

src/menu/Menu.tsx

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import { useDOMRef } from '../utils';
2+
import {
3+
AriaLabelingProps,
4+
CollectionBase,
5+
DOMProps,
6+
DOMRef,
7+
FocusStrategy,
8+
MultipleSelection,
9+
} from '../types';
10+
import { MenuContext } from './context';
11+
import { MenuItem } from './MenuItem';
12+
import { MenuSection } from './MenuSection';
13+
import { mergeProps, useSyncRef } from '@react-aria/utils';
14+
import React, { Key, ReactElement, useContext } from 'react';
15+
import { SpectrumMenuProps } from '@react-types/menu';
16+
import { useMenu } from '@react-aria/menu';
17+
import { useTreeState } from '@react-stately/tree';
18+
import theme from '../theme';
19+
import { css } from '@emotion/core';
20+
21+
export interface MenuProps<T> extends CollectionBase<T>, MultipleSelection {
22+
/** Where the focus should be set. */
23+
autoFocus?: boolean | FocusStrategy;
24+
/** Whether keyboard navigation is circular. */
25+
shouldFocusWrap?: boolean;
26+
/** Handler that is called when an item is selected. */
27+
onAction?: (key: Key) => void;
28+
/** Handler that is called when the menu should close after selecting an item. */
29+
onClose?: () => void;
30+
}
31+
32+
export interface AriaMenuProps<T>
33+
extends MenuProps<T>,
34+
DOMProps,
35+
AriaLabelingProps {}
36+
37+
export interface MenuComponentProps<T> extends AriaMenuProps<T> {}
38+
39+
const menuULCSS = css`
40+
background-color: ${theme.colors.gray500};
41+
border-radius: 4px;
42+
color: ${theme.textColors.white90};
43+
box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.4);
44+
outline: none;
45+
border: 1px solid ${theme.components.dropdown.borderColor};
46+
max-height: inherit;
47+
list-style: none;
48+
margin: 0;
49+
padding: 0;
50+
`;
51+
function Menu<T extends object>(
52+
props: MenuComponentProps<T>,
53+
ref: DOMRef<HTMLUListElement>
54+
) {
55+
let contextProps = useContext(MenuContext);
56+
let completeProps = {
57+
...mergeProps(contextProps, props),
58+
};
59+
60+
let domRef = useDOMRef(ref);
61+
let state = useTreeState(completeProps);
62+
let { menuProps } = useMenu(completeProps, state, domRef);
63+
useSyncRef(contextProps, domRef);
64+
65+
return (
66+
<ul {...menuProps} ref={domRef} className={'ac-menu'} css={menuULCSS}>
67+
{[...state.collection].map(item => {
68+
if (item.type === 'section') {
69+
return (
70+
<MenuSection
71+
key={item.key}
72+
item={item}
73+
state={state}
74+
onAction={completeProps.onAction}
75+
/>
76+
);
77+
}
78+
79+
let menuItem = (
80+
<MenuItem
81+
key={item.key}
82+
item={item}
83+
state={state}
84+
onAction={completeProps.onAction}
85+
/>
86+
);
87+
88+
if (item.wrapper) {
89+
menuItem = item.wrapper(menuItem);
90+
}
91+
92+
return menuItem;
93+
})}
94+
</ul>
95+
);
96+
}
97+
98+
/**
99+
* Menus display a list of actions or options that a user can choose.
100+
*/
101+
// forwardRef doesn't support generic parameters, so cast the result to the correct type
102+
// https://stackoverflow.com/questions/58469229/react-with-typescript-generics-while-using-react-forwardref
103+
const _Menu = React.forwardRef(Menu) as <T>(
104+
props: SpectrumMenuProps<T> & { ref?: DOMRef<HTMLUListElement> }
105+
) => ReactElement;
106+
export { _Menu as Menu };

0 commit comments

Comments
 (0)