@fibery/ui-kit 1.27.1 → 1.27.2

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.
Files changed (2) hide show
  1. package/package.json +6 -6
  2. 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.27.1",
3
+ "version": "1.27.2",
4
4
  "private": false,
5
5
  "files": [
6
6
  "src/antd/styles.ts",
@@ -32,7 +32,7 @@
32
32
  "src/dropdown-menu",
33
33
  "src/shortcut-badge",
34
34
  "src/tsfixme",
35
- "src/togle.tsx"
35
+ "src/toggle.tsx"
36
36
  ],
37
37
  "license": "UNLICENSED",
38
38
  "dependencies": {
@@ -74,8 +74,8 @@
74
74
  "screenfull": "6.0.1",
75
75
  "ua-parser-js": "0.7.24",
76
76
  "@fibery/emoji-data": "2.4.0",
77
- "@fibery/react": "1.3.1",
78
- "@fibery/helpers": "1.2.0"
77
+ "@fibery/helpers": "1.2.0",
78
+ "@fibery/react": "1.3.1"
79
79
  },
80
80
  "peerDependencies": {
81
81
  "react": "^18.2.0",
@@ -108,8 +108,8 @@
108
108
  "svgo": "2.8.0",
109
109
  "typescript": "5.1.6",
110
110
  "unist-util-reduce": "0.2.2",
111
- "@fibery/babel-preset": "7.4.0",
112
- "@fibery/eslint-config": "8.5.1"
111
+ "@fibery/eslint-config": "8.5.1",
112
+ "@fibery/babel-preset": "7.4.0"
113
113
  },
114
114
  "jest": {
115
115
  "testEnvironment": "jsdom",
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
+ };