Skip to content

Commit 11df547

Browse files
authored
Merge pull request #50 from solved-ac/feature/switch
Add Switch component
2 parents 3b96504 + 89bb228 commit 11df547

File tree

4 files changed

+182
-2
lines changed

4 files changed

+182
-2
lines changed
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { Switch } from '@solved-ac/ui-react'
2+
import { ComponentMeta, ComponentStory } from '@storybook/react'
3+
import React from 'react'
4+
5+
export default {
6+
title: 'Components/Switch',
7+
component: Switch,
8+
argTypes: {
9+
value: {
10+
control: 'boolean',
11+
description: 'Whether the switch is on or off',
12+
defaultValue: false,
13+
},
14+
backgroundColor: {
15+
control: 'color',
16+
description: 'The background color of the switch',
17+
},
18+
backgroundActiveColor: {
19+
control: 'color',
20+
description: 'The background color of the switch when active',
21+
},
22+
knobColor: {
23+
control: 'color',
24+
description: 'The color of the knob',
25+
},
26+
knobBorderColor: {
27+
control: 'color',
28+
description: 'The border color of the knob',
29+
},
30+
knobActiveColor: {
31+
control: 'color',
32+
description: 'The color of the knob when active',
33+
},
34+
knobActiveBorderColor: {
35+
control: 'color',
36+
description: 'The border color of the knob when active',
37+
},
38+
},
39+
} as ComponentMeta<typeof Switch>
40+
41+
const Template: ComponentStory<typeof Switch> = (args) => <Switch {...args} />
42+
43+
export const Default = Template.bind({})
44+
Default.args = {
45+
value: true,
46+
}

src/components/$Table/Table.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,23 @@ export interface TableProps {
1818
fullWidth?: boolean
1919
sticky?: boolean | number | string
2020
padding?: 'none' | 'dense' | 'normal' | 'wide'
21+
verticalAlign?: 'top' | 'middle' | 'bottom'
2122
}
2223

