@ultraviolet/ui 1.15.1 → 1.17.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/README.md CHANGED
@@ -20,13 +20,13 @@ You will also need to import fonts in your project by adding:
20
20
  ### Usage
21
21
 
22
22
  ```js
23
- import { theme, normalize, Button } from '@ultraviolet/ui'
24
- import { Global, css, ThemeProvider } from '@emotion/react'
23
+ import { Global, ThemeProvider, css } from '@emotion/react'
24
+ import { Button, normalize, theme } from '@ultraviolet/ui'
25
25
 
26
26
  const App = () => (
27
27
  <ThemeProvider theme={theme}>
28
28
  <Global styles={css`${normalize()}`} />
29
- <Button variant="primary" onClick={() => console.log('clicked')}>
29
+ <Button onClick={() => console.log('clicked')}>
30
30
  Click Me
31
31
  </Button>
32
32
  </ThemeProvider>
@@ -42,10 +42,10 @@ Example, in a `emotion.d.ts` file:
42
42
 
43
43
  ```ts
44
44
  import '@emotion/react'
45
- import type { SCWUITheme } from '@ultraviolet/ui'
45
+ import type { UltravioletUITheme } from '@ultraviolet/ui'
46
46
 
47
47
  declare module '@emotion/react' {
48
- export interface Theme extends SCWUITheme {}
48
+ export interface Theme extends UltravioletUITheme {}
49
49
  }
