@koslibs/components 1.11.1 → 1.13.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 +20 -0
- package/dist/components/Button/index_module.css +4 -0
- package/dist/components/Collapse/collapse.d.ts +10 -0
- package/dist/components/Collapse/collapse.js +2 -1
- package/dist/components/Collapse/index_module.css +6 -5
- package/dist/components/Input/index_module.css +8 -7
- package/dist/components/Input/input.d.ts +1 -0
- package/dist/components/Input/input.js +2 -1
- package/dist/components/Input/types.d.ts +5 -0
- package/dist/components/Modal/components/modal-surface/index.js +1 -1
- package/dist/components/Select/components/select-dropdown.d.ts +2 -2
- package/dist/components/Select/components/select-dropdown.js +2 -1
- package/dist/components/Select/index_module.css +5 -4
- package/dist/components/Select/select.js +3 -1
- package/dist/components/Select/types.d.ts +1 -1
- package/dist/components/Sidepanel/components/content/index.d.ts +13 -0
- package/dist/components/Sidepanel/components/content/index.js +21 -0
- package/dist/components/Sidepanel/components/content/index.module.js +5 -0
- package/dist/components/Sidepanel/components/content/index_module.css +14 -0
- package/dist/components/Sidepanel/components/footer/index.d.ts +66 -0
- package/dist/components/Sidepanel/components/footer/index.js +25 -0
- package/dist/components/Sidepanel/components/footer/index.module.js +19 -0
- package/dist/components/Sidepanel/components/footer/index_module.css +57 -0
- package/dist/components/Sidepanel/components/header/index.d.ts +33 -0
- package/dist/components/Sidepanel/components/header/index.js +45 -0
- package/dist/components/Sidepanel/components/header/index.module.js +8 -0
- package/dist/components/Sidepanel/components/header/index_module.css +32 -0
- package/dist/components/Sidepanel/components/sidepanel-surface/index.d.ts +4 -0
- package/dist/components/Sidepanel/components/sidepanel-surface/index.js +92 -0
- package/dist/components/Sidepanel/context.d.ts +6 -0
- package/dist/components/Sidepanel/context.js +3 -0
- package/dist/components/Sidepanel/hooks/use-dialog-transition.d.ts +5 -0
- package/dist/components/Sidepanel/hooks/use-dialog-transition.js +83 -0
- package/dist/components/Sidepanel/index.d.ts +8 -0
- package/dist/components/Sidepanel/index.js +4 -0
- package/dist/components/Sidepanel/index.module.js +8 -0
- package/dist/components/Sidepanel/index_module.css +68 -0
- package/dist/components/Sidepanel/scrollbar.module.js +5 -0
- package/dist/components/Sidepanel/scrollbar_module.css +41 -0
- package/dist/components/Sidepanel/sidepanel.d.ts +9 -0
- package/dist/components/Sidepanel/sidepanel.js +28 -0
- package/dist/components/Sidepanel/types.d.ts +36 -0
- package/dist/components/Sidepanel/types.js +0 -0
- package/dist/components/Sidepanel/vars.css +12 -0
- package/dist/components/Tabs/index_module.css +1 -1
- package/dist/components/Textarea/index_module.css +3 -2
- package/dist/components/Textarea/textarea.d.ts +1 -0
- package/dist/components/Textarea/textarea.js +2 -1
- package/dist/components/Textarea/types.d.ts +5 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/utils/lock-scroll.d.ts +1 -0
- package/dist/utils/lock-scroll.js +49 -0
- package/package.json +1 -1
- package/dist/components/Modal/utils/lock-scroll.d.ts +0 -1
- package/dist/components/Modal/utils/lock-scroll.js +0 -31
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @koslibs/components
|
|
2
2
|
|
|
3
|
+
## 1.13.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#15](https://github.com/koslibs/components/pull/15) [`061457d`](https://github.com/koslibs/components/commit/061457d29c63e8fc4ad1929d7c7ca2b9fffae075) Thanks [@holypower777](https://github.com/holypower777)! - Установлен курсор `not-allowed` для disabled-состояний Button и Tab. У Input, Textarea и Select курсор применяется ко всему компоненту, включая внешние подписи и подсказки. У Select disabled имеет приоритет над readOnly.
|
|
8
|
+
|
|
9
|
+
Добавлен Sidepanel: панель шириной 500 px с выездом и уходом справа, бекдропом Modal, Header с необязательным заголовком и hasCloser, прокручиваемым Content и Footer только для Button. Поддержаны строковая и вертикальная раскладки кнопок, управляемое закрытие, удержание и возврат фокуса, Portal и блокировка прокрутки до завершения анимации. Добавлены Storybook, типы, тесты и отдельный импорт.
|
|
10
|
+
|
|
11
|
+
Общая блокировка прокрутки Modal и Sidepanel вынесена в src/utils/lock-scroll.ts. Она сохраняет положение страницы при временном снятии scrollbar-gutter, чтобы панель доходила до края окна.
|
|
12
|
+
|
|
13
|
+
Пустой Header Sidepanel не занимает места. Скроллбар показывает только слайдер без стрелок и фона. Footer поддерживает sticky с дефолтом true; при false кнопки прокручиваются вместе с содержимым. Переключение режима выполнено через классы CSS Modules без служебного data-атрибута.
|
|
14
|
+
|
|
15
|
+
Footer Sidepanel принимает компоненты ComponentType<ButtonProps>: обязательный primary справа и необязательный secondary слева. Внешний вид кнопок задаётся снаружи. gap принимает 12/16/24/32 с дефолтом 12; layout — start/end/center/space-between/column с дефолтом space-between.
|
|
16
|
+
|
|
17
|
+
## 1.12.0
|
|
18
|
+
|
|
19
|
+
### Minor Changes
|
|
20
|
+
|
|
21
|
+
- [#14](https://github.com/koslibs/components/pull/14) [`242a16c`](https://github.com/koslibs/components/commit/242a16ca5c8ba04bdfab319bf75752a9c4b62826) Thanks [@holypower777](https://github.com/holypower777)! - Добавлен проп `hasOutline` для Input, Textarea, Select и Collapse. Outline при фокусе и раскрытии Select теперь включается явно через `hasOutline={true}`; по умолчанию он выключен. Для отключения используется `hasOutline={false}`. Select передаёт настройку поисковому Input. В Storybook добавлены переключатели и примеры.
|
|
22
|
+
|
|
3
23
|
## 1.11.1
|
|
4
24
|
|
|
5
25
|
### Patch Changes
|
|
@@ -27,6 +27,11 @@ export type CollapseProps = Omit<HTMLAttributes<HTMLDivElement>, 'onTransitionEn
|
|
|
27
27
|
* @default false
|
|
28
28
|
*/
|
|
29
29
|
showLeftChevron?: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Показывает outline кнопки при клавиатурном фокусе.
|
|
32
|
+
* @default false
|
|
33
|
+
*/
|
|
34
|
+
hasOutline?: boolean;
|
|
30
35
|
/**
|
|
31
36
|
* Запрос изменения состояния. В controlled-режиме обновите expanded.
|
|
32
37
|
*/
|
|
@@ -72,6 +77,11 @@ export declare const Collapse: import("react").ForwardRefExoticComponent<Omit<HT
|
|
|
72
77
|
* @default false
|
|
73
78
|
*/
|
|
74
79
|
showLeftChevron?: boolean;
|
|
80
|
+
/**
|
|
81
|
+
* Показывает outline кнопки при клавиатурном фокусе.
|
|
82
|
+
* @default false
|
|
83
|
+
*/
|
|
84
|
+
hasOutline?: boolean;
|
|
75
85
|
/**
|
|
76
86
|
* Запрос изменения состояния. В controlled-режиме обновите expanded.
|
|
77
87
|
*/
|
|
@@ -4,7 +4,7 @@ import classnames from "classnames";
|
|
|
4
4
|
import { forwardRef, useId, useLayoutEffect, useRef, useState } from "react";
|
|
5
5
|
import { TypographyText } from "../Typography/text.js";
|
|
6
6
|
import index_module from "./index.module.js";
|
|
7
|
-
const Collapse = /*#__PURE__*/ forwardRef(({ expanded, defaultExpanded = false, collapsedLabel, expandedLabel, showRightChevron = true, showLeftChevron = false, onExpandedChange, onTransitionEnd, expandedContentClassName, dataTestId, className, children, ...restProps }, ref)=>{
|
|
7
|
+
const Collapse = /*#__PURE__*/ forwardRef(({ expanded, defaultExpanded = false, collapsedLabel, expandedLabel, showRightChevron = true, showLeftChevron = false, hasOutline = false, onExpandedChange, onTransitionEnd, expandedContentClassName, dataTestId, className, children, ...restProps }, ref)=>{
|
|
8
8
|
const [expandedState, setExpandedState] = useState(defaultExpanded);
|
|
9
9
|
const isExpanded = expanded ?? expandedState;
|
|
10
10
|
const contentId = `collapse-${useId()}`;
|
|
@@ -51,6 +51,7 @@ const Collapse = /*#__PURE__*/ forwardRef(({ expanded, defaultExpanded = false,
|
|
|
51
51
|
...restProps,
|
|
52
52
|
ref: ref,
|
|
53
53
|
className: classnames(index_module.component, className),
|
|
54
|
+
"data-has-outline": hasOutline || void 0,
|
|
54
55
|
"data-test-id": dataTestId,
|
|
55
56
|
children: [
|
|
56
57
|
label && /*#__PURE__*/ jsxs("button", {
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
cursor: pointer;
|
|
38
38
|
background: none;
|
|
39
39
|
border: 0;
|
|
40
|
+
outline: none;
|
|
40
41
|
display: inline-flex;
|
|
41
42
|
|
|
42
43
|
&:hover {
|
|
@@ -47,12 +48,12 @@
|
|
|
47
48
|
text-underline-offset: 3px;
|
|
48
49
|
text-decoration: underline;
|
|
49
50
|
}
|
|
51
|
+
}
|
|
50
52
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
53
|
+
.component-tPiInR[data-has-outline] .toggle-YA8uJB:focus-visible {
|
|
54
|
+
outline: 2px solid var(--collapse-focus-color);
|
|
55
|
+
outline-offset: 2px;
|
|
56
|
+
border-radius: var(--border-radius-4, 4px);
|
|
56
57
|
}
|
|
57
58
|
|
|
58
59
|
.icon-wFeaQN {
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
--field-label-color: var(--input-disabled-color);
|
|
43
43
|
--field-placeholder-color: var(--input-disabled-color);
|
|
44
44
|
--field-icon-color: var(--input-disabled-color);
|
|
45
|
+
cursor: not-allowed;
|
|
45
46
|
}
|
|
46
47
|
}
|
|
47
48
|
|
|
@@ -100,13 +101,13 @@
|
|
|
100
101
|
}
|
|
101
102
|
}
|
|
102
103
|
|
|
103
|
-
.component-aUdiT5:not([data-disabled]) .field-MFnvYv:focus-within {
|
|
104
|
+
.component-aUdiT5[data-has-outline]:not([data-disabled]) .field-MFnvYv:focus-within {
|
|
104
105
|
box-shadow: none;
|
|
105
106
|
outline: 2px solid var(--input-focus-border-color);
|
|
106
107
|
outline-offset: 0;
|
|
107
108
|
}
|
|
108
109
|
|
|
109
|
-
.component-aUdiT5[data-error]:not([data-disabled]) .field-MFnvYv:focus-within {
|
|
110
|
+
.component-aUdiT5[data-has-outline][data-error]:not([data-disabled]) .field-MFnvYv:focus-within {
|
|
110
111
|
outline-color: var(--input-error-border-color);
|
|
111
112
|
}
|
|
112
113
|
|
|
@@ -274,11 +275,6 @@
|
|
|
274
275
|
color: var(--field-icon-color);
|
|
275
276
|
}
|
|
276
277
|
|
|
277
|
-
&:focus-visible {
|
|
278
|
-
outline: 2px solid var(--input-focus-border-color);
|
|
279
|
-
outline-offset: 2px;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
278
|
& svg {
|
|
283
279
|
width: var(--input-icon-size);
|
|
284
280
|
height: var(--input-icon-size);
|
|
@@ -286,6 +282,11 @@
|
|
|
286
282
|
}
|
|
287
283
|
}
|
|
288
284
|
|
|
285
|
+
.component-aUdiT5[data-has-outline] .clear-A5Krz8:focus-visible {
|
|
286
|
+
outline: 2px solid var(--input-focus-border-color);
|
|
287
|
+
outline-offset: 2px;
|
|
288
|
+
}
|
|
289
|
+
|
|
289
290
|
.component-aUdiT5 .message-ArUnJU {
|
|
290
291
|
color: var(--input-hint-color);
|
|
291
292
|
overflow-wrap: anywhere;
|
|
@@ -7,6 +7,7 @@ export declare const Input: import("react").ForwardRefExoticComponent<Omit<impor
|
|
|
7
7
|
view?: "primary" | "secondary";
|
|
8
8
|
size?: 40 | 48 | 56 | 64 | 72;
|
|
9
9
|
block?: boolean;
|
|
10
|
+
hasOutline?: boolean;
|
|
10
11
|
label?: import("react").ReactNode;
|
|
11
12
|
labelView?: "outer" | "inner";
|
|
12
13
|
hint?: import("react").ReactNode;
|
|
@@ -6,7 +6,7 @@ import { useDataTestId } from "../../hooks/use-data-test-id.js";
|
|
|
6
6
|
import { Button } from "../Button/index.js";
|
|
7
7
|
import { TypographyText } from "../Typography/text.js";
|
|
8
8
|
import index_module from "./index.module.js";
|
|
9
|
-
const Input = /*#__PURE__*/ forwardRef(({ view = 'primary', size = 40, block = false, label, labelView = 'outer', hint, error, leftAddon, rightAddon, clear = false, clearLabel = 'Очистить поле', value, defaultValue, maxLength, showValueLength = false, onChange, onClear, disabled = false, readOnly = false, type = 'text', id, className, style, fieldClassName, inputClassName, labelClassName, messageClassName, dataTestId, ...restProps }, ref)=>{
|
|
9
|
+
const Input = /*#__PURE__*/ forwardRef(({ view = 'primary', size = 40, block = false, hasOutline = false, label, labelView = 'outer', hint, error, leftAddon, rightAddon, clear = false, clearLabel = 'Очистить поле', value, defaultValue, maxLength, showValueLength = false, onChange, onClear, disabled = false, readOnly = false, type = 'text', id, className, style, fieldClassName, inputClassName, labelClassName, messageClassName, dataTestId, ...restProps }, ref)=>{
|
|
10
10
|
const generatedId = useId();
|
|
11
11
|
const inputId = id ?? generatedId;
|
|
12
12
|
const inputRef = useRef(null);
|
|
@@ -92,6 +92,7 @@ const Input = /*#__PURE__*/ forwardRef(({ view = 'primary', size = 40, block = f
|
|
|
92
92
|
style: style,
|
|
93
93
|
"data-view": view,
|
|
94
94
|
"data-block": block || void 0,
|
|
95
|
+
"data-has-outline": hasOutline || void 0,
|
|
95
96
|
"data-disabled": disabled || void 0,
|
|
96
97
|
"data-read-only": readOnly || void 0,
|
|
97
98
|
"data-error": hasError || void 0,
|
|
@@ -35,6 +35,11 @@ export type InputProps = Omit<InputHTMLAttributes<HTMLInputElement>, 'size' | 'v
|
|
|
35
35
|
* @default false
|
|
36
36
|
*/
|
|
37
37
|
block?: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Показывает outline при фокусе.
|
|
40
|
+
* @default false
|
|
41
|
+
*/
|
|
42
|
+
hasOutline?: boolean;
|
|
38
43
|
/**
|
|
39
44
|
* Название поля. Связывается с input через htmlFor и id.
|
|
40
45
|
*/
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
2
|
import classnames from "classnames";
|
|
3
3
|
import { forwardRef, useCallback, useLayoutEffect, useMemo, useRef } from "react";
|
|
4
|
+
import { lockScroll } from "../../../../utils/lock-scroll.js";
|
|
4
5
|
import { ModalContext } from "../../context.js";
|
|
5
|
-
import { lockScroll } from "../../utils/lock-scroll.js";
|
|
6
6
|
import colors_module from "../../colors.module.js";
|
|
7
7
|
import index_module from "../../index.module.js";
|
|
8
8
|
const ModalSurface = /*#__PURE__*/ forwardRef(({ onClose, size = 720, escapeKeyDown = true, backdropClick = true, lockScroll: shouldLockScroll = true, className, dataTestId, children, onPointerDown, onClick, ...restProps }, ref)=>{
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { SelectState } from '../hooks/use-select-state.js';
|
|
2
2
|
import type { SelectProps } from '../types.js';
|
|
3
|
-
type Props = Pick<SelectProps, 'multiple' | 'searchable' | 'searchPlaceholder' | 'noResultsText' | 'dataTestId'> & {
|
|
3
|
+
type Props = Pick<SelectProps, 'multiple' | 'searchable' | 'searchPlaceholder' | 'noResultsText' | 'dataTestId' | 'hasOutline'> & {
|
|
4
4
|
state: SelectState;
|
|
5
5
|
};
|
|
6
|
-
export declare function SelectDropdown({ state, multiple, searchable, searchPlaceholder, noResultsText, dataTestId, }: Props): import("react").JSX.Element;
|
|
6
|
+
export declare function SelectDropdown({ state, multiple, searchable, hasOutline, searchPlaceholder, noResultsText, dataTestId, }: Props): import("react").JSX.Element;
|
|
7
7
|
export {};
|
|
@@ -7,7 +7,7 @@ import { useDataTestId } from "../../../hooks/use-data-test-id.js";
|
|
|
7
7
|
import { Input } from "../../Input/index.js";
|
|
8
8
|
import { TypographyText } from "../../Typography/text.js";
|
|
9
9
|
import index_module from "../index.module.js";
|
|
10
|
-
function SelectDropdown({ state, multiple, searchable, searchPlaceholder = 'Поиск по списку', noResultsText = 'Ничего не найдено', dataTestId }) {
|
|
10
|
+
function SelectDropdown({ state, multiple, searchable, hasOutline, searchPlaceholder = 'Поиск по списку', noResultsText = 'Ничего не найдено', dataTestId }) {
|
|
11
11
|
const getDataTestId = useDataTestId(dataTestId);
|
|
12
12
|
const { options, selectedIds, search, activeId, setSearch, handleKeyDown, select } = state;
|
|
13
13
|
const activeOptionRef = useRef(null);
|
|
@@ -23,6 +23,7 @@ function SelectDropdown({ state, multiple, searchable, searchPlaceholder = 'По
|
|
|
23
23
|
searchable && /*#__PURE__*/ jsx(Input, {
|
|
24
24
|
block: true,
|
|
25
25
|
autoFocus: true,
|
|
26
|
+
hasOutline: hasOutline,
|
|
26
27
|
size: 40,
|
|
27
28
|
view: "secondary",
|
|
28
29
|
value: search,
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
--field-icon-color: var(--select-disabled-color);
|
|
42
42
|
--field-placeholder-color: var(--select-disabled-color);
|
|
43
43
|
--field-border: transparent;
|
|
44
|
+
cursor: not-allowed;
|
|
44
45
|
}
|
|
45
46
|
}
|
|
46
47
|
|
|
@@ -89,13 +90,13 @@
|
|
|
89
90
|
}
|
|
90
91
|
}
|
|
91
92
|
|
|
92
|
-
.component-cM8DTg:not(.disabled-fZIeN_) .field-jGXYY5:focus-within, .component-cM8DTg.open-CCkiBd .field-jGXYY5 {
|
|
93
|
+
.component-cM8DTg[data-has-outline]:not(.disabled-fZIeN_) .field-jGXYY5:focus-within, .component-cM8DTg[data-has-outline].open-CCkiBd .field-jGXYY5 {
|
|
93
94
|
box-shadow: none;
|
|
94
95
|
outline: 2px solid var(--select-focus-border-color);
|
|
95
96
|
outline-offset: 0;
|
|
96
97
|
}
|
|
97
98
|
|
|
98
|
-
.component-cM8DTg.error-TrKhzv:not(.disabled-fZIeN_) .field-jGXYY5:focus-within, .component-cM8DTg.error-TrKhzv.open-CCkiBd .field-jGXYY5 {
|
|
99
|
+
.component-cM8DTg[data-has-outline].error-TrKhzv:not(.disabled-fZIeN_) .field-jGXYY5:focus-within, .component-cM8DTg[data-has-outline].error-TrKhzv.open-CCkiBd .field-jGXYY5 {
|
|
99
100
|
outline-color: var(--select-error-border-color);
|
|
100
101
|
}
|
|
101
102
|
|
|
@@ -204,11 +205,11 @@
|
|
|
204
205
|
}
|
|
205
206
|
}
|
|
206
207
|
|
|
207
|
-
.component-cM8DTg.disabled-fZIeN_ .trigger-nKdmww {
|
|
208
|
+
.component-cM8DTg.disabled-fZIeN_ .trigger-nKdmww, .component-cM8DTg.disabled-fZIeN_ .label-rrakc7 {
|
|
208
209
|
cursor: not-allowed;
|
|
209
210
|
}
|
|
210
211
|
|
|
211
|
-
.component-cM8DTg.readOnly-zwkIeK .trigger-nKdmww {
|
|
212
|
+
.component-cM8DTg.readOnly-zwkIeK:not(.disabled-fZIeN_) .trigger-nKdmww {
|
|
212
213
|
cursor: default;
|
|
213
214
|
}
|
|
214
215
|
|
|
@@ -22,7 +22,7 @@ const dropdownOffset = [
|
|
|
22
22
|
8
|
|
23
23
|
];
|
|
24
24
|
const Select = /*#__PURE__*/ forwardRef((props, ref)=>{
|
|
25
|
-
const { view = 'primary', size = 40, label, labelView = 'outer', block = false, placeholder = 'Выберите значение', hint, error, clear = false, disabled = false, readOnly = false, className, style, labelClassName, messageClassName, dropdownClassName, dataTestId, id, name, form, onClear: _onClear, getPortalContainer, options: _options, multiple, value: _value, defaultValue: _defaultValue, onChange: _onChange, searchable, searchPlaceholder, open: _open, defaultOpen: _defaultOpen, onOpenChange: _onOpenChange, noResultsText, ...buttonProps } = props;
|
|
25
|
+
const { view = 'primary', size = 40, label, labelView = 'outer', block = false, hasOutline = false, placeholder = 'Выберите значение', hint, error, clear = false, disabled = false, readOnly = false, className, style, labelClassName, messageClassName, dropdownClassName, dataTestId, id, name, form, onClear: _onClear, getPortalContainer, options: _options, multiple, value: _value, defaultValue: _defaultValue, onChange: _onChange, searchable, searchPlaceholder, open: _open, defaultOpen: _defaultOpen, onOpenChange: _onOpenChange, noResultsText, ...buttonProps } = props;
|
|
26
26
|
const generatedId = useId();
|
|
27
27
|
const triggerId = id ?? generatedId;
|
|
28
28
|
const getDataTestId = useDataTestId(dataTestId);
|
|
@@ -48,6 +48,7 @@ const Select = /*#__PURE__*/ forwardRef((props, ref)=>{
|
|
|
48
48
|
[index_module.labelRaised]: innerLabel && raisedLabel
|
|
49
49
|
}, className),
|
|
50
50
|
style: style,
|
|
51
|
+
"data-has-outline": hasOutline || void 0,
|
|
51
52
|
"data-test-id": getDataTestId('form-control'),
|
|
52
53
|
children: [
|
|
53
54
|
hasLabel && 'outer' === labelView && /*#__PURE__*/ jsx("label", {
|
|
@@ -149,6 +150,7 @@ const Select = /*#__PURE__*/ forwardRef((props, ref)=>{
|
|
|
149
150
|
state: state,
|
|
150
151
|
multiple: multiple,
|
|
151
152
|
searchable: searchable,
|
|
153
|
+
hasOutline: hasOutline,
|
|
152
154
|
searchPlaceholder: searchPlaceholder,
|
|
153
155
|
noResultsText: noResultsText,
|
|
154
156
|
dataTestId: dataTestId
|
|
@@ -27,7 +27,7 @@ export type SelectChangePayload<Value = string | null> = {
|
|
|
27
27
|
*/
|
|
28
28
|
selectedOptions: SelectOption[];
|
|
29
29
|
};
|
|
30
|
-
type CommonProps = Pick<InputProps, 'view' | 'size' | 'block' | 'hint' | 'error' | 'clear' | 'className' | 'style' | 'labelClassName' | 'messageClassName'> & Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'value' | 'defaultValue' | 'onChange' | 'children' | 'name' | 'type' | 'className' | 'style'> & {
|
|
30
|
+
type CommonProps = Pick<InputProps, 'view' | 'size' | 'block' | 'hasOutline' | 'hint' | 'error' | 'clear' | 'className' | 'style' | 'labelClassName' | 'messageClassName'> & Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'value' | 'defaultValue' | 'onChange' | 'children' | 'name' | 'type' | 'className' | 'style'> & {
|
|
31
31
|
/**
|
|
32
32
|
* Варианты с уникальными id. Порядок строк сохраняется при выборе.
|
|
33
33
|
*/
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type HTMLAttributes } from 'react';
|
|
2
|
+
export type ContentProps = HTMLAttributes<HTMLDivElement> & {
|
|
3
|
+
/**
|
|
4
|
+
* Базовый идентификатор части -content. По умолчанию наследуется от Sidepanel.
|
|
5
|
+
*/
|
|
6
|
+
dataTestId?: string;
|
|
7
|
+
};
|
|
8
|
+
export declare const Content: import("react").ForwardRefExoticComponent<HTMLAttributes<HTMLDivElement> & {
|
|
9
|
+
/**
|
|
10
|
+
* Базовый идентификатор части -content. По умолчанию наследуется от Sidepanel.
|
|
11
|
+
*/
|
|
12
|
+
dataTestId?: string;
|
|
13
|
+
} & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import classnames from "classnames";
|
|
3
|
+
import { forwardRef, useContext } from "react";
|
|
4
|
+
import { useDataTestId } from "../../../../hooks/use-data-test-id.js";
|
|
5
|
+
import { SidepanelContext } from "../../context.js";
|
|
6
|
+
import index_module from "../../index.module.js";
|
|
7
|
+
import scrollbar_module from "../../scrollbar.module.js";
|
|
8
|
+
import index_module_0 from "./index.module.js";
|
|
9
|
+
const Content = /*#__PURE__*/ forwardRef(({ className, dataTestId, children, ...restProps }, ref)=>{
|
|
10
|
+
const { dataTestId: panelDataTestId } = useContext(SidepanelContext);
|
|
11
|
+
const getDataTestId = useDataTestId(dataTestId ?? panelDataTestId);
|
|
12
|
+
return /*#__PURE__*/ jsx("div", {
|
|
13
|
+
...restProps,
|
|
14
|
+
ref: ref,
|
|
15
|
+
className: classnames(index_module_0.component, index_module.content, scrollbar_module.scrollbar, className),
|
|
16
|
+
"data-test-id": getDataTestId('content'),
|
|
17
|
+
children: children
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
Content.displayName = 'SidepanelContent';
|
|
21
|
+
export { Content };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
.component-vYcjBo {
|
|
2
|
+
box-sizing: border-box;
|
|
3
|
+
gap: var(--size-16);
|
|
4
|
+
min-width: 0;
|
|
5
|
+
min-height: 0;
|
|
6
|
+
padding: var(--sidepanel-padding);
|
|
7
|
+
overscroll-behavior: contain;
|
|
8
|
+
overflow-wrap: anywhere;
|
|
9
|
+
flex-direction: column;
|
|
10
|
+
flex: auto;
|
|
11
|
+
display: flex;
|
|
12
|
+
overflow: auto;
|
|
13
|
+
}
|
|
14
|
+
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { type ComponentType, type HTMLAttributes } from 'react';
|
|
2
|
+
import type { ButtonProps } from '../../../Button/index.js';
|
|
3
|
+
export type FooterProps = Omit<HTMLAttributes<HTMLDivElement>, 'children' | 'dangerouslySetInnerHTML'> & {
|
|
4
|
+
/**
|
|
5
|
+
* Компонент основной кнопки. Обязателен; располагается после secondary (справа в строке).
|
|
6
|
+
* Внешний вид и обработчики задаются внутри переданного компонента.
|
|
7
|
+
*/
|
|
8
|
+
primary: ComponentType<ButtonProps>;
|
|
9
|
+
/**
|
|
10
|
+
* Компонент вторичной кнопки. Располагается перед primary (слева в строке).
|
|
11
|
+
* Не выводится, если проп не передан.
|
|
12
|
+
*/
|
|
13
|
+
secondary?: ComponentType<ButtonProps>;
|
|
14
|
+
/**
|
|
15
|
+
* Минимальное расстояние между кнопками в пикселях из общей шкалы отступов.
|
|
16
|
+
* @default 12
|
|
17
|
+
*/
|
|
18
|
+
gap?: 12 | 16 | 24 | 32;
|
|
19
|
+
/**
|
|
20
|
+
* Оставляет кнопки видимыми при прокрутке. При false Footer прокручивается с Content.
|
|
21
|
+
* @default true
|
|
22
|
+
*/
|
|
23
|
+
sticky?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Выравнивание кнопок. В space-between кнопки находятся у противоположных краёв,
|
|
26
|
+
* единственная primary — справа. В column secondary находится над primary.
|
|
27
|
+
* @default 'space-between'
|
|
28
|
+
*/
|
|
29
|
+
layout?: 'start' | 'end' | 'center' | 'space-between' | 'column';
|
|
30
|
+
/**
|
|
31
|
+
* Базовый идентификатор части -footer. По умолчанию наследуется от Sidepanel.
|
|
32
|
+
*/
|
|
33
|
+
dataTestId?: string;
|
|
34
|
+
};
|
|
35
|
+
export declare const Footer: import("react").ForwardRefExoticComponent<Omit<HTMLAttributes<HTMLDivElement>, "children" | "dangerouslySetInnerHTML"> & {
|
|
36
|
+
/**
|
|
37
|
+
* Компонент основной кнопки. Обязателен; располагается после secondary (справа в строке).
|
|
38
|
+
* Внешний вид и обработчики задаются внутри переданного компонента.
|
|
39
|
+
*/
|
|
40
|
+
primary: ComponentType<ButtonProps>;
|
|
41
|
+
/**
|
|
42
|
+
* Компонент вторичной кнопки. Располагается перед primary (слева в строке).
|
|
43
|
+
* Не выводится, если проп не передан.
|
|
44
|
+
*/
|
|
45
|
+
secondary?: ComponentType<ButtonProps>;
|
|
46
|
+
/**
|
|
47
|
+
* Минимальное расстояние между кнопками в пикселях из общей шкалы отступов.
|
|
48
|
+
* @default 12
|
|
49
|
+
*/
|
|
50
|
+
gap?: 12 | 16 | 24 | 32;
|
|
51
|
+
/**
|
|
52
|
+
* Оставляет кнопки видимыми при прокрутке. При false Footer прокручивается с Content.
|
|
53
|
+
* @default true
|
|
54
|
+
*/
|
|
55
|
+
sticky?: boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Выравнивание кнопок. В space-between кнопки находятся у противоположных краёв,
|
|
58
|
+
* единственная primary — справа. В column secondary находится над primary.
|
|
59
|
+
* @default 'space-between'
|
|
60
|
+
*/
|
|
61
|
+
layout?: "start" | "end" | "center" | "space-between" | "column";
|
|
62
|
+
/**
|
|
63
|
+
* Базовый идентификатор части -footer. По умолчанию наследуется от Sidepanel.
|
|
64
|
+
*/
|
|
65
|
+
dataTestId?: string;
|
|
66
|
+
} & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import classnames from "classnames";
|
|
3
|
+
import { forwardRef, useContext } from "react";
|
|
4
|
+
import { useDataTestId } from "../../../../hooks/use-data-test-id.js";
|
|
5
|
+
import { SidepanelContext } from "../../context.js";
|
|
6
|
+
import index_module from "../../index.module.js";
|
|
7
|
+
import index_module_0 from "./index.module.js";
|
|
8
|
+
const Footer = /*#__PURE__*/ forwardRef(({ primary: Primary, secondary: Secondary, gap = 12, sticky = true, layout = 'space-between', className, dataTestId, ...restProps }, ref)=>{
|
|
9
|
+
const { dataTestId: panelDataTestId } = useContext(SidepanelContext);
|
|
10
|
+
const getDataTestId = useDataTestId(dataTestId ?? panelDataTestId);
|
|
11
|
+
return /*#__PURE__*/ jsxs("div", {
|
|
12
|
+
...restProps,
|
|
13
|
+
ref: ref,
|
|
14
|
+
className: classnames(index_module_0.component, index_module_0[layout], index_module_0[`gap-${gap}`], {
|
|
15
|
+
[index_module.nonStickyFooter]: !sticky
|
|
16
|
+
}, className),
|
|
17
|
+
"data-test-id": getDataTestId('footer'),
|
|
18
|
+
children: [
|
|
19
|
+
Secondary && /*#__PURE__*/ jsx(Secondary, {}),
|
|
20
|
+
/*#__PURE__*/ jsx(Primary, {})
|
|
21
|
+
]
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
Footer.displayName = 'SidepanelFooter';
|
|
25
|
+
export { Footer };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import "./index_module.css";
|
|
2
|
+
const index_module = {
|
|
3
|
+
component: "component-skRGIM",
|
|
4
|
+
column: "column-eFrOSV",
|
|
5
|
+
start: "start-AsGQua",
|
|
6
|
+
end: "end-GUmizA",
|
|
7
|
+
center: "center-ZCtISA",
|
|
8
|
+
"space-between": "space-between-JgT7jT",
|
|
9
|
+
spaceBetween: "space-between-JgT7jT",
|
|
10
|
+
"gap-12": "gap-12-vpXLHP",
|
|
11
|
+
gap12: "gap-12-vpXLHP",
|
|
12
|
+
"gap-16": "gap-16-YnuaQb",
|
|
13
|
+
gap16: "gap-16-YnuaQb",
|
|
14
|
+
"gap-24": "gap-24-Z4lCD9",
|
|
15
|
+
gap24: "gap-24-Z4lCD9",
|
|
16
|
+
"gap-32": "gap-32-dJPD9x",
|
|
17
|
+
gap32: "gap-32-dJPD9x"
|
|
18
|
+
};
|
|
19
|
+
export default index_module;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
.component-skRGIM {
|
|
2
|
+
box-sizing: border-box;
|
|
3
|
+
padding: var(--sidepanel-padding);
|
|
4
|
+
flex-shrink: 0;
|
|
5
|
+
align-items: center;
|
|
6
|
+
display: flex;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.component-skRGIM:not(.column-eFrOSV) > button[data-block="true"] {
|
|
10
|
+
flex: 1 1 0;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.start-AsGQua {
|
|
14
|
+
justify-content: flex-start;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.end-GUmizA {
|
|
18
|
+
justify-content: flex-end;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.center-ZCtISA {
|
|
22
|
+
justify-content: center;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.space-between-JgT7jT {
|
|
26
|
+
justify-content: space-between;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.space-between-JgT7jT > :only-child {
|
|
30
|
+
margin-left: auto;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.column-eFrOSV {
|
|
34
|
+
flex-direction: column;
|
|
35
|
+
align-items: stretch;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.column-eFrOSV > button {
|
|
39
|
+
width: 100%;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.gap-12-vpXLHP {
|
|
43
|
+
gap: var(--size-12);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.gap-16-YnuaQb {
|
|
47
|
+
gap: var(--size-16);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.gap-24-Z4lCD9 {
|
|
51
|
+
gap: var(--size-24);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.gap-32-dJPD9x {
|
|
55
|
+
gap: var(--size-32);
|
|
56
|
+
}
|
|
57
|
+
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type HTMLAttributes } from 'react';
|
|
2
|
+
export type HeaderProps = Omit<HTMLAttributes<HTMLDivElement>, 'title' | 'children'> & {
|
|
3
|
+
/**
|
|
4
|
+
* Необязательный заголовок панели. Без заголовка и крестика Header не выводится.
|
|
5
|
+
*/
|
|
6
|
+
title?: string;
|
|
7
|
+
/**
|
|
8
|
+
* Показывает крестик, который вызывает onClose ближайшего Sidepanel.
|
|
9
|
+
* @default true
|
|
10
|
+
*/
|
|
11
|
+
hasCloser?: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Базовый идентификатор частей -header и -closer.
|
|
14
|
+
* По умолчанию наследуется от Sidepanel.
|
|
15
|
+
*/
|
|
16
|
+
dataTestId?: string;
|
|
17
|
+
};
|
|
18
|
+
export declare const Header: import("react").ForwardRefExoticComponent<Omit<HTMLAttributes<HTMLDivElement>, "children" | "title"> & {
|
|
19
|
+
/**
|
|
20
|
+
* Необязательный заголовок панели. Без заголовка и крестика Header не выводится.
|
|
21
|
+
*/
|
|
22
|
+
title?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Показывает крестик, который вызывает onClose ближайшего Sidepanel.
|
|
25
|
+
* @default true
|
|
26
|
+
*/
|
|
27
|
+
hasCloser?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Базовый идентификатор частей -header и -closer.
|
|
30
|
+
* По умолчанию наследуется от Sidepanel.
|
|
31
|
+
*/
|
|
32
|
+
dataTestId?: string;
|
|
33
|
+
} & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { CrossHeavyMIcon } from "@koslibs/icons/CrossHeavyMIcon";
|
|
3
|
+
import classnames from "classnames";
|
|
4
|
+
import { forwardRef, useContext } from "react";
|
|
5
|
+
import { useDataTestId } from "../../../../hooks/use-data-test-id.js";
|
|
6
|
+
import { Button } from "../../../Button/index.js";
|
|
7
|
+
import { TypographyText } from "../../../Typography/index.js";
|
|
8
|
+
import { SidepanelContext } from "../../context.js";
|
|
9
|
+
import index_module from "../../index.module.js";
|
|
10
|
+
import index_module_0 from "./index.module.js";
|
|
11
|
+
const Header = /*#__PURE__*/ forwardRef(({ title, hasCloser = true, className, dataTestId, ...restProps }, ref)=>{
|
|
12
|
+
const { onClose, dataTestId: panelDataTestId } = useContext(SidepanelContext);
|
|
13
|
+
const getDataTestId = useDataTestId(dataTestId ?? panelDataTestId);
|
|
14
|
+
if (!title?.trim() && !hasCloser) return null;
|
|
15
|
+
return /*#__PURE__*/ jsxs("div", {
|
|
16
|
+
...restProps,
|
|
17
|
+
ref: ref,
|
|
18
|
+
className: classnames(index_module_0.component, index_module.header, className),
|
|
19
|
+
"data-test-id": getDataTestId('header'),
|
|
20
|
+
children: [
|
|
21
|
+
/*#__PURE__*/ jsx("div", {
|
|
22
|
+
className: index_module_0.title,
|
|
23
|
+
children: title && /*#__PURE__*/ jsx(TypographyText, {
|
|
24
|
+
size: 20,
|
|
25
|
+
weight: "semibold",
|
|
26
|
+
children: title
|
|
27
|
+
})
|
|
28
|
+
}),
|
|
29
|
+
hasCloser && /*#__PURE__*/ jsx(Button, {
|
|
30
|
+
size: 32,
|
|
31
|
+
view: "transparent",
|
|
32
|
+
className: index_module_0.closer,
|
|
33
|
+
labelClassName: index_module_0.closerLabel,
|
|
34
|
+
onClick: onClose,
|
|
35
|
+
dataTestId: getDataTestId('closer'),
|
|
36
|
+
children: /*#__PURE__*/ jsx(CrossHeavyMIcon, {
|
|
37
|
+
width: 24,
|
|
38
|
+
height: 24
|
|
39
|
+
})
|
|
40
|
+
})
|
|
41
|
+
]
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
Header.displayName = 'SidepanelHeader';
|
|
45
|
+
export { Header };
|