2324
export const Table: PC<'table', TableProps> = forwardRefWithGenerics(
2425
<T extends ElementType>(props: PP<T, TableProps>, ref?: PR<T>) => {
2526
const {
2627
fullWidth = false,
2728
padding = 'normal',
29+
verticalAlign = 'top',
2830
sticky = false,
2931
as = 'table',
3032
...rest
3133
} = props
3234

3335
return (
34-
<TableContext.Provider value={{ padding, sticky }}>
35-
<TableRowGroupContext.Provider value={{ header: false }}>
36+
<TableContext.Provider value={{ padding, sticky, verticalAlign }}>
37+
<TableRowGroupContext.Provider value={{ header: false, verticalAlign }}>
3638
<TableContainer fullWidth={fullWidth} ref={ref} as={as} {...rest} />
3739
</TableRowGroupContext.Provider>
3840
</TableContext.Provider>

src/components/Switch.tsx

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
import styled from '@emotion/styled'
2+
import React, { ElementType } from 'react'
3+
import { PP, PR } from '../types/PolymorphicElementProps'
4+
import { computeHoverColor } from '../utils/color'
5+
import { forwardRefWithGenerics } from '../utils/ref'
6+
import { cssVariables } from '../utils/styles'
7+
8+
const { vars, v, styles } = cssVariables(
9+
{
10+
backgroundColor: (theme) => theme.color.background.page,
11+
backgroundActiveColor: (theme) => theme.color.solvedAc,
12+
knobColor: (theme) => theme.color.background.page,
13+
knobBorderColor: (theme) => theme.color.border,
14+
knobActiveColor: (theme) => theme.color.background.page,
15+
knobActiveBorderColor: (theme) => theme.color.border,
16+
},
17+
'button'
18+
)
19+
20+
interface SwitchBaseProps {
21+
active: boolean
22+
}
23+
24+
const SwitchBase = styled.div<SwitchBaseProps>`
25+
${({ theme }) => styles(theme)}
26+
height: 30px;
27+
width: 56px;
28+
display: inline-block;
29+
background-color: ${({ active }) =>
30+
active ? v.backgroundActiveColor : v.backgroundColor};
31+
border-radius: 30px;
32+
cursor: pointer;
33+
border: ${({ theme }) => theme.styles.border()};
34+
box-shadow: inset 1px 1px 9px -3px rgba(4, 4, 4, 0.08),
35+
1px 2px 6px -2px rgba(0, 0, 0, 0.01);
36+
transition: background-color 0.2s ease-in;
37+
`
38+
39+
const SwitchKnob = styled.div<SwitchBaseProps>`
40+
width: 26px;
41+
height: 26px;
42+
display: inline-block;
43+
background-color: ${({ active }) =>
44+
active ? v.knobActiveColor : v.knobColor};
45+
border: ${({ active }) =>
46+
`1px solid ${active ? v.knobActiveBorderColor : v.knobBorderColor}`};
47+
box-shadow: 0 1px 3px rgba(107, 106, 106, 0.26),
48+
0 5px 1px rgba(107, 106, 106, 0.13);
49+
border-radius: 26px;
50+
margin: 1px 1px;
51+
margin-left: 1px;
52+
transform: ${({ active }) => (active ? 'translateX(26px)' : 'translateX(0)')};
53+
transition: transform 0.2s ease-in, background-color 0.2s ease-in,
54+
border-color 0.2s ease-in;
55+
`
56+
57+
export interface SwitchProps {
58+
value: boolean
59+
onChange?: (value: boolean) => void
60+
backgroundColor?: string
61+
backgroundActiveColor?: string
62+
knobColor?: string
63+
knobBorderColor?: string
64+
knobActiveColor?: string
65+
knobActiveBorderColor?: string
66+
}
67+
68+
const computeKnobBorderColor = (props: SwitchProps): string | undefined => {
69+
const { knobColor, knobBorderColor } = props
70+
71+
if (knobBorderColor) return knobBorderColor
72+
if (knobColor) return computeHoverColor(knobColor)
73+
return undefined
74+
}
75+
76+
const computeKnobActiveBorderColor = (
77+
props: SwitchProps
78+
): string | undefined => {
79+
const {
80+
knobColor,
81+
knobActiveColor = knobColor,
82+
knobBorderColor,
83+
knobActiveBorderColor = knobBorderColor,
84+
} = props
85+
86+
if (knobActiveBorderColor) return knobActiveBorderColor
87+
if (knobActiveColor) return computeHoverColor(knobActiveColor)
88+
return undefined
89+
}
90+
91+
export const Switch = forwardRefWithGenerics(
92+
<T extends ElementType>(props: PP<T, SwitchProps>, ref?: PR<T>) => {
93+
const {
94+
value,
95+
onChange,
96+
backgroundColor,
97+
backgroundActiveColor,
98+
knobColor,
99+
knobActiveColor = knobColor,
100+
...rest
101+
} = props
102+
103+
const computedKnobBorderColor = computeKnobBorderColor(props)
104+
const computedKnobActiveBorderColor = computeKnobActiveBorderColor(props)
105+
106+
return (
107+
<SwitchBase
108+
ref={ref}
109+
active={value}
110+
onClick={() => onChange && onChange(!value)}
111+
style={{
112+
[vars.backgroundColor]: backgroundColor,
113+
[vars.backgroundActiveColor]: backgroundActiveColor,
114+
}}
115+
{...rest}
116+
>
117+
<SwitchKnob
118+
active={value}
119+
style={{
120+
[vars.knobColor]: knobColor,
121+
[vars.knobActiveColor]: knobActiveColor,
122+
[vars.knobBorderColor]: computedKnobBorderColor,
123+
[vars.knobActiveBorderColor]: computedKnobActiveBorderColor,
124+
}}
125+
/>
126+
</SwitchBase>
127+
)
128+
}
129+
)
130+
131+
export default Switch

src/components/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export * from './PaginationItem'
1616
export * from './Paragraph'
1717
export * from './Select'
1818
export * from './Space'
19+
export * from './Switch'
1920
export * from './TextField'
2021
export * from './Tooltip'
2122
export * from './Typo'

0 commit comments

Comments
 (0)