-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(SelectableCards): new component thumbnail variant
- Loading branch information
1 parent
75e7e14
commit 7877a0d
Showing
16 changed files
with
421 additions
and
0 deletions.
There are no files selected for viewing
49 changes: 49 additions & 0 deletions
49
packages/react-components/src/components/SelectableCard/SelectableCard.module.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
$base-class: 'selectable-card'; | ||
|
||
.#{$base-class} { | ||
display: flex; | ||
transition: border-color var(--transition-duration-fast-2) ease-in-out; | ||
border: 1px solid var(--border-basic-secondary); | ||
border-radius: var(--radius-3); | ||
background: var(--surface-primary-default); | ||
width: max-content; | ||
|
||
&:hover { | ||
border-color: var(--border-basic-hover); | ||
cursor: pointer; | ||
} | ||
|
||
&:focus-visible { | ||
outline: 0; | ||
box-shadow: var(--shadow-focus); | ||
} | ||
|
||
&--thumbnail { | ||
padding: var(--spacing-3) var(--spacing-5); | ||
} | ||
|
||
&--gallery { | ||
padding: var(--spacing-5); | ||
} | ||
|
||
&--interactive { | ||
border-radius: var(--radius-4); | ||
padding: var(--spacing-9) var(--spacing-8); | ||
} | ||
|
||
&--selected, | ||
&--selected:hover { | ||
border-color: var(--action-primary-default); | ||
} | ||
|
||
&__select-indicator { | ||
display: flex; | ||
align-items: center; | ||
margin-right: var(--spacing-2); | ||
height: 21px; | ||
|
||
&__checkbox { | ||
height: 16px; | ||
} | ||
} | ||
} |
87 changes: 87 additions & 0 deletions
87
...ages/react-components/src/components/SelectableCard/SelectableCard.stories.components.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import * as React from 'react'; | ||
|
||
import { Building } from '@livechat/design-system-icons'; | ||
|
||
import { Icon } from '../Icon'; | ||
|
||
import { ThumbnailSelectableCard } from './components'; | ||
|
||
interface IRadioCardsProps { | ||
withDescription?: boolean; | ||
withIcon?: boolean; | ||
withCustomElement?: boolean; | ||
} | ||
|
||
export const RadioCards: React.FC<IRadioCardsProps> = ({ | ||
withDescription, | ||
withIcon, | ||
withCustomElement, | ||
}) => { | ||
const [selectedIndex, setSelectedIndex] = React.useState<number>(0); | ||
|
||
return [...Array(4)].map((_, index) => ( | ||
<ThumbnailSelectableCard | ||
key={index} | ||
label={`Card ${index + 1}`} | ||
selectionType="radio" | ||
isSelected={selectedIndex === index} | ||
onClick={() => setSelectedIndex(index)} | ||
{...(withDescription && { | ||
description: `Description for card ${index + 1}`, | ||
})} | ||
{...(withIcon && { icon: <Icon source={Building} /> })} | ||
{...(withCustomElement && { | ||
customElement: ( | ||
<div className="custom-element"> | ||
<Icon size="small" source={Building} /> | ||
<div>{`Custom element ${index + 1}`}</div> | ||
</div> | ||
), | ||
})} | ||
/> | ||
)); | ||
}; | ||
|
||
interface ICheckboxCardsProps { | ||
withDescription?: boolean; | ||
withIcon?: boolean; | ||
withCustomElement?: boolean; | ||
} | ||
|
||
export const CheckboxCards: React.FC<ICheckboxCardsProps> = ({ | ||
withDescription, | ||
withIcon, | ||
withCustomElement, | ||
}) => { | ||
const [selectedIndex, setSelectedIndex] = React.useState<number[]>([]); | ||
|
||
const handleCardClick = (index: number) => { | ||
if (selectedIndex.includes(index)) { | ||
setSelectedIndex(selectedIndex.filter((selected) => selected !== index)); | ||
} else { | ||
setSelectedIndex([...selectedIndex, index]); | ||
} | ||
}; | ||
|
||
return [...Array(4)].map((_, index) => ( | ||
<ThumbnailSelectableCard | ||
key={index} | ||
label={`Card ${index + 1}`} | ||
selectionType="checkbox" | ||
isSelected={selectedIndex.includes(index)} | ||
onClick={() => handleCardClick(index)} | ||
{...(withDescription && { | ||
description: `Description for card ${index + 1}`, | ||
})} | ||
{...(withIcon && { icon: <Icon source={Building} /> })} | ||
{...(withCustomElement && { | ||
customElement: ( | ||
<div className="custom-element"> | ||
<Icon size="small" source={Building} /> | ||
<div>{`Custom element ${index + 1}`}</div> | ||
</div> | ||
), | ||
})} | ||
/> | ||
)); | ||
}; |
12 changes: 12 additions & 0 deletions
12
packages/react-components/src/components/SelectableCard/SelectableCard.stories.css
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
.custom-element { | ||
display: flex; | ||
flex-direction: column; | ||
align-items: center; | ||
justify-content: center; | ||
border: 1px dashed var(--border-default); | ||
border-radius: var(--radius-1); | ||
background-color: var(--surface-basic-subtle); | ||
padding: var(--spacing-2); | ||
color: var(--content-subtle); | ||
font-size: 12px; | ||
} |
47 changes: 47 additions & 0 deletions
47
packages/react-components/src/components/SelectableCard/SelectableCard.stories.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import { Meta } from '@storybook/react'; | ||
|
||
import { StoryDescriptor } from '../../stories/components/StoryDescriptor'; | ||
|
||
import { SelectableCard } from './SelectableCard'; | ||
import { CheckboxCards, RadioCards } from './SelectableCard.stories.components'; | ||
|
||
import './SelectableCard.stories.css'; | ||
|
||
export default { | ||
title: 'Components/SelectableCard', | ||
component: SelectableCard, | ||
} as Meta<typeof SelectableCard>; | ||
|
||
export const ThumbnailSelectableCardAsRadioType = () => ( | ||
<> | ||
<StoryDescriptor title="With Label"> | ||
<RadioCards /> | ||
</StoryDescriptor> | ||
<StoryDescriptor title="With Label, Description"> | ||
<RadioCards withDescription /> | ||
</StoryDescriptor> | ||
<StoryDescriptor title="With Label, Description and Icon"> | ||
<RadioCards withDescription withIcon /> | ||
</StoryDescriptor> | ||
<StoryDescriptor title="With Custom element"> | ||
<RadioCards withDescription withIcon withCustomElement /> | ||
</StoryDescriptor> | ||
</> | ||
); | ||
|
||
export const ThumbnailSelectableCardAsCheckboxType = () => ( | ||
<> | ||
<StoryDescriptor title="With Label"> | ||
<CheckboxCards /> | ||
</StoryDescriptor> | ||
<StoryDescriptor title="With Label, Description"> | ||
<CheckboxCards withDescription /> | ||
</StoryDescriptor> | ||
<StoryDescriptor title="With Label, Description and Icon"> | ||
<CheckboxCards withDescription withIcon /> | ||
</StoryDescriptor> | ||
<StoryDescriptor title="With Custom element"> | ||
<CheckboxCards withDescription withIcon withCustomElement /> | ||
</StoryDescriptor> | ||
</> | ||
); |
73 changes: 73 additions & 0 deletions
73
packages/react-components/src/components/SelectableCard/SelectableCard.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import { FC, KeyboardEvent } from 'react'; | ||
|
||
import cx from 'clsx'; | ||
|
||
import { useInteractive } from '../../hooks'; | ||
import { Checkbox } from '../Checkbox'; | ||
import { RadioButton } from '../RadioButton'; | ||
|
||
import { ISelectableCardProps } from './types'; | ||
|
||
import styles from './SelectableCard.module.scss'; | ||
|
||
const baseClass = 'selectable-card'; | ||
|
||
export const SelectableCard: FC<ISelectableCardProps> = ({ | ||
children, | ||
className, | ||
kind, | ||
selectionType, | ||
isSelected = false, | ||
onClick, | ||
}) => { | ||
const mergedClassName = cx( | ||
styles[baseClass], | ||
styles[`${baseClass}--${kind}`], | ||
{ | ||
[styles[`${baseClass}--selected`]]: isSelected, | ||
}, | ||
className | ||
); | ||
const { handleInteractiveClick } = useInteractive({ onClick }); | ||
|
||
const handleOnKeyDown = (e: KeyboardEvent<HTMLDivElement>) => { | ||
if (e.currentTarget !== document.activeElement) { | ||
return; | ||
} | ||
|
||
if ( | ||
e.key === 'Enter' || | ||
e.key === ' ' || | ||
e.key === 'Spacebar' || | ||
e.key === 'Space' | ||
) { | ||
e.preventDefault(); | ||
|
||
onClick?.(); | ||
} | ||
}; | ||
|
||
return ( | ||
<div | ||
role="button" | ||
tabIndex={0} | ||
className={mergedClassName} | ||
onClick={handleInteractiveClick} | ||
onKeyDown={handleOnKeyDown} | ||
> | ||
<div className={styles[`${baseClass}__select-indicator`]}> | ||
{selectionType === 'radio' ? ( | ||
<RadioButton tabIndex={-1} onClick={onClick} checked={isSelected} /> | ||
) : ( | ||
<Checkbox | ||
tabIndex={-1} | ||
onClick={onClick} | ||
className={styles[`${baseClass}__select-indicator__checkbox`]} | ||
checked={isSelected} | ||
/> | ||
)} | ||
</div> | ||
{children} | ||
</div> | ||
); | ||
}; |
20 changes: 20 additions & 0 deletions
20
...nts/SelectableCard/components/ThumbnailSelectableCard/ThumbnailSelectableCard.module.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
$base-class: 'thumbnail-selectable-card'; | ||
|
||
.#{$base-class} { | ||
display: flex; | ||
gap: var(--spacing-2); | ||
|
||
&__icon { | ||
display: flex; | ||
height: 21px; | ||
} | ||
|
||
&__content { | ||
display: flex; | ||
flex-direction: column; | ||
|
||
&__description { | ||
color: var(--content-basic-secondary); | ||
} | ||
} | ||
} |
39 changes: 39 additions & 0 deletions
39
.../components/SelectableCard/components/ThumbnailSelectableCard/ThumbnailSelectableCard.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import { FC } from 'react'; | ||
|
||
import { Text } from '../../../Typography'; | ||
import { SelectableCard } from '../../SelectableCard'; | ||
|
||
import { IThumbnailSelectableCardProps } from './types'; | ||
|
||
import styles from './ThumbnailSelectableCard.module.scss'; | ||
|
||
const baseClass = `thumbnail-selectable-card`; | ||
|
||
export const ThumbnailSelectableCard: FC<IThumbnailSelectableCardProps> = ({ | ||
label, | ||
description, | ||
icon, | ||
customElement, | ||
...props | ||
}) => ( | ||
<SelectableCard {...props} kind="thumbnail"> | ||
<div className={styles[baseClass]}> | ||
{icon && <div className={styles[`${baseClass}__icon`]}>{icon}</div>} | ||
{!customElement && ( | ||
<div className={styles[`${baseClass}__content`]}> | ||
<Text as="span" className={styles[`${baseClass}__content__label`]}> | ||
{label} | ||
</Text> | ||
<Text | ||
size="sm" | ||
as="span" | ||
className={styles[`${baseClass}__content__description`]} | ||
> | ||
{description} | ||
</Text> | ||
</div> | ||
)} | ||
{customElement} | ||
</div> | ||
</SelectableCard> | ||
); |
23 changes: 23 additions & 0 deletions
23
...eact-components/src/components/SelectableCard/components/ThumbnailSelectableCard/types.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import * as React from 'react'; | ||
|
||
import { ISelectableCardCoreProps } from '../../types'; | ||
|
||
export interface IThumbnailSelectableCardProps | ||
extends ISelectableCardCoreProps { | ||
/** | ||
* The label of the card | ||
*/ | ||
label: string; | ||
/** | ||
* The description of the card | ||
*/ | ||
description?: string; | ||
/** | ||
* The icon of the card | ||
*/ | ||
icon?: React.ReactNode; | ||
/** | ||
* The custom element of the card | ||
*/ | ||
customElement?: React.ReactNode; | ||
} |
1 change: 1 addition & 0 deletions
1
packages/react-components/src/components/SelectableCard/components/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { ThumbnailSelectableCard } from './ThumbnailSelectableCard/ThumbnailSelectableCard'; |
2 changes: 2 additions & 0 deletions
2
packages/react-components/src/components/SelectableCard/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export { SelectableCard } from './SelectableCard'; | ||
export { ThumbnailSelectableCard } from './components/'; |
25 changes: 25 additions & 0 deletions
25
packages/react-components/src/components/SelectableCard/types.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import * as React from 'react'; | ||
|
||
import { ComponentCoreProps } from '../../utils/types'; | ||
|
||
export interface ISelectableCardCoreProps extends ComponentCoreProps { | ||
/** | ||
* Set the selection type of the card | ||
*/ | ||
selectionType: 'radio' | 'checkbox'; | ||
/** | ||
* Set the card selection state | ||
*/ | ||
isSelected?: boolean; | ||
/** | ||
* Set the card onClick handler | ||
*/ | ||
onClick: (e?: React.MouseEvent<HTMLElement, MouseEvent>) => void; | ||
} | ||
|
||
export interface ISelectableCardProps extends ISelectableCardCoreProps { | ||
/** | ||
* Set the card type | ||
*/ | ||
kind?: 'thumbnail' | 'gallery' | 'interactive'; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
export { useAnimations } from './useAnimations'; | ||
export { useHeightResizer } from './useHeightResizer'; | ||
export { useMobileViewDetector } from './useMobileViewDetector'; | ||
export { useInteractive } from './useInteractive'; |
Oops, something went wrong.