-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into TET-895-Toggle-Component
- Loading branch information
Showing
31 changed files
with
1,480 additions
and
3 deletions.
There are no files selected for viewing
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,9 @@ | ||
import { HTMLAttributes } from 'react'; | ||
|
||
import { ButtonGroupConfig } from './ButtonGroup.styles'; | ||
|
||
export type ButtonGroupSize = 'medium' | 'small'; | ||
export type ButtonGroupProps = { | ||
size?: ButtonGroupSize; | ||
custom?: ButtonGroupConfig; | ||
} & Omit<HTMLAttributes<HTMLSpanElement>, 'color'>; |
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 type { Meta, StoryObj } from '@storybook/react'; | ||
|
||
import { ButtonGroup } from './ButtonGroup'; | ||
import { Button } from '../Button/Button'; | ||
|
||
import { ButtonGroupDocs } from '@/docs-components/ButtonGroupDocs'; | ||
import { TetDocs } from '@/docs-components/TetDocs'; | ||
|
||
const meta = { | ||
title: 'ButtonGroup', | ||
component: ButtonGroup, | ||
tags: ['autodocs'], | ||
argTypes: { | ||
size: { | ||
options: ['small', 'medium'], | ||
defaultValue: 'medium', | ||
control: { type: 'radio' }, | ||
}, | ||
}, | ||
parameters: { | ||
docs: { | ||
description: { | ||
component: | ||
'A set of related buttons that are visually and functionally grouped. Button Group acts as a cohesive unit, providing users with clear options for actions or navigation.', | ||
}, | ||
page: () => ( | ||
<TetDocs docs="https://docs.tetrisly.com/components/list/buttongroup"> | ||
<ButtonGroupDocs /> | ||
</TetDocs> | ||
), | ||
}, | ||
}, | ||
} satisfies Meta<typeof ButtonGroup>; | ||
|
||
export default meta; | ||
type Story = StoryObj<typeof meta>; | ||
|
||
export const Default: Story = { | ||
args: { | ||
children: [ | ||
<Button label="button" />, | ||
<Button label="button" />, | ||
<Button label="button" />, | ||
<Button label="button" />, | ||
], | ||
}, | ||
}; |
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,50 @@ | ||
import { BaseProps } from '@/types'; | ||
|
||
export type ButtonGroupConfig = { | ||
button: { | ||
size: { | ||
medium: BaseProps; | ||
small: BaseProps; | ||
}; | ||
} & BaseProps; | ||
} & BaseProps; | ||
|
||
export const defaultConfig = { | ||
display: 'inline-flex', | ||
justifyContent: 'center', | ||
alignItems: 'center', | ||
button: { | ||
color: { | ||
_: '$color-action-neutral-normal', | ||
hover: '$color-action-neutral-hover', | ||
}, | ||
backgroundColor: { | ||
_: '$color-action-inverted-normal', | ||
active: '$color-action-ghost-active', | ||
hover: '$color-action-ghost-hover', | ||
selected: '$color-action-ghost-selected', | ||
}, | ||
ringColor: '$color-action-outline-normal', | ||
size: { | ||
// TODO think if it can be done by passing size prop to a button component | ||
medium: { | ||
h: '$size-medium', | ||
px: '$space-component-padding-large', | ||
}, | ||
small: { | ||
h: '$size-small', | ||
px: '$space-component-padding-medium', | ||
}, | ||
}, | ||
borderRadius: { | ||
first: `$border-radius-large 0px 0px $border-radius-large`, | ||
last: `0px $border-radius-large $border-radius-large 0px`, | ||
}, | ||
transition: true, | ||
transitionDuration: 200, | ||
}, | ||
} as const satisfies ButtonGroupConfig; | ||
|
||
export const buttonGroupStyles = { | ||
defaultConfig, | ||
}; |
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,41 @@ | ||
import { render } from '../../tests/render'; | ||
|
||
import { ButtonGroup } from '.'; | ||
|
||
import { customPropTester } from '@/tests/customPropTester'; | ||
|
||
// TODO | ||
|
||
const getButtonGroup = (jsx: JSX.Element) => { | ||
const { getByTestId } = render(jsx); | ||
return { | ||
buttonGroup: getByTestId('button-group'), | ||
}; | ||
}; | ||
describe('ButtonGroup', () => { | ||
it('should render the ButtonGroup ', () => { | ||
const { buttonGroup } = getButtonGroup(<ButtonGroup />); | ||
expect(buttonGroup).toBeInTheDocument(); | ||
}); | ||
|
||
it('should render correct number of children', () => { | ||
const { buttonGroup } = getButtonGroup( | ||
<ButtonGroup> | ||
<ButtonGroup.Item label="label" /> | ||
<ButtonGroup.Item label="label" /> | ||
<ButtonGroup.Item label="label" /> | ||
<ButtonGroup.Item label="label" /> | ||
<ButtonGroup.Item label="label" /> | ||
</ButtonGroup>, | ||
); | ||
|
||
expect(buttonGroup?.children.length).toEqual(5); | ||
}); | ||
|
||
customPropTester(<ButtonGroup />, { | ||
containerId: 'button-group', | ||
props: { | ||
options: ['small', 'medium'], | ||
}, | ||
}); | ||
}); |
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,58 @@ | ||
import { MarginProps } from '@xstyled/styled-components'; | ||
import { | ||
Children, | ||
cloneElement, | ||
isValidElement, | ||
PropsWithChildren, | ||
useMemo, | ||
type FC, | ||
} from 'react'; | ||
|
||
import { ButtonGroupProps } from './ButtonGroup.props'; | ||
import { stylesBuilder } from './stylesBuilder'; | ||
import { Button, ButtonProps } from '../Button'; | ||
|
||
import { tet } from '@/tetrisly'; | ||
|
||
type Props = FC<PropsWithChildren<ButtonGroupProps & MarginProps>> & { | ||
Item: FC<ButtonProps & MarginProps>; | ||
}; | ||
|
||
export const ButtonGroup: Props = ({ | ||
size = 'medium', | ||
children, | ||
custom, | ||
...rest | ||
}) => { | ||
const styles = useMemo( | ||
() => | ||
stylesBuilder({ | ||
size, | ||
custom, | ||
}), | ||
[custom, size], | ||
); | ||
|
||
Children.forEach(children, (child) => { | ||
if (isValidElement(child) && child?.type !== ButtonGroup.Item) { | ||
console.error( | ||
'You should use only ButtonGroup.Item as a child of a CheckboxGroup component.', | ||
); | ||
} | ||
}); | ||
|
||
const childrenWithProps = Children.map(children, (child) => { | ||
if (isValidElement(child)) { | ||
return cloneElement(child, { ...styles.button }); | ||
} | ||
return child; | ||
}); | ||
|
||
return ( | ||
<tet.span data-testid="button-group" {...styles.container} {...rest}> | ||
{childrenWithProps} | ||
</tet.span> | ||
); | ||
}; | ||
|
||
ButtonGroup.Item = Button; |
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,3 @@ | ||
export { ButtonGroup } from './ButtonGroup'; | ||
export type { ButtonGroupProps } from './ButtonGroup.props'; | ||
export { buttonGroupStyles } from './ButtonGroup.styles'; |
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,31 @@ | ||
import type { ButtonGroupSize } from './ButtonGroup.props'; | ||
import { ButtonGroupConfig, defaultConfig } from './ButtonGroup.styles'; | ||
|
||
import { mergeConfigWithCustom } from '@/services'; | ||
import { BaseProps } from '@/types/BaseProps'; | ||
|
||
type ButtonGroupStyleBuilder = { | ||
container: BaseProps; | ||
button: BaseProps; | ||
}; | ||
|
||
type ButtonGroupStyleBuilderInput = { | ||
size: ButtonGroupSize; | ||
custom?: ButtonGroupConfig; | ||
}; | ||
|
||
export const stylesBuilder = ({ | ||
size, | ||
custom, | ||
}: ButtonGroupStyleBuilderInput): ButtonGroupStyleBuilder => { | ||
const { button, ...container } = mergeConfigWithCustom({ | ||
defaultConfig, | ||
custom, | ||
}); | ||
const buttonStyles = { ...button, ...button.size[size] }; | ||
|
||
return { | ||
container, | ||
button: buttonStyles, | ||
}; | ||
}; |
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,11 @@ | ||
import { InlineMetricsConfig } from './InlineMetrics.styles'; | ||
|
||
export type TrendType = 'None' | 'Positive' | 'Negative'; | ||
|
||
export type InlineMetricsProps = { | ||
metrics?: string; | ||
label?: string; | ||
trend?: TrendType; | ||
trendValue?: string; | ||
custom?: InlineMetricsConfig; | ||
}; |
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 type { Meta, StoryObj } from '@storybook/react'; | ||
|
||
import { InlineMetrics } from './InlineMetrics'; | ||
|
||
import { InlineMetricsDocs } from '@/docs-components/InlineMetricsDocs'; | ||
import { TetDocs } from '@/docs-components/TetDocs'; | ||
|
||
const meta = { | ||
title: 'Metrics / InlineMetrics', | ||
component: InlineMetrics, | ||
tags: ['autodocs'], | ||
args: {}, | ||
parameters: { | ||
backgrounds: {}, | ||
docs: { | ||
description: { | ||
component: | ||
'A set of several grouped components that displays numerical data, such as, for example, key performance indicators (KPIs). Metrics provide users with a clear, visual representation of essential statistics or progress.', | ||
}, | ||
page: () => ( | ||
<TetDocs docs="https://docs.tetrisly.com/components/in-progress/metrics"> | ||
<InlineMetricsDocs /> | ||
</TetDocs> | ||
), | ||
}, | ||
}, | ||
} satisfies Meta<typeof InlineMetrics>; | ||
|
||
export default meta; | ||
type Story = StoryObj<typeof meta>; | ||
|
||
export const Default: Story = { | ||
args: { | ||
trend: 'Negative', | ||
trendValue: '+24%', | ||
metrics: '$123.12', | ||
label: 'Total Earnings', | ||
}, | ||
}; |
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,76 @@ | ||
import type { TrendType } from './InlineMetrics.props'; | ||
|
||
import type { BaseProps } from '@/types/BaseProps'; | ||
import { IconName } from '@/utility-types/IconName'; | ||
|
||
export type InlineMetricsConfig = { | ||
innerElements: { | ||
label: BaseProps; | ||
metric: BaseProps; | ||
trendContainer: BaseProps; | ||
trend: { trend: Partial<Record<TrendType, BaseProps>> } & BaseProps; | ||
icon: BaseProps; | ||
trendValue: BaseProps; | ||
}; | ||
} & BaseProps; | ||
|
||
export const defaultConfig = { | ||
w: 'fill', | ||
h: '', | ||
display: 'flex', | ||
flexDirection: 'column', | ||
innerElements: { | ||
trendContainer: { | ||
display: 'flex', | ||
color: '$color-content-primary', | ||
gap: '$space-component-gap-medium', | ||
}, | ||
label: { | ||
color: '$color-content-secondary', | ||
text: '$typo-body-medium', | ||
marginBottom: '$space-component-gap-medium', | ||
}, | ||
metric: { | ||
text: '$typo-header-4xLarge', | ||
color: '$color-content-primary', | ||
}, | ||
trend: { | ||
gap: '$space-component-gap-small', | ||
padding: '$space-component-padding-xSmall 0', | ||
display: 'flex', | ||
alignItems: 'center', | ||
alignSelf: 'flex-end', | ||
trend: { | ||
None: {}, | ||
Positive: { | ||
color: '$color-content-positive-secondary', | ||
}, | ||
Negative: { | ||
color: '$color-content-negative-secondary', | ||
}, | ||
}, | ||
}, | ||
icon: { | ||
display: 'flex', | ||
}, | ||
trendValue: { | ||
text: '$typo-body-strong-medium', | ||
display: 'flex', | ||
alignItems: 'end', | ||
}, | ||
}, | ||
} satisfies InlineMetricsConfig; | ||
|
||
export const inlineMetricsStyles = { | ||
defaultConfig, | ||
}; | ||
|
||
export const resolveIconName = (trend: TrendType) => { | ||
const iconConfig = { | ||
None: '20-minus', | ||
Positive: '20-trend-up', | ||
Negative: '20-trend-down', | ||
} satisfies Record<TrendType, IconName<20>>; | ||
|
||
return iconConfig[trend]; | ||
}; |
Oops, something went wrong.