Skip to content

Commit

Permalink
feat: styling CheckboxButtons, building out typography sprinkles
Browse files Browse the repository at this point in the history
  • Loading branch information
skinread committed Dec 17, 2024
1 parent cdc388a commit 4e1a773
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 15 deletions.
61 changes: 55 additions & 6 deletions lib/components/CheckboxButtons/CheckboxButtons.css.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { style } from '@vanilla-extract/css';
import { recipe } from '@vanilla-extract/recipes';

import { tokens } from 'lib/themes/base/tokens';

import { odStyle, type ODStyle } from '../../styles/sprinkles.css';

const border: ODStyle = {
borderColor: 'light',
borderColor: 'gray',
borderStyle: 'solid',
borderWidth: '1',
};
Expand All @@ -15,32 +18,70 @@ const focusOutline: ODStyle = {
outlineWidth: { initial: 'none', focusVisible: 'default' },
};

const buttonBorderRadius = tokens.border.radius['2'];

export const checkboxButton = recipe({
base: [
odStyle({
background: { initial: 'gray100', hover: 'gray300' },
background: {
initial: 'white',
hover: 'gray100',
},
...border,
borderRadius: '2',
cursor: { hover: 'pointer' },
display: 'flex',
gap: '2',
padding: '2',
paddingX: '4',
paddingY: '3',
width: '100%',
}),
style({
selectors: {
['&+&']: {
borderTopStyle: 'none',
},
['&:first-child']: {
borderTopLeftRadius: buttonBorderRadius,
borderTopRightRadius: buttonBorderRadius,
},
['&:last-child']: {
borderBottomLeftRadius: buttonBorderRadius,
borderBottomRightRadius: buttonBorderRadius,
},
},
}),
],
variants: {
disabled: {
true: style({
opacity: 0.6,
selectors: {
['&&']: {
background: 'none',
cursor: 'default',
},
},
}),
},
},
});

