Skip to content

Commit

Permalink
feat: FilterChip component
Browse files Browse the repository at this point in the history
  • Loading branch information
arturbien committed Jan 25, 2024
1 parent 7ff220c commit ee88a06
Show file tree
Hide file tree
Showing 6 changed files with 304 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import type { Meta, StoryObj } from '@storybook/react';

import React from 'react';
import { FilterChip, Flex } from '../../../src/components';
import { filterChipPropDefs } from '../../../src/components/filter-chip.props';

const ExampleIcon = ({ size }: { size: number }) => (
<svg
width={size}
height={size}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M3 8C3 6 5.70833 3 9.5 3C13.2917 3 16 6 16 8M16 8H13M16 8V8C16.5523 8 17 7.55228 17 7V4"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M17 12C17 14 14.2917 17 10.5 17C6.70833 17 4 14 4 12M4 12H7M4 12V12C3.44772 12 3 12.4477 3 13V16"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);

// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
const meta = {
title: 'Controls/FilterChip',
component: FilterChip,
parameters: {
// Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/react/configure/story-layout
layout: 'centered',
},
args: {
children: null,
},
// This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/react/writing-docs/autodocs
tags: ['autodocs'],
} satisfies Meta<typeof FilterChip>;

export default meta;
type Story = StoryObj<typeof meta>;

// More on writing stories with args: https://storybook.js.org/docs/react/writing-stories/args
export const Default: Story = {
args: {
size: filterChipPropDefs.size.default,
color: filterChipPropDefs.color.default,
},
render: (args) => (
<Flex gap="2" direction="row">
<FilterChip defaultChecked {...args}></FilterChip>
<FilterChip defaultChecked={true} disabled {...args}>
<ExampleIcon size={16} />
Disabled checked
</FilterChip>
<FilterChip defaultChecked={false} disabled {...args}>
<ExampleIcon size={16} />
Disabled unchecked
</FilterChip>
</Flex>
),
};

export const Size: Story = {
render: (args) => (
<Flex gap="2">
<FilterChip defaultChecked {...args} size="1">
<ExampleIcon size={16} /> Size 1
</FilterChip>
<FilterChip defaultChecked {...args} size="2">
<ExampleIcon size={20} /> Size 2
</FilterChip>
<FilterChip defaultChecked {...args} size="3">
<ExampleIcon size={24} /> Size 3
</FilterChip>
</Flex>
),
};

export const Color: Story = {
render: (args) => (
<Flex gap="2">
<FilterChip {...args} color="indigo" defaultChecked>
<ExampleIcon size={20} />
Indigo
</FilterChip>
<FilterChip {...args} color="cyan" defaultChecked>
<ExampleIcon size={20} />
Cyan
</FilterChip>
<FilterChip {...args} color="orange" defaultChecked>
<ExampleIcon size={20} />
Orange
</FilterChip>
<FilterChip {...args} color="crimson" defaultChecked>
<ExampleIcon size={20} />
Crimson
</FilterChip>
</Flex>
),
};
117 changes: 117 additions & 0 deletions packages/frosted-ui/src/components/filter-chip.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
.fui-BaseChip {
display: inline-flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
flex-shrink: 0;
user-select: none;
vertical-align: top;
color: var(--base-chip-color);
}

/***************************************************************************************************
* *
* SIZES *
* *
***************************************************************************************************/

.fui-BaseChip {
height: var(--base-chip-height);
border-radius: var(--radius-thumb);
}

@breakpoints {
.fui-BaseChip {
&:where(.fui-r-size-1) {
--base-chip-height: var(--space-5);
padding-left: var(--space-2);
padding-right: var(--space-2);

gap: var(--space-1);
font-size: var(--font-size-1);
line-height: var(--line-height-1);
letter-spacing: var(--letter-spacing-1);
font-weight: var(--font-weight-medium);
}
&:where(.fui-r-size-2) {
--base-chip-height: var(--space-6);
padding-left: var(--space-3);
padding-right: var(--space-3);

gap: calc(1.5 * var(--space-1));
font-size: var(--font-size-2);
line-height: var(--line-height-2);
letter-spacing: var(--letter-spacing-2);
font-weight: var(--font-weight-medium);
}
&:where(.fui-r-size-3) {
--base-chip-height: var(--space-7);
padding-left: var(--space-4);
padding-right: var(--space-4);

gap: var(--space-2);
font-size: var(--font-size-3);
line-height: var(--line-height-3);
letter-spacing: var(--letter-spacing-3);
font-weight: var(--font-weight-medium);
}
}
}