50
50
  ```
51
51
 
package/dist/index.d.ts CHANGED
@@ -37,7 +37,11 @@ type ActionBarProps = {
37
37
  declare const ActionBar: ({ children, role, rank, className, "data-testid": dataTestId, }: ActionBarProps) => react.ReactPortal;
38
38
 
39
39
  type ScreenSize = keyof typeof consoleLightTheme.screens;
40
+ /**
41
+ * @deprecated use UltravioletUITheme instead
42
+ */
40
43
  type SCWUITheme = typeof consoleLightTheme;
44
+ type UltravioletUITheme = typeof consoleLightTheme;
41
45
  declare const typography: {
42
46
  body: {
43
47
  fontFamily: string;
@@ -177,10 +181,10 @@ type RecursivePartial<T> = {
177
181
  };
178
182
  /**
179
183
  * Will extend theme with new theme properties
180
- * @param {SCWUITheme} baseTheme the theme you want to extend from, by default it is set to light theme
181
- * @param {RecursivePartial<SCWUITheme>} extendedTheme the properties of a new theme you want to apply from baseTheme
184
+ * @param {UltravioletUITheme} baseTheme the theme you want to extend from, by default it is set to light theme
185
+ * @param {RecursivePartial<UltravioletUITheme>} extendedTheme the properties of a new theme you want to apply from baseTheme
182
186
  */
183
- declare const extendTheme: (extendedTheme: RecursivePartial<SCWUITheme>) => {
187
+ declare const extendTheme: (extendedTheme: RecursivePartial<UltravioletUITheme>) => {
184
188
  colors: {
185
189
  danger: {
186
190
  background: string;
@@ -803,6 +807,9 @@ type CommonProps = {
803
807
  onClick?: MouseEventHandler<HTMLElement>;
804
808
  tooltip?: string;
805
809
  tabIndex?: ButtonHTMLAttributes<HTMLButtonElement>['tabIndex'];
810
+ onMouseDown?: MouseEventHandler<HTMLElement>;
811
+ onMouseUp?: MouseEventHandler<HTMLElement>;
812
+ onMouseOut?: MouseEventHandler<HTMLElement>;
806
813
  };
807
814
  type FinalProps = CommonProps & ({
808
815
  children: ReactNode;
@@ -1414,7 +1421,7 @@ type LoaderProps = {
1414
1421
  */
1415
1422
  declare const Loader: ({ percentage, text, size, strokeWidth, color, trailColor, active, label, }: LoaderProps) => _emotion_react_jsx_runtime.JSX.Element;
1416
1423
 
1417
- type DisclosureElement = ((popover: Partial<PopoverStateReturn>) => ReactElement<ButtonHTMLAttributes<HTMLButtonElement>>) | (ReactElement<ButtonHTMLAttributes<HTMLButtonElement>> & {
1424
+ type DisclosureElement$1 = ((popover: Partial<PopoverStateReturn>) => ReactElement<ButtonHTMLAttributes<HTMLButtonElement>>) | (ReactElement<ButtonHTMLAttributes<HTMLButtonElement>> & {
1418
1425
  ref?: Ref<HTMLButtonElement>;
1419
1426
  });
1420
1427
  declare const arrowPlacementStyles: {
@@ -1426,13 +1433,13 @@ declare const arrowPlacementStyles: {
1426
1433
  readonly 'top-start': (theme: Theme) => _emotion_react.SerializedStyles;
1427
1434
  };
1428
1435
  type ArrowPlacement = keyof typeof arrowPlacementStyles;
1429
- type MenuProps = {
1436
+ type MenuProps$1 = {
1430
1437
  ariaLabel?: string;
1431
1438
  id?: string;
1432
1439
  placement?: ArrowPlacement;
1433
1440
  children?: ((props: PopoverStateReturn) => ReactNode) | ReactNode;
1434
1441
  className?: string;
1435
- disclosure: DisclosureElement;
1442
+ disclosure: DisclosureElement$1;
1436
1443
  hasArrow?: boolean;
1437
1444
  visible?: boolean;
1438
1445
  'data-testid'?: string;
@@ -1442,8 +1449,9 @@ type MenuProps = {
1442
1449
  * A menu is usually opened, or made visible, by activating a menu button, choosing an item in a menu that opens a
1443
1450
  * sub menu, or by invoking a command, such as `Shift + F10` on Windows, that opens a context specific menu.
1444
1451
  * When a user activates a choice in a menu, the menu usually closes unless the choice opened a submenu.
1452
+ * @deprecated use MenuV2 component instead
1445
1453
  */
1446
- declare const Menu: react.ForwardRefExoticComponent<MenuProps & react.RefAttributes<HTMLButtonElement>> & {
1454
+ declare const Menu: react.ForwardRefExoticComponent<MenuProps$1 & react.RefAttributes<HTMLButtonElement>> & {
1447
1455
  Item: react.ForwardRefExoticComponent<{
1448
1456
  href?: string | undefined;
1449
1457
  disabled?: boolean | undefined;
@@ -1722,7 +1730,7 @@ declare const PieChart: ({ height, width, data, emptyLegend, content, withLegend
1722
1730
 
1723
1731
  type PopupPlacement = 'top' | 'right' | 'bottom' | 'left' | 'auto';
1724
1732
 
1725
- type TooltipProps$1 = {
1733
+ type PopupProps = {
1726
1734
  /**
1727
1735
  * Id is automatically generated if not set. It is used for associating tooltip wrapper with tooltip portal.
1728
1736
  */
@@ -1758,10 +1766,11 @@ type TooltipProps$1 = {
1758
1766
  'data-testid'?: string;
1759
1767
  hasArrow?: boolean;
1760
1768
  onClose?: () => void;
1769
+ tabIndex?: number;
1761
1770
  onKeyDown?: KeyboardEventHandler;
1762
1771
  'aria-haspopup'?: HTMLAttributes<HTMLDivElement>['aria-haspopup'];
1763
1772
  };
1764
- declare const Popup: react.ForwardRefExoticComponent<TooltipProps$1 & react.RefAttributes<HTMLDivElement>>;
1773
+ declare const Popup: react.ForwardRefExoticComponent<PopupProps & react.RefAttributes<HTMLDivElement>>;
1765
1774
 
1766
1775
  type SentimentType = 'neutral' | 'primary';
1767
1776
  declare const SIZES_WIDTH: {
@@ -1825,7 +1834,7 @@ type RowProps = {
1825
1834
  'data-testid'?: string;
1826
1835
  children: ReactNode;
1827
1836
  templateColumns: string;
1828
- gap?: keyof SCWUITheme['space'] | number;
1837
+ gap?: keyof UltravioletUITheme['space'] | number;
1829
1838
  alignItems?: CSSProperties['alignItems'];
1830
1839
  justifyContent?: CSSProperties['justifyContent'];
1831
1840
  };
@@ -2002,7 +2011,7 @@ type SnippetProps = {
2002
2011
  declare const Snippet: ({ children, copyText, copiedText, showText, hideText, prefix, className, "data-testid": dataTestId, }: SnippetProps) => _emotion_react_jsx_runtime.JSX.Element;
2003
2012
 
2004
2013
  type StackProps = {
2005
- gap?: keyof SCWUITheme['space'] | number;
2014
+ gap?: keyof UltravioletUITheme['space'] | number;
2006
2015
  direction?: 'row' | 'column';
2007
2016
  alignItems?: CSSProperties['alignItems'];
2008
2017
  justifyContent?: CSSProperties['justifyContent'];
@@ -2592,6 +2601,43 @@ declare const RadioGroup: {
2592
2601
  Radio: ({ onFocus, onBlur, disabled, error, name, value, label, helper, className, autoFocus, onKeyDown, "data-testid": dataTestId, }: RadioGroupRadioProps) => _emotion_react_jsx_runtime.JSX.Element;
2593
2602
  };
2594
2603
 
2604
+ type DisclosureProps = {
2605
+ visible: boolean;
2606
+ };
2607
+ type DisclosureElement = ((disclosure: DisclosureProps) => ReactElement<ButtonHTMLAttributes<HTMLButtonElement>>) | (ReactElement<ButtonHTMLAttributes<HTMLButtonElement>> & {
2608
+ ref?: Ref<HTMLButtonElement>;
2609
+ });
2610
+ type MenuProps = {
2611
+ id?: string;
2612
+ ariaLabel?: string;
2613
+ placement?: ComponentProps<typeof Popup>['placement'];
2614
+ children?: ReactNode;
2615
+ className?: string;
2616
+ disclosure: DisclosureElement;
2617
+ hasArrow?: boolean;
2618
+ visible?: boolean;
2619
+ 'data-testid'?: string;
2620
+ };
2621
+ /**
2622
+ * A menu is a widget that offers a list of choices to the user, such as a set of actions or functions.
2623
+ * A menu is usually opened, or made visible, by activating a menu button, choosing an item in a menu that opens a
2624
+ * sub menu, or by invoking a command, such as `Shift + F10` on Windows, that opens a context specific menu.
2625
+ * When a user activates a choice in a menu, the menu usually closes unless the choice opened a submenu.
2626
+ */
2627
+ declare const MenuV2: react.ForwardRefExoticComponent<MenuProps & react.RefAttributes<HTMLButtonElement>> & {
2628
+ Item: react.ForwardRefExoticComponent<{
2629
+ href?: string | undefined;
2630
+ disabled?: boolean | undefined;
2631
+ tooltip?: string | undefined;
2632
+ className?: string | undefined;
2633
+ children: ReactNode;
2634
+ onClick?: react.MouseEventHandler<HTMLElement> | undefined;
2635
+ borderless?: boolean | undefined;
2636
+ sentiment?: ("neutral" | "danger") | undefined;
2637
+ 'data-testid'?: string | undefined;
2638
+ } & react.RefAttributes<HTMLElement>>;
2639
+ };
2640
+
2595
2641
  declare const getUUID: (prefix?: string) => string;
2596
2642
 
2597
2643
  declare const bounce: _emotion_react.Keyframes;
@@ -2635,4 +2681,4 @@ declare const down: (size: ScreenSize, rules: string) => string;
2635
2681
 
2636
2682
  declare const normalize: () => string;
2637
2683
 
2638
- export { ActionBar, Alert, Avatar, Badge, Banner, BarChart, BarStack, Breadcrumbs, Breakpoint, Bullet, Button, Card, Carousel, Checkbox, CheckboxGroup, CheckboxGroupCheckbox, CopyButton, DateInput, EmptyState, Expandable, LineChart, Link, List, Loader, Menu, Meter, Modal, Notice, NumberInput, Pagination, PasswordCheck, PasswordStrengthMeter, PieChart, Popover, ProgressBar, Radio, RadioGroup, Row, type SCWUITheme, SelectInput, SelectableCard, Separator, Skeleton, Snippet, Stack, Status, StepList, Stepper, SwitchButton, Table, Tabs, Tag, TagInput, TagList, Text, TextInput, TimeInput, ToastContainer, Toggle, ToggleGroup, Tooltip, VerificationCode, bounce, down, extendTheme, fadeIn, fadeOut, flash, getUUID, normalize, ping, pulse, quickScaleDown, scaleBack, scaleDown, scaleForward, scaleUp, sketchIn, sketchOut, slideDownLarge, slideFromBottom, slideFromLeft, slideFromRight, slideFromTop, slideToBottom, slideToLeft, slideToRight, slideToTop, slideUpLarge, toast, unfoldIn, unfoldOut, up, zoomIn, zoomOut };
2684
+ export { ActionBar, Alert, Avatar, Badge, Banner, BarChart, BarStack, Breadcrumbs, Breakpoint, Bullet, Button, Card, Carousel, Checkbox, CheckboxGroup, CheckboxGroupCheckbox, CopyButton, DateInput, EmptyState, Expandable, LineChart, Link, List, Loader, Menu, MenuV2, Meter, Modal, Notice, NumberInput, Pagination, PasswordCheck, PasswordStrengthMeter, PieChart, Popover, ProgressBar, Radio, RadioGroup, Row, type SCWUITheme, SelectInput, SelectableCard, Separator, Skeleton, Snippet, Stack, Status, StepList, Stepper, SwitchButton, Table, Tabs, Tag, TagInput, TagList, Text, TextInput, TimeInput, ToastContainer, Toggle, ToggleGroup, Tooltip, type UltravioletUITheme, VerificationCode, bounce, down, extendTheme, fadeIn, fadeOut, flash, getUUID, normalize, ping, pulse, quickScaleDown, scaleBack, scaleDown, scaleForward, scaleUp, sketchIn, sketchOut, slideDownLarge, slideFromBottom, slideFromLeft, slideFromRight, slideFromTop, slideToBottom, slideToLeft, slideToRight, slideToTop, slideUpLarge, toast, unfoldIn, unfoldOut, up, zoomIn, zoomOut };
@@ -115,7 +115,7 @@ const Alert = _ref6 => {
115
115
  children: [title ? jsx(Text, {
116
116
  variant: "bodyStronger",
117
117
  as: "span",
118
- color: sentiment,
118
+ sentiment: sentiment,
119
119
  children: title
120
120
  }) : null, typeof children === 'string' ? jsx(Text, {
121
121
  variant: "body",
@@ -7,15 +7,6 @@ import capitalize from '../../utils/capitalize.js';
7
7
  import { Text } from '../Text/index.js';
8
8
  import { jsxs, jsx } from '@emotion/react/jsx-runtime';
9
9
 
10
- const StyledText = /*#__PURE__*/_styled(Text, {
11
- target: "ej33bna1"
12
- })("text-transform:uppercase;font-size:", _ref => {
13
- let {
14
- fontSize
15
- } = _ref;
16
- return fontSize;
17
- }, "px;color:inherit;");
18
-
19
10
  // TODO: remove when typography has been created
20
11
  const TEXT_SIZES = {
21
12
  large: 14,
@@ -35,11 +26,11 @@ const PROMINENCES = {
35
26
  /**
36
27
  * Generate all styles available for badge based on prominence and sentiments
37
28
  */
38
- const generateStyles = _ref2 => {
29
+ const generateStyles = _ref => {
39
30
  let {
40
31
  prominence,
41
32
  theme
42
- } = _ref2;
33
+ } = _ref;
43
34
  const definedProminence = prominence === PROMINENCES.strong ? capitalize(PROMINENCES.strong) : '';
44
35
  const text = `text${definedProminence}`;
45
36
  const background = `background${definedProminence}`;
@@ -64,36 +55,41 @@ const generateStyles = _ref2 => {
64
55
  `
