Skip to content

Commit

Permalink
feat: TET-901 selectable pill (#145)
Browse files Browse the repository at this point in the history
* feat: TET-901 selectable pill

* feat: TET-901 remove onChange

* feat: TET-901 beforeComponent changes
  • Loading branch information
golas-m authored May 15, 2024
1 parent a3c89de commit 4f08a7a
Show file tree
Hide file tree
Showing 10 changed files with 713 additions and 0 deletions.
27 changes: 27 additions & 0 deletions src/components/SelectablePill/SelectablePill.props.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { HTMLAttributes } from 'react';

import { SelectablePillConfig } from './SelectablePill.styles';
import { AvatarAppearance } from '../Avatar/types';

import { InnerComponent } from '@/types';
import { IconName } from '@/utility-types/IconName';

namespace BeforeComponent {
export type Icon = InnerComponent<'icon', { name: IconName<20> }>;
export type Avatar = InnerComponent<
'avatar',
| { appearance?: 'image'; image: string }
| { appearance: Exclude<AvatarAppearance, 'image'>; initials: string }
>;
}

export type SelectablePillProps = {
text: string;
prefix?: string;
state?: 'default' | 'disabled';
isSelected?: boolean;
isInverted?: boolean;
tabIndex?: number;
custom?: SelectablePillConfig;
beforeComponent?: BeforeComponent.Avatar | BeforeComponent.Icon;
} & Omit<HTMLAttributes<HTMLSpanElement>, 'color'>;
117 changes: 117 additions & 0 deletions src/components/SelectablePill/SelectablePill.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import type { Meta, StoryObj } from '@storybook/react';

import { SelectablePill } from './SelectablePill';

import { SelectablePillDocs } from '@/docs-components/SelectablePillDocs';
import { TetDocs } from '@/docs-components/TetDocs';

const meta = {
title: 'SelectablePill',
component: SelectablePill,
tags: ['autodocs'],
argTypes: {},
args: {
state: 'default',
text: 'Value',
},
parameters: {
docs: {
description: {
component:
'A compact, rounded indicator used to represent tags, categories, or statuses. Pills often include text and/or icons and can be interactive, such as allowing users to remove a filter or tag.',
},
page: () => (
<TetDocs docs="https://docs.tetrisly.com/components/in-progress/pill">
<SelectablePillDocs />
</TetDocs>
),
},
},
} satisfies Meta<typeof SelectablePill>;

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

export const Default: Story = {
args: {
state: 'default',
},
};

export const Disabled: Story = {
args: {
state: 'disabled',
},
};

export const Selected: Story = {
args: {
isSelected: true,
},
};

export const Inverted: Story = {
args: {
isInverted: true,
},
};

export const WithIcon: Story = {
args: {
beforeComponent: { type: 'icon', props: { name: '20-tree' } },
},
};

export const DisabledWithIcon: Story = {
args: {
state: 'disabled',
beforeComponent: { type: 'icon', props: { name: '20-tree' } },
},
};

export const WithIconAndPrefix: Story = {
args: {
prefix: 'Prefix',
beforeComponent: { type: 'icon', props: { name: '20-tree' } },
},
};

export const SelectedWithIcon: Story = {
args: {
isSelected: true,
beforeComponent: { type: 'icon', props: { name: '20-tree' } },
},
};

export const InvertedWithPrefix: Story = {
args: {
isInverted: true,
prefix: 'Prefix',
},
};

export const WithAvatar: Story = {
args: {
beforeComponent: {
type: 'avatar',
props: { image: 'https://thispersondoesnotexist.com/' },
},
},
};

export const WithAvatarInitialsAndPrefix: Story = {
args: {
prefix: 'Prefix',
beforeComponent: {
type: 'avatar',
props: { appearance: 'blue', initials: 'M' },
},
},
};

export const SelectedWithPrefix: Story = {
args: {
prefix: 'Prefix',
isSelected: true,
},
};
131 changes: 131 additions & 0 deletions src/components/SelectablePill/SelectablePill.styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import { SelectablePillState } from './SelectablePillState.type';

import { BaseProps } from '@/types';

export type SelectablePillConfig = {
isSelected: BaseProps;
state?: Partial<
Record<SelectablePillState, Record<'primary' | 'inverted', BaseProps>>
>;
hasIcon?: BaseProps;
hasAvatar?: BaseProps;
hasPrefix?: BaseProps;
innerElements?: {
icon?: BaseProps;
actionIcon?: BaseProps;
prefix?: BaseProps;
contentContainer?: Record<'small' | 'xSmall', BaseProps>;
textContainer?: BaseProps;
};
} & BaseProps;

export const defaultConfig = {
display: 'inline-flex',
justifyContent: 'center',
alignItems: 'center',
textAlign: 'center',
whiteSpace: 'nowrap',
h: '$size-small',
padding: '$space-component-padding-xSmall $space-component-padding-small',
pl: '$space-component-padding-medium',
gap: '$space-component-gap-small',
borderRadius: '$border-radius-large',
color: '$color-content-primary',
borderWidth: '$border-width-small',
borderColor: '$color-transparent',
transition: true,
transitionDuration: 200,
outline: {
focus: 'solid',
},
outlineColor: {
_: '$color-interaction-focus-default',
focus: '$color-interaction-focus-default',
},
outlineWidth: {
focus: '$border-width-focus',
},
outlineOffset: 1,
hasIcon: {
pl: '$space-component-padding-small',
},
hasPrefix: {
pl: '$space-component-padding-medium',
},
hasAvatar: {
pl: '$space-component-padding-xSmall',
},
isSelected: {
backgroundColor: '$color-interaction-background-formField',
borderColor: {
_: '$color-interaction-border-neutral-normal',
hover: '$color-interaction-border-neutral-hover',
active: '$color-interaction-border-neutral-active',
},
},
innerElements: {
icon: {
color: '$color-content-secondary',
},
actionIcon: {
color: '$color-action-neutral-normal',
},
prefix: {
text: '$typo-body-medium',
color: '$color-content-secondary',
},
textContainer: {
display: 'inline-flex',
alignItems: 'center',
gap: '$space-component-gap-xSmall',
},
contentContainer: {
xSmall: {
display: 'inline-flex',
alignItems: 'center',
gap: '$space-component-gap-xSmall',
},
small: {
display: 'inline-flex',
alignItems: 'center',
gap: '$space-component-gap-small',
},
},
},
state: {
default: {
primary: {
backgroundColor: {
_: '$color-interaction-neutral-subtle-normal',
hover: '$color-interaction-neutral-subtle-hover',
active: '$color-interaction-neutral-subtle-active',
},
},
inverted: {
backgroundColor: '$color-interaction-background-formField',
borderColor: {
_: '$color-interaction-border-neutral-normal',
hover: '$color-interaction-border-neutral-hover',
active: '$color-interaction-border-neutral-active',
},
},
},
disabled: {
primary: {
backgroundColor: '$color-interaction-neutral-subtle-normal',
opacity: '$opacity-disabled',
pointerEvents: 'none',
},
inverted: {
backgroundColor: '$color-interaction-background-formField',
borderColor: '$color-interaction-border-neutral-normal',
opacity: '$opacity-disabled',
pointerEvents: 'none',
},
},
},
} as const satisfies SelectablePillConfig;

export const selectablePillStyles = {
defaultConfig,
};
Loading

0 comments on commit 4f08a7a

Please sign in to comment.