.fui-BaseChip:where([data-state='unchecked']) {
box-shadow: inset 0 0 0 1px var(--gray-a5);
--base-chip-color: var(--gray-a12);

&:where(:hover) {
background-color: var(--gray-a2);
}
&:where(:active) {
background-color: var(--gray-a3);
}

&:where(:focus-visible) {
outline: 2px solid var(--color-focus-root);
outline-offset: -1px;
}

&:where([data-disabled]) {
cursor: var(--cursor-disabled);
--base-chip-color: var(--gray-a8);
box-shadow: inset 0 0 0 1px var(--gray-a4);
background-color: transparent;
}
&:where(:not([data-disabled])) > svg {
color: var(--gray-a11);
}
}

.fui-BaseChip:where([data-state='checked']) {
--base-chip-color: var(--accent-11);
background-color: var(--accent-a3);
box-shadow: inset 0 0 0 1px var(--accent-a6);

&:where(:focus-visible) {
outline: 2px solid var(--accent-8);
outline-offset: -1px;
}
@media (hover: hover) {
&:where(:hover) {
background-color: var(--accent-a4);
}
}

&:where(:active) {
background-color: var(--accent-a5);
}

&:where([data-disabled]) {
cursor: var(--cursor-disabled);
--base-chip-color: var(--gray-8);
background-color: var(--gray-a3);
box-shadow: inset 0 0 0 1px var(--gray-a5);
}

&:where(:not([data-disabled])) > svg {
color: var(--accent-10);
}
}
14 changes: 14 additions & 0 deletions packages/frosted-ui/src/components/filter-chip.props.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import type { PropDef } from '../helpers';
import { colorProp } from '../helpers';

const sizes = ['1', '2', '3'] as const;

const filterChipPropDefs = {
size: { type: 'enum', values: sizes, default: '2', responsive: true },
color: colorProp,
} satisfies {
size: PropDef<(typeof sizes)[number]>;
color: typeof colorProp;
};

export { filterChipPropDefs };
62 changes: 62 additions & 0 deletions packages/frosted-ui/src/components/filter-chip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
'use client';

import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
import classNames from 'classnames';
import * as React from 'react';
import {
extractMarginProps,
withBreakpoints,
withMarginProps,
} from '../helpers';
import { filterChipPropDefs } from './filter-chip.props';

import type {
GetPropDefTypes,
MarginProps,
PropsWithoutRefOrColor,
} from '../helpers';

type FilterChipElement = React.ElementRef<typeof CheckboxPrimitive.Root>;
type FilterChipOwnProps = GetPropDefTypes<typeof filterChipPropDefs>;
interface FilterChipProps
extends PropsWithoutRefOrColor<typeof CheckboxPrimitive.Root>,
MarginProps,
FilterChipOwnProps {
children: React.ReactNode;
}

const FilterChip = React.forwardRef<FilterChipElement, FilterChipProps>(
(props, forwardedRef) => {
const { rest: marginRest, ...marginProps } = extractMarginProps(props);
const {
children,
className,
style,
size = filterChipPropDefs.size.default,
color = filterChipPropDefs.color.default,
...checkboxProps
} = marginRest;

return (
<CheckboxPrimitive.Root
data-accent-color={color}
{...checkboxProps}
ref={forwardedRef}
className={classNames(
'fui-reset',
'fui-BaseChip',
className,
withBreakpoints(size, 'fui-r-size'),
withMarginProps(marginProps),
)}
style={style}
>
{children}
</CheckboxPrimitive.Root>
);
},
);
FilterChip.displayName = 'FilterChip';

export { FilterChip };
export type { FilterChipProps };
2 changes: 2 additions & 0 deletions packages/frosted-ui/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ export { DatePicker } from './date-picker';
export * from './date-picker.props';
export { DateRangePicker } from './date-range-picker';
export * from './date-range-picker.props';
export { FilterChip } from './filter-chip';
export * from './filter-chip.props';
export { Shine } from './lab/shine';
export {
Select,
Expand Down
1 change: 1 addition & 0 deletions packages/frosted-ui/src/styles/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
@import '../components/drawer.css';
@import '../components/dropdown-menu.css';
@import '../components/em.css';
@import '../components/filter-chip.css';
@import '../components/flex.css';
@import '../components/grid.css';
@import '../components/heading.css';
Expand Down

0 comments on commit ee88a06

Please # to comment.