65
56
  };
66
57
  };
67
- const StyledSpan = /*#__PURE__*/_styled('span', {
68
- shouldForwardProp: prop => !['sentiment', 'size'].includes(prop),
58
+ const StyledSpan = /*#__PURE__*/_styled(Text, {
59
+ shouldForwardProp: prop => !['sentimentStyles', 'size', 'fontSize'].includes(prop),
69
60
  target: "ej33bna0"
70
- })("display:inline-flex;align-items:center;justify-content:center;white-space:nowrap;border-radius:", _ref3 => {
61
+ })("display:inline-flex;align-items:center;justify-content:center;white-space:nowrap;border-radius:", _ref2 => {
71
62
  let {
72
63
  theme
73
- } = _ref3;
64
+ } = _ref2;
74
65
  return theme.radii.xlarge;
75
- }, ";padding:0 ", _ref4 => {
66
+ }, ";padding:0 ", _ref3 => {
76
67
  let {
77
68
  theme,
78
69
  size
79
- } = _ref4;
70
+ } = _ref3;
80
71
  return size === SIZES.small ? theme.space['1'] : theme.space['2'];
81
- }, ";gap:", _ref5 => {
72
+ }, ";gap:", _ref4 => {
82
73
  let {
83
74
  theme,
84
75
  size
85
- } = _ref5;
76
+ } = _ref4;
86
77
  return size === SIZES.small ? theme.space['0.5'] : theme.space['1'];
87
- }, ";width:fit-content;height:", _ref6 => {
78
+ }, ";width:fit-content;height:", _ref5 => {
88
79
  let {
89
80
  size
90
- } = _ref6;
81
+ } = _ref5;
91
82
  return size;
