Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: Chip without Box #257

Merged
merged 6 commits into from
Jul 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
59 changes: 58 additions & 1 deletion packages/fuselage/.storybook/helpers.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';

import { Box, Text } from '../src';
import { Box } from '../src';

export function PropsVariationSection({ component: Component, common = {}, xAxis = {}, yAxis = {} }) {
return <Box is='table' marginBlock='x16' marginInline='auto' style={{ borderCollapse: 'collapse' }}>
Expand All @@ -25,3 +25,60 @@ export function PropsVariationSection({ component: Component, common = {}, xAxis
</Box>
</Box>;
}

export const exampleAvatar = `data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAA
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
v/L21v8BT/ZVoe1UItsAAAAASUVORK5CYII=`;

export const blankAvatar = `data:image/gif;base64,R0lGODlhAQABAIAAAMLCwgAAACH5BA
AAAAAALAAAAAABAAEAAAICRAEAOw==`;
13 changes: 8 additions & 5 deletions packages/fuselage/src/components/AutoComplete/index.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import React, { useState, useEffect, useRef } from 'react';

import { Box, PositionAnimated } from '../Box';
import { Chip } from '../Chip';
import Chip from '../Chip';
import { Icon } from '../Icon';
import { useCursor, Options } from '../Options';
import { InputBox } from '../InputBox';
import Margins from '../Margins';

const Item = (props) => <Box is='div' marginInline='x4' {...props} />;

Expand Down Expand Up @@ -59,10 +60,12 @@ export function AutoComplete({

return (
<Container ref={containerRef} onClick={() => ref.current.focus()}>
<Chip.Wrapper role='listbox'>
<InputBox.Input ref={ref} onInput={(e) => setFilter(e.currentTarget.value)} onBlur={hide} onFocus={show} onKeyDown={handleKeyDown} placeholder={placeholder} order={1} rcx-input-box--undecorated value={value}/>
{currentValue.map((value) => <SelectedOptions role='option' key={value} onMouseDown={(e) => prevent(e) & internalChanged(value) && false} children={getLabel(options.find((option) => getValue(option) === value))}/>)}
</Chip.Wrapper>
<Box is='div' display='flex' alignItems='center' flexWrap='wrap' margin='-x4' role='listbox'>
<Margins all='x4'>
<InputBox.Input ref={ref} onInput={(e) => setFilter(e.currentTarget.value)} onBlur={hide} onFocus={show} onKeyDown={handleKeyDown} placeholder={placeholder} order={1} rcx-input-box--undecorated value={value}/>
{currentValue.map((value) => <SelectedOptions role='option' key={value} onMouseDown={(e) => prevent(e) & internalChanged(value) && false} children={getLabel(options.find((option) => getValue(option) === value))}/>)}
</Margins>
</Box>
<Addon children={<Icon name='magnifier' size='x20' />}/>
<PositionAnimated visible={visible} anchor={containerRef}>
<Options role='option' renderEmpty={renderEmpty} cursor={cursor} value={value} options={options.map(({ label, value }) => [value, label])} />
Expand Down
2 changes: 2 additions & 0 deletions packages/fuselage/src/components/Box/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
@extend %box;

&--full {
@extend %box--animated;
@extend %box--full;

&::before,
&::after {
@extend %box;
@extend %box--animated;
@extend %box--full;
}
}
Expand Down
26 changes: 26 additions & 0 deletions packages/fuselage/src/components/Box/withBoxStyling.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { createElement } from 'react';

import { useStyleSheet } from '../../hooks/useStyleSheet';
import { useStylingProps } from './stylingProps';

export const withBoxStyling = (component) => {
const render = (props) => {
if (typeof component === 'function') {
return component(props);
}

return createElement(component, props);
};

const WithBoxStyling = (props) => {
useStyleSheet();
props = useStylingProps(props);
return render(props);
};

if (process.env.NODE_ENV !== 'production') {
WithBoxStyling.displayName = `WithBoxStyling(${ component.displayName || component.name || 'Component' })`;
}

return WithBoxStyling;
};
78 changes: 38 additions & 40 deletions packages/fuselage/src/components/Chip/index.js
Original file line number Diff line number Diff line change
@@ -1,52 +1,50 @@
import PropTypes from 'prop-types';
import React from 'react';

import { prependClassName } from '../../helpers/prependClassName';
import { Avatar } from '../Avatar';
import { Box, Flex } from '../Box';
import { withBoxStyling } from '../Box/withBoxStyling';
import { Icon } from '../Icon';
import Margins from '../Margins';

const ThumbDefault = ({ url }) => <Avatar size='x20' url={url}/>;
const RemoveDefault = () => <Icon name='cross' size='x16' />;
const defaultRenderThumb = ({ url }) => <Avatar size='x20' url={url} />;
const defaultRenderDismissSymbol = () => <Icon name='cross' size='x16' />;

export const Chip = ({
const Chip = ({
children,
className,
thumbUrl,
Thumb = ThumbDefault,
onClick,
onMouseDown,
Remove = RemoveDefault,
...props
}) => (
<Flex.Container>
<Box rcx-chip is='button' type='button' disabled={!(onClick || onMouseDown)} onClick={onClick || onMouseDown} {...props}>
{Thumb && thumbUrl && <Margins all='x4'>
<Thumb url={thumbUrl} />
</Margins>}
{children && <Flex.Item shrink={1}>
<Margins all='x4'>
<Box is='span' fontScale='p1' color='default' rcx-chip__text>{children}</Box>
</Margins>
</Flex.Item>}
{Remove && (onClick || onMouseDown) && <Margins all='x4'>
<Box>
<Remove/>
</Box>
</Margins>}
</Box>
</Flex.Container>
);
renderThumb = defaultRenderThumb,
renderDismissSymbol = defaultRenderDismissSymbol,
...rest
}) => {
const onDismiss = onClick || onMouseDown;

Chip.Wrapper = ({ children, width, alignItems = 'center', wrap = 'wrap', ...props }) =>
<Margins all='neg-x4'>
<Flex.Container alignItems={alignItems} wrap={wrap}>
<Box rcx-chip__wrapper is='div' {...props}>
{children.map((children, i) =>
<Flex.Item key={i} shrink={1}>
<Margins all='x4'>
{children}
</Margins>
</Flex.Item>,
)}
</Box>
</Flex.Container>
</Margins>;
return <button
type='button'
className={prependClassName(className, 'rcx-box rcx-chip')}
disabled={!onDismiss}
onClick={onDismiss}
{...rest}
>
<Margins all='x4'>
{thumbUrl && renderThumb && renderThumb({ url: thumbUrl })}
{children && <span className='rcx-box rcx-chip__text'>{children}</span>}
{onDismiss && renderDismissSymbol && renderDismissSymbol()}
</Margins>
</button>;
};

if (process.env.NODE_ENV !== 'production') {
Chip.displayName = 'Chip';

Chip.propTypes = {
thumbUrl: PropTypes.string,
renderThumb: PropTypes.func,
renderDismissSymbol: PropTypes.func,
};
}

export default withBoxStyling(Chip);
49 changes: 38 additions & 11 deletions packages/fuselage/src/components/Chip/stories.mdx
Original file line number Diff line number Diff line change
@@ -1,22 +1,49 @@
import { Meta, Preview, Props, Story } from '@storybook/addon-docs/blocks';
import { action } from '@storybook/addon-actions';
import { exampleAvatar, blankAvatar } from '../../../.storybook/helpers';
import { Box, Chip, Margins } from '../..';

import { Chip, Margins } from '../..';
const thumb = 'data:image/gif;base64,R0lGODlhAQABAIAAAMLCwgAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==';

<Meta title='Misc/Chip' parameters={{ jest: ['Chip/spec'] }} />
<Meta title='Data Display/Chip' parameters={{ jest: ['Chip/spec'] }} />

# Chip

<Preview>
<Story name='Default'>
<Chip.Wrapper>
<Chip onClick={action('click')} thumbUrl={thumb}>Chip</Chip>
<Chip thumbUrl={thumb}>Chip Chip Chip Chip Chip</Chip>
<Chip onClick={action('click')} >Chip Chip Chip Chip Chip Chip Chip Chip Chip Chip</Chip>
<Chip>Chip Chip Chip Chip Chip Chip Chip Chip Chip Chip</Chip>
</Chip.Wrapper>
<Story name='Example'>
<Chip thumbUrl={exampleAvatar} onClick={action('click')}>Marie Rowe</Chip>
</Story>
</Preview>

<Props of={Chip} />

### Default

<Preview>
<Story name='Default'>
<Chip>Chip</Chip>
</Story>
</Preview>

### Dismissible

<Preview>
<Story name='Dismissible'>
<Chip onClick={action('click')}>Chip</Chip>
</Story>
</Preview>

### With thumb

<Preview>
<Story name='With thumb' decorators={[
(storyFn) => <Box display='flex' margin='-x4'>
<Margins all='x4'>
{storyFn()}
</Margins>
</Box>,
]}>
<>
<Chip thumbUrl={blankAvatar}>Chip</Chip>
<Chip thumbUrl={blankAvatar} onClick={action('click')}>Chip</Chip>
</>
</Story>
</Preview>
25 changes: 21 additions & 4 deletions packages/fuselage/src/components/Chip/styles.scss
Original file line number Diff line number Diff line change
@@ -1,12 +1,23 @@
@use '../../styles/colors.scss';
@use '../../styles/lengths.scss';
@use '../../styles/typography.scss';

.rcx-chip {
@include clickable;
@include typography.use-text-ellipsis;

@extend %box--animated;
@extend %box--full;
@extend %button--secondary;

display: flex;
overflow: hidden;
align-items: center;

min-height: lengths.size(28);

border-width: 0;

@include clickable;
@include typography.use-font-scale('p1');

&.disabled,
&:disabled {
color: $button-colors-secondary-color;
Expand All @@ -15,7 +26,13 @@
}

&__text {
@include typography.use-text-ellipsis;
white-space: nowrap;
letter-spacing: inherit;

color: inherit;

font: inherit;

@include typography.use-text-ellipsis;
}
}
10 changes: 5 additions & 5 deletions packages/fuselage/src/components/Select/MultiSelect.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useState, useRef, useEffect, useCallback } from 'react';

import { AnimatedVisibility, Box, Flex, Position } from '../Box';
import { Chip } from '../Chip';
import Chip from '../Chip';
import { Icon } from '../Icon';
import { InputBox } from '../InputBox';
import Margins from '../Margins';
Expand Down Expand Up @@ -79,12 +79,12 @@ export const MultiSelect = ({
<Margins inline='x4'>
<Flex.Container>
<Box is='div'>
<Margins all='neg-x8'>
<Chip.Wrapper role='listbox'>
<Box is='div' display='flex' alignItems='center' flexWrap='wrap' margin='-x8' role='listbox'>
<Margins all='x4'>
<Anchor disabled={disabled} ref={ref} aria-haspopup='listbox' onClick={show} onBlur={hide} onKeyUp={handleKeyUp} onKeyDown={handleKeyDown} order={1} rcx-input-box--undecorated children={!value ? option || placeholder : null}/>
{currentValue.map((value) => <SelectedOptions tabIndex={-1} role='option' key={value} onMouseDown={(e) => prevent(e) & internalChanged([value]) && false} children={getLabel(options.find(([val]) => val === value))}/>)}
</Chip.Wrapper>
</Margins>
</Margins>
</Box>
</Box>
</Flex.Container>
</Margins>
Expand Down
2 changes: 1 addition & 1 deletion packages/fuselage/src/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export * from './ButtonGroup';
export * from './Callout';
export * from './CheckBox';
export * from './Chevron';
export * from './Chip';
export { default as Chip } from './Chip';
export * from './Divider';
export * from './EmailInput';
export * from './Field';
Expand Down
10 changes: 6 additions & 4 deletions packages/fuselage/src/styles/primitives/box.scss
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,17 @@
-moz-osx-font-smoothing: grayscale;
}

%box--full {
margin: lengths.margin('none');
padding: lengths.padding('none');

%box--animated {
transition: all 230ms;

@media (prefers-reduced-motion) {
transition: none;
}
}

%box--full {
margin: lengths.margin('none');
padding: lengths.padding('none');

border-width: lengths.border-width('none');
border-style: solid;
Expand Down