@via-profit/ui-kit 0.8.0 → 0.9.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.
Files changed (70) 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 +18 -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/BaseModal/ModalWrapper.js +3 -1
  45. package/Skeleton/index.d.ts +39 -0
  46. package/Skeleton/index.js +69 -0
  47. package/esm/Autocomplete/AutocompleteContainer.js +46 -7
  48. package/esm/Badge/BadgeBase.js +9 -2
  49. package/esm/Badge/BadgeDot.js +15 -0
  50. package/esm/Badge/BadgeStyled.js +67 -26
  51. package/esm/EmptyState/EmptyStateAction.js +11 -0
  52. package/esm/EmptyState/EmptyStateContainer.js +29 -0
  53. package/esm/EmptyState/EmptyStateContent.js +10 -0
  54. package/esm/EmptyState/EmptyStateIcon.js +33 -0
  55. package/esm/EmptyState/EmptyStateTitle.js +8 -0
  56. package/esm/EmptyState/index.js +42 -0
  57. package/esm/FileDropzone/FileDropzoneArea.js +76 -0
  58. package/esm/FileDropzone/index.js +148 -0
  59. package/esm/FileDropzone/utils.js +37 -0
  60. package/esm/HintPopover/HintPopoverButton.js +62 -0
  61. package/esm/HintPopover/HintPopoverContainer.js +47 -0
  62. package/esm/HintPopover/index.js +52 -0
  63. package/esm/InfoNote/InfoNoteContainer.js +49 -0
  64. package/esm/InfoNote/InfoNoteContent.js +11 -0
  65. package/esm/InfoNote/InfoNoteIcon.js +42 -0
  66. package/esm/InfoNote/InfoNoteTitle.js +8 -0
  67. package/esm/InfoNote/index.js +40 -0
  68. package/esm/Modal/BaseModal/ModalWrapper.js +3 -1
  69. package/esm/Skeleton/index.js +64 -0
  70. package/package.json +121 -1