92
- }, "px;", _ref7 => {
83
+ }, "px;text-transform:uppercase;font-size:", _ref6 => {
84
+ let {
85
+ fontSize
86
+ } = _ref6;
87
+ return fontSize;
88
+ }, "px;color:inherit;", _ref7 => {
93
89
  let {
94
- sentiment
90
+ sentimentStyles
95
91
  } = _ref7;
96
- return sentiment;
92
+ return sentimentStyles;
97
93
  }, ";");
98
94
  /**
99
95
  * Badge component is used to display a status or a label in a small container.
@@ -121,22 +117,19 @@ const Badge = _ref8 => {
121
117
  }), [prominence, theme]);
122
118
  const sizeValue = SIZES[size];
123
119
  return jsxs(StyledSpan, {
124
- role: "status",
125
120
  "aria-label": ariaLabel,
126
- sentiment: disabled ? generatedStyles['disabled'] : generatedStyles[sentiment],
121
+ sentimentStyles: disabled ? generatedStyles['disabled'] : generatedStyles[sentiment],
127
122
  size: sizeValue,
123
+ variant: "bodyStrong",
124
+ as: "span",
125
+ fontSize: TEXT_SIZES[size],
126
+ prominence: disabled ? 'weak' : 'default',
128
127
  className: className,
129
128
  "data-testid": dataTestId,
130
129
  children: [icon && sizeValue !== SIZES.small ? jsx(Icon, {
131
130
  name: icon,
132
131
  size: 16
133
- }) : null, jsx(StyledText, {
134
- variant: "bodyStrong",
135
- as: "p",
136
- fontSize: TEXT_SIZES[size],
137
- prominence: disabled ? 'weak' : 'default',
138
- children: children
139
- })]
132
+ }) : null, children]
140
133
  });
141
134
  };
142
135
 
@@ -135,13 +135,13 @@ const Banner = _ref8 => {
135
135
  children: [jsx(Text, {
136
136
  as: "p",
137
137
  variant: size === 'medium' ? 'headingSmall' : 'bodyStronger',
138
- color: variant === 'promotional' && theme !== 'light' ? 'neutral' : 'primary',
138
+ sentiment: variant === 'promotional' && theme !== 'light' ? 'neutral' : 'primary',
139
139
  prominence: variant === 'intro' ? 'default' : 'strong',
140
140
  children: title
141
141
  }), jsx(Text, {
142
142
  as: "p",
143
143
  variant: "body",
144
- color: "neutral",
144
+ sentiment: "neutral",
145
145
  prominence: variant === 'intro' || variant === 'promotional' && theme !== 'light' ? 'default' : 'stronger',
146
146
  children: children
147
147
  })]
@@ -48,7 +48,7 @@ const BarChartToolTip = _ref5 => {
48
48
  children: [jsx(Text, {
49
49
  variant: "bodyStronger",
50
50
  as: "p",
51
- color: "primary",
51
+ sentiment: "primary",
52
52
  children: formattedValue
53
53
  }), jsx(Text, {
54
54
  variant: "bodySmall",
@@ -231,6 +231,9 @@ const Button = /*#__PURE__*/forwardRef((_ref10, ref) => {
231
231
  isLoading = false,
232
232
  children,
233
233
  onClick,
234
+ onMouseDown,
235
+ onMouseUp,
236
+ onMouseOut,
234
237
  name,
235
238
  'aria-label': ariaLabel,
236
239
  'aria-current': ariaCurrent,
@@ -289,6 +292,9 @@ const Button = /*#__PURE__*/forwardRef((_ref10, ref) => {
289
292
  iconOnly: !!icon && !children,
290
293
  tabIndex: tabIndex,
291
294
  autoFocus: autoFocus,
295
+ onMouseDown: onMouseDown,
296
+ onMouseUp: onMouseUp,
297
+ onMouseOut: onMouseOut,
292
298
  children: content
293
299
  })
294
300
  });
@@ -318,6 +324,9 @@ const Button = /*#__PURE__*/forwardRef((_ref10, ref) => {
318
324
  iconOnly: !!icon && !children,
319
325
  tabIndex: tabIndex,
320
326
  autoFocus: autoFocus,
327
+ onMouseDown: onMouseDown,
328
+ onMouseUp: onMouseUp,
329
+ onMouseOut: onMouseOut,
321
330
  children: content
322
331
  })
323
332
  });
@@ -480,12 +480,12 @@ const Checkbox = /*#__PURE__*/forwardRef((_ref64, ref) => {
480
480
  variant: "bodySmall",
481
481
  as: "p",
482
482
  prominence: "weak",
483
- color: "neutral",
483
+ sentiment: "neutral",
484
484
  children: helper
485
485
  }) : null, error ? jsx(ErrorText, {
486
486
  variant: "bodySmall",
487
487
  as: "p",
488
- color: "danger",
488
+ sentiment: "danger",
489
489
  children: error
490
490
  }) : null]
491
491
  })]
