@koslibs/components 0.0.0 → 1.0.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/CHANGELOG.md +24 -0
- package/README.md +15 -14
- package/dist/components/Button/button.d.ts +67 -0
- package/dist/components/Button/button.js +88 -0
- package/dist/components/Button/colors.module.js +14 -0
- package/dist/components/Button/colors_module.css +164 -0
- package/dist/components/Button/index.d.ts +2 -0
- package/dist/components/Button/index.js +1 -0
- package/dist/components/Button/index.module.js +30 -0
- package/dist/components/Button/index_module.css +242 -0
- package/dist/components/Button/vars.css +24 -0
- package/dist/components/Spinner/colors.module.js +5 -0
- package/dist/components/Spinner/colors_module.css +6 -0
- package/dist/components/Spinner/index.d.ts +2 -0
- package/dist/components/Spinner/index.js +1 -0
- package/dist/components/Spinner/index.module.js +9 -0
- package/dist/components/Spinner/index_module.css +29 -0
- package/dist/components/Spinner/preset.module.js +7 -0
- package/dist/components/Spinner/preset_module.css +12 -0
- package/dist/components/Spinner/spinner.d.ts +31 -0
- package/dist/components/Spinner/spinner.js +80 -0
- package/dist/components/Spinner/vars.css +7 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +2 -0
- package/package.json +6 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,27 @@
|
|
|
1
1
|
# @koslibs/components
|
|
2
2
|
|
|
3
|
+
## 1.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- [#1](https://github.com/koslibs/components/pull/1) [`8954b64`](https://github.com/koslibs/components/commit/8954b64becb19165000479731114463317438bcd) Thanks [@holypower777](https://github.com/holypower777)! - Первый стабильный выпуск 1.0.0 с Button и Spinner, перенесёнными из core-components GullEye.
|
|
8
|
+
|
|
9
|
+
Компонент доступен через `import { Button } from '@koslibs/components/Button'` вместе с типом ButtonProps. Поддерживает шесть вариантов оформления, размеры 32–72, формы rectangular и rounded, левый и правый аддоны, подпись, полную ширину, disabled и loading. Сохранены ref, стандартные HTML-атрибуты и минимальное время отображения загрузки 500 мс.
|
|
10
|
+
|
|
11
|
+
Spinner доступен отдельно через `import { Spinner } from '@koslibs/components/Spinner'` вместе с типом SpinnerProps. Поддерживает размеры 16, 24 и 48, управление видимостью, настройку цвета через style.color, className, id и dataTestId. Button использует этот же публичный Spinner для отображения загрузки.
|
|
12
|
+
|
|
13
|
+
CSS Modules подключаются вместе с используемыми компонентами. Добавлены значения по умолчанию для CSS-переменных размеров, скруглений и шрифтов, чтобы компоненты работали без глобальных стилей GullEye. Отдельный импорт Spinner не включает Button и его стили. Для обоих компонентов в Storybook доступны Docs и Playground.
|
|
14
|
+
|
|
15
|
+
Docs каждого компонента разделены на вкладки «Документация», «Разработчику» и «Обновления». Во вкладке разработчика доступны публичный импорт, Props и CSS-переменные из исходных стилей; обновления отображают CHANGELOG конкретного компонента.
|
|
16
|
+
|
|
17
|
+
Проверка отдельных импортов разделена на общий fixture и декларативные сценарии: JS и типы всех публичных компонентов проверяются автоматически, библиотека собирается один раз, а выбранные production-потребители — одним запуском builder в независимых environments с общей установленной копией пакета и отдельными выходными папками.
|
|
18
|
+
|
|
19
|
+
## 0.1.0
|
|
20
|
+
|
|
21
|
+
### Minor Changes
|
|
22
|
+
|
|
23
|
+
- [`ee39a5b`](https://github.com/koslibs/components/commit/ee39a5bb32f94a3a76e4367ec6b14d9cbe4d41b2) Thanks [@holypower777](https://github.com/holypower777)! - Подготовлен каркас @koslibs/components для React 18/19 и TypeScript: сборка ESM, деклараций и CSS Modules через @koslibs/builder@1.0.0, общие настройки и release-инструменты @koslibs/configs@1.0.0, Storybook и workflow деплоя на GitHub Pages.
|
|
24
|
+
|
|
25
|
+
Настроены отдельные импорты вида @koslibs/components/Button. Тест production-сборки проверяет, что в бандл потребителя входят выбранный компонент и его CSS, а независимые соседние компоненты исключаются. Добавлены CI, Changesets и документация по переносу компонентов и ведению их историй изменений. Runtime-компоненты будут перенесены отдельно.
|
|
26
|
+
|
|
3
27
|
Опубликованных версий пока нет. После первого релиза Changesets добавит сюда историю пакета.
|
package/README.md
CHANGED
|
@@ -20,18 +20,18 @@ src/components/Button/
|
|
|
20
20
|
также добавить реэкспорт в `src/index.ts`; отдельный импорт компонента его не использует.
|
|
21
21
|
3. Общий шаблон в `package.json` → `exports` уже связывает каждый компонент с его файлами:
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"./*": {
|
|
26
|
+
"types": "./dist/components/*/index.d.ts",
|
|
27
|
+
"import": "./dist/components/*/index.js"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
31
|
|
|
32
32
|
4. Добавьте Docs, Playground и `CHANGELOG.md` по [примеру документации](https://github.com/koslibs/components/blob/main/docs/component-changelogs.md).
|
|
33
|
-
5. Добавьте тесты поведения.
|
|
34
|
-
|
|
33
|
+
5. Добавьте тесты поведения. `npm run test:unit` запускает unit-тесты через
|
|
34
|
+
`koslibs-builder lib:test`; `npm test` также проверяет отдельные импорты.
|
|
35
35
|
6. Выполните сборку и проверьте реальные пути JS, деклараций и CSS в `dist`.
|
|
36
36
|
|
|
37
37
|
После публикации предполагается такой импорт:
|
|
@@ -53,10 +53,11 @@ Builder сохраняет отдельные JS-модули и отдельн
|
|
|
53
53
|
|
|
54
54
|
Тест `tests/component-imports.test.mjs` запускается через Node.js test runner командой
|
|
55
55
|
`npm test` (или отдельно `npm run test:imports`) и проверяет схему через builder:
|
|
56
|
-
собирает временную библиотеку с Button
|
|
57
|
-
|
|
58
|
-
Проверка подтверждает наличие Button
|
|
59
|
-
|
|
56
|
+
собирает временную библиотеку с настоящим Button и независимым тестовым Spinner,
|
|
57
|
+
затем приложение с импортом только `@koslibs/components/Button`.
|
|
58
|
+
Проверка подтверждает наличие Button, его внутреннего спиннера загрузки и их CSS
|
|
59
|
+
и отсутствие независимого Spinner в production-бандле.
|
|
60
|
+
Временная библиотека находится в `.cache` и не публикуется.
|
|
60
61
|
|
|
61
62
|
Пакет выпускается в ESM. CSS помечен как side effect, чтобы оптимизация потребителя
|
|
62
63
|
не удаляла стили. Builder сохраняет структуру модулей; Docs, stories и Markdown
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import React, { type ButtonHTMLAttributes, type ReactNode } from 'react';
|
|
2
|
+
type ButtonOwnProps = {
|
|
3
|
+
/**
|
|
4
|
+
* Тип кнопки
|
|
5
|
+
* @default 'primary'
|
|
6
|
+
*/
|
|
7
|
+
view?: 'primary' | 'secondary' | 'accent' | 'outlined' | 'transparent' | 'text';
|
|
8
|
+
/**
|
|
9
|
+
* Скругление кнопки
|
|
10
|
+
* @default 'rectangular'
|
|
11
|
+
*/
|
|
12
|
+
shape?: 'rectangular' | 'rounded';
|
|
13
|
+
/**
|
|
14
|
+
* Размер кнопки
|
|
15
|
+
* @default 40
|
|
16
|
+
*/
|
|
17
|
+
size?: 32 | 40 | 48 | 56 | 64 | 72;
|
|
18
|
+
/**
|
|
19
|
+
* Аддон слева от лейбла
|
|
20
|
+
*/
|
|
21
|
+
leftAddon?: ReactNode;
|
|
22
|
+
/**
|
|
23
|
+
* Аддон справа от лейбла
|
|
24
|
+
*/
|
|
25
|
+
rightAddon?: ReactNode;
|
|
26
|
+
/**
|
|
27
|
+
* Подпись под основным текстом
|
|
28
|
+
*/
|
|
29
|
+
hint?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Заставляет кнопку растянуться на ширину контейнера.
|
|
32
|
+
* @default false
|
|
33
|
+
*/
|
|
34
|
+
block?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Показать лоадер
|
|
37
|
+
* @default false
|
|
38
|
+
*/
|
|
39
|
+
loading?: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Айди для автотестов.
|
|
42
|
+
*/
|
|
43
|
+
dataTestId?: string;
|
|
44
|
+
/**
|
|
45
|
+
* Дополнительный класс
|
|
46
|
+
*/
|
|
47
|
+
className?: string;
|
|
48
|
+
/**
|
|
49
|
+
* Дополнительный класс для label
|
|
50
|
+
*/
|
|
51
|
+
labelClassName?: string;
|
|
52
|
+
/**
|
|
53
|
+
* Дополнительный класс для hint
|
|
54
|
+
*/
|
|
55
|
+
hintClassName?: string;
|
|
56
|
+
/**
|
|
57
|
+
* Дополнительный класс для спиннера
|
|
58
|
+
*/
|
|
59
|
+
spinnerClassName?: string;
|
|
60
|
+
/**
|
|
61
|
+
* Текст кнопки
|
|
62
|
+
*/
|
|
63
|
+
children?: ReactNode;
|
|
64
|
+
};
|
|
65
|
+
export type ButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & ButtonOwnProps;
|
|
66
|
+
export declare const Button: React.ForwardRefExoticComponent<React.ButtonHTMLAttributes<HTMLButtonElement> & ButtonOwnProps & React.RefAttributes<HTMLButtonElement>>;
|
|
67
|
+
export {};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import classnames from "classnames";
|
|
3
|
+
import react, { forwardRef, useEffect, useRef, useState } from "react";
|
|
4
|
+
import { Spinner } from "../Spinner/index.js";
|
|
5
|
+
import colors_module from "./colors.module.js";
|
|
6
|
+
import index_module from "./index.module.js";
|
|
7
|
+
const Button = /*#__PURE__*/ forwardRef(({ view = 'primary', shape = 'rectangular', size = 40, leftAddon, rightAddon, hint, block = false, loading = false, dataTestId, className, labelClassName, hintClassName, spinnerClassName, children, onClick, ...restProps }, ref)=>{
|
|
8
|
+
const [loaderTimePassed, setLoaderTimePassed] = useState(true);
|
|
9
|
+
const timerId = useRef(0);
|
|
10
|
+
const showLoader = loading || !loaderTimePassed;
|
|
11
|
+
const showHint = hint && [
|
|
12
|
+
56,
|
|
13
|
+
64,
|
|
14
|
+
72
|
|
15
|
+
].includes(size);
|
|
16
|
+
const { disabled, type = 'button', ...restButtonProps } = restProps;
|
|
17
|
+
const buttonChildren = /*#__PURE__*/ jsxs(react.Fragment, {
|
|
18
|
+
children: [
|
|
19
|
+
leftAddon && /*#__PURE__*/ jsx("span", {
|
|
20
|
+
className: index_module.addons,
|
|
21
|
+
children: leftAddon
|
|
22
|
+
}),
|
|
23
|
+
children && /*#__PURE__*/ jsxs("span", {
|
|
24
|
+
className: classnames(index_module.label, labelClassName, {
|
|
25
|
+
[index_module.stretchText]: !(leftAddon || rightAddon)
|
|
26
|
+
}),
|
|
27
|
+
children: [
|
|
28
|
+
children,
|
|
29
|
+
showHint && /*#__PURE__*/ jsx("span", {
|
|
30
|
+
className: classnames(index_module.hint, colors_module.hint, hintClassName),
|
|
31
|
+
children: hint
|
|
32
|
+
})
|
|
33
|
+
]
|
|
34
|
+
}),
|
|
35
|
+
showLoader && /*#__PURE__*/ jsx(Spinner, {
|
|
36
|
+
size: 24,
|
|
37
|
+
dataTestId: dataTestId ? `${dataTestId}-loader` : void 0,
|
|
38
|
+
visible: true,
|
|
39
|
+
className: classnames(index_module.loader, colors_module.loader, spinnerClassName)
|
|
40
|
+
}),
|
|
41
|
+
rightAddon && /*#__PURE__*/ jsx("span", {
|
|
42
|
+
className: index_module.addons,
|
|
43
|
+
children: rightAddon
|
|
44
|
+
})
|
|
45
|
+
]
|
|
46
|
+
});
|
|
47
|
+
useEffect(()=>{
|
|
48
|
+
if (loading) {
|
|
49
|
+
window.clearTimeout(timerId.current);
|
|
50
|
+
setLoaderTimePassed(false);
|
|
51
|
+
timerId.current = window.setTimeout(()=>{
|
|
52
|
+
setLoaderTimePassed(true);
|
|
53
|
+
}, 500);
|
|
54
|
+
}
|
|
55
|
+
}, [
|
|
56
|
+
loading
|
|
57
|
+
]);
|
|
58
|
+
useEffect(()=>()=>{
|
|
59
|
+
window.clearTimeout(timerId.current);
|
|
60
|
+
}, []);
|
|
61
|
+
const handleClick = (e)=>{
|
|
62
|
+
if (disabled || showLoader) {
|
|
63
|
+
e.preventDefault();
|
|
64
|
+
e.stopPropagation();
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
onClick?.(e);
|
|
68
|
+
};
|
|
69
|
+
return /*#__PURE__*/ jsx("button", {
|
|
70
|
+
...restButtonProps,
|
|
71
|
+
className: classnames(index_module.component, index_module[view], index_module[`size-${size}`], index_module[shape], colors_module.component, colors_module[view], {
|
|
72
|
+
[index_module.block]: block,
|
|
73
|
+
[index_module.loading]: showLoader,
|
|
74
|
+
[index_module.withRightAddon]: Boolean(rightAddon),
|
|
75
|
+
[index_module.withLeftAddon]: Boolean(leftAddon),
|
|
76
|
+
[colors_module.loading]: showLoader
|
|
77
|
+
}, className),
|
|
78
|
+
"data-test-id": dataTestId,
|
|
79
|
+
type: type,
|
|
80
|
+
disabled: disabled || showLoader,
|
|
81
|
+
"aria-busy": showLoader,
|
|
82
|
+
onClick: handleClick,
|
|
83
|
+
ref: ref,
|
|
84
|
+
children: buttonChildren
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
Button.displayName = 'Button';
|
|
88
|
+
export { Button };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import "./colors_module.css";
|
|
2
|
+
const colors_module = {
|
|
3
|
+
primary: "primary-jF1frT",
|
|
4
|
+
secondary: "secondary-em6CEW",
|
|
5
|
+
accent: "accent-cr9M8g",
|
|
6
|
+
transparent: "transparent-osSlaN",
|
|
7
|
+
text: "text-fLOhKS",
|
|
8
|
+
loader: "loader-wrwZSN",
|
|
9
|
+
hint: "hint-JAXcv5",
|
|
10
|
+
outlined: "outlined-xzRrKO",
|
|
11
|
+
component: "component-GmKJmC",
|
|
12
|
+
loading: "loading-LzTYPE"
|
|
13
|
+
};
|
|
14
|
+
export default colors_module;
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
@import "./vars.css";
|
|
2
|
+
|
|
3
|
+
.primary-jF1frT, .secondary-em6CEW, .accent-cr9M8g, .transparent-osSlaN, .text-fLOhKS {
|
|
4
|
+
box-shadow: none;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.primary-jF1frT {
|
|
8
|
+
color: var(--button-inverse-color);
|
|
9
|
+
background-color: var(--button-primary-background-color);
|
|
10
|
+
|
|
11
|
+
@media (hover: hover) {
|
|
12
|
+
&:hover {
|
|
13
|
+
background-color: var(--button-primary-hover-background-color);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
&:active {
|
|
18
|
+
background-color: var(--button-primary-active-background-color);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
& > .loader-wrwZSN {
|
|
22
|
+
color: var(--button-inverse-color);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
&:not([disabled]) .hint-JAXcv5 {
|
|
26
|
+
color: var(--button-inverse-hint-color);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.secondary-em6CEW {
|
|
31
|
+
color: var(--button-default-color);
|
|
32
|
+
background-color: var(--button-secondary-background-color);
|
|
33
|
+
|
|
34
|
+
@media (hover: hover) {
|
|
35
|
+
&:hover {
|
|
36
|
+
background-color: var(--button-secondary-hover-background-color);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
&:active {
|
|
41
|
+
background-color: var(--button-secondary-active-background-color);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
& > .loader-wrwZSN {
|
|
45
|
+
color: var(--button-default-color);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
&:not([disabled]) .hint-JAXcv5 {
|
|
49
|
+
color: var(--button-hint-color);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.accent-cr9M8g {
|
|
54
|
+
color: var(--button-inverse-color);
|
|
55
|
+
background-color: var(--button-accent-background-color);
|
|
56
|
+
|
|
57
|
+
@media (hover: hover) {
|
|
58
|
+
&:hover {
|
|
59
|
+
background-color: var(--button-accent-hover-background-color);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
&:active {
|
|
64
|
+
background-color: var(--button-accent-active-background-color);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
& > .loader-wrwZSN {
|
|
68
|
+
color: var(--button-inverse-color);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
&:not([disabled]) .hint-JAXcv5 {
|
|
72
|
+
color: var(--button-inverse-hint-color);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.outlined-xzRrKO {
|
|
77
|
+
color: var(--button-default-color);
|
|
78
|
+
box-shadow: inset 0 0 0 1px var(--button-primary-background-color);
|
|
79
|
+
background: none;
|
|
80
|
+
|
|
81
|
+
@media (hover: hover) {
|
|
82
|
+
&:hover {
|
|
83
|
+
background-color: var(--button-subtle-hover-background-color);
|
|
84
|
+
box-shadow: inset 0 0 0 1px var(--button-primary-hover-background-color);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
&:active {
|
|
89
|
+
background-color: var(--button-subtle-active-background-color);
|
|
90
|
+
box-shadow: inset 0 0 0 1px var(--button-primary-active-background-color);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
& > .loader-wrwZSN {
|
|
94
|
+
color: var(--button-default-color);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
&:not([disabled]) .hint-JAXcv5 {
|
|
98
|
+
color: var(--button-hint-color);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.transparent-osSlaN {
|
|
103
|
+
color: var(--button-default-color);
|
|
104
|
+
background-color: var(--button-transparent-background-color);
|
|
105
|
+
|
|
106
|
+
@media (hover: hover) {
|
|
107
|
+
&:hover {
|
|
108
|
+
background-color: var(--button-subtle-hover-background-color);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
&:active {
|
|
113
|
+
background-color: var(--button-subtle-active-background-color);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
& > .loader-wrwZSN {
|
|
117
|
+
color: var(--button-default-color);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
&:not([disabled]) .hint-JAXcv5 {
|
|
121
|
+
color: var(--button-hint-color);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.text-fLOhKS {
|
|
126
|
+
background-color: var(--button-transparent-background-color);
|
|
127
|
+
color: var(--button-default-color);
|
|
128
|
+
|
|
129
|
+
@media (hover: hover) {
|
|
130
|
+
&:hover {
|
|
131
|
+
color: var(--button-text-hover-color);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
&:active {
|
|
136
|
+
color: var(--button-text-active-color);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
& > .loader-wrwZSN {
|
|
140
|
+
color: var(--button-default-color);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
&:not([disabled]) .hint-JAXcv5 {
|
|
144
|
+
color: var(--button-hint-color);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.component-GmKJmC[disabled] {
|
|
149
|
+
&:not(.loading-LzTYPE) {
|
|
150
|
+
background-color: var(--button-disabled-background-color);
|
|
151
|
+
color: var(--button-disabled-color);
|
|
152
|
+
box-shadow: none;
|
|
153
|
+
|
|
154
|
+
&.hint-JAXcv5 {
|
|
155
|
+
color: var(--button-disabled-hint-color);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
&.transparent-osSlaN, &.text-fLOhKS {
|
|
160
|
+
background-color: var(--button-transparent-background-color);
|
|
161
|
+
color: var(--button-disabled-color);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Button } from "./button.js";
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import "./index_module.css";
|
|
2
|
+
const index_module = {
|
|
3
|
+
component: "component-vxc0gC",
|
|
4
|
+
"size-32": "size-32-oD8MDp",
|
|
5
|
+
size32: "size-32-oD8MDp",
|
|
6
|
+
"size-40": "size-40-Pu2_h6",
|
|
7
|
+
size40: "size-40-Pu2_h6",
|
|
8
|
+
"size-48": "size-48-U3XIYx",
|
|
9
|
+
size48: "size-48-U3XIYx",
|
|
10
|
+
"size-56": "size-56-P_94sz",
|
|
11
|
+
size56: "size-56-P_94sz",
|
|
12
|
+
"size-64": "size-64-ZlQLt3",
|
|
13
|
+
size64: "size-64-ZlQLt3",
|
|
14
|
+
"size-72": "size-72-zkSrcs",
|
|
15
|
+
size72: "size-72-zkSrcs",
|
|
16
|
+
withRightAddon: "withRightAddon-TNcFTm",
|
|
17
|
+
text: "text-Ifdq0q",
|
|
18
|
+
withLeftAddon: "withLeftAddon-N3YDHw",
|
|
19
|
+
addons: "addons-NxGsiY",
|
|
20
|
+
block: "block-xREK1A",
|
|
21
|
+
rectangular: "rectangular-PFbww7",
|
|
22
|
+
rounded: "rounded-kQqesg",
|
|
23
|
+
loading: "loading-DPEeSl",
|
|
24
|
+
label: "label-gwmTIK",
|
|
25
|
+
stretchText: "stretchText-Nm2RYn",
|
|
26
|
+
hint: "hint-AFu_zz",
|
|
27
|
+
loader: "loader-BRksFP",
|
|
28
|
+
transparent: "transparent-w7vhL3"
|
|
29
|
+
};
|
|
30
|
+
export default index_module;
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
@import "./vars.css";
|
|
2
|
+
|
|
3
|
+
.component-vxc0gC {
|
|
4
|
+
box-sizing: border-box;
|
|
5
|
+
vertical-align: middle;
|
|
6
|
+
width: fit-content;
|
|
7
|
+
font-family: var(--font-ubuntu, "Ubuntu", sans-serif);
|
|
8
|
+
font-size: var(--size-16, 16px);
|
|
9
|
+
text-align: center;
|
|
10
|
+
margin: var(--size-0, 0px);
|
|
11
|
+
padding: var(--size-0, 0px) var(--size-24, 24px);
|
|
12
|
+
cursor: pointer;
|
|
13
|
+
-webkit-user-select: none;
|
|
14
|
+
user-select: none;
|
|
15
|
+
border: none;
|
|
16
|
+
outline: none;
|
|
17
|
+
flex-flow: row;
|
|
18
|
+
justify-content: center;
|
|
19
|
+
align-items: center;
|
|
20
|
+
text-decoration: none;
|
|
21
|
+
transition: background-color .1s ease-in-out, color .1s ease-in-out, box-shadow .1s ease-in-out;
|
|
22
|
+
display: inline-flex;
|
|
23
|
+
position: relative;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.size-32-oD8MDp, .size-40-Pu2_h6 {
|
|
27
|
+
font-size: 14px;
|
|
28
|
+
font-weight: 500;
|
|
29
|
+
line-height: 20px;
|
|
30
|
+
font-family: var(--font-family-system, system-ui, sans-serif);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.size-32-oD8MDp {
|
|
34
|
+
min-width: 80px;
|
|
35
|
+
min-height: 32px;
|
|
36
|
+
padding: var(--size-0, 0px) var(--size-16, 16px);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.size-40-Pu2_h6 {
|
|
40
|
+
min-width: 88px;
|
|
41
|
+
min-height: 40px;
|
|
42
|
+
padding: var(--size-0, 0px) var(--size-20, 20px);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.size-48-U3XIYx, .size-56-P_94sz {
|
|
46
|
+
font-size: 16px;
|
|
47
|
+
font-weight: 500;
|
|
48
|
+
line-height: 20px;
|
|
49
|
+
font-family: var(--font-family-system, system-ui, sans-serif);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.size-48-U3XIYx {
|
|
53
|
+
min-width: 104px;
|
|
54
|
+
min-height: 48px;
|
|
55
|
+
padding: var(--size-0, 0px) var(--size-24, 24px);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.size-56-P_94sz {
|
|
59
|
+
min-width: 128px;
|
|
60
|
+
min-height: 56px;
|
|
61
|
+
padding: var(--size-0, 0px) var(--size-28, 28px);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.size-64-ZlQLt3, .size-72-zkSrcs {
|
|
65
|
+
font-size: 18px;
|
|
66
|
+
font-weight: 500;
|
|
67
|
+
line-height: 24px;
|
|
68
|
+
font-family: var(--font-family-system, system-ui, sans-serif);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.size-64-ZlQLt3 {
|
|
72
|
+
min-width: 160px;
|
|
73
|
+
min-height: 64px;
|
|
74
|
+
padding: var(--size-0, 0px) var(--size-32, 32px);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.size-72-zkSrcs {
|
|
78
|
+
min-width: 168px;
|
|
79
|
+
min-height: 72px;
|
|
80
|
+
padding: var(--size-0, 0px) var(--size-36, 36px);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.withRightAddon-TNcFTm {
|
|
84
|
+
&.size-32-oD8MDp {
|
|
85
|
+
padding-right: var(--size-12, 12px);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
&.size-40-Pu2_h6 {
|
|
89
|
+
padding-right: var(--size-16, 16px);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
&.size-48-U3XIYx {
|
|
93
|
+
padding-right: var(--size-20, 20px);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
&.size-56-P_94sz {
|
|
97
|
+
padding-right: var(--size-24, 24px);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
&.size-64-ZlQLt3 {
|
|
101
|
+
padding-right: var(--size-28, 28px);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
&.size-72-zkSrcs {
|
|
105
|
+
padding-right: var(--size-32, 32px);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
&.text-Ifdq0q {
|
|
109
|
+
padding-right: var(--size-0, 0px);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.withLeftAddon-N3YDHw {
|
|
114
|
+
&.size-32-oD8MDp {
|
|
115
|
+
padding-left: var(--size-12, 12px);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
&.size-40-Pu2_h6 {
|
|
119
|
+
padding-left: var(--size-16, 16px);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
&.size-48-U3XIYx {
|
|
123
|
+
padding-left: var(--size-20, 20px);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
&.size-56-P_94sz {
|
|
127
|
+
padding-left: var(--size-24, 24px);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
&.size-64-ZlQLt3 {
|
|
131
|
+
padding-left: var(--size-28, 28px);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
&.size-72-zkSrcs {
|
|
135
|
+
padding-left: var(--size-32, 32px);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
&.text-Ifdq0q {
|
|
139
|
+
padding-left: var(--size-0, 0px);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.text-Ifdq0q {
|
|
144
|
+
min-width: 0;
|
|
145
|
+
min-height: 0;
|
|
146
|
+
padding: var(--size-0, 0px);
|
|
147
|
+
appearance: none;
|
|
148
|
+
border: none;
|
|
149
|
+
|
|
150
|
+
&.size-48-U3XIYx, &.size-56-P_94sz {
|
|
151
|
+
min-height: 24px;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.size-48-U3XIYx, .size-56-P_94sz {
|
|
156
|
+
& .addons-NxGsiY:first-child {
|
|
157
|
+
margin-right: var(--size-8, 8px);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
& .addons-NxGsiY:last-child {
|
|
161
|
+
margin-left: var(--size-8, 8px);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
& .addons-NxGsiY:only-child {
|
|
165
|
+
margin: var(--size-0, 0px);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.size-64-ZlQLt3, .size-72-zkSrcs {
|
|
170
|
+
& .addons-NxGsiY:first-child {
|
|
171
|
+
margin-right: var(--size-12, 12px);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
& .addons-NxGsiY:last-child {
|
|
175
|
+
margin-left: var(--size-12, 12px);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
& .addons-NxGsiY:only-child {
|
|
179
|
+
margin: var(--size-0, 0px);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.block-xREK1A {
|
|
184
|
+
width: 100%;
|
|
185
|
+
display: flex;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.rectangular-PFbww7 {
|
|
189
|
+
border-radius: var(--border-radius-8, 8px);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.rounded-kQqesg {
|
|
193
|
+
border-radius: var(--border-radius-pill, 99px);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.addons-NxGsiY {
|
|
197
|
+
margin: var(--size-0, 0px);
|
|
198
|
+
flex-shrink: 0;
|
|
199
|
+
align-items: center;
|
|
200
|
+
display: flex;
|
|
201
|
+
|
|
202
|
+
&:first-child {
|
|
203
|
+
margin-right: var(--size-6, 6px);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
&:last-child {
|
|
207
|
+
margin-left: var(--size-6, 6px);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
&:only-child {
|
|
211
|
+
margin: var(--size-0, 0px);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
.loading-DPEeSl .label-gwmTIK, .loading-DPEeSl .addons-NxGsiY {
|
|
216
|
+
opacity: 0;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.stretchText-Nm2RYn {
|
|
220
|
+
flex-grow: 1;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.hint-AFu_zz {
|
|
224
|
+
font-size: 14px;
|
|
225
|
+
font-weight: 400;
|
|
226
|
+
line-height: 18px;
|
|
227
|
+
font-family: var(--font-primary, "Inter", sans-serif);
|
|
228
|
+
color: var(--button-hint-color);
|
|
229
|
+
display: block;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
.loader-BRksFP {
|
|
233
|
+
left: var(--size-0, 0px);
|
|
234
|
+
right: var(--size-0, 0px);
|
|
235
|
+
margin: var(--size-0, 0px) auto;
|
|
236
|
+
position: absolute;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
.transparent-w7vhL3 {
|
|
240
|
+
min-width: 0;
|
|
241
|
+
}
|
|
242
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--button-default-color: #1c1a18;
|
|
3
|
+
--button-inverse-color: #f5f3ec;
|
|
4
|
+
--button-hint-color: #1c1a1862;
|
|
5
|
+
--button-inverse-hint-color: #f5f3ec72;
|
|
6
|
+
--button-primary-background-color: #ff6b0a;
|
|
7
|
+
--button-primary-hover-background-color: #f05f00;
|
|
8
|
+
--button-primary-active-background-color: #d95300;
|
|
9
|
+
--button-secondary-background-color: #e0dbce;
|
|
10
|
+
--button-secondary-hover-background-color: #d5cdbc;
|
|
11
|
+
--button-secondary-active-background-color: #c8beaa;
|
|
12
|
+
--button-accent-background-color: #7967f2;
|
|
13
|
+
--button-accent-hover-background-color: #6c5ae6;
|
|
14
|
+
--button-accent-active-background-color: #5e4cd8;
|
|
15
|
+
--button-transparent-background-color: transparent;
|
|
16
|
+
--button-subtle-hover-background-color: #f2f3ea;
|
|
17
|
+
--button-subtle-active-background-color: #e5e7db;
|
|
18
|
+
--button-text-hover-color: #4a463f;
|
|
19
|
+
--button-text-active-color: #6a645a;
|
|
20
|
+
--button-disabled-background-color: #cfd1cb;
|
|
21
|
+
--button-disabled-color: #858981;
|
|
22
|
+
--button-disabled-hint-color: #9da099;
|
|
23
|
+
}
|
|
24
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Spinner } from "./spinner.js";
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
@import "./vars.css";
|
|
2
|
+
|
|
3
|
+
.spinner-KHk8mw {
|
|
4
|
+
box-sizing: content-box;
|
|
5
|
+
animation: spin_animation-pow2iy var(--spinner-animation-duration) infinite
|
|
6
|
+
var(--spinner-animation-timing-function);
|
|
7
|
+
display: none;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.visible-wk34JZ {
|
|
11
|
+
display: var(--spinner-display-visible);
|
|
12
|
+
vertical-align: middle;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.gradient-QKWB8G {
|
|
16
|
+
width: 100%;
|
|
17
|
+
height: 100%;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@keyframes spin_animation-pow2iy {
|
|
21
|
+
from {
|
|
22
|
+
transform: rotate(0);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
to {
|
|
26
|
+
transform: rotate(360deg);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export type SpinnerProps = {
|
|
3
|
+
/**
|
|
4
|
+
* Управление видимостью компонента
|
|
5
|
+
* @default false
|
|
6
|
+
*/
|
|
7
|
+
visible?: boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Размер спиннера
|
|
10
|
+
*
|
|
11
|
+
* @default 24
|
|
12
|
+
*/
|
|
13
|
+
size?: 16 | 24 | 48;
|
|
14
|
+
/**
|
|
15
|
+
* Дополнительный класс
|
|
16
|
+
*/
|
|
17
|
+
className?: string;
|
|
18
|
+
/**
|
|
19
|
+
* Идентификатор компонента в DOM
|
|
20
|
+
*/
|
|
21
|
+
id?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Идентификатор для систем автоматизированного тестирования
|
|
24
|
+
*/
|
|
25
|
+
dataTestId?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Дополнительные инлайн стили для cпиннера
|
|
28
|
+
*/
|
|
29
|
+
style?: React.CSSProperties;
|
|
30
|
+
};
|
|
31
|
+
export declare const Spinner: ({ visible, size, className, id, dataTestId, style }: SpinnerProps) => React.JSX.Element;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import classnames from "classnames";
|
|
3
|
+
import { useId } from "react";
|
|
4
|
+
import colors_module from "./colors.module.js";
|
|
5
|
+
import index_module from "./index.module.js";
|
|
6
|
+
import preset_module from "./preset.module.js";
|
|
7
|
+
const PRESET_CONFIG = {
|
|
8
|
+
16: [
|
|
9
|
+
2,
|
|
10
|
+
14,
|
|
11
|
+
'preset16'
|
|
12
|
+
],
|
|
13
|
+
24: [
|
|
14
|
+
2,
|
|
15
|
+
20,
|
|
16
|
+
'preset24'
|
|
17
|
+
],
|
|
18
|
+
48: [
|
|
19
|
+
4,
|
|
20
|
+
40,
|
|
21
|
+
'preset48'
|
|
22
|
+
]
|
|
23
|
+
};
|
|
24
|
+
const Spinner = ({ visible, size = 24, className, id, dataTestId, style })=>{
|
|
25
|
+
const [lineWidth, presetSize, styleKey] = PRESET_CONFIG[size];
|
|
26
|
+
const presetClassname = preset_module[styleKey];
|
|
27
|
+
const uniqId = useId();
|
|
28
|
+
const radius = presetSize / 2 - lineWidth / 2;
|
|
29
|
+
const rotationAngle = Math.ceil(180 * Math.asin(lineWidth / 2 / radius) / Math.PI);
|
|
30
|
+
const gap = 90;
|
|
31
|
+
const pathLength = 360;
|
|
32
|
+
const strokeDasharray = `${pathLength - gap - rotationAngle} ${gap + rotationAngle}`;
|
|
33
|
+
const gradient = `conic-gradient(from ${rotationAngle}deg, transparent ${gap - 2 * rotationAngle}deg, currentColor)`;
|
|
34
|
+
return /*#__PURE__*/ jsxs("svg", {
|
|
35
|
+
"aria-hidden": "true",
|
|
36
|
+
viewBox: `0 0 ${presetSize} ${presetSize}`,
|
|
37
|
+
style: {
|
|
38
|
+
...style,
|
|
39
|
+
height: presetSize,
|
|
40
|
+
width: presetSize
|
|
41
|
+
},
|
|
42
|
+
className: classnames(index_module.spinner, colors_module.component, presetClassname, className, {
|
|
43
|
+
[index_module.visible]: visible
|
|
44
|
+
}),
|
|
45
|
+
"data-test-id": dataTestId,
|
|
46
|
+
id: id,
|
|
47
|
+
children: [
|
|
48
|
+
/*#__PURE__*/ jsx("defs", {
|
|
49
|
+
children: /*#__PURE__*/ jsx("mask", {
|
|
50
|
+
id: uniqId,
|
|
51
|
+
children: /*#__PURE__*/ jsx("circle", {
|
|
52
|
+
cx: "50%",
|
|
53
|
+
cy: "50%",
|
|
54
|
+
r: radius,
|
|
55
|
+
strokeWidth: lineWidth,
|
|
56
|
+
strokeLinecap: "round",
|
|
57
|
+
stroke: "#fff",
|
|
58
|
+
strokeDashoffset: -rotationAngle,
|
|
59
|
+
strokeDasharray: strokeDasharray,
|
|
60
|
+
pathLength: pathLength
|
|
61
|
+
})
|
|
62
|
+
})
|
|
63
|
+
}),
|
|
64
|
+
/*#__PURE__*/ jsx("foreignObject", {
|
|
65
|
+
x: "0",
|
|
66
|
+
y: "0",
|
|
67
|
+
width: presetSize,
|
|
68
|
+
height: presetSize,
|
|
69
|
+
mask: `url(#${uniqId})`,
|
|
70
|
+
children: /*#__PURE__*/ jsx("div", {
|
|
71
|
+
className: index_module.gradient,
|
|
72
|
+
style: {
|
|
73
|
+
backgroundImage: gradient
|
|
74
|
+
}
|
|
75
|
+
})
|
|
76
|
+
})
|
|
77
|
+
]
|
|
78
|
+
});
|
|
79
|
+
};
|
|
80
|
+
export { Spinner };
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@koslibs/components",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Shared React components for koslibs projects",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -49,7 +49,8 @@
|
|
|
49
49
|
"format:check": "koslibs-lint format:check",
|
|
50
50
|
"storybook": "koslibs-builder storybook:start",
|
|
51
51
|
"build-storybook": "koslibs-builder storybook:build",
|
|
52
|
-
"test": "
|
|
52
|
+
"test": "npm run test:unit && npm run test:imports",
|
|
53
|
+
"test:unit": "koslibs-builder lib:test",
|
|
53
54
|
"test:imports": "node --test tests/component-imports.test.mjs",
|
|
54
55
|
"prepack": "koslibs-builder lib:build",
|
|
55
56
|
"changeset": "koslibs-release add",
|
|
@@ -76,5 +77,8 @@
|
|
|
76
77
|
"peerDependencies": {
|
|
77
78
|
"react": "^18.3.1 || ^19.0.0",
|
|
78
79
|
"react-dom": "^18.3.1 || ^19.0.0"
|
|
80
|
+
},
|
|
81
|
+
"dependencies": {
|
|
82
|
+
"classnames": "2.5.1"
|
|
79
83
|
}
|
|
80
84
|
}
|