@@ -29,7 +29,7 @@ const AutocompleteMenuList = React.forwardRef((props, ref) => (React.createEleme
29
29
  AutocompleteMenuList.displayName = 'AutocompleteMenuList';
30
30
  const MENU_OVERRIDES = { List: AutocompleteMenuList };
31
31
  const Autocomplete = React.forwardRef((props, ref) => {
32
- 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"]);
32
+ 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"]);
33
33
  const menuRef = React.useRef(null);
34
34
  const fieldInputRef = React.useRef(null);
35
35
  const isFocusedRef = React.useRef(false);
@@ -39,10 +39,12 @@ const Autocomplete = React.forwardRef((props, ref) => {
39
39
  const overridesMap = React.useMemo(() => ({
40
40
  TextField: (overrides === null || overrides === void 0 ? void 0 : overrides.TextField) || TextField,
41
41
  }), [overrides]);
42
+ const isInputControlled = typeof controlledInputValue === 'string';
42
43
  const clear = React.useCallback(() => {
43
44
  if (onChange) {
44
45
  onChange((multiple ? [] : null));
45
46
  }
47
+ onInputValueChange === null || onInputValueChange === void 0 ? void 0 : onInputValueChange('');
46
48
  dispatch(actionSetPartial({
47
49
  filteredItems: items,
48
50
  inputValue: '',
@@ -51,7 +53,7 @@ const Autocomplete = React.forwardRef((props, ref) => {
51
53
  var _a;
52
54
  (_a = fieldInputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
53
55
  }, 15);
54
- }, [dispatch, onChange, items, multiple]);
56
+ }, [dispatch, onChange, onInputValueChange, items, multiple]);
55
57
  /**
56
58
  * API
57
59
  */
@@ -70,13 +72,27 @@ const Autocomplete = React.forwardRef((props, ref) => {
70
72
  */
71
73
  const restoreInputValue = React.useCallback(() => {
72
74
  // With multiple the field holds only the search text, the selected items are tags
73
- const newInputValue = multiple || currentValue === null ? '' : selectedItemToString(currentValue);
75
+ // The controlled text is the value itself: it stays as it is
76
+ const newInputValue = isInputControlled
77
+ ? controlledInputValue
78
+ : multiple || currentValue === null
79
+ ? ''
80
+ : selectedItemToString(currentValue);
74
81
  const newFilteredItems = applyFilterForItems(newInputValue, items);
75
82
  dispatch(actionSetPartial({
76
83
  filteredItems: newFilteredItems,
77
84
  inputValue: newInputValue,
78
85
  }));
79
- }, [currentValue, selectedItemToString, multiple, applyFilterForItems, items, dispatch]);
86
+ }, [
87
+ currentValue,
88
+ selectedItemToString,
89
+ multiple,
90
+ applyFilterForItems,
91
+ items,
92
+ dispatch,
93
+ isInputControlled,
94
+ controlledInputValue,
95
+ ]);
80
96
  const inputKeydownEvent = React.useCallback((event) => {
81
97
  var _a, _b, _c, _d, _e;
82
98
  if (!isFocusedRef.current) {
@@ -169,14 +185,35 @@ const Autocomplete = React.forwardRef((props, ref) => {
169
185
  if (value === currentValue) {
170
186
  return;
171
187
  }
172
- // With multiple the selected items are shown as tags and the search text is kept
173
- dispatch(actionSetPartial(multiple
188
+ // With multiple the selected items are shown as tags and the search text is kept,
189
+ // the controlled text is not replaced by the text of the item
190
+ dispatch(actionSetPartial(multiple || isInputControlled
174
191
  ? { currentValue: value }
175
192
  : {
176
193
  currentValue: value,
177
194
  inputValue: value === null ? '' : selectedItemToString(value),
178
195
  }));
179
- }, [value, multiple, currentValue, inputValue, dispatch, selectedItemToString]);
196
+ }, [
197
+ value,
198
+ multiple,
199
+ currentValue,
200
+ inputValue,
201
+ dispatch,
202
+ selectedItemToString,
203
+ isInputControlled,
204
+ ]);
205
+ /**
206
+ * The controlled text: the field follows `inputValue`
207
+ */
208
+ React.useEffect(() => {
209
+ if (!isInputControlled || controlledInputValue === inputValue) {
210
+ return;
211
+ }
212
+ dispatch(actionSetPartial({
213
+ inputValue: controlledInputValue,
214
+ filteredItems: applyFilterForItems(controlledInputValue, items),
215
+ }));
216
+ }, [isInputControlled, controlledInputValue, inputValue, dispatch, applyFilterForItems, items]);
180
217
  React.useEffect(() => {
181
218
  if (currentOpen && menuRef.current) {
182
219
  menuRef.current.scrollToFirstSelected();
@@ -267,6 +304,7 @@ const Autocomplete = React.forwardRef((props, ref) => {
267
304
  if (typeof onInputChange === 'function') {
268
305
  onInputChange(event);
269
306
  }
307
+ onInputValueChange === null || onInputValueChange === void 0 ? void 0 : onInputValueChange(event.currentTarget.value);
270
308
  // If openOnFocus is false, but value is not empty
271
309
  // we should open menu list if is not opened
272
310
  if (!openOnFocus && isFocusedRef.current && !currentOpen && filteredItems.length > 0) {
@@ -290,6 +328,7 @@ const Autocomplete = React.forwardRef((props, ref) => {
290
328
  filteredItems.length,
291
329
  items,
292
330
  onInputChange,
331
+ onInputValueChange,
293
332
  onRequestClose,
294
333
  onRequestOpen,
295
334
  openOnFocus,
@@ -14,14 +14,16 @@ import IconWrapper from './BadgeIconWrapper';
14
14
  import TextWrapper from './BadgeTextWrapper';
15
15
  import Container from './BadgeContainer';
16
16
  import ButtonDelete from './BadgeDeleteButton';
17
+ import Dot from './BadgeDot';
17
18
  const BadgeBase = (props, ref) => {
18
- const { children, startIcon, color, variant, overrides, onDelete, deleteButtonLabel = 'Delete', onClick, onKeyDown } = props, nativeProps = __rest(props, ["children", "startIcon", "color", "variant", "overrides", "onDelete", "deleteButtonLabel", "onClick", "onKeyDown"]);
19
+ 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"]);
19
20
  const clickable = typeof onClick === 'function';
20
21
  const overridesMap = React.useMemo(() => ({
21
22
  TextWrapper: (overrides === null || overrides === void 0 ? void 0 : overrides.TextWrapper) || TextWrapper,
22
23
  IconWrapper: (overrides === null || overrides === void 0 ? void 0 : overrides.IconWrapper) || IconWrapper,
23
24
  Container: (overrides === null || overrides === void 0 ? void 0 : overrides.Container) || Container,
24
25
  ButtonDelete: (overrides === null || overrides === void 0 ? void 0 : overrides.ButtonDelete) || ButtonDelete,
26
+ Dot: (overrides === null || overrides === void 0 ? void 0 : overrides.Dot) || Dot,
25
27
  }), [overrides]);
26
28
  // A clickable badge acts as a button, so it is activated by Enter and Space too
27
29
  const handleKeyDown = React.useCallback((event) => {
@@ -41,8 +43,13 @@ const BadgeBase = (props, ref) => {
41
43
  onDelete === null || onDelete === void 0 ? void 0 : onDelete(event);
42
44
  }, [onDelete]);
43
45
  return (React.createElement(overridesMap.Container, Object.assign({ role: clickable ? 'button' : undefined, tabIndex: clickable ? 0 : undefined }, nativeProps, { onClick: onClick, onKeyDown: handleKeyDown, color: color, ref: ref }),
46
+ dot && React.createElement(overridesMap.Dot, null),
44
47
  typeof startIcon !== 'undefined' && startIcon !== null && (React.createElement(overridesMap.IconWrapper, null, startIcon)),
45
48
  React.createElement(overridesMap.TextWrapper, null, children),
46
- typeof onDelete === 'function' && (React.createElement(overridesMap.ButtonDelete, { variant: variant, onClick: handleDelete, color: color, "aria-label": deleteButtonLabel }))));
49
+ typeof onDelete === 'function' && (React.createElement(overridesMap.ButtonDelete
50
+ // the pale soft badge has the colored icon, as the outlined one
51
+ , {
52
+ // the pale soft badge has the colored icon, as the outlined one
53
+ variant: variant === 'soft' ? 'outlined' : variant, onClick: handleDelete, color: color, "aria-label": deleteButtonLabel }))));
47
54
  };
48
55
  export default React.forwardRef(BadgeBase);
@@ -0,0 +1,15 @@
1
+ import React from 'react';
2
+ import styled from '@emotion/styled';
3
+ /**
4
+ * The color of the badge (`--badge-dot-color`), not the color of its text
5
+ */
6
+ const StyledDot = styled.span `
7
+ flex: none;
8
+ width: 0.5em;
9
+ height: 0.5em;
10
+ margin-left: 0.55em;
11
+ border-radius: 50%;
12
+ background-color: var(--badge-dot-color, currentColor);
13
+ `;
14
+ const BadgeDot = (props, ref) => (React.createElement(StyledDot, Object.assign({ "aria-hidden": true }, props, { ref: ref })));
15
+ export default React.forwardRef(BadgeDot);
@@ -65,6 +65,23 @@ const getOutlinedColors = (color, theme) => {
65
65
  }
66
66
  }
67
67
  };
68
+ /**
69
+ * The pale background of the color and the text of the same hue: dark on the light theme,
70
+ * light on the dark one. `$background` is the color itself
71
+ */
72
+ const getSoftColors = (color, theme) => {
73
+ const base = color === 'primary'
74
+ ? theme.color.accentPrimary
75
+ : color === 'secondary'
76
+ ? theme.color.accentSecondary
77
+ : typeof color === 'undefined' || color === 'default'
78
+ ? theme.color.textPrimary
79
+ : parseColor(String(color), theme.color.textPrimary);
80
+ return {
81
+ $background: base,
82
+ $color: theme.isDark ? base.lighten(60) : base.darken(60),
83
+ };
84
+ };
68
85
  /**
69
86
  * Both variants are one styled component: switching the variant (e.g. a toggling filter badge)
70
87
  * must not remount the element, otherwise the focused badge loses the focus
@@ -73,42 +90,62 @@ const StyledBadge = styled(BadgeBase) `
73
90
  border-style: solid;
74
91
  border-width: ${BORDER_WIDTH};
75
92
  border-color: ${({ $background }) => $background.toString()};
93
+ --badge-dot-color: ${({ $variant, $background, $color }) => ($variant === 'standard' ? $color : $background).toString()};
76
94
 
77
- ${({ $variant, $color, $background, theme }) => $variant === 'outlined'
78
- ? css `
79
- color: ${$color.darken(30).toString()};
80
- background-color: transparent;
95
+ ${({ $variant, $color, $background }) => $variant === 'soft' &&
96
+ css `
97
+ color: ${$color.toString()};
98
+ background-color: ${$background.alpha(0.18).toString()};
99
+ border-color: transparent;
81
100
 
82
- &:focus-visible {
83
- outline-style: solid;
84
- outline-width: 0.14em;
85
- outline-color: ${$background.rgbString()};
86
- }
87
- `
88
- : css `
89
- color: ${$color.toString()};
90
- background-color: ${$background.toString()};
101
+ &:focus-visible {
102
+ outline-style: solid;
103
+ outline-width: 0.14em;
104
+ outline-color: ${$background.alpha(0.6).toString()};
105
+ }
106
+ `}
91
107
 
92
- &:focus-visible {
93
- outline-color: ${$background.rgbString() === theme.color.accentPrimary.rgbString()
94
- ? theme.color.textPrimary.toString()
95
- : theme.color.accentPrimary.toString()};
96
- }
97
- `}
108
+ ${({ $variant, $color, $background, theme }) => $variant === 'soft'
109
+ ? ''
110
+ : $variant === 'outlined'
111
+ ? css `
112
+ color: ${$color.darken(30).toString()};
113
+ background-color: transparent;
114
+
115
+ &:focus-visible {
116
+ outline-style: solid;
117
+ outline-width: 0.14em;
118
+ outline-color: ${$background.rgbString()};
119
+ }
120
+ `
121
+ : css `
122
+ color: ${$color.toString()};
123
+ background-color: ${$background.toString()};
124
+
125
+ &:focus-visible {
126
+ outline-color: ${$background.rgbString() === theme.color.accentPrimary.rgbString()
127
+ ? theme.color.textPrimary.toString()
128
+ : theme.color.accentPrimary.toString()};
129
+ }
130
+ `}
98
131
 
99
132
  ${({ $clickable, $variant, $background }) => $clickable &&
100
133
  css `
101
134
  cursor: pointer;
102
135
 
103
136
  &:hover {
104
- ${$variant === 'outlined'
137
+ ${$variant === 'soft'
105
138
  ? css `
106
- background-color: ${$background.darken(20).alpha(0.1).toString()};
139
+ background-color: ${$background.alpha(0.3).toString()};
107
140
  `
108
- : css `
109
- background-color: ${$background.darken(30).toString()};
110
- border-color: ${$background.darken(30).toString()};
111
- `}
141
+ : $variant === 'outlined'
142
+ ? css `
143
+ background-color: ${$background.darken(20).alpha(0.1).toString()};
144
+ `
145
+ : css `
146
+ background-color: ${$background.darken(30).toString()};
147
+ border-color: ${$background.darken(30).toString()};
148
+ `}
112
149
  }
113
150
  `}
114
151
  ${({ theme }) => themeFocusRing(theme)}
@@ -116,7 +153,11 @@ const StyledBadge = styled(BadgeBase) `
116
153
  const BadgeStyled = (props, ref) => {
117
154
  const { children, color, variant = 'standard', onClick } = props, restProps = __rest(props, ["children", "color", "variant", "onClick"]);
118
155
  const theme = useTheme();
119
- const { $background, $color } = React.useMemo(() => variant === 'outlined' ? getOutlinedColors(color, theme) : getStandardColors(color, theme), [color, variant, theme]);
156
+ const { $background, $color } = React.useMemo(() => variant === 'soft'
157
+ ? getSoftColors(color, theme)
158
+ : variant === 'outlined'
159
+ ? getOutlinedColors(color, theme)
160
+ : getStandardColors(color, theme), [color, variant, theme]);
120
161
  return (React.createElement(StyledBadge, Object.assign({ "$variant": variant, "$clickable": typeof onClick === 'function', "$color": $color, "$background": $background, color: color, variant: variant, onClick: onClick }, restProps, { ref: ref }), children));
121
162
  };
122
163
  export default React.forwardRef(BadgeStyled);
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ import styled from '@emotion/styled';
3
+ const StyledAction = styled.div `
4
+ display: flex;
5
+ flex-wrap: wrap;
6
+ justify-content: center;
7
+ gap: 0.5em;
8
+ margin-top: 0.5em;
9
+ `;
10
+ const EmptyStateAction = (props, ref) => React.createElement(StyledAction, Object.assign({}, props, { ref: ref }));
11
+ export default React.forwardRef(EmptyStateAction);
@@ -0,0 +1,29 @@
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 React from 'react';
13
+ import styled from '@emotion/styled';
14
+ const StyledContainer = styled.div `
15
+ box-sizing: border-box;
16
+ display: flex;
17
+ flex-direction: column;
18
+ align-items: center;
19
+ justify-content: center;
20
+ gap: 0.75em;
21
+ padding: 2em 1em;
22
+ text-align: center;
23
+ height: ${({ $fullHeight }) => ($fullHeight ? '100%' : 'auto')};
24
+ `;
25
+ const EmptyStateContainer = (props, ref) => {
26
+ const { fullHeight } = props, nativeProps = __rest(props, ["fullHeight"]);
27
+ return React.createElement(StyledContainer, Object.assign({}, nativeProps, { "$fullHeight": fullHeight, ref: ref }));
28
+ };
29
+ export default React.forwardRef(EmptyStateContainer);
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import styled from '@emotion/styled';
3
+ const StyledContent = styled.div `
4
+ max-width: 22em;
5
+ font-size: 0.9em;
6
+ line-height: 1.45;
7
+ color: ${({ theme }) => theme.color.textSecondary.toString()};
8
+ `;
9
+ const EmptyStateContent = (props, ref) => React.createElement(StyledContent, Object.assign({}, props, { ref: ref }));
10
+ export default React.forwardRef(EmptyStateContent);
@@ -0,0 +1,33 @@
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 React from 'react';
13
+ import styled from '@emotion/styled';
14
+ const StyledIcon = styled.span `
15
+ display: inline-flex;
16
+ margin-bottom: 0.75em;
17
+ font-size: 6em;
18
+ color: ${({ theme }) => theme.color.textPrimary.alpha(0.6).toString()};
19
+ `;
20
+ const Path = styled.path `
21
+ fill: currentColor;
22
+ `;
23
+ /**
24
+ * The open empty box. `children` replaces it
25
+ */
26
+ const EmptyStateIcon = (props, ref) => {
27
+ const { children } = props, nativeProps = __rest(props, ["children"]);
28
+ return (React.createElement(StyledIcon, Object.assign({ "aria-hidden": true }, nativeProps, { ref: ref }), children !== null && children !== void 0 ? children : (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "1em", height: "1em", viewBox: "0 0 511.99 511.99" },
29
+ React.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" }),
30
+ React.createElement(Path, { d: "M122.952 31.63h30v100.174h-30z", transform: "rotate(-30 137.947 81.722)" }),
31
+ React.createElement(Path, { d: "M323.951 66.717h100.174v30H323.951z", transform: "rotate(-60 374.044 81.724)" })))));
32
+ };
33
+ export default React.forwardRef(EmptyStateIcon);
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import styled from '@emotion/styled';
3
+ const StyledTitle = styled.div `
4
+ font-weight: 600;
5
+ color: ${({ theme }) => theme.color.textPrimary.toString()};
6
+ `;
7
+ const EmptyStateTitle = (props, ref) => React.createElement(StyledTitle, Object.assign({}, props, { ref: ref }));
8
+ export default React.forwardRef(EmptyStateTitle);
@@ -0,0 +1,42 @@
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 React from 'react';
13
+ import Container from './EmptyStateContainer';
14
+ import Icon from './EmptyStateIcon';
15
+ import Title from './EmptyStateTitle';
16
+ import Content from './EmptyStateContent';
17
+ import Action from './EmptyStateAction';
18
+ /**
19
+ * The empty list, the nothing found, the not chosen yet: the illustration, what is empty
20
+ * and what to do next
21
+ */
22
+ const EmptyState = (props, ref) => {
23
+ const { title, children, action, icon, fullHeight = false, overrides } = props, nativeProps = __rest(props, ["title", "children", "action", "icon", "fullHeight", "overrides"]);
24
+ const overridesMap = React.useMemo(() => ({
25
+ Container: (overrides === null || overrides === void 0 ? void 0 : overrides.Container) || Container,
26
+ Icon: (overrides === null || overrides === void 0 ? void 0 : overrides.Icon) || Icon,
27
+ Title: (overrides === null || overrides === void 0 ? void 0 : overrides.Title) || Title,
28
+ Content: (overrides === null || overrides === void 0 ? void 0 : overrides.Content) || Content,
29
+ Action: (overrides === null || overrides === void 0 ? void 0 : overrides.Action) || Action,
30
+ }), [overrides]);
31
+ return (React.createElement(overridesMap.Container, Object.assign({}, nativeProps, { fullHeight: fullHeight, ref: ref }),
32
+ icon !== false && React.createElement(overridesMap.Icon, null, icon),
33
+ title && React.createElement(overridesMap.Title, null, title),
34
+ children && React.createElement(overridesMap.Content, null, children),
35
+ action && React.createElement(overridesMap.Action, null, action)));
36
+ };
37
+ export * from './EmptyStateContainer';
38
+ export * from './EmptyStateIcon';
39
+ export * from './EmptyStateTitle';
40
+ export * from './EmptyStateContent';
41
+ export * from './EmptyStateAction';
42
+ export default React.forwardRef(EmptyState);
@@ -0,0 +1,76 @@
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 React from 'react';
13
+ import styled from '@emotion/styled';
14
+ import { css } from '@emotion/react';
15
+ const StyledArea = styled.div `
16
+ box-sizing: border-box;
17
+ display: flex;
18
+ width: 100%;
19
+ min-height: 6.5em;
20
+ padding: 1em;
21
+ border-radius: ${({ theme }) => theme.shape.radiusFactor * 1.6}em;
22
+ border: 1px ${({ $filled }) => ($filled ? 'solid' : 'dashed')}
23
+ ${({ theme, $active }) => ($active ? theme.color.accentPrimary : theme.color.textSecondary.alpha(0.45)).toString()};
24
+ background-color: ${({ theme, $active }) => ($active
25
+ ? theme.color.accentPrimary.alpha(0.1)
26
+ : theme.color.textPrimary.alpha(0.03)).toString()};
27
+ color: ${({ theme }) => theme.color.textPrimary.toString()};
28
+ transition:
29
+ border-color 120ms ease-out,
30
+ background-color 120ms ease-out;
31
+
32
+ ${({ $filled, $disabled, theme }) => !$filled &&
33
+ !$disabled &&
34
+ css `
35
+ cursor: pointer;
36
+
37
+ &:hover,
38
+ &:focus-visible {
39
+ border-color: ${theme.color.accentPrimary.toString()};
40
+ }
41
+ `}
42
+
43
+ ${({ $filled }) => $filled
44
+ ? css `
45
+ flex-direction: row;
46
+ align-items: center;
47
+ gap: 0.75em;
48
+ `
49
+ : css `
50
+ flex-direction: column;
51
+ align-items: center;
52
+ justify-content: center;
53
+ gap: 0.3em;
54
+ text-align: center;
55
+ `}
56
+
57
+ ${({ $disabled }) => $disabled &&
58
+ css `
59
+ opacity: 0.5;
60
+ cursor: default;
61
+ `}
62
+
63
+ &:focus-visible {
64
+ outline: 2px solid ${({ theme }) => theme.color.accentPrimary.alpha(0.4).toString()};
65
+ outline-offset: 2px;
66
+ }
67
+ `;
68
+ /**
69
+ * The area: without the file — the icon and two lines in the middle (it chooses the file),
70
+ * with the file — the row of the file
71
+ */
72
+ const FileDropzoneArea = (props, ref) => {
73
+ const { active, filled, disabled } = props, nativeProps = __rest(props, ["active", "filled", "disabled"]);
74
+ return (React.createElement(StyledArea, Object.assign({}, nativeProps, { "$active": active, "$filled": filled, "$disabled": disabled, ref: ref })));
75
+ };
76
+ export default React.forwardRef(FileDropzoneArea);
@@ -0,0 +1,148 @@
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 React from 'react';
13
+ import styled from '@emotion/styled';
14
+ import Button from '../Button';
15
+ import Area from './FileDropzoneArea';
16
+ import { formatFileSize, isFileAccepted } from './utils';
17
+ export { formatFileSize, isFileAccepted };
18
+ const Icon = styled.span `
19
+ flex: none;
20
+ display: inline-flex;
21
+ font-size: 1.5em;
22
+ color: ${({ theme }) => theme.color.textSecondary.toString()};
23
+ `;
24
+ const Label = styled.span `
25
+ font-size: 0.875em;
26
+ font-weight: 600;
27
+ `;
28
+ const Hint = styled.span `
29
+ font-size: 0.75em;
30
+ color: ${({ theme }) => theme.color.textSecondary.toString()};
31
+ `;
32
+ const FileText = styled.span `
33
+ flex: 1;
34
+ min-width: 0;
35
+ display: flex;
36
+ flex-direction: column;
37
+ gap: 0.15em;
38
+ text-align: left;
39
+ `;
40
+ /**
41
+ * The long name in one line: the whole name is in the tooltip
42
+ */
43
+ const FileName = styled(Label) `
44
+ white-space: nowrap;
45
+ overflow: hidden;
46
+ text-overflow: ellipsis;
47
+ `;
48
+ const Path = styled.path `
49
+ fill: currentColor;
50
+ `;
51
+ const UploadIcon = () => (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "1em", height: "1em", viewBox: "0 0 24 24", "aria-hidden": true },
52
+ React.createElement(Path, { d: "M19.35 10.04A7.49 7.49 0 0 0 12 4C9.11 4 6.6 5.64 5.35 8.04A5.994 5.994 0 0 0 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM19 18H6c-2.21 0-4-1.79-4-4 0-2.05 1.53-3.76 3.56-3.97l1.07-.11.5-.95A5.469 5.469 0 0 1 12 6c2.62 0 4.88 1.86 5.39 4.43l.3 1.5 1.53.11A2.98 2.98 0 0 1 22 15c0 1.65-1.35 3-3 3zM8 13h2.55v3h2.9v-3H16l-4-4z" })));
53
+ const FileIcon = () => (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "1em", height: "1em", viewBox: "0 0 24 24", "aria-hidden": true },
54
+ React.createElement(Path, { d: "M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6zM6 20V4h7v5h5v11H6zm2-6h8v2H8zm0 3h5v2H8z" })));
55
+ const TrashIcon = () => (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "1em", height: "1em", viewBox: "0 0 24 24", "aria-hidden": true },
56
+ React.createElement(Path, { d: "M16 9v10H8V9h8m-1.5-6h-5l-1 1H5v2h14V4h-3.5l-1-1zM18 7H6v12c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7z" })));
57
+ /**
58
+ * The file by the click or by the drop: one area with the dashed border. The chosen file
59
+ * is the row with its name and size, «Replace» and the delete button; a new file can be
60
+ * dropped onto it too
61
+ */
62
+ const FileDropzone = (props, ref) => {
63
+ const { value, onChange, accept, maxSize, onReject, label = 'Choose a file', hint, replaceLabel = 'Replace', removeLabel = 'Remove the file', formatSize = formatFileSize, disabled = false, overrides } = props, nativeProps = __rest(props, ["value", "onChange", "accept", "maxSize", "onReject", "label", "hint", "replaceLabel", "removeLabel", "formatSize", "disabled", "overrides"]);
64
+ const AreaComponent = (overrides === null || overrides === void 0 ? void 0 : overrides.Area) || Area;
65
+ const inputRef = React.useRef(null);
66
+ // dragenter/dragleave fire on every child: the counter keeps the highlight steady
67
+ const dragDepthRef = React.useRef(0);
68
+ const [isDragActive, setDragActive] = React.useState(false);
69
+ const take = (file) => {
70
+ if (!file) {
71
+ return;
72
+ }
73
+ if (!isFileAccepted(file, accept)) {
74
+ onReject === null || onReject === void 0 ? void 0 : onReject(file, 'type');
75
+ return;
76
+ }
77
+ if (typeof maxSize === 'number' && file.size > maxSize) {
78
+ onReject === null || onReject === void 0 ? void 0 : onReject(file, 'size');
79
+ return;
80
+ }
81
+ onChange(file);
82
+ };
83
+ const choose = () => {
84
+ var _a;
85
+ if (!disabled) {
86
+ (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.click();
87
+ }
88
+ };
89
+ const dropHandlers = disabled
90
+ ? {}
91
+ : {
92
+ onDragEnter: (event) => {
93
+ event.preventDefault();
94
+ dragDepthRef.current += 1;
95
+ setDragActive(true);
96
+ },
97
+ onDragOver: (event) => {
98
+ event.preventDefault();
99
+ },
100
+ onDragLeave: () => {
101
+ dragDepthRef.current = Math.max(0, dragDepthRef.current - 1);
102
+ if (dragDepthRef.current === 0) {
103
+ setDragActive(false);
104
+ }
105
+ },
106
+ onDrop: (event) => {
107
+ var _a;
108
+ event.preventDefault();
109
+ dragDepthRef.current = 0;
110
+ setDragActive(false);
111
+ take((_a = event.dataTransfer.files) === null || _a === void 0 ? void 0 : _a[0]);
112
+ },
113
+ };
114
+ const input = (React.createElement("input", { hidden: true, ref: inputRef, type: "file", accept: accept, disabled: disabled,
115
+ // the input is inside the area: its click must not reach the area and open the dialog again
116
+ onClick: event => event.stopPropagation(), onChange: event => {
117
+ var _a;
118
+ const file = (_a = event.currentTarget.files) === null || _a === void 0 ? void 0 : _a[0];
119
+ // the same file can be chosen again after the removal
120
+ event.currentTarget.value = '';
121
+ take(file);
122
+ } }));
123
+ if (value) {
124
+ return (React.createElement(AreaComponent, Object.assign({}, nativeProps, dropHandlers, { active: isDragActive, filled: true, disabled: disabled, ref: ref }),
125
+ input,
126
+ React.createElement(Icon, null,
127
+ React.createElement(FileIcon, null)),
128
+ React.createElement(FileText, null,
129
+ React.createElement(FileName, { title: value.name }, value.name),
130
+ React.createElement(Hint, null, formatSize(value.size))),
131
+ React.createElement(Button, { type: "button", variant: "plain", disabled: disabled, onClick: choose }, replaceLabel),
132
+ React.createElement(Button, { type: "button", variant: "plain", color: "error", iconOnly: true, disabled: disabled, title: removeLabel, "aria-label": removeLabel, onClick: () => onChange(null) },
133
+ React.createElement(TrashIcon, null))));
134
+ }
135
+ return (React.createElement(AreaComponent, Object.assign({ role: "button", tabIndex: disabled ? -1 : 0, "aria-disabled": disabled || undefined }, nativeProps, dropHandlers, { active: isDragActive, filled: false, disabled: disabled, onClick: choose, onKeyDown: event => {
136
+ if (event.key === 'Enter' || event.key === ' ') {
137
+ event.preventDefault();
138
+ choose();
139
+ }
140
+ }, ref: ref }),
141
+ input,
142
+ React.createElement(Icon, null,
143
+ React.createElement(UploadIcon, null)),
144
+ React.createElement(Label, null, label),
145
+ hint && React.createElement(Hint, null, hint)));
146
+ };
147
+ export * from './FileDropzoneArea';
148
+ export default React.forwardRef(FileDropzone);