@@ -117,7 +117,7 @@ const CustomLegend = _ref3 => {
117
117
  children: [jsx(Text, {
118
118
  as: "span",
119
119
  variant: "bodySmall",
120
- color: "neutral",
120
+ sentiment: "neutral",
121
121
  children: row?.['label']
122
122
  }), jsx("div", {
123
123
  "data-testid": `label-${id}`,
@@ -40,13 +40,13 @@ const LineChartTooltip = _ref5 => {
40
40
  }), jsxs("div", {
41
41
  children: [jsx(Text, {
42
42
  variant: "bodyStronger",
43
- color: "neutral",
43
+ sentiment: "neutral",
44
44
  prominence: "stronger",
45
45
  as: "div",
46
46
  children: point.data.yFormatted
47
47
  }), jsx(Text, {
48
48
  variant: "bodySmall",
49
- color: "neutral",
49
+ sentiment: "neutral",
50
50
  prominence: "stronger",
51
51
  as: "div",
52
52
  children: point.data.xFormatted
@@ -119,7 +119,7 @@ const Link = /*#__PURE__*/forwardRef((_ref9, ref) => {
119
119
  const usedRef = ref ?? elementRef;
120
120
  const finalStringChildren = recursivelyGetChildrenString(children);
121
121
  useEffect(() => {
122
- if (oneLine && usedRef && usedRef.current) {
122
+ if (oneLine && usedRef?.current) {
123
123
  const {
124
124
  offsetWidth,
125
125
  scrollWidth
@@ -145,6 +145,7 @@ const FwdMenu = /*#__PURE__*/forwardRef((_ref9, ref) => {
145
145
  * A menu is usually opened, or made visible, by activating a menu button, choosing an item in a menu that opens a
146
146
  * sub menu, or by invoking a command, such as `Shift + F10` on Windows, that opens a context specific menu.
147
147
  * When a user activates a choice in a menu, the menu usually closes unless the choice opened a submenu.
148
+ * @deprecated use MenuV2 component instead
148
149
  */
149
150
  const Menu = /*#__PURE__*/Object.assign(FwdMenu, {
150
151
  Item
@@ -0,0 +1,122 @@
1
+ import _styled from '@emotion/styled/base';
2
+ import { forwardRef } from 'react';
3
+ import { Tooltip } from '../Tooltip/index.js';
4
+ import { jsx } from '@emotion/react/jsx-runtime';
5
+
6
+ const itemCoreStyle = _ref => {
7
+ let {
8
+ theme,
9
+ borderless,
10
+ sentiment,
11
+ disabled
12
+ } = _ref;
13
+ return `
14
+ display: inline-block;
15
+ font-size: ${theme.typography.bodySmall.fontSize};
16
+ line-height: ${theme.typography.bodySmall.lineHeight};
17
+ font-weight: inherit;
18
+ padding: ${`${theme.space['0.5']} ${theme.space['1']}`};
19
+ border: none;
20
+ ${borderless ? '' : `border-bottom: 1px solid ${theme.colors.neutral.border};`}
21
+ cursor: pointer;
22
+ min-width: 110px;
23
+
24
+ color: ${theme.colors[sentiment][disabled ? 'textDisabled' : 'text']};
25
+ svg {
26
+ fill: ${theme.colors[sentiment][disabled ? 'textDisabled' : 'text']};
27
+ }
28
+
29
+ ${disabled ? `
30
+ cursor: not-allowed;
31
+ ` : `
32
+ &:hover,
33
+ &:focus {
34
+ color: ${theme.colors[sentiment].textHover};
35
+ svg {
36
+ fill: ${theme.colors[sentiment].textHover};
37
+ }
38
+ }`}
39
+ `;
40
+ };
41
+ const StyledItem = /*#__PURE__*/_styled('button', {
42
+ shouldForwardProp: prop => !['borderless', 'sentiment'].includes(prop),
43
+ target: "ei26g5y1"
44
+ })(_ref2 => {
45
+ let {
46
+ theme,
47
+ borderless,
48
+ sentiment,
49
+ disabled
50
+ } = _ref2;
51
+ return itemCoreStyle({
52
+ theme,
53
+ borderless,
54
+ sentiment,
55
+ disabled
56
+ });
57
+ }, " background:none;");
58
+ const StyledLinkItem = /*#__PURE__*/_styled('a', {
59
+ shouldForwardProp: prop => !['borderless', 'sentiment'].includes(prop),
60
+ target: "ei26g5y0"
61
+ })(_ref3 => {
62
+ let {
63
+ theme,
64
+ borderless,
65
+ sentiment,
66
+ disabled
67
+ } = _ref3;
68
+ return itemCoreStyle({
69
+ theme,
70
+ borderless,
71
+ sentiment,
72
+ disabled
73
+ });
74
+ }, " text-decoration:none;&:focus{text-decoration:none;}");
75
+ const Item = /*#__PURE__*/forwardRef((_ref4, ref) => {
76
+ let {
77
+ borderless = false,
78
+ disabled = false,
79
+ onClick,
80
+ sentiment = 'neutral',
81
+ href,
82
+ children,
83
+ tooltip,
84
+ className,
85
+ 'data-testid': dataTestId
86
+ } = _ref4;
87
+ if (href && !disabled) {
88
+ return jsx(Tooltip, {
89
+ text: tooltip,
90
+ children: jsx(StyledLinkItem, {
91
+ borderless: true,
92
+ href: href,
93
+ ref: ref,
94
+ onClick: disabled ? undefined : onClick,
95
+ role: "menuitem",
96
+ disabled: disabled,
97
+ sentiment: sentiment,
98
+ className: className,
99
+ "data-testid": dataTestId,
100
+ children: children
101
+ })
102
+ });
103
+ }
104
+ return jsx(Tooltip, {
105
+ text: tooltip,
106
+ children: jsx(StyledItem, {
107
+ type: "button",
108
+ ref: ref,
109
+ role: "menuitem",
110
+ disabled: disabled,
111
+ onClick: onClick,
112
+ borderless: borderless,
113
+ sentiment: sentiment,
114
+ className: className,
115
+ "data-testid": dataTestId,
116
+ children: children
117
+ })
118
+ });
119
+ });
120
+ var Item$1 = Item;
121
+
122
+ export { Item$1 as default };
@@ -0,0 +1,126 @@
1
+ import _styled from '@emotion/styled/base';
2
+ import { forwardRef, useState, useRef, useId, isValidElement, useImperativeHandle, cloneElement } from 'react';
3
+ import { Stack } from '../Stack/index.js';
4
+ import Item from './Item.js';
5
+ import { jsx } from '@emotion/react/jsx-runtime';
6
+ import { Popup } from '../../internalComponents/Popup/index.js';
7
+
8
+ const StyledPopup = /*#__PURE__*/_styled(Popup, {
9
+ target: "e1jn11gg1"
10
+ })("background-color:", _ref => {
11
+ let {
12
+ theme
13
+ } = _ref;
14
+ return theme.colors.neutral.background;
15
+ }, ";box-shadow:", _ref2 => {
16
+ let {
17
+ theme
18
+ } = _ref2;
19
+ return theme.shadows.menu;
20
+ }, ";padding:0;&[data-has-arrow='true']{&::after{border-color:", _ref3 => {
21
+ let {
22
+ theme
23
+ } = _ref3;
24
+ return theme.colors.neutral.background;
25
+ }, " transparent transparent transparent;}}");
26
+ const MenuList = /*#__PURE__*/_styled(Stack, {
27
+ target: "e1jn11gg0"
28
+ })("&:after,&:before{border:solid transparent;border-width:9px;content:' ';height:0;width:0;position:absolute;pointer-events:none;}&:after{border-color:transparent;}&:before{border-color:transparent;}background-color:", _ref4 => {
29
+ let {
30
+ theme
31
+ } = _ref4;
32
+ return theme.colors.neutral.backgroundWeakElevated;
33
+ }, ";color:", _ref5 => {
34
+ let {
35
+ theme
36
+ } = _ref5;
37
+ return theme.colors.neutral.text;
38
+ }, ";border-radius:", _ref6 => {
39
+ let {
40
+ theme
41
+ } = _ref6;
42
+ return theme.radii.default;
43
+ }, ";position:relative;");
44
+ const FwdMenu = /*#__PURE__*/forwardRef((_ref7, ref) => {
45
+ let {
46
+ id,
47
+ ariaLabel = 'Menu',
48
+ children,
49
+ disclosure,
50
+ hasArrow = true,
51
+ placement = 'bottom',
52
+ visible = false,
53
+ className,
54
+ 'data-testid': dataTestId
55
+ } = _ref7;
56
+ const [isVisible, setIsVisible] = useState(visible);
57
+ const popupRef = useRef(null);
58
+ const disclosureRef = useRef(null);
59
+ const tempId = useId();
60
+ const finalId = `menu-${id ?? tempId}`;
61
+
62
+ // if you need dialog inside your component, use function, otherwise component is fine
63
+ const target = /*#__PURE__*/isValidElement(disclosure) ? disclosure : disclosure({
64
+ visible: isVisible
65
+ });
66
+ const innerRef = useRef(target);
67
+ useImperativeHandle(ref, () => innerRef.current);
68
+ const toggleVisible = () => {
69
+ setIsVisible(!isVisible);
70
+
71
+ // Focus the first item when the menu is opened
72
+ if (!isVisible) {
73
+ requestIdleCallback(() => {
74
+ // We have to wait for the popup to be inserted in the DOM
75
+ if (popupRef.current?.firstChild?.firstChild instanceof HTMLElement) {
76
+ popupRef.current.firstChild.firstChild.focus();
77
+ }
78
+ });
79
+ }
80
+ };
81
+ const onClose = () => {
82
+ setIsVisible(false);
83
+
84
+ // Focus the disclosure when the menu is closed
85
+ disclosureRef.current?.focus();
86
+ };
87
+ const finalDisclosure = /*#__PURE__*/cloneElement(target, {
88
+ onClick: toggleVisible,
89
+ 'aria-haspopup': 'dialog',
90
+ 'aria-expanded': isVisible,
91
+ // @ts-expect-error not sure how to fix this
92
+ ref: disclosureRef
93
+ });
94
+ return jsx(StyledPopup, {
95
+ "aria-label": ariaLabel,
96
+ className: className,
97
+ visible: isVisible,
98
+ placement: placement,
99
+ hasArrow: hasArrow,
100
+ "data-has-arrow": hasArrow,
101
+ role: "dialog",
102
+ id: finalId,
103
+ ref: popupRef,
104
+ onClose: onClose,
105
+ tabIndex: -1,
106
+ text: jsx(MenuList, {
107
+ "data-testid": dataTestId,
108
+ className: className,
109
+ role: "menu",
110
+ children: children
111
+ }),
112
+ children: finalDisclosure
113
+ });
114
+ });
115
+
116
+ /**
117
+ * A menu is a widget that offers a list of choices to the user, such as a set of actions or functions.
118
+ * A menu is usually opened, or made visible, by activating a menu button, choosing an item in a menu that opens a
119
+ * sub menu, or by invoking a command, such as `Shift + F10` on Windows, that opens a context specific menu.
120
+ * When a user activates a choice in a menu, the menu usually closes unless the choice opened a submenu.
121
+ */
122
+ const MenuV2 = /*#__PURE__*/Object.assign(FwdMenu, {
123
+ Item
124
+ });
125
+
126
+ export { MenuV2 };
@@ -56,7 +56,7 @@ const Modal = _ref3 => {
56
56
  } else {
57
57
  const promise = onBeforeClose?.();
58
58
  if (promise && 'catch' in promise) {
59
- promise.catch(undefined);
59
+ promise.catch(() => null);
60
60
  }
61
61
  setVisible(false);
62
62
  }
@@ -1,35 +1,39 @@
1
+ import _styled from '@emotion/styled/base';
1
2
  import { Icon } from '@ultraviolet/icons';
2
- import { Stack } from '../Stack/index.js';
3
3
  import { Text } from '../Text/index.js';
4
4
  import { jsxs, jsx } from '@emotion/react/jsx-runtime';
5
5
 
6
+ const StyledSpan = /*#__PURE__*/_styled(Text, {
7
+ target: "e19pqvs30"
8
+ })("display:flex;align-items:center;gap:", _ref => {
9
+ let {
10
+ theme
11
+ } = _ref;
12
+ return theme.space['1'];
13
+ }, ";");
14
+
6
15
  /**
7
16
  * A Notice is used to display a short message to the user.
8
17
  */
9
- const Notice = _ref => {
18
+ const Notice = _ref2 => {
10
19
  let {
11
20
  children,
12
21
  className,
13
22
  'data-testid': dataTestId
14
- } = _ref;
15
- return jsxs(Stack, {
16
- direction: "row",
17
- alignItems: "center",
18
- gap: 1,
23
+ } = _ref2;
24
+ return jsxs(StyledSpan, {
25
+ as: "span",
26
+ variant: "caption",
27
+ sentiment: "neutral",
28
+ prominence: "weak",
19
29
  "data-testid": dataTestId,
20
30
  className: className,
21
31
  children: [jsx(Icon, {
22
32
  name: "information-outline",
23
- size: 20,
33
+ size: 16,
24
34
  color: "neutral",
25
35
  prominence: "weak"
26
- }), typeof children === 'string' ? jsx(Text, {
27
- as: "p",
28
- variant: "caption",
29
- color: "neutral",
30
- prominence: "weak",
31
- children: children
32
- }) : children]
36
+ }), children]
33
37
  });
34
38
  };
35
39
 
@@ -359,7 +359,7 @@ const NumberInput = _ref21 => {
359
359
  }), typeof error === 'string' ? jsx(Text, {
360
360
  as: "span",
361
361
  variant: "bodySmall",
362
- color: "danger",
362
+ sentiment: "danger",
363
363
  prominence: "weak",
364
364
  children: error
365
365
  }) : null]
@@ -88,7 +88,7 @@ const PasswordStrengthMeter = _ref7 => {
88
88
  useEffect(() => {
89
89
  setBackgroundColor(strength[score].color);
90
90
  handleChange(score);
91
- getScore(password).then(s => setScore(s)).catch(null);
91
+ getScore(password).then(s => setScore(s)).catch(() => null);
92
92
  const toValue = (score + 1) / strength.length * 100;
93
93
  setWidth(`${toValue}%`);
94
94
  }, [getScore, handleChange, password, score, strength]);
@@ -3,7 +3,6 @@ import { HeaderCell } from './HeaderCell.js';
3
3
  import { useTableContext } from './TableContext.js';
4
4
  import { jsxs, jsx } from '@emotion/react/jsx-runtime';
5
5
 
6
- const SELECT_CHECKBOX_SIZE = 24;
7
6
  const HeaderRow = _ref => {
8
7
  let {
9
8
  children,
@@ -18,18 +17,17 @@ const HeaderRow = _ref => {
18
17
  const selectableRowCount = Object.keys(selectedRowIds).length;
19
18
  return jsxs("tr", {
20
19
  children: [hasSelectAllColumn ? jsx(HeaderCell, {
21
- width: `${SELECT_CHECKBOX_SIZE}px`,
20
+ width: "24px",
22
21
  children: jsx(Checkbox, {
23
22
  name: "table-select-all-checkbox",
24
23
  value: "all",
25
24
  "aria-label": "select all",
26
25
  checked: allRowSelectValue,
27
26
  onChange: allRowSelectValue === false ? selectAll : unselectAll,
28
- disabled: selectableRowCount === 0,
29
- size: SELECT_CHECKBOX_SIZE
27
+ disabled: selectableRowCount === 0
30
28
  })
31
29
  }) : null, children]
32
30
  });
33
31
  };
34
32
 
35
- export { HeaderRow, SELECT_CHECKBOX_SIZE };
33
+ export { HeaderRow };
@@ -3,7 +3,6 @@ import { useEffect } from 'react';
3
3
  import { Checkbox } from '../Checkbox/index.js';
4
4
  import { Tooltip } from '../Tooltip/index.js';
5
5
  import { Cell } from './Cell.js';
6
- import { SELECT_CHECKBOX_SIZE } from './HeaderRow.js';
7
6
  import { useTableContext } from './TableContext.js';
8
7
  import { jsxs, jsx } from '@emotion/react/jsx-runtime';
9
8
 
@@ -58,8 +57,7 @@ const Row = _ref2 => {
58
57
  selectRow(id);
59
58
  }
60
59
  },
61
- disabled: selectDisabled !== undefined,
62
- size: SELECT_CHECKBOX_SIZE
60
+ disabled: selectDisabled !== undefined
63
61
  })
64
62
  })
65
63
  })
@@ -82,7 +82,7 @@ const Text = _ref2 => {
82
82
  const elementRef = useRef(null);
83
83
  const finalStringChildren = recursivelyGetChildrenString(children);
84
84
  useEffect(() => {
85
- if (oneLine && elementRef && elementRef.current) {
85
+ if (oneLine && elementRef?.current) {
86
86
  const {
87
87
  offsetWidth,
88
88
  scrollWidth
@@ -149,7 +149,7 @@ const StyledNotice = /*#__PURE__*/_styled(Notice, {
149
149
  let {
150
150
  theme
151
151
  } = _ref13;
152
- return theme.space['1'];
152
+ return theme.space['0.5'];
153
153
  }, ";");
154
154
  const StyledInput = /*#__PURE__*/_styled('input', {
155
155
  shouldForwardProp: prop => !['as', 'error', 'fillAvailable', 'hasLabel', 'isPlaceholderVisible', 'multiline', 'resizable', 'inputSize', 'paddingRightFactor'].includes(prop),
@@ -50,34 +50,34 @@ const CloseButton = _ref3 => {
50
50
  };
51
51
  const Content = _ref4 => {
52
52
  let {
53
- variant,
53
+ sentiment,
54
54
  children
55
55
  } = _ref4;
56
56
  return jsxs(Stack, {
57
57
  gap: 2,
58
58
  direction: "row",
59
59
  children: [jsx(Icon, {
60
- name: TOAST_ICONS[variant],
60
+ name: TOAST_ICONS[sentiment],
61
61
  size: 24
62
62
  }), jsx(Text, {
63
63
  variant: "body",
64
64
  as: "span",
65
- color: variant,
65
+ sentiment: sentiment,
66
66
  children: children
67
67
  })]
68
68
  });
69
69
  };
70
70
  const toast = {
71
71
  error: (children, options) => toast$1.error(jsx(Content, {
72
- variant: "danger",
72
+ sentiment: "danger",
73
73
  children: children
74
74
  }), options),
75
75
  info: (children, options) => toast$1.info(jsx(Content, {
76
- variant: "info",
76
+ sentiment: "info",
77
77
  children: children
78
78
  }), options),
79
79
  success: (children, options) => toast$1.success(jsx(Content, {
80
- variant: "success",
80
+ sentiment: "success",
81
81
  children: children
82
82
  }), options)
83
83
  };
package/dist/src/index.js CHANGED
@@ -65,3 +65,4 @@ export { Tooltip } from './components/Tooltip/index.js';
65
65
  export { VerificationCode } from './components/VerificationCode/index.js';
66
66
  export { RadioGroup } from './components/RadioGroup/index.js';
67
67
  export { Icon } from '@ultraviolet/icons';
68
+ export { MenuV2 } from './components/MenuV2/index.js';
@@ -119,6 +119,7 @@ const Popup = /*#__PURE__*/forwardRef((_ref13, tooltipRef) => {
119
119
  'data-testid': dataTestId,
120
120
  hasArrow = true,
121
121
  onClose,
122
+ tabIndex = 0,
122
123
  onKeyDown,
123
124
  'aria-haspopup': ariaHasPopup
124
125
  } = _ref13;
@@ -291,7 +292,7 @@ const Popup = /*#__PURE__*/forwardRef((_ref13, tooltipRef) => {
291
292
  onPointerEnter: !isControlled ? onPointerEvent(true) : noop,
292
293
  onPointerLeave: !isControlled ? onPointerEvent(false) : noop,
293
294
  ref: childrenRef,
294
- tabIndex: 0,
295
+ tabIndex: tabIndex,
295
296
  onKeyDown: event => {
296
297
  onKeyDown?.(event);
297
298
  onLocalKeyDown(event);
@@ -300,7 +301,7 @@ const Popup = /*#__PURE__*/forwardRef((_ref13, tooltipRef) => {
300
301
  "aria-haspopup": ariaHasPopup,
301
302
  children: children
302
303
  });
303
- }, [ariaHasPopup, children, containerFullWidth, generatedId, isControlled, onKeyDown, onLocalKeyDown, onPointerEvent]);
304
+ }, [ariaHasPopup, children, containerFullWidth, generatedId, isControlled, onKeyDown, onLocalKeyDown, onPointerEvent, tabIndex]);
304
305
  if (!text) {
305
306
  if (typeof children === 'function') return null;
306
307
  return jsx(Fragment, {
@@ -2,6 +2,10 @@ import { consoleLightTheme } from '@ultraviolet/themes';
2
2
  export { consoleDarkTheme as darkTheme, consoleLightTheme as default } from '@ultraviolet/themes';
3
3
  import deepmerge from 'deepmerge';
4
4
 
5
+ /**
6
+ * @deprecated use UltravioletUITheme instead
7
+ */
8
+
5
9
  const {
6
10
  colors,
7
11
  shadows,
@@ -12,8 +16,8 @@ const {
12
16
  } = consoleLightTheme;
13
17
  /**
14
18
  * Will extend theme with new theme properties
15
- * @param {SCWUITheme} baseTheme the theme you want to extend from, by default it is set to light theme
16
- * @param {RecursivePartial<SCWUITheme>} extendedTheme the properties of a new theme you want to apply from baseTheme
19
+ * @param {UltravioletUITheme} baseTheme the theme you want to extend from, by default it is set to light theme
20
+ * @param {RecursivePartial<UltravioletUITheme>} extendedTheme the properties of a new theme you want to apply from baseTheme
17
21
  */
18
22
  const extendTheme = extendedTheme => deepmerge(consoleLightTheme, extendedTheme);
19
23
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ultraviolet/ui",
3
- "version": "1.15.1",
3
+ "version": "1.17.0",
4
4
  "description": "Ultraviolet UI",
5
5
  "homepage": "https://github.com/scaleway/ultraviolet#readme",
6
6
  "repository": {
@@ -39,11 +39,11 @@
39
39
  "react-dom": "18.2.0"
40
40
  },
41
41
  "devDependencies": {
42
- "@babel/core": "7.22.17",
42
+ "@babel/core": "7.22.20",
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.21",
46
+ "@types/react": "18.2.22",
47
47
  "@types/react-datepicker": "4.15.0",
48
48
  "@types/react-dom": "18.2.7",
49
49
  "react": "18.2.0",
@@ -60,14 +60,13 @@
60
60
  "@scaleway/random-name": "4.0.2",
61
61
  "@scaleway/use-media": "2.0.1",
62
62
  "deepmerge": "4.3.1",
63
- "prop-types": "15.8.1",
64
- "react-datepicker": "4.17.0",
63
+ "react-datepicker": "4.18.0",
65
64
  "react-flatten-children": "1.1.2",
66
- "react-select": "5.7.4",
65
+ "react-select": "5.7.5",
67
66
  "react-toastify": "9.1.3",
68
67
  "react-use-clipboard": "1.0.9",
69
68
  "reakit": "1.3.11",
70
69
  "@ultraviolet/themes": "1.2.1",
71
- "@ultraviolet/icons": "2.0.2"
70
+ "@ultraviolet/icons": "2.1.0"
72
71
  }
73
72
  }