export const checkbox = recipe({
base: odStyle({
size: '6',
alignItems: 'center',
...border,
borderRadius: '1',
display: 'flex',
flexShrink: 0,
justifyContent: 'center',
...focusOutline,
size: '6',
}),
variants: {
checked: {
true: odStyle({
background: 'blue800',
background: 'gray900',
borderColor: 'dark',
}),
false: odStyle({
background: 'white',
Expand All @@ -51,3 +92,11 @@ export const checkbox = recipe({
},
},
});

export const groupLabel = recipe({
base: odStyle({
font: 'xxl',
fontWeight: 'bold',
marginBottom: '6',
}),
});
13 changes: 10 additions & 3 deletions lib/components/CheckboxButtons/CheckboxButtons.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const meta: Meta<typeof CheckboxButtons> = {
title: 'Components/Checkbox Buttons',
component: CheckboxButtons,
args: {
label: 'Add something extra',
label: 'Commonly requested extras',
children: itemData.map((item, idx) => (
<CheckboxButtons.Item key={idx} value={`${idx}`}>
{item[0]}
Expand Down Expand Up @@ -43,8 +43,8 @@ export const Simple: Story = {};

/**
* To acheive the the split-column layout in the checkbox label, use a CheckboxButtons.SplitLabel layout helper
* inside the CheckboxButtons.Item component. Populate the `items` prop on the SplitLabel with a string array
* (content left, content right).
* inside the CheckboxButtons.Item component. Currently supports text only. Populate the `items` prop on the SplitLabel
* with a string array (content left, content right).
*/
export const SplitLabel: Story = {
args: {
Expand All @@ -55,3 +55,10 @@ export const SplitLabel: Story = {
)),
},
};

export const Disabled: Story = {
args: {
...SplitLabel.args,
isDisabled: true,
},
};
7 changes: 5 additions & 2 deletions lib/components/CheckboxButtons/CheckboxButtons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { createContext } from 'react';
import { useCheckboxGroup, type AriaCheckboxGroupProps } from 'react-aria';
import { type CheckboxGroupState, useCheckboxGroupState } from 'react-stately';

import { groupLabel } from './CheckboxButtons.css';
import { CheckboxItem, SplitLabel } from './CheckboxItem';

export interface CheckboxButtonsProps extends AriaCheckboxGroupProps {
Expand Down Expand Up @@ -43,9 +44,11 @@ export const CheckboxButtons = (props: CheckboxButtonsProps) => {

return (
<div {...groupProps}>
<span {...labelProps}>{label}</span>
<div {...labelProps} className={groupLabel()}>
{label}
</div>
<CheckboxButtonsContext.Provider value={state}>
{children}
<div>{children}</div>
</CheckboxButtonsContext.Provider>
{description && <div {...descriptionProps}>{description}</div>}
</div>
Expand Down
7 changes: 5 additions & 2 deletions lib/components/CheckboxButtons/CheckboxItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import {
useCheckboxGroupItem,
useFocusRing,
mergeProps,
VisuallyHidden,
type AriaCheckboxGroupItemProps,
} from 'react-aria';

import { odStyle } from '../../styles/sprinkles.css';
import { VisuallyHidden } from '../VisuallyHidden';

import { CheckboxButtonsContext } from './CheckboxButtons';
import { checkbox, checkboxButton } from './CheckboxButtons.css';
Expand Down Expand Up @@ -43,10 +43,11 @@ export const CheckboxItem = (props: FilteredCheckboxProps) => {
const state = useContext(CheckboxButtonsContext)!;
const { inputProps } = useCheckboxGroupItem(props, state, ref);
const { isFocusVisible, focusProps } = useFocusRing();
const isDisabled = state.isDisabled;
const isSelected = state.isSelected(props.value);

return (
<label className={checkboxButton()}>
<label className={checkboxButton({ disabled: isDisabled })}>
<VisuallyHidden>
<input {...mergeProps(inputProps, focusProps)} ref={ref} />
</VisuallyHidden>
Expand All @@ -67,6 +68,8 @@ export const CheckboxItem = (props: FilteredCheckboxProps) => {
</div>
<div
className={odStyle({
alignSelf: 'center',
font: 'sm',
width: '100%',
})}
>
Expand Down
51 changes: 49 additions & 2 deletions lib/styles/sprinkles.css.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { createSprinkles, defineProperties } from '@vanilla-extract/sprinkles';

import { tokens } from '../themes/base/tokens';
const { border, colours, elevation, space } = tokens;
const { border, colours, elevation, space, typography } = tokens;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { none, ...spaceWithoutNone } = space;

Expand Down Expand Up @@ -35,11 +35,54 @@ const responsiveProperties = defineProperties({
},
});

const typographyProperties = defineProperties({
properties: {
fontSize: {
xxs: typography.size[1].fontSize,
xs: typography.size[2].fontSize,
sm: typography.size[3].fontSize,
md: typography.size[4].fontSize,
lg: typography.size[5].fontSize,
xl: typography.size[6].fontSize,
xxl: typography.size[7].fontSize,
'2xl': typography.size[8].fontSize,
'3xl': typography.size[9].fontSize,
},
lineHeight: {
xxs: typography.size[1].lineHeight,
xs: typography.size[2].lineHeight,
sm: typography.size[3].lineHeight,
md: typography.size[4].lineHeight,
lg: typography.size[5].lineHeight,
xl: typography.size[6].lineHeight,
xxl: typography.size[7].lineHeight,
'2xl': typography.size[8].lineHeight,
'3xl': typography.size[9].lineHeight,
},
fontWeight: {
normal: '400',
semibold: '500',
bold: '700',
},
},
shorthands: {
font: ['fontSize', 'lineHeight'],
},
});

const borderProperties = defineProperties({
properties: {
borderColor: { ...border.colours },
borderRadius: { ...border.radius },
borderStyle: ['solid', 'dotted', 'dashed'],
borderBottomLeftRadius: { ...border.radius },
borderBottomRightRadius: { ...border.radius },
borderTopLeftRadius: { ...border.radius },
borderTopRightRadius: { ...border.radius },
borderStyle: ['none', 'solid', 'dotted', 'dashed'],
borderBottomStyle: ['none', 'solid', 'dotted', 'dashed'],
borderLeftStyle: ['none', 'solid', 'dotted', 'dashed'],
borderRightStyle: ['none', 'solid', 'dotted', 'dashed'],
borderTopStyle: ['none', 'solid', 'dotted', 'dashed'],
borderWidth: { ...border.width },
boxShadow: { ...elevation },
},
Expand All @@ -49,6 +92,8 @@ const displayProperties = defineProperties({
properties: {
display: ['none', 'block', 'flex'],
flexDirection: ['row', 'column'],
flexGrow: [0, 1],
flexShrink: [0, 1],
flexWrap: ['nowrap', 'wrap', 'wrap-reverse'],
alignItems: ['stretch', 'flex-start', 'center', 'flex-end'],
justifyContent: [
Expand All @@ -58,6 +103,7 @@ const displayProperties = defineProperties({
'space-between',
'flex-end',
],
alignSelf: ['flex-start', 'center', 'flex-end'],
height: {
...spaceWithoutNone,
'100%': '100%',
Expand Down Expand Up @@ -107,6 +153,7 @@ const interactionProperties = defineProperties({

export const odStyle = createSprinkles(
responsiveProperties,
typographyProperties,
borderProperties,
displayProperties,
gamutProperties,
Expand Down

0 comments on commit 4e1a773

Please sign in to comment.