@via-profit/ui-kit 0.7.0 → 0.9.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.
Files changed (77) hide show
  1. package/Autocomplete/AutocompleteContainer.d.ts +13 -0
  2. package/Autocomplete/AutocompleteContainer.js +46 -7
  3. package/Badge/BadgeBase.d.ts +10 -1
  4. package/Badge/BadgeBase.js +9 -2
  5. package/Badge/BadgeDot.d.ts +4 -0
  6. package/Badge/BadgeDot.js +20 -0
  7. package/Badge/BadgeStyled.js +67 -26
  8. package/Badge/index.d.ts +4 -4
  9. package/CHANGELOG.md +20 -0
  10. package/EmptyState/EmptyStateAction.d.ts +4 -0
  11. package/EmptyState/EmptyStateAction.js +16 -0
  12. package/EmptyState/EmptyStateContainer.d.ts +8 -0
  13. package/EmptyState/EmptyStateContainer.js +34 -0
  14. package/EmptyState/EmptyStateContent.d.ts +4 -0
  15. package/EmptyState/EmptyStateContent.js +15 -0
  16. package/EmptyState/EmptyStateIcon.d.ts +4 -0
  17. package/EmptyState/EmptyStateIcon.js +38 -0
  18. package/EmptyState/EmptyStateTitle.d.ts +4 -0
  19. package/EmptyState/EmptyStateTitle.js +13 -0
  20. package/EmptyState/index.d.ts +82 -0
  21. package/EmptyState/index.js +61 -0
  22. package/FileDropzone/FileDropzoneArea.d.ts +24 -0
  23. package/FileDropzone/FileDropzoneArea.js +81 -0
  24. package/FileDropzone/index.d.ts +107 -0
  25. package/FileDropzone/index.js +169 -0
  26. package/FileDropzone/utils.d.ts +9 -0
  27. package/FileDropzone/utils.js +42 -0
  28. package/HintPopover/HintPopoverButton.d.ts +4 -0
  29. package/HintPopover/HintPopoverButton.js +67 -0
  30. package/HintPopover/HintPopoverContainer.d.ts +4 -0
  31. package/HintPopover/HintPopoverContainer.js +52 -0
  32. package/HintPopover/index.d.ts +67 -0
  33. package/HintPopover/index.js +71 -0
  34. package/InfoNote/InfoNoteContainer.d.ts +14 -0
  35. package/InfoNote/InfoNoteContainer.js +56 -0
  36. package/InfoNote/InfoNoteContent.d.ts +4 -0
  37. package/InfoNote/InfoNoteContent.js +16 -0
  38. package/InfoNote/InfoNoteIcon.d.ts +9 -0
  39. package/InfoNote/InfoNoteIcon.js +47 -0
  40. package/InfoNote/InfoNoteTitle.d.ts +4 -0
  41. package/InfoNote/InfoNoteTitle.js +13 -0
  42. package/InfoNote/index.d.ts +65 -0
  43. package/InfoNote/index.js +59 -0
  44. package/Modal/Drawer/DrawerInner.d.ts +6 -0
  45. package/Modal/Drawer/DrawerInner.js +91 -2
  46. package/Modal/Drawer/index.d.ts +8 -0
  47. package/Modal/Drawer/index.js +3 -3
  48. package/Modal/Drawer/useSwipeToClose.d.ts +30 -0
  49. package/Modal/Drawer/useSwipeToClose.js +238 -0
  50. package/Skeleton/index.d.ts +39 -0
  51. package/Skeleton/index.js +69 -0
  52. package/esm/Autocomplete/AutocompleteContainer.js +46 -7
  53. package/esm/Badge/BadgeBase.js +9 -2
  54. package/esm/Badge/BadgeDot.js +15 -0
  55. package/esm/Badge/BadgeStyled.js +67 -26
  56. package/esm/EmptyState/EmptyStateAction.js +11 -0
  57. package/esm/EmptyState/EmptyStateContainer.js +29 -0
  58. package/esm/EmptyState/EmptyStateContent.js +10 -0
  59. package/esm/EmptyState/EmptyStateIcon.js +33 -0
  60. package/esm/EmptyState/EmptyStateTitle.js +8 -0
  61. package/esm/EmptyState/index.js +42 -0
  62. package/esm/FileDropzone/FileDropzoneArea.js +76 -0
  63. package/esm/FileDropzone/index.js +148 -0
  64. package/esm/FileDropzone/utils.js +37 -0
  65. package/esm/HintPopover/HintPopoverButton.js +62 -0
  66. package/esm/HintPopover/HintPopoverContainer.js +47 -0
  67. package/esm/HintPopover/index.js +52 -0
  68. package/esm/InfoNote/InfoNoteContainer.js +49 -0
  69. package/esm/InfoNote/InfoNoteContent.js +11 -0
  70. package/esm/InfoNote/InfoNoteIcon.js +42 -0
  71. package/esm/InfoNote/InfoNoteTitle.js +8 -0
  72. package/esm/InfoNote/index.js +40 -0
  73. package/esm/Modal/Drawer/DrawerInner.js +91 -2
  74. package/esm/Modal/Drawer/index.js +3 -3
  75. package/esm/Modal/Drawer/useSwipeToClose.js +233 -0
  76. package/esm/Skeleton/index.js +64 -0
  77. package/package.json +126 -1
