@dss-kit/ui-kit 1.0.3 → 1.0.4
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.
|
@@ -38,11 +38,15 @@ interface SwitchProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>,
|
|
|
38
38
|
*/
|
|
39
39
|
variant?: SwitchVariant;
|
|
40
40
|
/**
|
|
41
|
-
* Заголовок
|
|
41
|
+
* Заголовок переключателя — его доступное имя.
|
|
42
|
+
* Рендерится внутри `<label>`, поэтому `ReactNode` должен быть строчным
|
|
43
|
+
* контентом (без `div`, `p` и интерактивных элементов).
|
|
44
|
+
* Без `title` и `text` передайте `aria-label`.
|
|
42
45
|
*/
|
|
43
46
|
title?: string | React.ReactNode;
|
|
44
47
|
/**
|
|
45
|
-
* Текст переключателя.
|
|
48
|
+
* Текст переключателя. Вместе с `title` связывается с переключателем
|
|
49
|
+
* через `aria-describedby`. Ограничения на `ReactNode` те же, что у `title`.
|
|
46
50
|
*/
|
|
47
51
|
text?: string | React.ReactNode;
|
|
48
52
|
/**
|
|
@@ -73,13 +77,13 @@ interface SwitchProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>,
|
|
|
73
77
|
className?: string;
|
|
74
78
|
/** Класс для внешнего `Box`-обёртки над `<label>`. */
|
|
75
79
|
wrapperClassName?: string;
|
|
76
|
-
/** Класс для контейнера переключателя (
|
|
80
|
+
/** Класс для контейнера переключателя (`<span>` со `switchContainer`). */
|
|
77
81
|
switchContainerClassName?: string;
|
|
78
|
-
/** Класс для рельса-трека переключателя (`<
|
|
82
|
+
/** Класс для рельса-трека переключателя (`<span>` с `switch`). */
|
|
79
83
|
trackClassName?: string;
|
|
80
|
-
/** Класс для перемещаемой ручки переключателя (`<
|
|
84
|
+
/** Класс для перемещаемой ручки переключателя (`<span>` с `thumb`). */
|
|
81
85
|
thumbClassName?: string;
|
|
82
|
-
/** Класс для скрытого нативного `<input
|
|
86
|
+
/** Класс для визуально скрытого нативного `<input>` поверх трека. */
|
|
83
87
|
inputClassName?: string;
|
|
84
88
|
/** Класс для блока с заголовком/описанием. */
|
|
85
89
|
labelsContainerClassName?: string;
|
|
@@ -1,140 +1,163 @@
|
|
|
1
|
-
import { jsx as t, jsxs as
|
|
2
|
-
import { cx as
|
|
3
|
-
import { forwardRef as
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import { styles as
|
|
7
|
-
import { useControlled as
|
|
8
|
-
import { Text as
|
|
9
|
-
import { Box as
|
|
10
|
-
import { theme as
|
|
11
|
-
const { spacing:
|
|
1
|
+
import { jsx as t, jsxs as f } from "react/jsx-runtime";
|
|
2
|
+
import { cx as o } from "@emotion/css";
|
|
3
|
+
import { forwardRef as q, useId as A, useRef as G, useImperativeHandle as J, useCallback as K, useMemo as I } from "react";
|
|
4
|
+
import L from "../../../assets/svg/switch/fire.svg.js";
|
|
5
|
+
import O from "../../../assets/svg/switch/moon.svg.js";
|
|
6
|
+
import { styles as e } from "./styles.js";
|
|
7
|
+
import { useControlled as Q } from "../../../utils/hooks/useControlled.js";
|
|
8
|
+
import { Text as x } from "../../builders/Text/Text.js";
|
|
9
|
+
import { Box as U } from "../../builders/Box/Box.js";
|
|
10
|
+
import { theme as X } from "../../../utils/theme/index.js";
|
|
11
|
+
const { spacing: Y } = X, Z = q(
|
|
12
12
|
({
|
|
13
|
-
title:
|
|
14
|
-
text:
|
|
15
|
-
icon:
|
|
16
|
-
disabled:
|
|
17
|
-
onChange:
|
|
18
|
-
checked:
|
|
19
|
-
defaultValue:
|
|
20
|
-
className:
|
|
21
|
-
wrapperClassName:
|
|
22
|
-
switchContainerClassName:
|
|
23
|
-
trackClassName:
|
|
24
|
-
thumbClassName:
|
|
25
|
-
inputClassName:
|
|
26
|
-
labelsContainerClassName:
|
|
13
|
+
title: c,
|
|
14
|
+
text: s,
|
|
15
|
+
icon: B,
|
|
16
|
+
disabled: d,
|
|
17
|
+
onChange: n,
|
|
18
|
+
checked: S,
|
|
19
|
+
defaultValue: p,
|
|
20
|
+
className: $,
|
|
21
|
+
wrapperClassName: j,
|
|
22
|
+
switchContainerClassName: C,
|
|
23
|
+
trackClassName: R,
|
|
24
|
+
thumbClassName: V,
|
|
25
|
+
inputClassName: D,
|
|
26
|
+
labelsContainerClassName: E,
|
|
27
27
|
titleClassName: h,
|
|
28
|
-
textClassName:
|
|
29
|
-
size:
|
|
30
|
-
variant:
|
|
28
|
+
textClassName: b,
|
|
29
|
+
size: F = "md",
|
|
30
|
+
variant: y = "accent",
|
|
31
31
|
reverse: M = !1,
|
|
32
32
|
w: W = "auto",
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
"aria-describedby": _,
|
|
34
|
+
...g
|
|
35
|
+
}, z) => {
|
|
36
|
+
const [l, a] = Q(
|
|
37
|
+
S,
|
|
38
|
+
p ?? !1
|
|
39
|
+
), N = A(), m = `${N}-title`, u = `${N}-text`, k = !!(c && s), H = [k && u, _].filter(Boolean).join(" ") || void 0, i = G(null);
|
|
40
|
+
J(
|
|
41
|
+
z,
|
|
38
42
|
() => ({
|
|
39
43
|
focus: () => {
|
|
40
|
-
|
|
44
|
+
i.current?.focus();
|
|
41
45
|
},
|
|
42
46
|
blur: () => {
|
|
43
|
-
|
|
47
|
+
i.current?.blur();
|
|
44
48
|
},
|
|
45
49
|
get checked() {
|
|
46
|
-
return
|
|
50
|
+
return l ?? !1;
|
|
47
51
|
},
|
|
48
|
-
setChecked: (
|
|
49
|
-
|
|
52
|
+
setChecked: (r) => {
|
|
53
|
+
a(r), n?.(r);
|
|
50
54
|
},
|
|
51
55
|
toggle: () => {
|
|
52
|
-
const
|
|
53
|
-
|
|
56
|
+
const r = !l;
|
|
57
|
+
a(r), n?.(r);
|
|
54
58
|
},
|
|
55
|
-
isFocused: () => document.activeElement ===
|
|
56
|
-
isDisabled: () =>
|
|
57
|
-
getInputElement: () =>
|
|
58
|
-
checkValidity: () =>
|
|
59
|
+
isFocused: () => document.activeElement === i.current,
|
|
60
|
+
isDisabled: () => d ?? !1,
|
|
61
|
+
getInputElement: () => i.current,
|
|
62
|
+
checkValidity: () => i.current?.checkValidity() ?? !0,
|
|
59
63
|
reset: () => {
|
|
60
|
-
const
|
|
61
|
-
|
|
64
|
+
const r = p ?? !1;
|
|
65
|
+
a(r), n?.(r);
|
|
62
66
|
}
|
|
63
67
|
}),
|
|
64
|
-
[
|
|
68
|
+
[l, a, n, d, p]
|
|
65
69
|
);
|
|
66
|
-
const
|
|
67
|
-
(
|
|
68
|
-
|
|
70
|
+
const T = K(
|
|
71
|
+
(r) => {
|
|
72
|
+
a(r.target.checked), n?.(r.target.checked);
|
|
69
73
|
},
|
|
70
|
-
[
|
|
71
|
-
),
|
|
72
|
-
|
|
74
|
+
[n, a]
|
|
75
|
+
), v = I(() => c ? typeof c == "string" ? /* @__PURE__ */ t(
|
|
76
|
+
x,
|
|
73
77
|
{
|
|
78
|
+
id: m,
|
|
79
|
+
tag: "span",
|
|
74
80
|
variant: "body-1",
|
|
75
81
|
colorName: "primary",
|
|
76
82
|
fontWeight: "medium",
|
|
77
83
|
className: h,
|
|
78
|
-
children:
|
|
84
|
+
children: c
|
|
79
85
|
}
|
|
80
|
-
) :
|
|
81
|
-
|
|
86
|
+
) : /* @__PURE__ */ t("span", { id: m, children: c }) : null, [c, h, m]), w = I(() => s ? typeof s == "string" ? /* @__PURE__ */ t(
|
|
87
|
+
x,
|
|
82
88
|
{
|
|
89
|
+
id: u,
|
|
90
|
+
tag: "span",
|
|
83
91
|
variant: "body-2",
|
|
84
92
|
colorName: "secondary",
|
|
85
93
|
fontWeight: "regular",
|
|
86
|
-
className:
|
|
87
|
-
children:
|
|
94
|
+
className: b,
|
|
95
|
+
children: s
|
|
88
96
|
}
|
|
89
|
-
) :
|
|
90
|
-
return /* @__PURE__ */
|
|
91
|
-
/* @__PURE__ */
|
|
97
|
+
) : /* @__PURE__ */ t("span", { id: u, children: s }) : null, [s, b, u]);
|
|
98
|
+
return /* @__PURE__ */ f(U, { row: !0, w: W, gap: Y.sm, className: j, children: [
|
|
99
|
+
/* @__PURE__ */ f(
|
|
92
100
|
"label",
|
|
93
101
|
{
|
|
94
|
-
className:
|
|
95
|
-
[
|
|
96
|
-
[
|
|
102
|
+
className: o(e.container, $, {
|
|
103
|
+
[e.disabled]: d,
|
|
104
|
+
[e.reverse]: M
|
|
97
105
|
}),
|
|
98
106
|
children: [
|
|
99
|
-
/* @__PURE__ */
|
|
100
|
-
|
|
107
|
+
/* @__PURE__ */ f(
|
|
108
|
+
"span",
|
|
101
109
|
{
|
|
102
|
-
className:
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
110
|
+
className: o(
|
|
111
|
+
e.switchContainer,
|
|
112
|
+
e[`size_${F}`],
|
|
113
|
+
e[`variant_${y}`],
|
|
114
|
+
C
|
|
107
115
|
),
|
|
108
116
|
children: [
|
|
109
117
|
/* @__PURE__ */ t(
|
|
110
118
|
"input",
|
|
111
119
|
{
|
|
112
|
-
ref:
|
|
120
|
+
ref: i,
|
|
113
121
|
type: "checkbox",
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
onChange:
|
|
117
|
-
disabled:
|
|
118
|
-
|
|
119
|
-
|
|
122
|
+
role: "switch",
|
|
123
|
+
checked: l,
|
|
124
|
+
onChange: T,
|
|
125
|
+
disabled: d,
|
|
126
|
+
"aria-labelledby": k && !g["aria-label"] ? m : void 0,
|
|
127
|
+
"aria-describedby": H,
|
|
128
|
+
className: o(e.input, D),
|
|
129
|
+
...g
|
|
120
130
|
}
|
|
121
131
|
),
|
|
122
|
-
/* @__PURE__ */ t(
|
|
132
|
+
/* @__PURE__ */ t(
|
|
133
|
+
"span",
|
|
134
|
+
{
|
|
135
|
+
"aria-hidden": "true",
|
|
136
|
+
className: o(e.switch, R),
|
|
137
|
+
children: /* @__PURE__ */ t("span", { className: o(e.thumb, V), children: y === "theme" && (l ? /* @__PURE__ */ t(O, { className: e.icon }) : /* @__PURE__ */ t(L, { className: e.icon })) })
|
|
138
|
+
}
|
|
139
|
+
)
|
|
123
140
|
]
|
|
124
141
|
}
|
|
125
142
|
),
|
|
126
|
-
(
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
143
|
+
(v || w) && /* @__PURE__ */ f(
|
|
144
|
+
"span",
|
|
145
|
+
{
|
|
146
|
+
className: o(e.labelsContainer, E),
|
|
147
|
+
children: [
|
|
148
|
+
v,
|
|
149
|
+
w
|
|
150
|
+
]
|
|
151
|
+
}
|
|
152
|
+
)
|
|
130
153
|
]
|
|
131
154
|
}
|
|
132
155
|
),
|
|
133
|
-
|
|
156
|
+
B
|
|
134
157
|
] });
|
|
135
158
|
}
|
|
136
159
|
);
|
|
137
|
-
|
|
160
|
+
Z.displayName = "Switch";
|
|
138
161
|
export {
|
|
139
|
-
|
|
162
|
+
Z as Switch
|
|
140
163
|
};
|
|
@@ -3,6 +3,7 @@ export declare const styles: {
|
|
|
3
3
|
disabled: string;
|
|
4
4
|
reverse: string;
|
|
5
5
|
switchContainer: string;
|
|
6
|
+
input: string;
|
|
6
7
|
variant_accent: string;
|
|
7
8
|
variant_secondary: string;
|
|
8
9
|
variant_positive: string;
|
|
@@ -12,6 +13,6 @@ export declare const styles: {
|
|
|
12
13
|
size_lg: string;
|
|
13
14
|
switch: string;
|
|
14
15
|
thumb: string;
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
labelsContainer: string;
|
|
17
|
+
icon: string;
|
|
17
18
|
};
|
|
@@ -1,128 +1,131 @@
|
|
|
1
|
-
import { css as
|
|
2
|
-
import { theme as
|
|
3
|
-
const { color:
|
|
4
|
-
container:
|
|
1
|
+
import { css as t } from "@emotion/css";
|
|
2
|
+
import { theme as s } from "../../../utils/theme/index.js";
|
|
3
|
+
const { color: i, cornerRadius: h, height: e, spacing: r, transition: c } = s, l = {
|
|
4
|
+
container: t({
|
|
5
5
|
width: "100%",
|
|
6
6
|
cursor: "pointer",
|
|
7
|
-
outline: "none",
|
|
8
7
|
userSelect: "none",
|
|
9
8
|
display: "flex",
|
|
10
9
|
justifyContent: "space-between",
|
|
11
|
-
gap:
|
|
12
|
-
"&.disabled": {
|
|
13
|
-
cursor: "not-allowed",
|
|
14
|
-
opacity: 0.5
|
|
15
|
-
},
|
|
16
|
-
"&.reverse": {
|
|
17
|
-
flexDirection: "row-reverse"
|
|
18
|
-
}
|
|
10
|
+
gap: r.md
|
|
19
11
|
}),
|
|
20
|
-
disabled:
|
|
12
|
+
disabled: t({
|
|
21
13
|
cursor: "not-allowed",
|
|
22
14
|
opacity: 0.5
|
|
23
15
|
}),
|
|
24
|
-
reverse:
|
|
16
|
+
reverse: t({
|
|
25
17
|
flexDirection: "row-reverse"
|
|
26
18
|
}),
|
|
27
|
-
switchContainer:
|
|
19
|
+
switchContainer: t({
|
|
20
|
+
position: "relative",
|
|
21
|
+
display: "flex",
|
|
22
|
+
flexShrink: 0,
|
|
23
|
+
alignSelf: "flex-start",
|
|
28
24
|
"--width-switch-sm": "34px",
|
|
29
25
|
"--width-switch-md": "40px",
|
|
30
26
|
"--width-switch-lg": "52px",
|
|
31
27
|
"--size-thumb-sm": "18px",
|
|
32
28
|
"--size-thumb-md": "20px",
|
|
33
29
|
"--size-thumb-lg": "28px",
|
|
34
|
-
|
|
35
|
-
"
|
|
36
|
-
|
|
37
|
-
}
|
|
30
|
+
// Выключенное состояние у всех вариантов одинаковое
|
|
31
|
+
"--switch-bg-unchecked": i.fill.bg_tertiary,
|
|
32
|
+
"--thumb-bg-unchecked": i.fill.bg_primary
|
|
38
33
|
}),
|
|
39
|
-
//
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
34
|
+
// Нативный input прозрачен и лежит поверх трека: остаётся в tab-порядке и
|
|
35
|
+
// в дереве доступности, а relative-контейнер не даёт фокусу прокручивать
|
|
36
|
+
// страницу к случайной точке.
|
|
37
|
+
input: t({
|
|
38
|
+
position: "absolute",
|
|
39
|
+
inset: 0,
|
|
40
|
+
width: "100%",
|
|
41
|
+
height: "100%",
|
|
42
|
+
margin: 0,
|
|
43
|
+
opacity: 0,
|
|
44
|
+
cursor: "inherit"
|
|
49
45
|
}),
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
},
|
|
55
|
-
"&:has(input:checked)": {
|
|
56
|
-
"--switch-bg-color": t.fill.accent_secondary,
|
|
57
|
-
"--thumb-bg-color": t.fill.accent_primary
|
|
58
|
-
}
|
|
46
|
+
// Variant classes — задают цвета включённого состояния
|
|
47
|
+
variant_accent: t({
|
|
48
|
+
"--switch-bg-checked": i.fill.accent_primary,
|
|
49
|
+
"--thumb-bg-checked": i.fill.bg_primary
|
|
59
50
|
}),
|
|
60
|
-
|
|
61
|
-
"
|
|
62
|
-
|
|
63
|
-
"--thumb-bg-color": t.fill.bg_primary
|
|
64
|
-
},
|
|
65
|
-
"&:has(input:checked)": {
|
|
66
|
-
"--switch-bg-color": t.fill.positive_primary,
|
|
67
|
-
"--thumb-bg-color": t.fill.bg_primary
|
|
68
|
-
}
|
|
51
|
+
variant_secondary: t({
|
|
52
|
+
"--switch-bg-checked": i.fill.accent_secondary,
|
|
53
|
+
"--thumb-bg-checked": i.fill.accent_primary
|
|
69
54
|
}),
|
|
70
|
-
|
|
71
|
-
"
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
"
|
|
76
|
-
|
|
77
|
-
"--thumb-bg-color": t.fill.bg_tertiary
|
|
78
|
-
}
|
|
55
|
+
variant_positive: t({
|
|
56
|
+
"--switch-bg-checked": i.fill.positive_primary,
|
|
57
|
+
"--thumb-bg-checked": i.fill.bg_primary
|
|
58
|
+
}),
|
|
59
|
+
variant_theme: t({
|
|
60
|
+
"--switch-bg-checked": i.fill.bg_secondary,
|
|
61
|
+
"--thumb-bg-checked": i.fill.bg_tertiary
|
|
79
62
|
}),
|
|
80
63
|
// Size classes
|
|
81
|
-
size_sm:
|
|
64
|
+
size_sm: t({
|
|
82
65
|
"--switch-width": "var(--width-switch-sm)",
|
|
83
|
-
"--switch-height":
|
|
66
|
+
"--switch-height": e.switch.sm,
|
|
84
67
|
"--thumb-width": "var(--size-thumb-sm)",
|
|
85
68
|
"--thumb-height": "var(--size-thumb-sm)"
|
|
86
69
|
}),
|
|
87
|
-
size_md:
|
|
70
|
+
size_md: t({
|
|
88
71
|
"--switch-width": "var(--width-switch-md)",
|
|
89
|
-
"--switch-height":
|
|
72
|
+
"--switch-height": e.switch.md,
|
|
90
73
|
"--thumb-width": "var(--size-thumb-md)",
|
|
91
74
|
"--thumb-height": "var(--size-thumb-md)"
|
|
92
75
|
}),
|
|
93
|
-
size_lg:
|
|
76
|
+
size_lg: t({
|
|
94
77
|
"--switch-width": "var(--width-switch-lg)",
|
|
95
|
-
"--switch-height":
|
|
78
|
+
"--switch-height": e.switch.lg,
|
|
96
79
|
"--thumb-width": "var(--size-thumb-lg)",
|
|
97
80
|
"--thumb-height": "var(--size-thumb-lg)"
|
|
98
81
|
}),
|
|
99
|
-
switch:
|
|
82
|
+
switch: t({
|
|
83
|
+
"--switch-bg-color": "var(--switch-bg-unchecked)",
|
|
84
|
+
"--thumb-bg-color": "var(--thumb-bg-unchecked)",
|
|
85
|
+
"--thumb-translate": "0px",
|
|
100
86
|
width: "var(--switch-width)",
|
|
101
87
|
height: "var(--switch-height)",
|
|
102
|
-
transition:
|
|
88
|
+
transition: c.general,
|
|
89
|
+
transitionProperty: "background-color",
|
|
103
90
|
display: "flex",
|
|
104
91
|
alignItems: "center",
|
|
105
92
|
padding: 2,
|
|
106
93
|
backgroundColor: "var(--switch-bg-color)",
|
|
107
|
-
borderRadius:
|
|
94
|
+
borderRadius: h.xl,
|
|
95
|
+
// Прозрачный outline не виден, но в режиме высокой контрастности
|
|
96
|
+
// (forced-colors) браузер красит его системным цветом — без него фон
|
|
97
|
+
// трека и ручки заменяется на Canvas и переключатель пропадает.
|
|
98
|
+
outline: "1px solid transparent",
|
|
99
|
+
"input:checked + &": {
|
|
100
|
+
"--switch-bg-color": "var(--switch-bg-checked)",
|
|
101
|
+
"--thumb-bg-color": "var(--thumb-bg-checked)",
|
|
102
|
+
"--thumb-translate": "calc(var(--switch-width) - var(--thumb-width) - 4px)"
|
|
103
|
+
},
|
|
104
|
+
"input:focus-visible + &": {
|
|
105
|
+
outline: `2px solid ${i.border.accent_primary}`,
|
|
106
|
+
outlineOffset: 2
|
|
107
|
+
}
|
|
108
108
|
}),
|
|
109
|
-
thumb:
|
|
109
|
+
thumb: t({
|
|
110
110
|
display: "flex",
|
|
111
111
|
alignItems: "center",
|
|
112
112
|
justifyContent: "center",
|
|
113
113
|
padding: 4,
|
|
114
|
-
transition:
|
|
114
|
+
transition: c.general,
|
|
115
|
+
transitionProperty: "transform, background-color",
|
|
115
116
|
transform: "translateX(var(--thumb-translate, 0))",
|
|
116
117
|
width: "var(--thumb-width)",
|
|
117
118
|
height: "var(--thumb-height)",
|
|
118
119
|
backgroundColor: "var(--thumb-bg-color)",
|
|
119
|
-
borderRadius:
|
|
120
|
+
borderRadius: h.fullRound,
|
|
121
|
+
outline: "1px solid transparent"
|
|
120
122
|
}),
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
123
|
+
labelsContainer: t({
|
|
124
|
+
display: "flex",
|
|
125
|
+
flexDirection: "column",
|
|
126
|
+
gap: r.xs
|
|
124
127
|
}),
|
|
125
|
-
|
|
128
|
+
icon: t({
|
|
126
129
|
width: "100%",
|
|
127
130
|
height: "100%"
|
|
128
131
|
})
|