Skip to content

Commit

Permalink
DS-87 - Layer Group
Browse files Browse the repository at this point in the history
  • Loading branch information
AlejoYarce committed Nov 11, 2024
1 parent 5c6e932 commit e6b5e54
Show file tree
Hide file tree
Showing 16 changed files with 335 additions and 27 deletions.
105 changes: 105 additions & 0 deletions src/components/Layer/LayerGroup/LayerGroup.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import type { Meta, StoryObj } from '@storybook/react'
import LayerGroupContainer from './LayerGroupContainer'
import LayerGroup from '.'

const meta = {
title: 'Layers/LayerGroup',
component: LayerGroupContainer,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
} satisfies Meta<typeof LayerGroupContainer>

export default meta
type Story = StoryObj<typeof meta>

export const LayerGroupOpen: Story = {
args: {
defaultIndex: [0],
allowMultiple: true,
allowToggle: true,
children: (
<>
<LayerGroup
label='Title 1'
caption='Caption 1'
layerItems={[
{
name: 'layer-1-item-1',
label: 'Layer name 1',
caption: 'Caption',
},
{
name: 'layer-1-item-2',
label: 'Layer name 2',
caption: 'Caption',
},
]}
/>
<LayerGroup
label='Title 2'
caption='Caption 2'
layerItems={[
{
name: 'layer-2-item-1',
label: 'Layer name 1',
caption: 'Caption',
},
{
name: 'layer-2-item-2',
label: 'Layer name 2',
caption: 'Caption',
},
]}
/>
</>
)
},
}

// export const Radio: Story = {
// args: {
// name: 'radio-layer',
// label: 'Layer name',
// caption: 'Caption',
// variant: 'radio',
// },
// }

// export const Disabled: Story = {
// args: {
// name: 'switch-layer-1',
// label: 'Layer name',
// caption: 'Caption',
// isDisabled: true,
// },
// }

// export const RadioDisabeld: Story = {
// args: {
// name: 'radio-layer',
// label: 'Layer name',
// caption: 'Caption',
// variant: 'radio',
// isDisabled: true,
// },
// }

// export const NoInfoButton: Story = {
// args: {
// name: 'switch-layer-2',
// label: 'Layer name',
// caption: 'Caption',
// showInfoButton: false,
// },
// }

// export const CustomInfoButtonLabel: Story = {
// args: {
// name: 'switch-layer-3',
// label: 'Layer name',
// caption: 'Caption',
// infoButtonLabel: 'Another Label',
// },
// }
23 changes: 23 additions & 0 deletions src/components/Layer/LayerGroup/LayerGroupContainer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Accordion } from '@chakra-ui/react'
import { LayerGroupContainerProps } from './types'

const LayerGroupContainer = ({
children,
allowMultiple = true,
allowToggle = true,
defaultIndex = [0],
...rest
}: LayerGroupContainerProps) => (
<div style={{ width: '300px' }}>
<Accordion
allowMultiple={allowMultiple}
allowToggle={allowToggle}
defaultIndex={defaultIndex}
{...rest}
>
{children}
</Accordion>
</div>
)

export default LayerGroupContainer
80 changes: 80 additions & 0 deletions src/components/Layer/LayerGroup/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import {
AccordionItem,
AccordionButton,
AccordionPanel,
AccordionIcon,
useTheme,
RadioGroup,
} from '@chakra-ui/react'
import { useState } from 'react'
import { LayerGroupProps } from './types'
import { LayerGroupCaption, LayerGroupTitle } from './styled'
import { getThemedColor } from '../../../lib/theme'
import ActiveTag from '../../Tag/ActiveTag'
import LayerItem from '../LayerItem'

const LayerGroup = ({
label,
caption,
layerItems,
}: LayerGroupProps) => {
const [activeItems, setActiveItems] = useState<{ key?: string, value?: boolean }>({})
const theme = useTheme()

const handleOnChange = (e: React.ChangeEvent<HTMLInputElement>, onChange: ((e: React.ChangeEvent<HTMLInputElement>) => void) | undefined) => {
const newActiveItems = {
...activeItems,
[e.target.name]: e.target.checked,
}

setActiveItems(newActiveItems)

if (onChange) {
onChange(e)
}
}

const getActiveCount = Object.values(activeItems)
.filter(item => item === true).length

return (
<div style={{ width: '300px' }}>
<AccordionItem>
<h2>
<AccordionButton
style={{ alignItems: 'flex-start' }}
_hover={{ backgroundColor: 'transparent' }}
>
<LayerGroupTitle
as='span'
flex='1'
>
{label}
<ActiveTag count={getActiveCount} />
</LayerGroupTitle>
<AccordionIcon
width='30px'
height='30px'
color={getThemedColor(theme.colors, 'neutral', 700)}
/>
</AccordionButton>
</h2>
<LayerGroupCaption>
{caption}
</LayerGroupCaption>
<AccordionPanel pb={0}>
<RadioGroup name={label}>
{layerItems.map(layerItem => (
<LayerItem
{...layerItem}
onChange={(e) => handleOnChange(e, layerItem.onChange)}
/>
))}
</RadioGroup>
</AccordionPanel>
</AccordionItem>
</div>
)
}

