@fibery/ui-kit 1.27.1 → 1.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -2
- package/src/toggle-on-off.tsx +36 -0
- package/src/toggle.tsx +158 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fibery/ui-kit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.28.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"files": [
|
|
6
6
|
"src/antd/styles.ts",
|
|
@@ -32,7 +32,8 @@
|
|
|
32
32
|
"src/dropdown-menu",
|
|
33
33
|
"src/shortcut-badge",
|
|
34
34
|
"src/tsfixme",
|
|
35
|
-
"src/
|
|
35
|
+
"src/toggle.tsx",
|
|
36
|
+
"src/toggle-on-off.tsx"
|
|
36
37
|
],
|
|
37
38
|
"license": "UNLICENSED",
|
|
38
39
|
"dependencies": {
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import chroma from "chroma-js";
|
|
2
|
+
import {FC, ComponentProps, useMemo} from "react";
|
|
3
|
+
import {opacity, ThemeColors} from "./design-system";
|
|
4
|
+
import {useTheme} from "./theme-provider";
|
|
5
|
+
import {Toggle} from "./toggle";
|
|
6
|
+
|
|
7
|
+
const getBackgroundColors = (accentColor: string | undefined, theme: ThemeColors) => {
|
|
8
|
+
return accentColor && chroma.valid(accentColor)
|
|
9
|
+
? {
|
|
10
|
+
enabledColor: accentColor,
|
|
11
|
+
disabledColor: chroma(accentColor).alpha(opacity.opacity35).css(),
|
|
12
|
+
}
|
|
13
|
+
: {
|
|
14
|
+
enabledColor: theme.primaryBlue,
|
|
15
|
+
disabledColor: theme.disabledTextColor,
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
interface ToggleOnOffProps extends Omit<ComponentProps<typeof Toggle>, "backgroundColor"> {
|
|
20
|
+
color?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const ToggleOnOff: FC<ToggleOnOffProps> = ({value, color, ...rest}) => {
|
|
24
|
+
const theme = useTheme();
|
|
25
|
+
const {enabledColor, disabledColor} = useMemo(() => getBackgroundColors(color, theme), [color, theme]);
|
|
26
|
+
return <Toggle value={Boolean(value)} backgroundColor={value ? enabledColor : disabledColor} {...rest} />;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
interface ReduxFormToggleOnOffProps extends ToggleOnOffProps {
|
|
30
|
+
input?: ToggleOnOffProps;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const ReduxFormToggleOnOff: FC<ReduxFormToggleOnOffProps> = ({input, ...rest}) => {
|
|
34
|
+
const theme = useTheme();
|
|
35
|
+
return <ToggleOnOff color={theme.primaryBlue} {...input} {...rest} />;
|
|
36
|
+
};
|
package/src/toggle.tsx
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import {css, cx} from "@linaria/core";
|
|
2
|
+
import {styled} from "@linaria/react";
|
|
3
|
+
import chroma from "chroma-js";
|
|
4
|
+
import {ComponentProps, FC, ReactNode} from "react";
|
|
5
|
+
import {layout, space, textStyles, transition} from "./design-system";
|
|
6
|
+
import _ from "lodash";
|
|
7
|
+
|
|
8
|
+
const Input = styled.input<{containerSize: number; containerWidth: number; outlineColor: string}>`
|
|
9
|
+
position: absolute;
|
|
10
|
+
cursor: pointer;
|
|
11
|
+
top: 0;
|
|
12
|
+
left: 0;
|
|
13
|
+
appearance: none;
|
|
14
|
+
margin-right: 0;
|
|
15
|
+
background-color: transparent;
|
|
16
|
+
height: ${({containerSize}) => containerSize}px;
|
|
17
|
+
width: ${({containerWidth}) => containerWidth}px;
|
|
18
|
+
border-radius: ${({containerSize}) => containerSize / 2}px;
|
|
19
|
+
|
|
20
|
+
&:focus {
|
|
21
|
+
outline: none;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
&:focus-visible {
|
|
25
|
+
box-shadow: ${({outlineColor}) => `inset 0 0 0 1px ${outlineColor}`};
|
|
26
|
+
}
|
|
27
|
+
`;
|
|
28
|
+
|
|
29
|
+
const Label = styled.div<{labelPosition: "last" | "first"; disabled?: boolean}>`
|
|
30
|
+
${textStyles.regular}
|
|
31
|
+
margin-left: ${({labelPosition}) => (labelPosition === "last" ? `${space.s8}px` : 0)};
|
|
32
|
+
margin-right: ${({labelPosition}) => (labelPosition === "first" ? `${space.s8}px` : 0)};
|
|
33
|
+
opacity: ${({disabled}) => (disabled ? 0.5 : 1)};
|
|
34
|
+
line-height: ${layout.checkboxSize}px;
|
|
35
|
+
width: 100%;
|
|
36
|
+
`;
|
|
37
|
+
|
|
38
|
+
const labelWrapperStyle = css`
|
|
39
|
+
display: flex;
|
|
40
|
+
position: relative;
|
|
41
|
+
align-items: center;
|
|
42
|
+
`;
|
|
43
|
+
|
|
44
|
+
const getOutlineColor = _.memoize((color: string) => {
|
|
45
|
+
const alpha = chroma(color).alpha();
|
|
46
|
+
if (alpha < 1) {
|
|
47
|
+
return chroma(color)
|
|
48
|
+
.alpha(alpha + 0.3)
|
|
49
|
+
.css();
|
|
50
|
+
} else {
|
|
51
|
+
return chroma(color).darken(1).css();
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const CircleContainer = styled.div<{
|
|
56
|
+
containerSize: number;
|
|
57
|
+
containerWidth: number;
|
|
58
|
+
backgroundColor: string;
|
|
59
|
+
disabled?: boolean;
|
|
60
|
+
}>`
|
|
61
|
+
position: relative;
|
|
62
|
+
height: ${({containerSize}) => containerSize}px;
|
|
63
|
+
width: ${({containerWidth}) => containerWidth}px;
|
|
64
|
+
flex-shrink: 0;
|
|
65
|
+
border-radius: ${({containerSize}) => containerSize / 2}px;
|
|
66
|
+
background-color: ${({backgroundColor}) => backgroundColor};
|
|
67
|
+
padding: ${space.s2}px;
|
|
68
|
+
transition: background-color ${transition};
|
|
69
|
+
opacity: ${({disabled}) => (disabled ? 0.5 : 1)};
|
|
70
|
+
`;
|
|
71
|
+
|
|
72
|
+
const Circle = styled.div<{containerSize: number}>`
|
|
73
|
+
height: ${({containerSize}) => containerSize - space.s2 * 2}px;
|
|
74
|
+
width: ${({containerSize}) => containerSize - space.s2 * 2}px;
|
|
75
|
+
border-radius: ${({containerSize}) => containerSize / 2 - space.s2}px;
|
|
76
|
+
background-color: white;
|
|
77
|
+
transition: transform ${transition};
|
|
78
|
+
`;
|
|
79
|
+
|
|
80
|
+
interface ToggleProps extends Omit<ComponentProps<"input">, "value"> {
|
|
81
|
+
value?: boolean;
|
|
82
|
+
label?: ReactNode;
|
|
83
|
+
labelTitle?: string;
|
|
84
|
+
backgroundColor: string;
|
|
85
|
+
labelPosition?: "first" | "last";
|
|
86
|
+
wrapperClassName?: string;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export const Toggle: FC<ToggleProps> = ({
|
|
90
|
+
value,
|
|
91
|
+
label,
|
|
92
|
+
labelTitle,
|
|
93
|
+
disabled = false,
|
|
94
|
+
backgroundColor,
|
|
95
|
+
size = 16,
|
|
96
|
+
onChange,
|
|
97
|
+
labelPosition = "last",
|
|
98
|
+
className,
|
|
99
|
+
wrapperClassName,
|
|
100
|
+
...rest
|
|
101
|
+
}) => {
|
|
102
|
+
const width = size * 1.75;
|
|
103
|
+
const outlineColor = getOutlineColor(backgroundColor);
|
|
104
|
+
|
|
105
|
+
const circleTransformStyle = {
|
|
106
|
+
transform: `translateX(${value ? width - size : 0}px)`,
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
return (
|
|
110
|
+
<label
|
|
111
|
+
className={cx(
|
|
112
|
+
wrapperClassName,
|
|
113
|
+
labelWrapperStyle,
|
|
114
|
+
disabled
|
|
115
|
+
? css`
|
|
116
|
+
cursor: default;
|
|
117
|
+
`
|
|
118
|
+
: css`
|
|
119
|
+
cursor: pointer;
|
|
120
|
+
`,
|
|
121
|
+
labelPosition === "first"
|
|
122
|
+
? css`
|
|
123
|
+
flex-direction: row-reverse;
|
|
124
|
+
`
|
|
125
|
+
: css`
|
|
126
|
+
flex-direction: row;
|
|
127
|
+
`
|
|
128
|
+
)}
|
|
129
|
+
title={labelTitle}
|
|
130
|
+
>
|
|
131
|
+
<CircleContainer
|
|
132
|
+
containerSize={size}
|
|
133
|
+
containerWidth={width}
|
|
134
|
+
backgroundColor={backgroundColor}
|
|
135
|
+
disabled={disabled}
|
|
136
|
+
>
|
|
137
|
+
<Circle containerSize={size} style={circleTransformStyle} />
|
|
138
|
+
<Input
|
|
139
|
+
containerSize={size}
|
|
140
|
+
containerWidth={width}
|
|
141
|
+
outlineColor={outlineColor}
|
|
142
|
+
onChange={onChange}
|
|
143
|
+
className={className}
|
|
144
|
+
type="checkbox"
|
|
145
|
+
disabled={disabled}
|
|
146
|
+
checked={value}
|
|
147
|
+
{...rest}
|
|
148
|
+
/>
|
|
149
|
+
</CircleContainer>
|
|
150
|
+
|
|
151
|
+
{label && (
|
|
152
|
+
<Label disabled={disabled} labelPosition={labelPosition}>
|
|
153
|
+
{label}
|
|
154
|
+
</Label>
|
|
155
|
+
)}
|
|
156
|
+
</label>
|
|
157
|
+
);
|
|
158
|
+
};
|