@ultraviolet/ui 1.17.0 → 1.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1769,6 +1769,8 @@ type PopupProps = {
1769
1769
  tabIndex?: number;
1770
1770
  onKeyDown?: KeyboardEventHandler;
1771
1771
  'aria-haspopup'?: HTMLAttributes<HTMLDivElement>['aria-haspopup'];
1772
+ hideOnClickOutside?: boolean;
1773
+ needDebounce?: boolean;
1772
1774
  };
1773
1775
  declare const Popup: react.ForwardRefExoticComponent<PopupProps & react.RefAttributes<HTMLDivElement>>;
1774
1776
 
@@ -1975,6 +1977,10 @@ declare const variants$1: {
1975
1977
  readonly slider: ({ length }: {
1976
1978
  length?: number | undefined;
1977
1979
  }) => _emotion_react_jsx_runtime.JSX.Element;
1980
+ readonly square: _emotion_styled.StyledComponent<{
1981
+ theme?: _emotion_react.Theme | undefined;
1982
+ as?: react.ElementType<any> | undefined;
1983
+ }, react.DetailedHTMLProps<react.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {}>;
1978
1984
  };
1979
1985
  type SkeletonVariant = keyof typeof variants$1;
1980
1986
  type SkeletonProps = {
@@ -41,10 +41,10 @@ const CheckboxIconContainer = _ref4 => {
41
41
  const theme = useTheme();
42
42
  return jsxs("g", {
43
43
  children: [jsx(InnerCheckbox, {
44
- x: "2",
45
- y: "2",
46
- width: "20",
47
- height: "20",
44
+ x: "4",
45
+ y: "4",
46
+ width: "16",
47
+ height: "16",
48
48
  rx: theme.radii.small,
49
49
  strokeWidth: "2"
50
50
  }), children]
@@ -129,11 +129,11 @@ const CheckboxInput = /*#__PURE__*/_styled('input', {
129
129
  theme
130
130
  } = _ref18;
131
131
  return theme.colors.danger.background;
132
- }, ";outline:2px solid ", _ref19 => {
132
+ }, ";outline:1px solid ", _ref19 => {
133
133
  let {
134
134
  theme
135
135
  } = _ref19;
136
- return theme.colors.primary.backgroundHover;
136
+ return theme.shadows.focusPrimary;
137
137
  }, ";", InnerCheckbox, "{stroke:", _ref20 => {
138
138
  let {
139
139
  theme
@@ -154,11 +154,11 @@ const CheckboxInput = /*#__PURE__*/_styled('input', {
154
154
  theme
155
155
  } = _ref23;
156
156
  return theme.colors.danger.background;
157
- }, ";outline:2px solid ", _ref24 => {
157
+ }, ";outline:1px solid ", _ref24 => {
158
158
  let {
159
159
  theme
160
160
  } = _ref24;
161
- return theme.colors.danger.backgroundHover;
161
+ return theme.shadows.focusDanger;
162
162
  }, ";", InnerCheckbox, "{stroke:", _ref25 => {
163
163
  let {
164
164
  theme
@@ -445,12 +445,15 @@ const Checkbox = /*#__PURE__*/forwardRef((_ref64, ref) => {
445
445
  }), !progress ? jsx(StyledIcon, {
446
446
  size: size,
447
447
  viewBox: "0 0 24 24",
448
+ fill: "none",
448
449
  children: jsx(CheckboxIconContainer, {
449
450
  children: state !== 'indeterminate' ? jsx("path", {
450
451
  fillRule: "evenodd",
451
452
  clipRule: "evenodd",
452
- width: 14,
453
- height: 14,
453
+ width: 12,
454
+ height: 9,
455
+ x: "5",
456
+ y: "4",
454
457
  d: "M15.6678 5.26709C16.0849 5.6463 16.113 6.28907 15.7307 6.70276L9.29172 13.6705C9.10291 13.8748 8.83818 13.9937 8.55884 13.9998C8.2795 14.0058 8.0098 13.8984 7.81223 13.7024L4.30004 10.2185C3.89999 9.82169 3.89999 9.17831 4.30004 8.78149C4.70009 8.38467 5.34869 8.38467 5.74874 8.78149L8.50441 11.5149L14.2205 5.32951C14.6028 4.91583 15.2508 4.88788 15.6678 5.26709Z",
455
458
  fill: "white"
456
459
  }) : jsx(CheckMixedMark, {
@@ -92,6 +92,8 @@ const FwdMenu = /*#__PURE__*/forwardRef((_ref7, ref) => {
92
92
  ref: disclosureRef
93
93
  });
94
94
  return jsx(StyledPopup, {
95
+ needDebounce: false,
96
+ hideOnClickOutside: true,
95
97
  "aria-label": ariaLabel,
96
98
  className: className,
97
99
  visible: isVisible,
@@ -94,33 +94,12 @@ const Dialog = _ref9 => {
94
94
  onCloseRef.current = onClose;
95
95
  }, [onClose]);
96
96
 
97
- // Handle hide on esc press
97
+ // On open focus the modal
98
98
  useEffect(() => {
99
- const handleEscPress = event => {
100
- if (event.key === 'Escape' && hideOnEsc) {
101
- event.preventDefault();
102
- event.stopPropagation();
103
- onCloseRef.current();
104
- }
105
- };
106
99
  if (open) {
107
100
  dialogRef.current?.focus();
108
- document.body.addEventListener('keyup', handleEscPress, {
109
- capture: true
110
- });
111
- document.body.addEventListener('keydown', handleEscPress, {
112
- capture: true
113
- });
114
101
  }
115
- return () => {
116
- document.body.removeEventListener('keyup', handleEscPress, {
117
- capture: true
118
- });
119
- document.body.removeEventListener('keydown', handleEscPress, {
120
- capture: true
121
- });
122
- };
123
- }, [open, onCloseRef, hideOnEsc]);
102
+ }, [open]);
124
103
 
125
104
  // Handle body scroll
126
105
  useEffect(() => {
@@ -143,10 +122,23 @@ const Dialog = _ref9 => {
143
122
  event.stopPropagation();
144
123
  }, []);
145
124
 
146
- // Stop key up : used when having inputs in modals
147
- const stopKeyUp = useCallback(event => {
125
+ // handle key up : used when having inputs in modals - useful for hideOnEsc
126
+ const handleKeyUp = useCallback(event => {
148
127
  event.stopPropagation();
149
- }, []);
128
+ if (event.key === 'Escape' && hideOnEsc) {
129
+ event.preventDefault();
130
+ onCloseRef.current();
131
+ }
132
+ }, [hideOnEsc]);
133
+ const handleClose = useCallback(event => {
134
+ event.stopPropagation();
135
+ if (hideOnClickOutside) {
136
+ onCloseRef.current();
137
+ } else {
138
+ // Because overlay is not focusable we can't handle hideOnEsc properly
139
+ dialogRef.current?.focus();
140
+ }
141
+ }, [hideOnClickOutside]);
150
142
 
151
143
  // Enable focus trap inside the modal
152
144
  const handleFocusTrap = useCallback(event => {
@@ -185,14 +177,14 @@ const Dialog = _ref9 => {
185
177
  };
186
178
  return /*#__PURE__*/createPortal(jsx(StyledBackdrop, {
187
179
  "data-open": open,
188
- onClick: hideOnClickOutside ? onClose : undefined,
180
+ onClick: handleClose,
189
181
  className: backdropClassName,
190
182
  css: backdropCss,
191
183
  "data-testid": dataTestId ? `${dataTestId}-backdrop` : undefined,
192
184
  onFocus: stopFocus,
193
185
  children: jsx(StyledDialog, {
194
186
  css: dialogCss,
195
- onKeyUp: stopKeyUp,
187
+ onKeyUp: handleKeyUp,
196
188
  onKeyDown: handleFocusTrap,
197
189
  className: className,
198
190
  id: id,
@@ -118,17 +118,6 @@ const Popover = _ref6 => {
118
118
  useEffect(() => {
119
119
  setLocalVisible(visible);
120
120
  }, [visible]);
121
- const handleClickOutside = useCallback(event => {
122
- if (ref.current && !ref.current.contains(event.target)) {
123
- onClose?.();
124
- }
125
- }, [onClose]);
126
- useEffect(() => {
127
- document.addEventListener('click', handleClickOutside, true);
128
- return () => {
129
- document.removeEventListener('click', handleClickOutside, true);
130
- };
131
- }, [handleClickOutside]);
132
121
 
133
122
  // When space key is pressed we show the popover
134
123
  const onKeyDownSpace = useCallback(event => {
@@ -146,6 +135,8 @@ const Popover = _ref6 => {
146
135
  innerRef.current?.focus();
147
136
  }, [onClose]);
148
137
  return jsx(StyledPopup, {
138
+ hideOnClickOutside: true,
139
+ needDebounce: false,
149
140
  visible: localVisible,
150
141
  placement: placement,
151
142
  text: jsx(ContentWrapper, {
@@ -0,0 +1,12 @@
1
+ import _styled from '@emotion/styled/base';
2
+
3
+ const Square = /*#__PURE__*/_styled("div", {
4
+ target: "e1uz28830"
5
+ })("height:100%;width:100%;max-width:100%;background-color:", _ref => {
6
+ let {
7
+ theme
8
+ } = _ref;
9
+ return theme.colors.neutral.borderWeak;
10
+ }, ";");
11
+
12
+ export { Square };
@@ -7,6 +7,7 @@ import { Donut } from './Donut.js';
7
7
  import { Line } from './Line.js';
8
8
  import { List } from './List.js';
9
9
  import { Slider } from './Slider.js';
10
+ import { Square } from './Square.js';
10
11
  import { jsxs, jsx } from '@emotion/react/jsx-runtime';
11
12
 
12
13
  function _EMOTION_STRINGIFIED_CSS_ERROR__() { return "You have tried to stringify object returned from `css` function. It isn't supposed to be used directly (e.g. as value of the `className` prop), but rather handed to emotion so it can handle it (e.g. as value of `css` prop)."; }
@@ -21,11 +22,11 @@ const shineAnimation = keyframes`
21
22
  const StyledContainer = /*#__PURE__*/_styled("div", {
22
23
  target: "e183x2r81"
23
24
  })(process.env.NODE_ENV === "production" ? {
24
- name: "po0r11",
25
- styles: "position:relative;display:block;width:100%;overflow:hidden;cursor:progress"
25
+ name: "158ltsb",
26
+ styles: "position:relative;width:100%;overflow:hidden;cursor:progress;display:flex;flex-flow:column;height:100%"
26
27
  } : {
27
- name: "po0r11",
28
- styles: "position:relative;display:block;width:100%;overflow:hidden;cursor:progress",
28
+ name: "158ltsb",
29
+ styles: "position:relative;width:100%;overflow:hidden;cursor:progress;display:flex;flex-flow:column;height:100%",
29
30
  toString: _EMOTION_STRINGIFIED_CSS_ERROR__
30
31
  });
31
32
  const StyledDiv = /*#__PURE__*/_styled("div", {
@@ -63,7 +64,8 @@ const variants = {
63
64
  donut: Donut,
64
65
  line: Line,
65
66
  list: List,
66
- slider: Slider
67
+ slider: Slider,
68
+ square: Square
67
69
  };
68
70
  /**
69
71
  * Skeleton component is used to indicate that the data is loading.
@@ -7,7 +7,7 @@ import { jsx, Fragment, jsxs } from '@emotion/react/jsx-runtime';
7
7
 
8
8
  function _EMOTION_STRINGIFIED_CSS_ERROR__() { return "You have tried to stringify object returned from `css` function. It isn't supposed to be used directly (e.g. as value of the `className` prop), but rather handed to emotion so it can handle it (e.g. as value of `css` prop)."; }
9
9
  const ANIMATION_DURATION = 230; // in ms
10
-
10
+ const DEBOUNCE_DURATION = 200;
11
11
  function noop() {}
12
12
  const animation = positions => keyframes`
13
13
  0% {
@@ -121,7 +121,9 @@ const Popup = /*#__PURE__*/forwardRef((_ref13, tooltipRef) => {
121
121
  onClose,
122
122
  tabIndex = 0,
123
123
  onKeyDown,
124
- 'aria-haspopup': ariaHasPopup
124
+ 'aria-haspopup': ariaHasPopup,
125
+ hideOnClickOutside = false,
126
+ needDebounce = true
125
127
  } = _ref13;
126
128
  const childrenRef = useRef(null);
127
129
  useImperativeHandle(innerRef, () => childrenRef.current);
@@ -176,8 +178,8 @@ const Popup = /*#__PURE__*/forwardRef((_ref13, tooltipRef) => {
176
178
  unmountTooltip();
177
179
  onClose?.();
178
180
  }, ANIMATION_DURATION);
179
- }, 200);
180
- }, [onClose, unmountTooltip]);
181
+ }, needDebounce ? DEBOUNCE_DURATION : 0);
182
+ }, [needDebounce, onClose, unmountTooltip]);
181
183
 
182
184
  /**
183
185
  * When mouse hover or stop hovering children this function display or hide tooltip. A timeout is set to allow animation
@@ -244,7 +246,7 @@ const Popup = /*#__PURE__*/forwardRef((_ref13, tooltipRef) => {
244
246
  }
245
247
  }, [unmountTooltip]);
246
248
 
247
- // Handle hide on esc press
249
+ // Handle hide on esc press and hide on click outside
248
250
  useEffect(() => {
249
251
  const handleEscPress = event => {
250
252
  if (event.key === 'Escape') {
@@ -253,23 +255,26 @@ const Popup = /*#__PURE__*/forwardRef((_ref13, tooltipRef) => {
253
255
  hideTooltip();
254
256
  }
255
257
  };
258
+ const handleClickOutside = event => {
259
+ const tooltipCurrent = innerTooltipRef.current;
260
+ const childrenCurrent = childrenRef.current;
261
+ if (tooltipCurrent && hideOnClickOutside) {
262
+ if (event.target && event.target !== tooltipCurrent && event.target !== childrenCurrent && !childrenCurrent?.contains(event.target) && !tooltipCurrent.contains(event.target)) {
263
+ event.preventDefault();
264
+ event.stopPropagation();
265
+ hideTooltip();
266
+ }
267
+ }
268
+ };
256
269
  if (visibleInDom) {
257
- document.body.addEventListener('keyup', handleEscPress, {
258
- capture: true
259
- });
260
- document.body.addEventListener('keydown', handleEscPress, {
261
- capture: true
262
- });
270
+ document.body.addEventListener('keyup', handleEscPress);
271
+ document.body.addEventListener('click', handleClickOutside);
263
272
  }
264
273
  return () => {
265
- document.body.removeEventListener('keyup', handleEscPress, {
266
- capture: true
267
- });
268
- document.body.addEventListener('keydown', handleEscPress, {
269
- capture: true
270
- });
274
+ document.body.removeEventListener('keyup', handleEscPress);
275
+ document.body.removeEventListener('click', handleClickOutside);
271
276
  };
272
- }, [hideTooltip, onClose, unmountTooltip, visibleInDom]);
277
+ }, [hideTooltip, visibleInDom, innerTooltipRef, childrenRef, hideOnClickOutside]);
273
278
 
274
279
  /**
275
280
  * Will render children conditionally if children is a function or not.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ultraviolet/ui",
3
- "version": "1.17.0",
3
+ "version": "1.18.0",
4
4
  "description": "Ultraviolet UI",
5
5
  "homepage": "https://github.com/scaleway/ultraviolet#readme",
6
6
  "repository": {
@@ -39,13 +39,13 @@
39
39
  "react-dom": "18.2.0"
40
40
  },
41
41
  "devDependencies": {
42
- "@babel/core": "7.22.20",
42
+ "@babel/core": "7.23.0",
43
43
  "@emotion/babel-plugin": "11.11.0",
44
44
  "@emotion/react": "11.11.1",
45
45
  "@emotion/styled": "11.11.0",
46
- "@types/react": "18.2.22",
47
- "@types/react-datepicker": "4.15.0",
48
- "@types/react-dom": "18.2.7",
46
+ "@types/react": "18.2.25",
47
+ "@types/react-datepicker": "4.15.1",
48
+ "@types/react-dom": "18.2.10",
49
49
  "react": "18.2.0",
50
50
  "react-dom": "18.2.0"
51
51
  },
@@ -62,11 +62,11 @@
62
62
  "deepmerge": "4.3.1",
63
63
  "react-datepicker": "4.18.0",
64
64
  "react-flatten-children": "1.1.2",
65
- "react-select": "5.7.5",
65
+ "react-select": "5.7.7",
66
66
  "react-toastify": "9.1.3",
67
67
  "react-use-clipboard": "1.0.9",
68
68
  "reakit": "1.3.11",
69
69
  "@ultraviolet/themes": "1.2.1",
70
- "@ultraviolet/icons": "2.1.0"
70
+ "@ultraviolet/icons": "2.2.0"
71
71
  }
72
72
  }