export default LayerGroup
29 changes: 29 additions & 0 deletions src/components/Layer/LayerGroup/styled.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import styled from '@emotion/styled'
import { Box } from '@chakra-ui/react'
import { getThemedColor, ThemeProps } from '../../../lib/theme'

export const LayerGroupTitle = styled(Box) <{
theme?: ThemeProps
}>`
font-size: 16px;
font-weight: 700;
line-height: 24px;
text-align: left;
color: ${({ theme }) => getThemedColor(theme.colors, 'neutral', 800)};
display: flex;
align-items: center;
text-align: left;
gap: 10px;
`

export const LayerGroupCaption = styled(Box) <{
theme?: ThemeProps
}>`
font-size: 12px;
font-weight: 400;
line-height: 16px;
text-align: left;
color: ${({ theme }) => getThemedColor(theme.colors, 'neutral', 600)};
margin-left: 16px;
margin-bottom: 24px;
`
17 changes: 17 additions & 0 deletions src/components/Layer/LayerGroup/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { AccordionProps } from '@chakra-ui/react'
import { LayerItemProps } from '../LayerItem/types'

export type LayerGroupContainerProps = Omit<
AccordionProps,
'onChange'
> & {
allowMultiple?: boolean
allowToggle?: boolean
defaultIndex?: number[]
}

export type LayerGroupProps = {
label: string
caption: string
layerItems: LayerItemProps[]
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ type Story = StoryObj<typeof meta>

export const Switch: Story = {
args: {
id: 'switch-layer',
name: 'switch-layer',
label: 'Layer name',
caption: 'Caption',
},
}

export const Radio: Story = {
args: {
id: 'radio-layer',
name: 'radio-layer',
label: 'Layer name',
caption: 'Caption',
variant: 'radio',
Expand All @@ -32,7 +32,7 @@ export const Radio: Story = {

export const Disabled: Story = {
args: {
id: 'switch-layer-1',
name: 'switch-layer-1',
label: 'Layer name',
caption: 'Caption',
isDisabled: true,
Expand All @@ -41,7 +41,7 @@ export const Disabled: Story = {

export const RadioDisabeld: Story = {
args: {
id: 'radio-layer',
name: 'radio-layer',
label: 'Layer name',
caption: 'Caption',
variant: 'radio',
Expand All @@ -51,7 +51,7 @@ export const RadioDisabeld: Story = {

export const NoInfoButton: Story = {
args: {
id: 'switch-layer-2',
name: 'switch-layer-2',
label: 'Layer name',
caption: 'Caption',
showInfoButton: false,
Expand All @@ -60,7 +60,7 @@ export const NoInfoButton: Story = {

export const CustomInfoButtonLabel: Story = {
args: {
id: 'switch-layer-3',
name: 'switch-layer-3',
label: 'Layer name',
caption: 'Caption',
infoButtonLabel: 'Another Label',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { InfoIcon } from '@chakra-ui/icons'
import Button from '../Button'
import Switch from '../Switch'
import Radio from '../Radio'
import Button from '../../Button'
import Switch from '../../Switch'
import Radio from '../../Radio'
import { LayerItemProps } from './types'
import {
LayerCaption,
Expand All @@ -12,7 +12,7 @@ import {
} from './styled'

const LayerItem = ({
id,
name,
label,
caption,
showInfoButton = true,
Expand All @@ -21,6 +21,7 @@ const LayerItem = ({
isDisabled,
onInfoClick,
isDefaultSelected,
onChange,
}: LayerItemProps) => {
const isSwitch = variant === 'switch'

Expand All @@ -33,14 +34,17 @@ const LayerItem = ({
<LayerCaption>{caption}</LayerCaption>
</SwitchContent>
<Switch
id={id}
name={name}
isDisabled={isDisabled}
isChecked={isDefaultSelected}
onChange={onChange ? (e) => onChange(e) : () => { }}
/>
</SwitchContainer>
) : (
<div>
<Radio label={label} value={id} isDisabled={isDisabled} />
<Radio label={label} value={name} isDisabled={isDisabled}
onChange={onChange ? (e) => onChange(e) : () => { }}
/>
<LayerCaption style={{ marginLeft: '28px' }}>{caption}</LayerCaption>
</div>
)}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import styled from '@emotion/styled'
import { getThemedColor, ThemeProps } from '../../lib/theme'
import { getThemedColor, ThemeProps } from '../../../lib/theme'

export const LayerItemContainer = styled.div<{
isDisabled?: boolean
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export type LayerItemProps = {
id: string
name: string
label: string
caption?: string
showInfoButton?: boolean
Expand All @@ -8,4 +8,5 @@ export type LayerItemProps = {
isDisabled?: boolean
onInfoClick?: () => void
isDefaultSelected?: boolean
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void
}
Loading

0 comments on commit e6b5e54

Please sign in to comment.