@snack-uikit/button-combo 0.0.1-preview-a2f98ef7.0 → 0.1.1
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 +27 -0
- package/README.md +12 -7
- package/dist/cjs/ButtonCombo.d.ts +42 -0
- package/dist/cjs/{components/ButtonCombo.js → ButtonCombo.js} +39 -27
- package/dist/cjs/constants.d.ts +2 -2
- package/dist/cjs/constants.js +4 -5
- package/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/styles.module.css +91 -0
- package/dist/cjs/types.d.ts +1 -12
- package/dist/cjs/utils.d.ts +2 -0
- package/dist/cjs/{components/utils.js → utils.js} +0 -6
- package/dist/esm/ButtonCombo.d.ts +42 -0
- package/dist/esm/ButtonCombo.js +40 -0
- package/dist/esm/constants.d.ts +2 -2
- package/dist/esm/constants.js +4 -5
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/styles.module.css +91 -0
- package/dist/esm/types.d.ts +1 -12
- package/dist/esm/utils.d.ts +2 -0
- package/dist/esm/{components/utils.js → utils.js} +0 -5
- package/package.json +4 -4
- package/src/ButtonCombo.tsx +127 -0
- package/src/constants.ts +6 -6
- package/src/index.ts +1 -1
- package/src/styles.module.scss +28 -64
- package/src/types.ts +5 -19
- package/src/utils.ts +13 -0
- package/dist/cjs/components/ButtonCombo.d.ts +0 -11
- package/dist/cjs/components/index.d.ts +0 -1
- package/dist/cjs/components/index.js +0 -25
- package/dist/cjs/components/styles.module.css +0 -221
- package/dist/cjs/components/utils.d.ts +0 -3
- package/dist/esm/components/ButtonCombo.d.ts +0 -11
- package/dist/esm/components/ButtonCombo.js +0 -44
- package/dist/esm/components/index.d.ts +0 -1
- package/dist/esm/components/index.js +0 -1
- package/dist/esm/components/styles.module.css +0 -221
- package/dist/esm/components/utils.d.ts +0 -3
- package/src/components/ButtonCombo.tsx +0 -105
- package/src/components/index.ts +0 -1
- package/src/components/styles.module.scss +0 -114
- package/src/components/utils.ts +0 -25
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,30 @@
|
|
|
1
|
+
# Change Log
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
|
+
|
|
6
|
+
## 0.1.1 (2025-01-23)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* **PDS-53:** disappeared loading-icon in option button ([a6ca36c](https://github.com/cloud-ru-tech/snack-uikit/commit/a6ca36c7042cd01809b3cff7252c801412b68ea8))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# 0.1.0 (2025-01-23)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Features
|
|
21
|
+
|
|
22
|
+
* **PDS-53:** added ButtonCombo component ([a4ce25c](https://github.com/cloud-ru-tech/snack-uikit/commit/a4ce25c0f79120002445188413355f9b75e13159))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
1
28
|
## CHANGELOG
|
|
2
29
|
|
|
3
30
|
### v0.0.0
|
package/README.md
CHANGED
|
@@ -14,14 +14,19 @@
|
|
|
14
14
|
| name | type | default value | description |
|
|
15
15
|
|------|------|---------------|-------------|
|
|
16
16
|
| items* | `Item[]` | - | Основные элементы списка |
|
|
17
|
-
|
|
|
18
|
-
|
|
|
19
|
-
| loading
|
|
20
|
-
|
|
|
21
|
-
|
|
|
22
|
-
|
|
|
23
|
-
|
|
|
17
|
+
| className | `string` | - | CSS-класс |
|
|
18
|
+
| disabled | `boolean` | - | Флаг неактивности компонента |
|
|
19
|
+
| loading | `boolean` | - | Флаг состояния загрузки |
|
|
20
|
+
| size | enum Size: `"xs"`, `"s"`, `"m"`, `"l"` | s | Размер |
|
|
21
|
+
| tabIndex | `number` | - | HTML-аттрибут tab-index |
|
|
22
|
+
| fullWidth | `boolean` | - | Сделать кнопку во всю ширину |
|
|
23
|
+
| open | `boolean` | - | Управляет состоянием показан/не показан. |
|
|
24
|
+
| onOpenChange | `(isOpen: boolean) => void` | - | Колбек отображения компонента. Срабатывает при изменении состояния open. |
|
|
24
25
|
| dropdownClassName | `string` | - | CSS-класс Dropdown |
|
|
26
|
+
| optionClassName | `string` | - | CSS-класс Option кнопки |
|
|
27
|
+
| dropdownTriggerClassName | `string` | - | CSS-класс Dropdown trigger кнопки |
|
|
28
|
+
| value | `ItemId` | - | Controlled состояние |
|
|
29
|
+
| onChange | `(value: ItemId) => void` | - | Controlled обработчик измения состояния |
|
|
25
30
|
| defaultValue | `string` | - | Начальное состояние |
|
|
26
31
|
| defaultLabel | `string` | - | Начальное состояние лейбла |
|
|
27
32
|
| ref | `LegacyRef<HTMLDivElement>` | - | Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref). @see {@link https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom React Docs} |
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { ButtonFilledProps } from '@snack-uikit/button';
|
|
2
|
+
import { DroplistProps, ItemId } from '@snack-uikit/list';
|
|
3
|
+
import { WithSupportProps } from '@snack-uikit/utils';
|
|
4
|
+
import { Item } from './types';
|
|
5
|
+
export type ButtonComboProps = WithSupportProps<Pick<ButtonFilledProps, 'className' | 'disabled' | 'loading' | 'size' | 'tabIndex' | 'fullWidth'> & Pick<DroplistProps, 'open' | 'onOpenChange'> & {
|
|
6
|
+
/** CSS-класс Dropdown */
|
|
7
|
+
dropdownClassName?: string;
|
|
8
|
+
/** CSS-класс Option кнопки */
|
|
9
|
+
optionClassName?: string;
|
|
10
|
+
/** CSS-класс Dropdown trigger кнопки */
|
|
11
|
+
dropdownTriggerClassName?: string;
|
|
12
|
+
/** Controlled состояние */
|
|
13
|
+
value?: ItemId;
|
|
14
|
+
/** Controlled обработчик измения состояния */
|
|
15
|
+
onChange?(value: ItemId): void;
|
|
16
|
+
/** Начальное состояние */
|
|
17
|
+
defaultValue?: string;
|
|
18
|
+
/** Начальное состояние лейбла */
|
|
19
|
+
defaultLabel?: string;
|
|
20
|
+
/** Основные элементы списка */
|
|
21
|
+
items: Item[];
|
|
22
|
+
}>;
|
|
23
|
+
export declare const ButtonCombo: import("react").ForwardRefExoticComponent<{
|
|
24
|
+
'data-test-id'?: string;
|
|
25
|
+
} & import("react").AriaAttributes & Pick<ButtonFilledProps, "className" | "disabled" | "loading" | "size" | "tabIndex" | "fullWidth"> & Pick<DroplistProps, "open" | "onOpenChange"> & {
|
|
26
|
+
/** CSS-класс Dropdown */
|
|
27
|
+
dropdownClassName?: string;
|
|
28
|
+
/** CSS-класс Option кнопки */
|
|
29
|
+
optionClassName?: string;
|
|
30
|
+
/** CSS-класс Dropdown trigger кнопки */
|
|
31
|
+
dropdownTriggerClassName?: string;
|
|
32
|
+
/** Controlled состояние */
|
|
33
|
+
value?: ItemId;
|
|
34
|
+
/** Controlled обработчик измения состояния */
|
|
35
|
+
onChange?(value: ItemId): void;
|
|
36
|
+
/** Начальное состояние */
|
|
37
|
+
defaultValue?: string;
|
|
38
|
+
/** Начальное состояние лейбла */
|
|
39
|
+
defaultLabel?: string;
|
|
40
|
+
/** Основные элементы списка */
|
|
41
|
+
items: Item[];
|
|
42
|
+
} & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -20,59 +20,70 @@ exports.ButtonCombo = void 0;
|
|
|
20
20
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
21
21
|
const classnames_1 = __importDefault(require("classnames"));
|
|
22
22
|
const react_1 = require("react");
|
|
23
|
-
const
|
|
23
|
+
const button_1 = require("@snack-uikit/button");
|
|
24
24
|
const icons_1 = require("@snack-uikit/icons");
|
|
25
25
|
const list_1 = require("@snack-uikit/list");
|
|
26
26
|
const utils_1 = require("@snack-uikit/utils");
|
|
27
|
-
const constants_1 = require("
|
|
27
|
+
const constants_1 = require("./constants");
|
|
28
28
|
const styles_module_scss_1 = __importDefault(require('./styles.module.css'));
|
|
29
29
|
const utils_2 = require("./utils");
|
|
30
30
|
exports.ButtonCombo = (0, react_1.forwardRef)((_a, ref) => {
|
|
31
31
|
var _b;
|
|
32
32
|
var {
|
|
33
|
-
size =
|
|
34
|
-
type = button_private_1.HTML_TYPE.Button,
|
|
33
|
+
size = 's',
|
|
35
34
|
defaultLabel = '',
|
|
36
35
|
className,
|
|
37
36
|
dropdownClassName,
|
|
37
|
+
optionClassName,
|
|
38
|
+
dropdownTriggerClassName,
|
|
38
39
|
defaultValue,
|
|
39
40
|
items,
|
|
40
41
|
tabIndex,
|
|
41
|
-
fullWidth
|
|
42
|
+
fullWidth,
|
|
43
|
+
disabled,
|
|
44
|
+
loading,
|
|
45
|
+
value: valueProp,
|
|
46
|
+
open: openProp,
|
|
47
|
+
onOpenChange,
|
|
48
|
+
onChange
|
|
42
49
|
} = _a,
|
|
43
|
-
rest = __rest(_a, ["size", "
|
|
44
|
-
const [open, setOpen] = (0,
|
|
45
|
-
|
|
50
|
+
rest = __rest(_a, ["size", "defaultLabel", "className", "dropdownClassName", "optionClassName", "dropdownTriggerClassName", "defaultValue", "items", "tabIndex", "fullWidth", "disabled", "loading", "value", "open", "onOpenChange", "onChange"]);
|
|
51
|
+
const [open, setOpen] = (0, utils_1.useValueControl)({
|
|
52
|
+
value: openProp,
|
|
53
|
+
onChange: onOpenChange
|
|
54
|
+
});
|
|
55
|
+
const [value, setValue] = (0, utils_1.useValueControl)({
|
|
56
|
+
value: valueProp,
|
|
57
|
+
defaultValue,
|
|
58
|
+
onChange
|
|
59
|
+
});
|
|
46
60
|
const droplistItems = (0, react_1.useMemo)(() => items.map(utils_2.extractDroplistItemProps).map(item => Object.assign(Object.assign({}, item), {
|
|
47
61
|
id: item === null || item === void 0 ? void 0 : item.id,
|
|
48
62
|
content: item === null || item === void 0 ? void 0 : item.label
|
|
49
63
|
})), [items]);
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
option
|
|
64
|
+
const activeOption = (0, react_1.useMemo)(() => items.find(item => (item === null || item === void 0 ? void 0 : item.id) === value), [items, value]);
|
|
65
|
+
const handleSelectionChange = (0, react_1.useCallback)(selectionValue => {
|
|
66
|
+
if (selectionValue) {
|
|
67
|
+
const option = items.find(item => (item === null || item === void 0 ? void 0 : item.id) === selectionValue);
|
|
68
|
+
option && setValue(selectionValue);
|
|
54
69
|
}
|
|
55
|
-
}, [items]);
|
|
56
|
-
(0, utils_1.useLayoutEffect)(() => {
|
|
57
|
-
if (defaultValue) {
|
|
58
|
-
handleSelectionChange(defaultValue);
|
|
59
|
-
}
|
|
60
|
-
}, [defaultValue, handleSelectionChange]);
|
|
70
|
+
}, [items, setValue]);
|
|
61
71
|
return (0, jsx_runtime_1.jsxs)("div", Object.assign({}, (0, utils_1.extractSupportProps)(rest), {
|
|
62
72
|
ref: ref,
|
|
63
73
|
className: (0, classnames_1.default)(styles_module_scss_1.default.buttonComboWrapper, className),
|
|
64
74
|
tabIndex: tabIndex,
|
|
65
75
|
"data-full-width": fullWidth || undefined,
|
|
66
|
-
children: [(0, jsx_runtime_1.jsx)(
|
|
76
|
+
children: [(0, jsx_runtime_1.jsx)(button_1.ButtonFilled, {
|
|
67
77
|
"data-type": 'option',
|
|
68
78
|
size: size,
|
|
69
79
|
label: (_b = activeOption === null || activeOption === void 0 ? void 0 : activeOption.label) !== null && _b !== void 0 ? _b : defaultLabel,
|
|
70
|
-
|
|
80
|
+
onClick: activeOption === null || activeOption === void 0 ? void 0 : activeOption.onClick,
|
|
81
|
+
className: optionClassName,
|
|
71
82
|
fullWidth: fullWidth,
|
|
72
|
-
|
|
73
|
-
|
|
83
|
+
disabled: disabled,
|
|
84
|
+
loading: loading,
|
|
74
85
|
"data-test-id": 'button-combo__option'
|
|
75
|
-
})
|
|
86
|
+
}), (0, jsx_runtime_1.jsx)(list_1.Droplist, {
|
|
76
87
|
items: droplistItems,
|
|
77
88
|
open: open,
|
|
78
89
|
onOpenChange: setOpen,
|
|
@@ -86,14 +97,15 @@ exports.ButtonCombo = (0, react_1.forwardRef)((_a, ref) => {
|
|
|
86
97
|
placement: 'bottom-end',
|
|
87
98
|
closeDroplistOnItemClick: true,
|
|
88
99
|
"data-test-id": 'button-combo__dropdown',
|
|
89
|
-
children: (0, jsx_runtime_1.jsx)(
|
|
100
|
+
children: (0, jsx_runtime_1.jsx)(button_1.ButtonFilled, {
|
|
90
101
|
"data-type": 'dropdown',
|
|
102
|
+
className: dropdownTriggerClassName,
|
|
91
103
|
size: size,
|
|
92
|
-
|
|
93
|
-
|
|
104
|
+
disabled: disabled,
|
|
105
|
+
loading: loading,
|
|
94
106
|
icon: open ? (0, jsx_runtime_1.jsx)(icons_1.ChevronUpSVG, {}) : (0, jsx_runtime_1.jsx)(icons_1.ChevronDownSVG, {}),
|
|
95
107
|
"data-test-id": 'button-combo__dropdown-button'
|
|
96
|
-
})
|
|
108
|
+
})
|
|
97
109
|
})]
|
|
98
110
|
}));
|
|
99
111
|
});
|
package/dist/cjs/constants.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ButtonFilledProps } from '@snack-uikit/button';
|
|
2
2
|
import { DroplistProps } from '@snack-uikit/list';
|
|
3
|
-
export declare const DROPLIST_SIZE_MAP: Record<
|
|
3
|
+
export declare const DROPLIST_SIZE_MAP: Record<NonNullable<ButtonFilledProps['size']>, DroplistProps['size']>;
|
package/dist/cjs/constants.js
CHANGED
|
@@ -4,10 +4,9 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.DROPLIST_SIZE_MAP = void 0;
|
|
7
|
-
const button_private_1 = require("@snack-uikit/button-private");
|
|
8
7
|
exports.DROPLIST_SIZE_MAP = {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
xs: 's',
|
|
9
|
+
s: 's',
|
|
10
|
+
m: 'm',
|
|
11
|
+
l: 'l'
|
|
13
12
|
};
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export * from './
|
|
1
|
+
export * from './ButtonCombo';
|
package/dist/cjs/index.js
CHANGED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
.buttonComboWrapper{
|
|
2
|
+
display:inline-flex;
|
|
3
|
+
align-items:center;
|
|
4
|
+
}
|
|
5
|
+
.buttonComboWrapper[data-full-width]{
|
|
6
|
+
flex-grow:1;
|
|
7
|
+
flex-shrink:1;
|
|
8
|
+
width:100%;
|
|
9
|
+
}
|
|
10
|
+
.buttonComboWrapper button:focus-visible + button{
|
|
11
|
+
position:static;
|
|
12
|
+
}
|
|
13
|
+
.buttonComboWrapper button[data-type=option]{
|
|
14
|
+
border-right:var(--border-width-button-combo-divider, 1px) solid var(--sys-neutral-decor-default, #dde0ea);
|
|
15
|
+
}
|
|
16
|
+
.buttonComboWrapper button[data-type=option][data-size=xs]{
|
|
17
|
+
min-width:auto;
|
|
18
|
+
height:var(--size-button-xs, 24px);
|
|
19
|
+
border-top-left-radius:var(--radius-button-xs, 8px);
|
|
20
|
+
border-bottom-left-radius:var(--radius-button-xs, 8px);
|
|
21
|
+
border-top-right-radius:var(--dimension-0m, 0px);
|
|
22
|
+
border-bottom-right-radius:var(--dimension-0m, 0px);
|
|
23
|
+
padding-right:var(--space-button-xs-from-label, 8px);
|
|
24
|
+
padding-left:var(--space-button-xs-from-label, 8px);
|
|
25
|
+
border-right-width:var(--border-width-button-combo-divider, 1px);
|
|
26
|
+
}
|
|
27
|
+
.buttonComboWrapper button[data-type=option][data-size=s]{
|
|
28
|
+
min-width:auto;
|
|
29
|
+
height:var(--size-button-s, 32px);
|
|
30
|
+
border-top-left-radius:var(--radius-button-s, 12px);
|
|
31
|
+
border-bottom-left-radius:var(--radius-button-s, 12px);
|
|
32
|
+
border-top-right-radius:var(--dimension-0m, 0px);
|
|
33
|
+
border-bottom-right-radius:var(--dimension-0m, 0px);
|
|
34
|
+
padding-right:var(--space-button-s-from-label, 16px);
|
|
35
|
+
padding-left:var(--space-button-s-from-label, 16px);
|
|
36
|
+
border-right-width:var(--border-width-button-combo-divider, 1px);
|
|
37
|
+
}
|
|
38
|
+
.buttonComboWrapper button[data-type=option][data-size=m]{
|
|
39
|
+
min-width:auto;
|
|
40
|
+
height:var(--size-button-m, 40px);
|
|
41
|
+
border-top-left-radius:var(--radius-button-m, 14px);
|
|
42
|
+
border-bottom-left-radius:var(--radius-button-m, 14px);
|
|
43
|
+
border-top-right-radius:var(--dimension-0m, 0px);
|
|
44
|
+
border-bottom-right-radius:var(--dimension-0m, 0px);
|
|
45
|
+
padding-right:var(--space-button-m-from-label, 24px);
|
|
46
|
+
padding-left:var(--space-button-m-from-label, 24px);
|
|
47
|
+
border-right-width:var(--border-width-button-combo-divider, 1px);
|
|
48
|
+
}
|
|
49
|
+
.buttonComboWrapper button[data-type=option][data-size=l]{
|
|
50
|
+
min-width:auto;
|
|
51
|
+
height:var(--size-button-l, 48px);
|
|
52
|
+
border-top-left-radius:var(--radius-button-l, 16px);
|
|
53
|
+
border-bottom-left-radius:var(--radius-button-l, 16px);
|
|
54
|
+
border-top-right-radius:var(--dimension-0m, 0px);
|
|
55
|
+
border-bottom-right-radius:var(--dimension-0m, 0px);
|
|
56
|
+
padding-right:var(--space-button-l-from-label, 32px);
|
|
57
|
+
padding-left:var(--space-button-l-from-label, 32px);
|
|
58
|
+
border-right-width:var(--border-width-button-combo-divider, 1px);
|
|
59
|
+
}
|
|
60
|
+
.buttonComboWrapper button[data-type=dropdown][data-size=xs]{
|
|
61
|
+
border-top-left-radius:var(--dimension-0m, 0px);
|
|
62
|
+
border-bottom-left-radius:var(--dimension-0m, 0px);
|
|
63
|
+
border-top-right-radius:var(--radius-button-xs, 8px);
|
|
64
|
+
border-bottom-right-radius:var(--radius-button-xs, 8px);
|
|
65
|
+
width:var(--size-button-xs, 24px);
|
|
66
|
+
height:var(--size-button-xs, 24px);
|
|
67
|
+
}
|
|
68
|
+
.buttonComboWrapper button[data-type=dropdown][data-size=s]{
|
|
69
|
+
border-top-left-radius:var(--dimension-0m, 0px);
|
|
70
|
+
border-bottom-left-radius:var(--dimension-0m, 0px);
|
|
71
|
+
border-top-right-radius:var(--radius-button-s, 12px);
|
|
72
|
+
border-bottom-right-radius:var(--radius-button-s, 12px);
|
|
73
|
+
width:var(--size-button-s, 32px);
|
|
74
|
+
height:var(--size-button-s, 32px);
|
|
75
|
+
}
|
|
76
|
+
.buttonComboWrapper button[data-type=dropdown][data-size=m]{
|
|
77
|
+
border-top-left-radius:var(--dimension-0m, 0px);
|
|
78
|
+
border-bottom-left-radius:var(--dimension-0m, 0px);
|
|
79
|
+
border-top-right-radius:var(--radius-button-m, 14px);
|
|
80
|
+
border-bottom-right-radius:var(--radius-button-m, 14px);
|
|
81
|
+
width:var(--size-button-m, 40px);
|
|
82
|
+
height:var(--size-button-m, 40px);
|
|
83
|
+
}
|
|
84
|
+
.buttonComboWrapper button[data-type=dropdown][data-size=l]{
|
|
85
|
+
border-top-left-radius:var(--dimension-0m, 0px);
|
|
86
|
+
border-bottom-left-radius:var(--dimension-0m, 0px);
|
|
87
|
+
border-top-right-radius:var(--radius-button-l, 16px);
|
|
88
|
+
border-bottom-right-radius:var(--radius-button-l, 16px);
|
|
89
|
+
width:var(--size-button-l, 48px);
|
|
90
|
+
height:var(--size-button-l, 48px);
|
|
91
|
+
}
|
package/dist/cjs/types.d.ts
CHANGED
|
@@ -1,16 +1,5 @@
|
|
|
1
|
-
import { BaseButtonProps } from '@snack-uikit/button-private';
|
|
2
1
|
import { BaseItemProps } from '@snack-uikit/list';
|
|
3
|
-
export type Item = BaseItemProps & {
|
|
2
|
+
export type Item = Omit<BaseItemProps, 'onClick' | 'onMouseDown' | 'onKeyDown' | 'onFocus' | 'onBlur'> & Required<Pick<BaseItemProps, 'onClick'>> & {
|
|
4
3
|
/** Название */
|
|
5
4
|
label?: string;
|
|
6
5
|
};
|
|
7
|
-
export type BaseButtonComboProps = Pick<BaseButtonProps, 'className' | 'disabled' | 'loading' | 'size' | 'type' | 'tabIndex' | 'fullWidth'> & {
|
|
8
|
-
/** CSS-класс Dropdown */
|
|
9
|
-
dropdownClassName?: string;
|
|
10
|
-
/** Начальное состояние */
|
|
11
|
-
defaultValue?: string;
|
|
12
|
-
/** Начальное состояние лейбла */
|
|
13
|
-
defaultLabel?: string;
|
|
14
|
-
/** Основные элементы списка */
|
|
15
|
-
items: Item[];
|
|
16
|
-
};
|
|
@@ -4,14 +4,8 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.extractDroplistItemProps = extractDroplistItemProps;
|
|
7
|
-
exports.extractButtonActionsProps = extractButtonActionsProps;
|
|
8
7
|
function extractDroplistItemProps(props) {
|
|
9
8
|
return Object.keys(props).filter(item => !item.startsWith('on')).reduce((nextProps, prop) => Object.assign(Object.assign({}, nextProps), {
|
|
10
9
|
[prop]: props[prop]
|
|
11
10
|
}), {});
|
|
12
|
-
}
|
|
13
|
-
function extractButtonActionsProps(props) {
|
|
14
|
-
return Object.keys(props).filter(item => item.startsWith('on')).reduce((nextProps, prop) => Object.assign(Object.assign({}, nextProps), {
|
|
15
|
-
[prop]: props[prop]
|
|
16
|
-
}), {});
|
|
17
11
|
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { ButtonFilledProps } from '@snack-uikit/button';
|
|
2
|
+
import { DroplistProps, ItemId } from '@snack-uikit/list';
|
|
3
|
+
import { WithSupportProps } from '@snack-uikit/utils';
|
|
4
|
+
import { Item } from './types';
|
|
5
|
+
export type ButtonComboProps = WithSupportProps<Pick<ButtonFilledProps, 'className' | 'disabled' | 'loading' | 'size' | 'tabIndex' | 'fullWidth'> & Pick<DroplistProps, 'open' | 'onOpenChange'> & {
|
|
6
|
+
/** CSS-класс Dropdown */
|
|
7
|
+
dropdownClassName?: string;
|
|
8
|
+
/** CSS-класс Option кнопки */
|
|
9
|
+
optionClassName?: string;
|
|
10
|
+
/** CSS-класс Dropdown trigger кнопки */
|
|
11
|
+
dropdownTriggerClassName?: string;
|
|
12
|
+
/** Controlled состояние */
|
|
13
|
+
value?: ItemId;
|
|
14
|
+
/** Controlled обработчик измения состояния */
|
|
15
|
+
onChange?(value: ItemId): void;
|
|
16
|
+
/** Начальное состояние */
|
|
17
|
+
defaultValue?: string;
|
|
18
|
+
/** Начальное состояние лейбла */
|
|
19
|
+
defaultLabel?: string;
|
|
20
|
+
/** Основные элементы списка */
|
|
21
|
+
items: Item[];
|
|
22
|
+
}>;
|
|
23
|
+
export declare const ButtonCombo: import("react").ForwardRefExoticComponent<{
|
|
24
|
+
'data-test-id'?: string;
|
|
25
|
+
} & import("react").AriaAttributes & Pick<ButtonFilledProps, "className" | "disabled" | "loading" | "size" | "tabIndex" | "fullWidth"> & Pick<DroplistProps, "open" | "onOpenChange"> & {
|
|
26
|
+
/** CSS-класс Dropdown */
|
|
27
|
+
dropdownClassName?: string;
|
|
28
|
+
/** CSS-класс Option кнопки */
|
|
29
|
+
optionClassName?: string;
|
|
30
|
+
/** CSS-класс Dropdown trigger кнопки */
|
|
31
|
+
dropdownTriggerClassName?: string;
|
|
32
|
+
/** Controlled состояние */
|
|
33
|
+
value?: ItemId;
|
|
34
|
+
/** Controlled обработчик измения состояния */
|
|
35
|
+
onChange?(value: ItemId): void;
|
|
36
|
+
/** Начальное состояние */
|
|
37
|
+
defaultValue?: string;
|
|
38
|
+
/** Начальное состояние лейбла */
|
|
39
|
+
defaultLabel?: string;
|
|
40
|
+
/** Основные элементы списка */
|
|
41
|
+
items: Item[];
|
|
42
|
+
} & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
2
|
+
var t = {};
|
|
3
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
4
|
+
t[p] = s[p];
|
|
5
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
6
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
7
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
8
|
+
t[p[i]] = s[p[i]];
|
|
9
|
+
}
|
|
10
|
+
return t;
|
|
11
|
+
};
|
|
12
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
13
|
+
import cn from 'classnames';
|
|
14
|
+
import { forwardRef, useCallback, useMemo } from 'react';
|
|
15
|
+
import { ButtonFilled } from '@snack-uikit/button';
|
|
16
|
+
import { ChevronDownSVG, ChevronUpSVG } from '@snack-uikit/icons';
|
|
17
|
+
import { Droplist } from '@snack-uikit/list';
|
|
18
|
+
import { extractSupportProps, useValueControl } from '@snack-uikit/utils';
|
|
19
|
+
import { DROPLIST_SIZE_MAP } from './constants';
|
|
20
|
+
import styles from './styles.module.css';
|
|
21
|
+
import { extractDroplistItemProps } from './utils';
|
|
22
|
+
export const ButtonCombo = forwardRef((_a, ref) => {
|
|
23
|
+
var _b;
|
|
24
|
+
var { size = 's', defaultLabel = '', className, dropdownClassName, optionClassName, dropdownTriggerClassName, defaultValue, items, tabIndex, fullWidth, disabled, loading, value: valueProp, open: openProp, onOpenChange, onChange } = _a, rest = __rest(_a, ["size", "defaultLabel", "className", "dropdownClassName", "optionClassName", "dropdownTriggerClassName", "defaultValue", "items", "tabIndex", "fullWidth", "disabled", "loading", "value", "open", "onOpenChange", "onChange"]);
|
|
25
|
+
const [open, setOpen] = useValueControl({ value: openProp, onChange: onOpenChange });
|
|
26
|
+
const [value, setValue] = useValueControl({ value: valueProp, defaultValue, onChange });
|
|
27
|
+
const droplistItems = useMemo(() => items.map(extractDroplistItemProps).map(item => (Object.assign(Object.assign({}, item), { id: item === null || item === void 0 ? void 0 : item.id, content: item === null || item === void 0 ? void 0 : item.label }))), [items]);
|
|
28
|
+
const activeOption = useMemo(() => items.find(item => (item === null || item === void 0 ? void 0 : item.id) === value), [items, value]);
|
|
29
|
+
const handleSelectionChange = useCallback((selectionValue) => {
|
|
30
|
+
if (selectionValue) {
|
|
31
|
+
const option = items.find(item => (item === null || item === void 0 ? void 0 : item.id) === selectionValue);
|
|
32
|
+
option && setValue(selectionValue);
|
|
33
|
+
}
|
|
34
|
+
}, [items, setValue]);
|
|
35
|
+
return (_jsxs("div", Object.assign({}, extractSupportProps(rest), { ref: ref, className: cn(styles.buttonComboWrapper, className), tabIndex: tabIndex, "data-full-width": fullWidth || undefined, children: [_jsx(ButtonFilled, { "data-type": 'option', size: size, label: (_b = activeOption === null || activeOption === void 0 ? void 0 : activeOption.label) !== null && _b !== void 0 ? _b : defaultLabel, onClick: activeOption === null || activeOption === void 0 ? void 0 : activeOption.onClick, className: optionClassName, fullWidth: fullWidth, disabled: disabled, loading: loading, "data-test-id": 'button-combo__option' }), _jsx(Droplist, { items: droplistItems, open: open, onOpenChange: setOpen, selection: {
|
|
36
|
+
defaultValue,
|
|
37
|
+
mode: 'single',
|
|
38
|
+
onChange: handleSelectionChange,
|
|
39
|
+
}, className: dropdownClassName, size: DROPLIST_SIZE_MAP[size], placement: 'bottom-end', closeDroplistOnItemClick: true, "data-test-id": 'button-combo__dropdown', children: _jsx(ButtonFilled, { "data-type": 'dropdown', className: dropdownTriggerClassName, size: size, disabled: disabled, loading: loading, icon: open ? _jsx(ChevronUpSVG, {}) : _jsx(ChevronDownSVG, {}), "data-test-id": 'button-combo__dropdown-button' }) })] })));
|
|
40
|
+
});
|
package/dist/esm/constants.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ButtonFilledProps } from '@snack-uikit/button';
|
|
2
2
|
import { DroplistProps } from '@snack-uikit/list';
|
|
3
|
-
export declare const DROPLIST_SIZE_MAP: Record<
|
|
3
|
+
export declare const DROPLIST_SIZE_MAP: Record<NonNullable<ButtonFilledProps['size']>, DroplistProps['size']>;
|
package/dist/esm/constants.js
CHANGED
package/dist/esm/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export * from './
|
|
1
|
+
export * from './ButtonCombo';
|
package/dist/esm/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export * from './
|
|
1
|
+
export * from './ButtonCombo';
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
.buttonComboWrapper{
|
|
2
|
+
display:inline-flex;
|
|
3
|
+
align-items:center;
|
|
4
|
+
}
|
|
5
|
+
.buttonComboWrapper[data-full-width]{
|
|
6
|
+
flex-grow:1;
|
|
7
|
+
flex-shrink:1;
|
|
8
|
+
width:100%;
|
|
9
|
+
}
|
|
10
|
+
.buttonComboWrapper button:focus-visible + button{
|
|
11
|
+
position:static;
|
|
12
|
+
}
|
|
13
|
+
.buttonComboWrapper button[data-type=option]{
|
|
14
|
+
border-right:var(--border-width-button-combo-divider, 1px) solid var(--sys-neutral-decor-default, #dde0ea);
|
|
15
|
+
}
|
|
16
|
+
.buttonComboWrapper button[data-type=option][data-size=xs]{
|
|
17
|
+
min-width:auto;
|
|
18
|
+
height:var(--size-button-xs, 24px);
|
|
19
|
+
border-top-left-radius:var(--radius-button-xs, 8px);
|
|
20
|
+
border-bottom-left-radius:var(--radius-button-xs, 8px);
|
|
21
|
+
border-top-right-radius:var(--dimension-0m, 0px);
|
|
22
|
+
border-bottom-right-radius:var(--dimension-0m, 0px);
|
|
23
|
+
padding-right:var(--space-button-xs-from-label, 8px);
|
|
24
|
+
padding-left:var(--space-button-xs-from-label, 8px);
|
|
25
|
+
border-right-width:var(--border-width-button-combo-divider, 1px);
|
|
26
|
+
}
|
|
27
|
+
.buttonComboWrapper button[data-type=option][data-size=s]{
|
|
28
|
+
min-width:auto;
|
|
29
|
+
height:var(--size-button-s, 32px);
|
|
30
|
+
border-top-left-radius:var(--radius-button-s, 12px);
|
|
31
|
+
border-bottom-left-radius:var(--radius-button-s, 12px);
|
|
32
|
+
border-top-right-radius:var(--dimension-0m, 0px);
|
|
33
|
+
border-bottom-right-radius:var(--dimension-0m, 0px);
|
|
34
|
+
padding-right:var(--space-button-s-from-label, 16px);
|
|
35
|
+
padding-left:var(--space-button-s-from-label, 16px);
|
|
36
|
+
border-right-width:var(--border-width-button-combo-divider, 1px);
|
|
37
|
+
}
|
|
38
|
+
.buttonComboWrapper button[data-type=option][data-size=m]{
|
|
39
|
+
min-width:auto;
|
|
40
|
+
height:var(--size-button-m, 40px);
|
|
41
|
+
border-top-left-radius:var(--radius-button-m, 14px);
|
|
42
|
+
border-bottom-left-radius:var(--radius-button-m, 14px);
|
|
43
|
+
border-top-right-radius:var(--dimension-0m, 0px);
|
|
44
|
+
border-bottom-right-radius:var(--dimension-0m, 0px);
|
|
45
|
+
padding-right:var(--space-button-m-from-label, 24px);
|
|
46
|
+
padding-left:var(--space-button-m-from-label, 24px);
|
|
47
|
+
border-right-width:var(--border-width-button-combo-divider, 1px);
|
|
48
|
+
}
|
|
49
|
+
.buttonComboWrapper button[data-type=option][data-size=l]{
|
|
50
|
+
min-width:auto;
|
|
51
|
+
height:var(--size-button-l, 48px);
|
|
52
|
+
border-top-left-radius:var(--radius-button-l, 16px);
|
|
53
|
+
border-bottom-left-radius:var(--radius-button-l, 16px);
|
|
54
|
+
border-top-right-radius:var(--dimension-0m, 0px);
|
|
55
|
+
border-bottom-right-radius:var(--dimension-0m, 0px);
|
|
56
|
+
padding-right:var(--space-button-l-from-label, 32px);
|
|
57
|
+
padding-left:var(--space-button-l-from-label, 32px);
|
|
58
|
+
border-right-width:var(--border-width-button-combo-divider, 1px);
|
|
59
|
+
}
|
|
60
|
+
.buttonComboWrapper button[data-type=dropdown][data-size=xs]{
|
|
61
|
+
border-top-left-radius:var(--dimension-0m, 0px);
|
|
62
|
+
border-bottom-left-radius:var(--dimension-0m, 0px);
|
|
63
|
+
border-top-right-radius:var(--radius-button-xs, 8px);
|
|
64
|
+
border-bottom-right-radius:var(--radius-button-xs, 8px);
|
|
65
|
+
width:var(--size-button-xs, 24px);
|
|
66
|
+
height:var(--size-button-xs, 24px);
|
|
67
|
+
}
|
|
68
|
+
.buttonComboWrapper button[data-type=dropdown][data-size=s]{
|
|
69
|
+
border-top-left-radius:var(--dimension-0m, 0px);
|
|
70
|
+
border-bottom-left-radius:var(--dimension-0m, 0px);
|
|
71
|
+
border-top-right-radius:var(--radius-button-s, 12px);
|
|
72
|
+
border-bottom-right-radius:var(--radius-button-s, 12px);
|
|
73
|
+
width:var(--size-button-s, 32px);
|
|
74
|
+
height:var(--size-button-s, 32px);
|
|
75
|
+
}
|
|
76
|
+
.buttonComboWrapper button[data-type=dropdown][data-size=m]{
|
|
77
|
+
border-top-left-radius:var(--dimension-0m, 0px);
|
|
78
|
+
border-bottom-left-radius:var(--dimension-0m, 0px);
|
|
79
|
+
border-top-right-radius:var(--radius-button-m, 14px);
|
|
80
|
+
border-bottom-right-radius:var(--radius-button-m, 14px);
|
|
81
|
+
width:var(--size-button-m, 40px);
|
|
82
|
+
height:var(--size-button-m, 40px);
|
|
83
|
+
}
|
|
84
|
+
.buttonComboWrapper button[data-type=dropdown][data-size=l]{
|
|
85
|
+
border-top-left-radius:var(--dimension-0m, 0px);
|
|
86
|
+
border-bottom-left-radius:var(--dimension-0m, 0px);
|
|
87
|
+
border-top-right-radius:var(--radius-button-l, 16px);
|
|
88
|
+
border-bottom-right-radius:var(--radius-button-l, 16px);
|
|
89
|
+
width:var(--size-button-l, 48px);
|
|
90
|
+
height:var(--size-button-l, 48px);
|
|
91
|
+
}
|
package/dist/esm/types.d.ts
CHANGED
|
@@ -1,16 +1,5 @@
|
|
|
1
|
-
import { BaseButtonProps } from '@snack-uikit/button-private';
|
|
2
1
|
import { BaseItemProps } from '@snack-uikit/list';
|
|
3
|
-
export type Item = BaseItemProps & {
|
|
2
|
+
export type Item = Omit<BaseItemProps, 'onClick' | 'onMouseDown' | 'onKeyDown' | 'onFocus' | 'onBlur'> & Required<Pick<BaseItemProps, 'onClick'>> & {
|
|
4
3
|
/** Название */
|
|
5
4
|
label?: string;
|
|
6
5
|
};
|
|
7
|
-
export type BaseButtonComboProps = Pick<BaseButtonProps, 'className' | 'disabled' | 'loading' | 'size' | 'type' | 'tabIndex' | 'fullWidth'> & {
|
|
8
|
-
/** CSS-класс Dropdown */
|
|
9
|
-
dropdownClassName?: string;
|
|
10
|
-
/** Начальное состояние */
|
|
11
|
-
defaultValue?: string;
|
|
12
|
-
/** Начальное состояние лейбла */
|
|
13
|
-
defaultLabel?: string;
|
|
14
|
-
/** Основные элементы списка */
|
|
15
|
-
items: Item[];
|
|
16
|
-
};
|
|
@@ -3,8 +3,3 @@ export function extractDroplistItemProps(props) {
|
|
|
3
3
|
.filter(item => !item.startsWith('on'))
|
|
4
4
|
.reduce((nextProps, prop) => (Object.assign(Object.assign({}, nextProps), { [prop]: props[prop] })), {});
|
|
5
5
|
}
|
|
6
|
-
export function extractButtonActionsProps(props) {
|
|
7
|
-
return Object.keys(props)
|
|
8
|
-
.filter(item => item.startsWith('on'))
|
|
9
|
-
.reduce((nextProps, prop) => (Object.assign(Object.assign({}, nextProps), { [prop]: props[prop] })), {});
|
|
10
|
-
}
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
6
|
"title": "Button Combo",
|
|
7
|
-
"version": "0.
|
|
7
|
+
"version": "0.1.1",
|
|
8
8
|
"sideEffects": [
|
|
9
9
|
"*.css",
|
|
10
10
|
"*.woff",
|
|
@@ -36,11 +36,11 @@
|
|
|
36
36
|
"license": "Apache-2.0",
|
|
37
37
|
"scripts": {},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@snack-uikit/button
|
|
39
|
+
"@snack-uikit/button": "0.19.5",
|
|
40
40
|
"@snack-uikit/icons": "0.24.1",
|
|
41
|
-
"@snack-uikit/list": "0.
|
|
41
|
+
"@snack-uikit/list": "0.23.0",
|
|
42
42
|
"@snack-uikit/utils": "3.6.0",
|
|
43
43
|
"classnames": "2.5.1"
|
|
44
44
|
},
|
|
45
|
-
"gitHead": "
|
|
45
|
+
"gitHead": "7e01ebe58fd9bf9a4c06064e6415ed6c16cc06e5"
|
|
46
46
|
}
|