Skip to content

Commit c251bc9

Browse files
devongovettGitHub Enterprise
authored andcommitted
Add UI icons and checkbox implementation (#8)
1 parent 4a0035c commit c251bc9

37 files changed

+313
-18
lines changed

.storybook-s2/.parcelrc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"extends": "@parcel/config-default",
33
"resolvers": ["parcel-resolver-storybook", "..."],
44
"transformers": {
5-
"{src,stories}/*.tsx": ["../parcel-transformer-react-docgen-typescript/ReactDocgenTSTransformer.ts", "..."]
5+
"{src,stories}/*.tsx": ["../parcel-transformer-react-docgen-typescript/ReactDocgenTSTransformer.ts", "..."],
6+
"*.svg": ["@parcel/transformer-svg-react"]
67
}
78
}

packages/@react-spectrum/s2/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"devDependencies": {
1818
"@adobe/spectrum-tokens": "^13.0.0-beta.9",
1919
"@parcel/config-default": "2.0.0-nightly.1484",
20+
"@parcel/transformer-svg-react": "^2.11.0",
2021
"@storybook/addon-designs": "^7.0.5",
2122
"@storybook/addon-essentials": "^7.5.3",
2223
"@storybook/addon-interactions": "^7.5.3",

packages/@react-spectrum/s2/src/CenterBaseline.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ interface CenterBaselineProps {
88

99
export function CenterBaseline(props: CenterBaselineProps) {
1010
return (
11-
<div className={props.className + ' ' + raw('display: flex; align-items: center; &::before { content: "\u00a0"; width: 0; visibility: hidden }')}>
11+
<div className={(props.className || '') + ' ' + raw('display: flex; align-items: center; &::before { content: "\u00a0"; width: 0; visibility: hidden }')}>
1212
{props.children}
1313
</div>
1414
);

packages/@react-spectrum/s2/src/Checkbox.tsx

Lines changed: 120 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,127 @@
1-
import {Checkbox as AriaCheckbox, CheckboxProps} from 'react-aria-components';
1+
import {Checkbox as AriaCheckbox, CheckboxProps as AriaCheckboxProps, CheckboxRenderProps} from 'react-aria-components';
2+
import {style, baseColor} from '../style-macro/spectrum-theme.ts' with {type: 'macro'};
3+
import {focusRing} from './style-utils.ts' with {type: 'macro'};
4+
import {CenterBaseline} from './CenterBaseline.tsx';
5+
import CheckmarkIcon from '../ui-icons/S2_CheckmarkSize100.svg';
6+
import DashIcon from '../ui-icons/S2_DashSize100.svg';
7+
import {useRef} from 'react';
8+
import {pressScale} from './pressScale';
9+
import {mergeStyles} from '../style-macro/runtime.ts';
210

11+
interface CheckboxStyleProps {
12+
size?: 'S' | 'M' | 'L' | 'XL',
13+
isEmphasized?: boolean
14+
}
15+
16+
interface RenderProps extends CheckboxRenderProps, CheckboxStyleProps {}
17+
18+
interface CheckboxProps extends Omit<AriaCheckboxProps, 'className'>, CheckboxStyleProps {
19+
className?: string
20+
}
21+
22+
const wrapper = style<RenderProps>({
23+
display: 'flex',
24+
columnGap: 'text-to-control',
25+
alignItems: 'baseline',
26+
fontFamily: 'sans',
27+
fontSize: 'control',
28+
transition: 'colors',
29+
color: {
30+
default: 'neutral',
31+
isDisabled: {
32+
default: 'disabled',
33+
forcedColors: 'GrayText'
34+
}
35+
}
36+
});
37+
38+
const box = style<RenderProps>({
39+
...focusRing(),
40+
size: 'control-sm',
41+
borderRadius: 'control-sm',
42+
flexShrink: 0,
43+
display: 'flex',
44+
alignItems: 'center',
45+
justifyContent: 'center',
46+
borderWidth: 2,
47+
boxSizing: 'border-box',
48+
borderStyle: 'solid',
49+
transition: 'default',
50+
forcedColorAdjust: 'none',
51+
backgroundColor: {
52+
default: 'gray-25',
53+
isSelected: {
54+
default: 'neutral',
55+
isEmphasized: baseColor('accent-900'),
56+
forcedColors: 'Highlight',
57+
isInvalid: {
58+
default: baseColor('negative-900'),
59+
forcedColors: 'Mark'
60+
},
61+
isDisabled: {
62+
default: 'disabled',
63+
forcedColors: 'GrayText'
64+
}
65+
}
66+
},
67+
borderColor: {
68+
default: baseColor('gray-800'),
69+
forcedColors: 'ButtonBorder',
70+
isInvalid: {
71+
default: 'negative',
72+
forcedColors: 'Mark'
73+
},
74+
isDisabled: {
75+
default: 'disabled',
76+
forcedColors: 'GrayText'
77+
},
78+
isSelected: 'transparent'
79+
}
80+
});
81+
82+
const iconStyles = style<RenderProps>({
83+
size: {
84+
default: 2.5,
85+
size: {
86+
XL: 3
87+
}
88+
},
89+
'--iconPrimary': {
90+
type: 'color',
91+
value: {
92+
default: 'gray-25',
93+
forcedColors: 'HighlightText',
94+
isDisabled: 'gray-400'
95+
}
96+
}
97+
});
398

4-
export function Checkbox({children, ...props}: CheckboxProps) {
99+
export function Checkbox({children, ...props}: CheckboxProps & CheckboxStyleProps) {
100+
let boxRef = useRef(null);
5101
return (
6-
<AriaCheckbox {...props}>
7-
{({isIndeterminate}) => (
102+
<AriaCheckbox
103+
{...props}
104+
className={renderProps => mergeStyles(props.className, wrapper({...renderProps, size: props.size || 'M'}))}>
105+
{renderProps => (
8106
<>
9-
<div className="checkbox">
10-
<svg viewBox="0 0 18 18" aria-hidden="true">
11-
{isIndeterminate
12-
? <rect x={1} y={7.5} width={15} height={3} />
13-
: <polyline points="1 9 7 14 15 4" />}
14-
</svg>
15-
</div>
107+
<CenterBaseline>
108+
<div
109+
ref={boxRef}
110+
style={pressScale(boxRef)(renderProps)}
111+
className={box({
112+
...renderProps,
113+
isSelected: renderProps.isSelected || renderProps.isIndeterminate,
114+
size: props.size || 'M',
115+
isEmphasized: props.isEmphasized
116+
})}>
117+
{renderProps.isIndeterminate &&
118+
<DashIcon className={iconStyles({...renderProps, size: props.size})} />
119+
}
120+
{renderProps.isSelected && !renderProps.isIndeterminate &&
121+
<CheckmarkIcon className={iconStyles({...renderProps, size: props.size})} />
122+
}
123+
</div>
124+
</CenterBaseline>
16125
{children}
17126
</>
18127
)}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
declare module '*.svg' {
2+
import {FunctionComponent, SVGProps} from 'react';
3+
const content: FunctionComponent<SVGProps<SVGSVGElement>> ;
4+
export default content;
5+
}
Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
1-
import {Checkbox} from '../src/Checkbox';
2-
31
import type {Meta} from '@storybook/react';
2+
import {Checkbox} from '../src/Checkbox';
3+
import {style} from '../style-macro/spectrum-theme.ts' with {type: 'macro'};
44

55
const meta: Meta<typeof Checkbox> = {
66
component: Checkbox,
77
parameters: {
88
layout: 'centered'
9-
}
9+
},
10+
tags: ['autodocs']
1011
};
1112

1213
export default meta;
1314

14-
export const Example = (args: any) => (<Checkbox {...args}>Unsubscribe
15-
</Checkbox>);
15+
export const Example = (args: any) => (<Checkbox {...args}>Unsubscribe</Checkbox>);
16+
17+
export const LongLabel = (args: any) => (<Checkbox {...args} className={style({maxWidth: 32})()}>Checkbox with very long label so we can see wrapping</Checkbox>);
18+
Lines changed: 5 additions & 0 deletions
Loading
Lines changed: 5 additions & 0 deletions
Loading
Lines changed: 6 additions & 0 deletions
Loading
Lines changed: 6 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)