@@ -122,6 +122,19 @@ export interface AutocompleteProps<T, Multiple extends boolean | undefined = und
122
122
  * The function that will be called at the moment when you change the input value of input element
123
123
  */
124
124
  readonly onInputChange?: React.ChangeEventHandler<HTMLInputElement>;
125
+ /**
126
+ * The text of the field controlled by you: the free text which is the value itself
127
+ * (INN, the name, the address), the items are the suggestions only.\
128
+ * With it the field shows this text, not the text of the selected item, and does not
129
+ * clear or restore it on blur. The choice of an item calls `onChange(item)`: put the text
130
+ * of the item into `inputValue` yourself, if needed.\
131
+ * Pass it together with `onInputValueChange`
132
+ */
133
+ readonly inputValue?: string;
134
+ /**
135
+ * Called with the new text of the field: on typing and on the clear button
136
+ */
137
+ readonly onInputValueChange?: (inputValue: string) => void;
125
138
  /**
126
139
  * The function that will be called at the moment when you want to open the selectbox
127
140
  */
@@ -67,7 +67,7 @@ const AutocompleteMenuList = react_1.default.forwardRef((props, ref) => (react_1
67
67
  AutocompleteMenuList.displayName = 'AutocompleteMenuList';
68
68
  const MENU_OVERRIDES = { List: AutocompleteMenuList };
69
69
  const Autocomplete = react_1.default.forwardRef((props, ref) => {
70
- const { items, value, multiple, isOpen = false, isLoading = false, clearOnBlur = true, anchorPos = 'bottom-fill', alternativePlacements = ['bottom-fill', 'top-fill'], openOnFocus = true, autoFlip = true, viewportMargin, positionStrategy, requiredAsterisk, startIcon, fullWidth, placeholder, label, error, errorText, inputRef, filterItems, children, onChange, selectedItemToString, clearable = true, onInputChange, getOptionSelected, onRequestOpen = () => undefined, onRequestClose = () => undefined, overrides } = props, nativeInputProps = __rest(props, ["items", "value", "multiple", "isOpen", "isLoading", "clearOnBlur", "anchorPos", "alternativePlacements", "openOnFocus", "autoFlip", "viewportMargin", "positionStrategy", "requiredAsterisk", "startIcon", "fullWidth", "placeholder", "label", "error", "errorText", "inputRef", "filterItems", "children", "onChange", "selectedItemToString", "clearable", "onInputChange", "getOptionSelected", "onRequestOpen", "onRequestClose", "overrides"]);
70
+ const { items, value, multiple, isOpen = false, isLoading = false, clearOnBlur = true, anchorPos = 'bottom-fill', alternativePlacements = ['bottom-fill', 'top-fill'], openOnFocus = true, autoFlip = true, viewportMargin, positionStrategy, requiredAsterisk, startIcon, fullWidth, placeholder, label, error, errorText, inputRef, filterItems, children, onChange, selectedItemToString, clearable = true, onInputChange, inputValue: controlledInputValue, onInputValueChange, getOptionSelected, onRequestOpen = () => undefined, onRequestClose = () => undefined, overrides } = props, nativeInputProps = __rest(props, ["items", "value", "multiple", "isOpen", "isLoading", "clearOnBlur", "anchorPos", "alternativePlacements", "openOnFocus", "autoFlip", "viewportMargin", "positionStrategy", "requiredAsterisk", "startIcon", "fullWidth", "placeholder", "label", "error", "errorText", "inputRef", "filterItems", "children", "onChange", "selectedItemToString", "clearable", "onInputChange", "inputValue", "onInputValueChange", "getOptionSelected", "onRequestOpen", "onRequestClose", "overrides"]);
71
71
  const menuRef = react_1.default.useRef(null);
72
72
  const fieldInputRef = react_1.default.useRef(null);
73
73
  const isFocusedRef = react_1.default.useRef(false);
@@ -77,10 +77,12 @@ const Autocomplete = react_1.default.forwardRef((props, ref) => {
77
77
  const overridesMap = react_1.default.useMemo(() => ({
78
78
  TextField: (overrides === null || overrides === void 0 ? void 0 : overrides.TextField) || TextField_1.default,
79
79
  }), [overrides]);
80
+ const isInputControlled = typeof controlledInputValue === 'string';
80
81
  const clear = react_1.default.useCallback(() => {
81
82
  if (onChange) {
82
83
  onChange((multiple ? [] : null));
83
84
  }
85
+ onInputValueChange === null || onInputValueChange === void 0 ? void 0 : onInputValueChange('');
84
86
  dispatch((0, context_1.actionSetPartial)({
85
87
  filteredItems: items,
86
88
  inputValue: '',
@@ -89,7 +91,7 @@ const Autocomplete = react_1.default.forwardRef((props, ref) => {
89
91
  var _a;
90
92
  (_a = fieldInputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
91
93
  }, 15);
92
- }, [dispatch, onChange, items, multiple]);
94
+ }, [dispatch, onChange, onInputValueChange, items, multiple]);
93
95
  /**
94
96
  * API
95
97
  */
@@ -108,13 +110,27 @@ const Autocomplete = react_1.default.forwardRef((props, ref) => {
108
110
  */
109
111
  const restoreInputValue = react_1.default.useCallback(() => {
110
112
  // With multiple the field holds only the search text, the selected items are tags
111
- const newInputValue = multiple || currentValue === null ? '' : selectedItemToString(currentValue);
113
+ // The controlled text is the value itself: it stays as it is
114
+ const newInputValue = isInputControlled
115
+ ? controlledInputValue
116
+ : multiple || currentValue === null
117
+ ? ''
118
+ : selectedItemToString(currentValue);
112
119
  const newFilteredItems = applyFilterForItems(newInputValue, items);
113
120
  dispatch((0, context_1.actionSetPartial)({
114
121
  filteredItems: newFilteredItems,
115
122
  inputValue: newInputValue,
116
123
  }));
117
- }, [currentValue, selectedItemToString, multiple, applyFilterForItems, items, dispatch]);
124
+ }, [
125
+ currentValue,
126
+ selectedItemToString,
127
+ multiple,
128
+ applyFilterForItems,
129
+ items,
130
+ dispatch,
131
+ isInputControlled,
132
+ controlledInputValue,
133
+ ]);
118
134
  const inputKeydownEvent = react_1.default.useCallback((event) => {
119
135
  var _a, _b, _c, _d, _e;
120
136
  if (!isFocusedRef.current) {
@@ -207,14 +223,35 @@ const Autocomplete = react_1.default.forwardRef((props, ref) => {
207
223
  if (value === currentValue) {
208
224
  return;
209
225
  }
210
- // With multiple the selected items are shown as tags and the search text is kept
211
- dispatch((0, context_1.actionSetPartial)(multiple
226
+ // With multiple the selected items are shown as tags and the search text is kept,
227
+ // the controlled text is not replaced by the text of the item
228
+ dispatch((0, context_1.actionSetPartial)(multiple || isInputControlled
212
229
  ? { currentValue: value }
213
230
  : {
214
231
  currentValue: value,
215
232
  inputValue: value === null ? '' : selectedItemToString(value),
216
233
  }));
217
- }, [value, multiple, currentValue, inputValue, dispatch, selectedItemToString]);
234
+ }, [
235
+ value,
236
+ multiple,
237
+ currentValue,
238
+ inputValue,
239
+ dispatch,
240
+ selectedItemToString,
241
+ isInputControlled,
242
+ ]);
243
+ /**
244
+ * The controlled text: the field follows `inputValue`
245
+ */
246
+ react_1.default.useEffect(() => {
247
+ if (!isInputControlled || controlledInputValue === inputValue) {
248
+ return;
249
+ }
250
+ dispatch((0, context_1.actionSetPartial)({
251
+ inputValue: controlledInputValue,
252
+ filteredItems: applyFilterForItems(controlledInputValue, items),
253
+ }));
254
+ }, [isInputControlled, controlledInputValue, inputValue, dispatch, applyFilterForItems, items]);
218
255
  react_1.default.useEffect(() => {
219
256
  if (currentOpen && menuRef.current) {
220
257
  menuRef.current.scrollToFirstSelected();
@@ -305,6 +342,7 @@ const Autocomplete = react_1.default.forwardRef((props, ref) => {
305
342
  if (typeof onInputChange === 'function') {
306
343
  onInputChange(event);
307
344
  }
345
+ onInputValueChange === null || onInputValueChange === void 0 ? void 0 : onInputValueChange(event.currentTarget.value);
308
346
  // If openOnFocus is false, but value is not empty
309
347
  // we should open menu list if is not opened
310
348
  if (!openOnFocus && isFocusedRef.current && !currentOpen && filteredItems.length > 0) {
@@ -328,6 +366,7 @@ const Autocomplete = react_1.default.forwardRef((props, ref) => {
328
366
  filteredItems.length,
329
367
  items,
330
368
  onInputChange,
369
+ onInputValueChange,
331
370
  onRequestClose,
332
371
  onRequestOpen,
333
372
  openOnFocus,
@@ -3,6 +3,7 @@ import { BadgeIconWrapperProps } from './BadgeIconWrapper';
3
3
  import { BadgeTextWrapperProps } from './BadgeTextWrapper';
4
4
  import { BadgeContainerProps } from './BadgeContainer';
5
5
  import { BadgeDeleteButtonProps } from './BadgeDeleteButton';
6
+ import { BadgeDotProps } from './BadgeDot';
6
7
  type BadgeNativeProps = React.HTMLAttributes<HTMLSpanElement>;
7
8
  export interface BadgeBaseProps extends Omit<BadgeNativeProps, 'color'> {
8
9
  /**
@@ -15,13 +16,17 @@ export interface BadgeBaseProps extends Omit<BadgeNativeProps, 'color'> {
15
16
  * ```
16
17
  */
17
18
  readonly startIcon?: React.JSX.Element;
19
+ /**
20
+ * The colored dot before the text: the status (active, overdue, paid)
21
+ */
22
+ readonly dot?: boolean;
18
23
  /**
19
24
  * Badge style variant\
20
25
  * Allowed variants: `standard` or `outlined`\
21
26
  * \
22
27
  * **Default**: `standard`
23
28
  */
24
- readonly variant?: 'standard' | 'outlined';
29
+ readonly variant?: 'standard' | 'outlined' | 'soft';
25
30
  /**
26
31
  * You can pass the primary, default, secondary name of the colors or your specified color value
27
32
  */
@@ -58,6 +63,10 @@ export interface BadgeBaseOverrides {
58
63
  * Icon delete
59
64
  */
60
65
  readonly ButtonDelete?: React.ComponentType<BadgeDeleteButtonProps & React.RefAttributes<HTMLButtonElement>>;
66
+ /**
67
+ * The dot. Rendered only with `dot`
68
+ */
69
+ readonly Dot?: React.ComponentType<BadgeDotProps & React.RefAttributes<HTMLSpanElement>>;
61
70
  }
62
71
  declare const _default: React.ForwardRefExoticComponent<BadgeBaseProps & React.RefAttributes<HTMLSpanElement>>;
63
72
  export default _default;
@@ -19,14 +19,16 @@ const BadgeIconWrapper_1 = __importDefault(require("./BadgeIconWrapper"));
19
19
  const BadgeTextWrapper_1 = __importDefault(require("./BadgeTextWrapper"));
20
20
  const BadgeContainer_1 = __importDefault(require("./BadgeContainer"));
21
21
  const BadgeDeleteButton_1 = __importDefault(require("./BadgeDeleteButton"));
22
+ const BadgeDot_1 = __importDefault(require("./BadgeDot"));
22
23
  const BadgeBase = (props, ref) => {
23
- const { children, startIcon, color, variant, overrides, onDelete, deleteButtonLabel = 'Delete', onClick, onKeyDown } = props, nativeProps = __rest(props, ["children", "startIcon", "color", "variant", "overrides", "onDelete", "deleteButtonLabel", "onClick", "onKeyDown"]);
24
+ const { children, startIcon, dot = false, color, variant, overrides, onDelete, deleteButtonLabel = 'Delete', onClick, onKeyDown } = props, nativeProps = __rest(props, ["children", "startIcon", "dot", "color", "variant", "overrides", "onDelete", "deleteButtonLabel", "onClick", "onKeyDown"]);
24
25
  const clickable = typeof onClick === 'function';
25
26
  const overridesMap = react_1.default.useMemo(() => ({
26
27
  TextWrapper: (overrides === null || overrides === void 0 ? void 0 : overrides.TextWrapper) || BadgeTextWrapper_1.default,
27
28
  IconWrapper: (overrides === null || overrides === void 0 ? void 0 : overrides.IconWrapper) || BadgeIconWrapper_1.default,
28
29
  Container: (overrides === null || overrides === void 0 ? void 0 : overrides.Container) || BadgeContainer_1.default,
29
30
  ButtonDelete: (overrides === null || overrides === void 0 ? void 0 : overrides.ButtonDelete) || BadgeDeleteButton_1.default,
31
+ Dot: (overrides === null || overrides === void 0 ? void 0 : overrides.Dot) || BadgeDot_1.default,
30
32
  }), [overrides]);
31
33
  // A clickable badge acts as a button, so it is activated by Enter and Space too
32
34
  const handleKeyDown = react_1.default.useCallback((event) => {
@@ -46,8 +48,13 @@ const BadgeBase = (props, ref) => {
46
48
  onDelete === null || onDelete === void 0 ? void 0 : onDelete(event);
47
49
  }, [onDelete]);
48
50
  return (react_1.default.createElement(overridesMap.Container, Object.assign({ role: clickable ? 'button' : undefined, tabIndex: clickable ? 0 : undefined }, nativeProps, { onClick: onClick, onKeyDown: handleKeyDown, color: color, ref: ref }),
51
+ dot && react_1.default.createElement(overridesMap.Dot, null),
49
52
  typeof startIcon !== 'undefined' && startIcon !== null && (react_1.default.createElement(overridesMap.IconWrapper, null, startIcon)),
50
53
  react_1.default.createElement(overridesMap.TextWrapper, null, children),
51
- typeof onDelete === 'function' && (react_1.default.createElement(overridesMap.ButtonDelete, { variant: variant, onClick: handleDelete, color: color, "aria-label": deleteButtonLabel }))));
54
+ typeof onDelete === 'function' && (react_1.default.createElement(overridesMap.ButtonDelete
55
+ // the pale soft badge has the colored icon, as the outlined one
56
+ , {
57
+ // the pale soft badge has the colored icon, as the outlined one
58
+ variant: variant === 'soft' ? 'outlined' : variant, onClick: handleDelete, color: color, "aria-label": deleteButtonLabel }))));
52
59
  };
53
60
  exports.default = react_1.default.forwardRef(BadgeBase);
@@ -0,0 +1,4 @@
1
+ import React from 'react';
2
+ export type BadgeDotProps = React.HTMLAttributes<HTMLSpanElement>;
3
+ declare const _default: React.ForwardRefExoticComponent<BadgeDotProps & React.RefAttributes<HTMLSpanElement>>;
4
+ export default _default;
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const react_1 = __importDefault(require("react"));
7
+ const styled_1 = __importDefault(require("@emotion/styled"));
8
+ /**
9
+ * The color of the badge (`--badge-dot-color`), not the color of its text
10
+ */
11
+ const StyledDot = styled_1.default.span `
12
+ flex: none;
13
+ width: 0.5em;
14
+ height: 0.5em;
15
+ margin-left: 0.55em;
16
+ border-radius: 50%;
17
+ background-color: var(--badge-dot-color, currentColor);
18
+ `;
19
+ const BadgeDot = (props, ref) => (react_1.default.createElement(StyledDot, Object.assign({ "aria-hidden": true }, props, { ref: ref })));
20
+ exports.default = react_1.default.forwardRef(BadgeDot);
@@ -70,6 +70,23 @@ const getOutlinedColors = (color, theme) => {
70
70
  }
71
71
  }
72
72
  };
73
+ /**
74
+ * The pale background of the color and the text of the same hue: dark on the light theme,
75
+ * light on the dark one. `$background` is the color itself
76
+ */
77
+ const getSoftColors = (color, theme) => {
78
+ const base = color === 'primary'
79
+ ? theme.color.accentPrimary
80
+ : color === 'secondary'
81
+ ? theme.color.accentSecondary
82
+ : typeof color === 'undefined' || color === 'default'
83
+ ? theme.color.textPrimary
84
+ : parseColor(String(color), theme.color.textPrimary);
85
+ return {
86
+ $background: base,
87
+ $color: theme.isDark ? base.lighten(60) : base.darken(60),
88
+ };
89
+ };
73
90
  /**
74
91
  * Both variants are one styled component: switching the variant (e.g. a toggling filter badge)
75
92
  * must not remount the element, otherwise the focused badge loses the focus
@@ -78,42 +95,62 @@ const StyledBadge = (0, styled_1.default)(BadgeBase_1.default) `
78
95
  border-style: solid;
79
96
  border-width: ${tokens_1.BORDER_WIDTH};
80
97
  border-color: ${({ $background }) => $background.toString()};
98
+ --badge-dot-color: ${({ $variant, $background, $color }) => ($variant === 'standard' ? $color : $background).toString()};
81
99
 
82
- ${({ $variant, $color, $background, theme }) => $variant === 'outlined'
83
- ? (0, react_2.css) `
84
- color: ${$color.darken(30).toString()};
85
- background-color: transparent;
100
+ ${({ $variant, $color, $background }) => $variant === 'soft' &&
101
+ (0, react_2.css) `
102
+ color: ${$color.toString()};
103
+ background-color: ${$background.alpha(0.18).toString()};
104
+ border-color: transparent;
86
105
 
87
- &:focus-visible {
88
- outline-style: solid;
89
- outline-width: 0.14em;
90
- outline-color: ${$background.rgbString()};
91
- }
92
- `
93
- : (0, react_2.css) `
94
- color: ${$color.toString()};
95
- background-color: ${$background.toString()};
106
+ &:focus-visible {
107
+ outline-style: solid;
108
+ outline-width: 0.14em;
109
+ outline-color: ${$background.alpha(0.6).toString()};
110
+ }
111
+ `}
96
112
 
97
- &:focus-visible {
98
- outline-color: ${$background.rgbString() === theme.color.accentPrimary.rgbString()
99
- ? theme.color.textPrimary.toString()
100
- : theme.color.accentPrimary.toString()};
101
- }
102
- `}
113
+ ${({ $variant, $color, $background, theme }) => $variant === 'soft'
114
+ ? ''
115
+ : $variant === 'outlined'
116
+ ? (0, react_2.css) `
117
+ color: ${$color.darken(30).toString()};
118
+ background-color: transparent;
119
+
120
+ &:focus-visible {
121
+ outline-style: solid;
122
+ outline-width: 0.14em;
123
+ outline-color: ${$background.rgbString()};
124
+ }
125
+ `
126
+ : (0, react_2.css) `
127
+ color: ${$color.toString()};
128
+ background-color: ${$background.toString()};
129
+
130
+ &:focus-visible {
131
+ outline-color: ${$background.rgbString() === theme.color.accentPrimary.rgbString()
132
+ ? theme.color.textPrimary.toString()
133
+ : theme.color.accentPrimary.toString()};
134
+ }
135
+ `}
103
136
 
104
137
  ${({ $clickable, $variant, $background }) => $clickable &&
105
138
  (0, react_2.css) `
106
139
  cursor: pointer;
107
140
 
108
141
  &:hover {
109
- ${$variant === 'outlined'
142
+ ${$variant === 'soft'
110
143
  ? (0, react_2.css) `
111
- background-color: ${$background.darken(20).alpha(0.1).toString()};
144
+ background-color: ${$background.alpha(0.3).toString()};
112
145
  `
113
- : (0, react_2.css) `
114
- background-color: ${$background.darken(30).toString()};
115
- border-color: ${$background.darken(30).toString()};
116
- `}
146
+ : $variant === 'outlined'
147
+ ? (0, react_2.css) `
148
+ background-color: ${$background.darken(20).alpha(0.1).toString()};
149
+ `
150
+ : (0, react_2.css) `
151
+ background-color: ${$background.darken(30).toString()};
152
+ border-color: ${$background.darken(30).toString()};
153
+ `}
117
154
  }
118
155
  `}
119
156
  ${({ theme }) => (0, tokens_1.themeFocusRing)(theme)}
@@ -121,7 +158,11 @@ const StyledBadge = (0, styled_1.default)(BadgeBase_1.default) `
121
158
  const BadgeStyled = (props, ref) => {
122
159
  const { children, color, variant = 'standard', onClick } = props, restProps = __rest(props, ["children", "color", "variant", "onClick"]);
123
160
  const theme = (0, react_2.useTheme)();
124
- const { $background, $color } = react_1.default.useMemo(() => variant === 'outlined' ? getOutlinedColors(color, theme) : getStandardColors(color, theme), [color, variant, theme]);
161
+ const { $background, $color } = react_1.default.useMemo(() => variant === 'soft'
162
+ ? getSoftColors(color, theme)
163
+ : variant === 'outlined'
164
+ ? getOutlinedColors(color, theme)
165
+ : getStandardColors(color, theme), [color, variant, theme]);
125
166
  return (react_1.default.createElement(StyledBadge, Object.assign({ "$variant": variant, "$clickable": typeof onClick === 'function', "$color": $color, "$background": $background, color: color, variant: variant, onClick: onClick }, restProps, { ref: ref }), children));
126
167
  };
127
168
  exports.default = react_1.default.forwardRef(BadgeStyled);
package/Badge/index.d.ts CHANGED
@@ -4,19 +4,19 @@ import type { BadgeOutlinedProps } from './BadgeOutlined';
4
4
  export type BadgeProps = (BadgeStandardProps | BadgeOutlinedProps) & {
5
5
  /**
6
6
  * Badge style variant\
7
- * Allowed variants: `standard` or `outlined`\
7
+ * Allowed variants: `standard`, `outlined` or `soft` (the pale background of the color)\
8
8
  * \
9
9
  * **Default**: `standard`
10
10
  */
11
- readonly variant?: 'standard' | 'outlined';
11
+ readonly variant?: 'standard' | 'outlined' | 'soft';
12
12
  };
13
13
  declare const _default: React.ForwardRefExoticComponent<import("./BadgeBase").BadgeBaseProps & {
14
14
  /**
15
15
  * Badge style variant\
16
- * Allowed variants: `standard` or `outlined`\
16
+ * Allowed variants: `standard`, `outlined` or `soft` (the pale background of the color)\
17
17
  * \
18
18
  * **Default**: `standard`
19
19
  */
20
- readonly variant?: "standard" | "outlined";
20
+ readonly variant?: "standard" | "outlined" | "soft";
21
21
  } & React.RefAttributes<HTMLSpanElement>>;
22
22
  export default _default;
package/CHANGELOG.md CHANGED
@@ -2,6 +2,26 @@
2
2
 
3
3
  Все заметные изменения пакета `@via-profit/ui-kit`. Формат основан на [Keep a Changelog](https://keepachangelog.com/ru/1.1.0/), версии следуют [семантическому версионированию](https://semver.org/lang/ru/).
4
4
 
5
+ ## 0.9.0 — 2026-10-19
6
+
7
+ ### Добавлено
8
+
9
+ - **InfoNote** — информер: короткий текст в форме или карточке, который важно увидеть сразу. Варианты `info`, `success`, `warning`, `error` с цветами темы, заголовок `title`, своя иконка или без неё (`icon`), части `Container`, `Icon`, `Content`, `Title`;
10
+ - **FileDropzone** — загрузка файла: область, куда файл выбирают нажатием или перетаскивают. Выбранный файл — строка с именем и размером, кнопками «Заменить» и удаления. Проверка `accept` и `maxSize` с `onReject`, подписи на языке интерфейса, `formatSize` и функция `formatFileSize`, часть `Area`;
11
+ - **Badge**: вариант `soft` — бледная подложка цвета и текст того же оттенка (тёмный в светлой теме, светлый в тёмной) — и свойство `dot`: точка цвета бейджа перед текстом, для меток статуса. Часть `Dot`;
12
+ - **Autocomplete**: свободный текст с подсказками — `inputValue` и `onInputValueChange`. Текст поля — само значение (ИНН, название, адрес), список только подсказывает: поле не подменяет текст текстом выбранного элемента и не стирает его при уходе фокуса;
13
+ - **Skeleton** — заглушка загрузки: серая мерцающая фигура на месте содержимого. Варианты `text`, `rect`, `circle`, `pill`, размеры `width` и `height`; мерцание выключается при уменьшении движения в системе;
14
+ - **EmptyState** — пустое состояние: иллюстрация, что пусто (`title`), почему (`children`) и следующий шаг (`action`). Своя иллюстрация или без неё (`icon`), `fullHeight`, части `Container`, `Icon`, `Title`, `Content`, `Action`;
15
+ - **HintPopover** — кнопка «?», которая по нажатию открывает всплывающий блок с пояснением. Кнопка берёт цвет окружающего текста, подсказка закрывается кликом вне неё и Escape (фокус возвращается на кнопку), показывается поверх модальных окон. Свойства `label`, `placement`, `isOpen`/`onOpenChange`, части `Button` и `Container`.
16
+
17
+ ## 0.8.0 — 2026-10-13
18
+
19
+ Drawer: закрытие свайпом.
20
+
21
+ ### Добавлено
22
+
23
+ - **Modal**: свойство `swipeToClose` у `drawer` — панель закрывается свайпом к своему краю. Она следует за пальцем, короткий свайп возвращает её на место, прокручиваемое содержимое сначала прокручивается. На стороне, обращённой к странице, появляется полоска-ручка, за которую панель перетаскивается мышью.
24
+
5
25
  ## 0.7.0 — 2026-10-09
6
26
 
7
27
  Swiper: дробный `slidesPerView` и `centered`, вертикальная прокрутка, затухание и бегущая лента.
@@ -0,0 +1,4 @@
1
+ import React from 'react';
2
+ export type EmptyStateActionProps = React.HTMLAttributes<HTMLDivElement>;
3
+ declare const _default: React.ForwardRefExoticComponent<EmptyStateActionProps & React.RefAttributes<HTMLDivElement>>;
4
+ export default _default;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const react_1 = __importDefault(require("react"));
7
+ const styled_1 = __importDefault(require("@emotion/styled"));
8
+ const StyledAction = styled_1.default.div `
9
+ display: flex;
10
+ flex-wrap: wrap;
11
+ justify-content: center;
12
+ gap: 0.5em;
13
+ margin-top: 0.5em;
14
+ `;
15
+ const EmptyStateAction = (props, ref) => react_1.default.createElement(StyledAction, Object.assign({}, props, { ref: ref }));
16
+ exports.default = react_1.default.forwardRef(EmptyStateAction);
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ export type EmptyStateContainerProps = React.HTMLAttributes<HTMLDivElement> & {
3
+ readonly fullHeight: boolean;
4
+ };
5
+ declare const _default: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & {
6
+ readonly fullHeight: boolean;
7
+ } & React.RefAttributes<HTMLDivElement>>;
8
+ export default _default;
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ var __rest = (this && this.__rest) || function (s, e) {
3
+ var t = {};
4
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
5
+ t[p] = s[p];
6
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
7
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
8
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
9
+ t[p[i]] = s[p[i]];
10
+ }
11
+ return t;
12
+ };
13
+ var __importDefault = (this && this.__importDefault) || function (mod) {
14
+ return (mod && mod.__esModule) ? mod : { "default": mod };
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ const react_1 = __importDefault(require("react"));
18
+ const styled_1 = __importDefault(require("@emotion/styled"));
19
+ const StyledContainer = styled_1.default.div `
20
+ box-sizing: border-box;
21
+ display: flex;
22
+ flex-direction: column;
23
+ align-items: center;
24
+ justify-content: center;
25
+ gap: 0.75em;
26
+ padding: 2em 1em;
27
+ text-align: center;
28
+ height: ${({ $fullHeight }) => ($fullHeight ? '100%' : 'auto')};
29
+ `;
30
+ const EmptyStateContainer = (props, ref) => {
31
+ const { fullHeight } = props, nativeProps = __rest(props, ["fullHeight"]);
32
+ return react_1.default.createElement(StyledContainer, Object.assign({}, nativeProps, { "$fullHeight": fullHeight, ref: ref }));
33
+ };
34
+ exports.default = react_1.default.forwardRef(EmptyStateContainer);
@@ -0,0 +1,4 @@
1
+ import React from 'react';
2
+ export type EmptyStateContentProps = React.HTMLAttributes<HTMLDivElement>;
3
+ declare const _default: React.ForwardRefExoticComponent<EmptyStateContentProps & React.RefAttributes<HTMLDivElement>>;
4
+ export default _default;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const react_1 = __importDefault(require("react"));
7
+ const styled_1 = __importDefault(require("@emotion/styled"));
8
+ const StyledContent = styled_1.default.div `
9
+ max-width: 22em;
10
+ font-size: 0.9em;
11
+ line-height: 1.45;
12
+ color: ${({ theme }) => theme.color.textSecondary.toString()};
13
+ `;
14
+ const EmptyStateContent = (props, ref) => react_1.default.createElement(StyledContent, Object.assign({}, props, { ref: ref }));
15
+ exports.default = react_1.default.forwardRef(EmptyStateContent);
@@ -0,0 +1,4 @@
1
+ import React from 'react';
2
+ export type EmptyStateIconProps = React.HTMLAttributes<HTMLSpanElement>;
3
+ declare const _default: React.ForwardRefExoticComponent<EmptyStateIconProps & React.RefAttributes<HTMLSpanElement>>;
4
+ export default _default;
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ var __rest = (this && this.__rest) || function (s, e) {
3
+ var t = {};
4
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
5
+ t[p] = s[p];
6
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
7
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
8
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
9
+ t[p[i]] = s[p[i]];
10
+ }
11
+ return t;
12
+ };
13
+ var __importDefault = (this && this.__importDefault) || function (mod) {
14
+ return (mod && mod.__esModule) ? mod : { "default": mod };
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ const react_1 = __importDefault(require("react"));
18
+ const styled_1 = __importDefault(require("@emotion/styled"));
19
+ const StyledIcon = styled_1.default.span `
20
+ display: inline-flex;
21
+ margin-bottom: 0.75em;
22
+ font-size: 6em;
23
+ color: ${({ theme }) => theme.color.textPrimary.alpha(0.6).toString()};
24
+ `;
25
+ const Path = styled_1.default.path `
26
+ fill: currentColor;
27
+ `;
28
+ /**
29
+ * The open empty box. `children` replaces it
30
+ */
31
+ const EmptyStateIcon = (props, ref) => {
32
+ const { children } = props, nativeProps = __rest(props, ["children"]);
33
+ return (react_1.default.createElement(StyledIcon, Object.assign({ "aria-hidden": true }, nativeProps, { ref: ref }), children !== null && children !== void 0 ? children : (react_1.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "1em", height: "1em", viewBox: "0 0 511.99 511.99" },
34
+ react_1.default.createElement(Path, { d: "M446.822 213.631l-190.827-63.256-190.827 63.256L.01 317.129l59.984 19.884V447.02l196 64.97 196-64.97V337.013l59.984-19.884zm-57.5 12.545l-133.327 44.195-133.327-44.195 133.327-44.195zm-343.52 74.527l35.627-56.592 151.67 50.276-35.626 56.591zm44.193 46.255L210.34 386.85l30.655-48.693v137.256l-151-50.054zm181 128.454V338.156l30.655 48.693 120.345-39.892v78.401zm43.522-124.433l-35.626-56.591 151.67-50.276 35.627 56.592zM240.995 0h30v100.174h-30z" }),
35
+ react_1.default.createElement(Path, { d: "M122.952 31.63h30v100.174h-30z", transform: "rotate(-30 137.947 81.722)" }),
36
+ react_1.default.createElement(Path, { d: "M323.951 66.717h100.174v30H323.951z", transform: "rotate(-60 374.044 81.724)" })))));
37
+ };
38
+ exports.default = react_1.default.forwardRef(EmptyStateIcon);
@@ -0,0 +1,4 @@
1
+ import React from 'react';
2
+ export type EmptyStateTitleProps = React.HTMLAttributes<HTMLDivElement>;
3
+ declare const _default: React.ForwardRefExoticComponent<EmptyStateTitleProps & React.RefAttributes<HTMLDivElement>>;
4
+ export default _default;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const react_1 = __importDefault(require("react"));
7
+ const styled_1 = __importDefault(require("@emotion/styled"));
8
+ const StyledTitle = styled_1.default.div `
9
+ font-weight: 600;
10
+ color: ${({ theme }) => theme.color.textPrimary.toString()};
11
+ `;
12
+ const EmptyStateTitle = (props, ref) => react_1.default.createElement(StyledTitle, Object.assign({}, props, { ref: ref }));
13
+ exports.default = react_1.default.forwardRef(EmptyStateTitle);