@scality/core-ui 0.116.0 → 0.117.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 (55) hide show
  1. package/.storybook/preview.js +32 -18
  2. package/README.md +1 -1
  3. package/dist/components/buttonv2/Buttonv2.component.d.ts +1 -0
  4. package/dist/components/buttonv2/Buttonv2.component.d.ts.map +1 -1
  5. package/dist/components/buttonv2/Buttonv2.component.js +9 -8
  6. package/dist/components/card/Card.component.d.ts.map +1 -1
  7. package/dist/components/card/Card.component.js +11 -11
  8. package/dist/components/checkbox/Checkbox.component.d.ts.map +1 -1
  9. package/dist/components/checkbox/Checkbox.component.js +2 -2
  10. package/dist/components/dropdown/Dropdown.component.d.ts.map +1 -1
  11. package/dist/components/dropdown/Dropdown.component.js +41 -57
  12. package/dist/components/inlineinput/InlineInput.d.ts +17 -0
  13. package/dist/components/inlineinput/InlineInput.d.ts.map +1 -0
  14. package/dist/components/inlineinput/InlineInput.js +85 -0
  15. package/dist/components/inputv2/inputv2.d.ts +8 -0
  16. package/dist/components/inputv2/inputv2.d.ts.map +1 -1
  17. package/dist/components/modal/Modal.component.d.ts.map +1 -1
  18. package/dist/components/modal/Modal.component.js +18 -1
  19. package/dist/components/navbar/Navbar.component.d.ts +1 -0
  20. package/dist/components/navbar/Navbar.component.d.ts.map +1 -1
  21. package/dist/components/navbar/Navbar.component.js +23 -6
  22. package/dist/components/sidebar/Sidebar.component.d.ts.map +1 -1
  23. package/dist/components/sidebar/Sidebar.component.js +18 -1
  24. package/dist/components/tablev2/MultiSelectableContent.d.ts.map +1 -1
  25. package/dist/components/tablev2/MultiSelectableContent.js +10 -1
  26. package/dist/components/tablev2/SingleSelectableContent.d.ts.map +1 -1
  27. package/dist/components/tablev2/SingleSelectableContent.js +20 -1
  28. package/dist/components/tablev2/Tablestyle.d.ts +1 -0
  29. package/dist/components/tablev2/Tablestyle.d.ts.map +1 -1
  30. package/dist/components/tablev2/Tablestyle.js +10 -1
  31. package/dist/components/text/Text.component.d.ts.map +1 -1
  32. package/dist/components/text/Text.component.js +2 -2
  33. package/dist/index.d.ts +1 -0
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +1 -0
  36. package/dist/spacing.js +1 -1
  37. package/package.json +5 -5
  38. package/src/lib/components/buttonv2/Buttonv2.component.tsx +11 -8
  39. package/src/lib/components/card/Card.component.tsx +11 -11
  40. package/src/lib/components/checkbox/Checkbox.component.tsx +2 -2
  41. package/src/lib/components/dropdown/Dropdown.component.tsx +65 -81
  42. package/src/lib/components/inlineinput/InlineInput.test.tsx +211 -0
  43. package/src/lib/components/inlineinput/InlineInput.tsx +179 -0
  44. package/src/lib/components/inputv2/inputv2.tsx +2 -2
  45. package/src/lib/components/modal/Modal.component.tsx +19 -1
  46. package/src/lib/components/navbar/Navbar.component.tsx +27 -19
  47. package/src/lib/components/sidebar/Sidebar.component.tsx +21 -0
  48. package/src/lib/components/tablev2/MultiSelectableContent.tsx +17 -1
  49. package/src/lib/components/tablev2/SingleSelectableContent.tsx +29 -1
  50. package/src/lib/components/tablev2/Tablestyle.tsx +15 -2
  51. package/src/lib/components/text/Text.component.tsx +2 -2
  52. package/src/lib/index.ts +1 -0
  53. package/src/lib/spacing.tsx +1 -1
  54. package/stories/InlineInput/InlineInput.stories.tsx +46 -0
  55. package/stories/navbar.stories.tsx +18 -0
@@ -1,12 +1,12 @@
1
- import React from 'react';
1
+ import React, { Fragment } from 'react';
2
2
  import styled, { css } from 'styled-components';
3
3
  import { Logo } from '../../icons/branding';
4
4
  import { spacing } from '../../spacing';
5
5
  import { fontSize, navbarHeight, navbarItemWidth } from '../../style/theme';
6
6
  import { getThemePropSelector } from '../../utils';
7
- import { Button } from '../button/Button.component';
8
7
  import { Dropdown, Item } from '../dropdown/Dropdown.component';
9
8
  import { Icon } from '../icon/Icon.component';
9
+ import { Button, FocusVisibleStyle } from '../buttonv2/Buttonv2.component';
10
10
  type Action = {
11
11
  type: string;
12
12
  items?: Array<Item>;
@@ -17,6 +17,7 @@ type Tab = {
17
17
  selected?: boolean;
18
18
  onClick?: (arg0: any) => void;
19
19
  link?: JSX.Element;
20
+ render?: JSX.Element;
20
21
  };
21
22
  export type Props = {
22
23
  onToggleClick?: () => void;
@@ -35,8 +36,7 @@ const NavbarContainer = styled.div`
35
36
  .sc-trigger-text {
36
37
  color: ${getThemePropSelector('textPrimary')};
37
38
  }
38
- border-bottom: ${spacing.r1} solid
39
- ${getThemePropSelector('backgroundLevel1')};
39
+ border-bottom: 0.5px solid ${(props) => props.theme.backgroundLevel3};
40
40
  `};
41
41
  `;
42
42
  const NavbarMenu = styled.div`
@@ -72,6 +72,11 @@ const NavbarTabs = styled.div`
72
72
  font-weight: bold;
73
73
  border-bottom-color: ${selectedActive};
74
74
  }
75
+ // :focus-visible is the keyboard-only version of :focus
76
+ &:focus-visible {
77
+ ${FocusVisibleStyle}
78
+ color: ${props.theme.textPrimary};
79
+ }
75
80
  `;
76
81
  }};
77
82
  }
@@ -92,6 +97,11 @@ const TabItem = styled.div<{ selected: boolean }>`
92
97
  border-top: ${spacing.r2} solid;
93
98
  cursor: pointer;
94
99
  }
100
+ // :focus-visible is the keyboard-only version of :focus
101
+ &:focus-visible {
102
+ ${FocusVisibleStyle}
103
+ color: ${props.theme.textPrimary};
104
+ }
95
105
  `;
96
106
  }};
97
107
  ${(props) =>
@@ -128,6 +138,11 @@ const NavbarMenuItem = styled.div`
128
138
  &:hover {
129
139
  background-color: ${getThemePropSelector('highlight')};
130
140
  }
141
+ // :focus-visible is the keyboard-only version of :focus
142
+ &:focus-visible {
143
+ ${FocusVisibleStyle}
144
+ color: ${(props) => props.theme.textPrimary};
145
+ }
131
146
  width: ${navbarItemWidth};
132
147
  }
133
148
  `;
@@ -156,14 +171,7 @@ const getActionRenderer = ({ type, items = null, ...rest }, index) => {
156
171
  />
157
172
  ) : null;
158
173
  } else if (type === 'button') {
159
- return (
160
- <Button
161
- key={`navbar_right_action_${index}`}
162
- size="larger"
163
- variant="backgroundLevel1"
164
- {...rest}
165
- />
166
- );
174
+ return <Button key={`navbar_right_action_${index}`} {...rest} />;
167
175
  } else if (type === 'custom') {
168
176
  return <rest.render key={`navbar_right_action_${index}`} />;
169
177
  }
@@ -183,12 +191,7 @@ function NavBar({
183
191
  <NavbarMenu>
184
192
  {onToggleClick && (
185
193
  <NavbarMenuItem onClick={onToggleClick}>
186
- <Button
187
- size="larger"
188
- variant="backgroundLevel1"
189
- icon={<Icon name="Lat-menu" />}
190
- title="Main Menu"
191
- />
194
+ <Button icon={<Icon name="Lat-menu" />} title="Main Menu" />
192
195
  </NavbarMenuItem>
193
196
  )}
194
197
  <NavbarMenuItem>
@@ -199,7 +202,12 @@ function NavBar({
199
202
  </NavbarMenu>
200
203
  {tabs.length ? (
201
204
  <NavbarTabs>
202
- {tabs.map(({ link, title, selected, onClick }, index) => {
205
+ {tabs.map(({ link, title, selected, onClick, render }, index) => {
206
+ if (render) {
207
+ return (
208
+ <Fragment key={`navbar_tab_item_${index}`}>{render}</Fragment>
209
+ );
210
+ }
203
211
  return link ? (
204
212
  React.cloneElement(link, {
205
213
  className: selected ? 'selected' : '',
@@ -11,6 +11,7 @@ import { getThemePropSelector } from '../../utils';
11
11
  import { Button } from '../button/Button.component';
12
12
  import { Icon } from '../icon/Icon.component';
13
13
  import { spacing } from '../../spacing';
14
+ import { FocusVisibleStyle } from '../buttonv2/Buttonv2.component';
14
15
  type Item = {
15
16
  label: string;
16
17
  onClick: (arg0: any) => void;
@@ -99,6 +100,9 @@ const SidebarContainer = styled.div<WrapperProps>`
99
100
  &:hover {
100
101
  background-color: ${getThemePropSelector('highlight')};
101
102
  }
103
+ &:focus-visible {
104
+ ${FocusVisibleStyle}
105
+ }
102
106
  height: ${sidebarItemHeight};
103
107
  width: ${sidebarWidth};
104
108
  padding: 0px;
@@ -121,12 +125,18 @@ const SidebarItem = styled.div<{ active?: boolean }>`
121
125
  background-color: ${highlight};
122
126
  color: ${textPrimary};
123
127
  cursor: default;
128
+ &:focus-visible {
129
+ ${FocusVisibleStyle}
130
+ }
124
131
  `
125
132
  : css`
126
133
  &:hover {
127
134
  background-color: ${highlight};
128
135
  color: ${textPrimary};
129
136
  }
137
+ &:focus-visible {
138
+ ${FocusVisibleStyle}
139
+ }
130
140
  &:active {
131
141
  background-color: ${highlight};
132
142
  color: ${textPrimary};
@@ -198,6 +208,17 @@ function Sidebar({
198
208
  active={active}
199
209
  title={label}
200
210
  onClick={onClick}
211
+ onKeyDown={(event) => {
212
+ if (
213
+ event.key === ' ' ||
214
+ event.key === 'Enter' ||
215
+ event.key === 'Spacebar'
216
+ ) {
217
+ event.preventDefault();
218
+ onClick(event);
219
+ }
220
+ }}
221
+ tabIndex={0}
201
222
  {...actionRest}
202
223
  >
203
224
  {!!icon && <MenuItemIcon>{icon}</MenuItemIcon>}
@@ -242,7 +242,23 @@ export const MultiSelectableContent = <
242
242
  );
243
243
 
244
244
  return (
245
- <TableHeader {...headerStyleProps} role="columnheader">
245
+ <TableHeader
246
+ {...headerStyleProps}
247
+ role="columnheader"
248
+ tabIndex={!column.disableSortBy ? 0 : undefined}
249
+ onKeyDown={(event) => {
250
+ if (
251
+ !column.disableSortBy &&
252
+ (event.key === ' ' ||
253
+ event.key === 'Enter' ||
254
+ event.key === 'Spacebar')
255
+ ) {
256
+ event.preventDefault();
257
+ // @ts-expect-error - getSortByToggleProps is joined to getHeaderProps
258
+ headerStyleProps.onClick(event);
259
+ }
260
+ }}
261
+ >
246
262
  <div>
247
263
  {column.id === 'selection' ? (
248
264
  <div
@@ -99,6 +99,18 @@ export function SingleSelectableContent<
99
99
  onClick: () => {
100
100
  if (onRowSelected) return onRowSelected(row);
101
101
  },
102
+ tabIndex: onRowSelected ? 0 : undefined,
103
+ onKeyDown: (event) => {
104
+ if (
105
+ onRowSelected &&
106
+ (event.key === ' ' ||
107
+ event.key === 'Enter' ||
108
+ event.key === 'Spacebar')
109
+ ) {
110
+ event.preventDefault();
111
+ onRowSelected(row);
112
+ }
113
+ },
102
114
  },
103
115
  };
104
116
 
@@ -167,7 +179,23 @@ export function SingleSelectableContent<
167
179
  }),
168
180
  );
169
181
  return (
170
- <TableHeader {...headerStyleProps} role="columnheader">
182
+ <TableHeader
183
+ {...headerStyleProps}
184
+ role="columnheader"
185
+ tabIndex={!column.disableSortBy ? 0 : undefined}
186
+ onKeyDown={(event) => {
187
+ if (
188
+ !column.disableSortBy &&
189
+ (event.key === ' ' ||
190
+ event.key === 'Enter' ||
191
+ event.key === 'Spacebar')
192
+ ) {
193
+ event.preventDefault();
194
+ // @ts-expect-error - getSortByToggleProps is joined to getHeaderProps
195
+ headerStyleProps.onClick(event);
196
+ }
197
+ }}
198
+ >
171
199
  <div>
172
200
  {column.render('Header')}
173
201
  <SortCaret column={column} />
@@ -8,6 +8,7 @@ import {
8
8
  } from './TableUtils';
9
9
  import { HeaderGroup } from 'react-table';
10
10
  import { Icon } from '../icon/Icon.component';
11
+ import { FocusVisibleStyle } from '../buttonv2/Buttonv2.component';
11
12
 
12
13
  const borderSize = '4px';
13
14
  export const SortIncentive = styled.span`
@@ -18,16 +19,26 @@ export const SortCaretWrapper = styled.span`
18
19
  padding-left: ${spacing.sp4};
19
20
  position: absolute;
20
21
  `;
21
- export const TableHeader = styled.div<{ headerHeight?: number | string }>`
22
+ export const TableHeader = styled.div<{
23
+ headerHeight?: number | string;
24
+ tabIndex: number | undefined;
25
+ }>`
22
26
  display: flex;
23
27
  flex-direction: column;
24
28
  justify-content: center;
25
29
  height: ${(props) => props.headerHeight};
30
+ cursor: ${(props) =>
31
+ props.tabIndex !== undefined && props.tabIndex >= 0
32
+ ? 'pointer'
33
+ : 'default'};
26
34
  &:hover {
27
35
  ${SortIncentive} {
28
36
  display: block;
29
37
  }
30
38
  }
39
+ &:focus-visible {
40
+ ${FocusVisibleStyle}
41
+ }
31
42
  `;
32
43
 
33
44
  type HeadRowType = {
@@ -46,7 +57,6 @@ export const HeadRow = styled.div<HeadRowType>`
46
57
  : `calc(100% - ${borderSize} ) !important;`}
47
58
  height: ${(props) => tableRowHeight[props.rowHeight]}rem;
48
59
  table-layout: fixed;
49
- cursor: pointer;
50
60
  color: ${(props) => props.theme.textPrimary};
51
61
  font-weight: bold;
52
62
  overflow: hidden;
@@ -78,6 +88,9 @@ export const TableRow = styled.div<TableRowType>`
78
88
  outline: none;
79
89
  cursor: pointer;
80
90
  }
91
+ &:focus-visible {
92
+ ${FocusVisibleStyle}
93
+ }
81
94
  `;
82
95
  }
83
96
  }}
@@ -2,6 +2,7 @@ import * as React from 'react';
2
2
  import styled from 'styled-components';
3
3
  import { spacing } from '../../spacing';
4
4
  import { CoreUITheme } from '../../style/theme';
5
+ import { FocusVisibleStyle } from '../buttonv2/Buttonv2.component';
5
6
 
6
7
  type Status = 'unknown' | 'healthy' | 'warning' | 'critical';
7
8
  type Props = {
@@ -188,7 +189,6 @@ export const Link = styled.a`
188
189
  }
189
190
  // :focus-visible is the keyboard-only version of :focus
190
191
  &:focus-visible {
191
- outline: dashed ${spacing.r2} ${(props) => props.theme.textLink};
192
- outline-offset: ${spacing.r2};
192
+ ${FocusVisibleStyle}
193
193
  }
194
194
  `;
package/src/lib/index.ts CHANGED
@@ -73,3 +73,4 @@ export { useMutationsHandler } from './components/toast/useMutationsHandler';
73
73
  export { Stepper } from './components/steppers/Stepper.component';
74
74
  export { InfoMessage } from './components/infomessage/InfoMessage.component';
75
75
  export { InputList } from './components/inputlist/InputList.component';
76
+ export { InlineInput } from './components/inlineinput/InlineInput';
@@ -36,7 +36,7 @@ export const spacing = {
36
36
  const HSeparator = styled.div`
37
37
  min-height: ${spacing.r40};
38
38
  min-width: ${spacing.r2};
39
- background: ${(props) => props.theme.backgroundLevel1};
39
+ background: ${(props) => props.theme.border};
40
40
  `;
41
41
 
42
42
  const VSeparator = styled.div`
@@ -0,0 +1,46 @@
1
+ import React from 'react';
2
+ import { InlineInput } from '../../src/lib';
3
+ import { useMutation } from 'react-query';
4
+
5
+ export default {
6
+ title: 'Components/InlineInput',
7
+ component: InlineInput,
8
+ args: {
9
+ id: 'instanceName',
10
+ defaultValue: 'My instance',
11
+ },
12
+ argTypes: {
13
+ changeMutation: {
14
+ table: {
15
+ disable: true,
16
+ },
17
+ },
18
+ },
19
+ render: ({ ...args }) => {
20
+ const changeMutation = useMutation<unknown, unknown, { value: string }>({
21
+ mutationFn: ({ value }) => {
22
+ return new Promise((resolve) => {
23
+ setTimeout(() => {
24
+ resolve(null);
25
+ }, 2000);
26
+ });
27
+ },
28
+ });
29
+ return <InlineInput {...args} changeMutation={changeMutation} />;
30
+ },
31
+ };
32
+
33
+ export const Playground = {
34
+ args: {
35
+ label: 'Playground',
36
+ },
37
+ };
38
+
39
+ export const WithConfirmationModal = {
40
+ args: {
41
+ confirmationModal: {
42
+ title: 'Confirm the instance name change',
43
+ body: 'Are you sure you want to change the instance name?',
44
+ },
45
+ },
46
+ };
@@ -2,9 +2,23 @@ import React from 'react';
2
2
  import { Navbar } from '../src/lib/components/navbar/Navbar.component';
3
3
  import { action } from '@storybook/addon-actions';
4
4
  import { Link } from '../src/lib/components/text/Text.component';
5
+ import { InlineInput } from '../src/lib';
5
6
  import { Stack } from '../src/lib/spacing';
6
7
 
7
8
  const tabs = [
9
+ {
10
+ render: (
11
+ <InlineInput
12
+ id="instanceName"
13
+ changeMutation={{
14
+ isLoading: false,
15
+ mutate: () => {},
16
+ }}
17
+ defaultValue="My instance"
18
+ maxLength={14}
19
+ />
20
+ ),
21
+ },
8
22
  {
9
23
  selected: true,
10
24
  title: 'Groups',
@@ -14,21 +28,25 @@ const tabs = [
14
28
  {
15
29
  selected: false,
16
30
  title: 'Users',
31
+ link: <a href="/users">Users</a>,
17
32
  onClick: action('Users clicked'),
18
33
  },
19
34
  {
20
35
  selected: false,
21
36
  title: 'Policies',
37
+ link: <a href="/policies">Policies</a>,
22
38
  onClick: action('Policies clicked'),
23
39
  },
24
40
  {
25
41
  selected: false,
26
42
  title: 'Buckets',
43
+ link: <a href="/buckets">Buckets</a>,
27
44
  onClick: action('Buckets clicked'),
28
45
  },
29
46
  {
30
47
  selected: false,
31
48
  title: 'Workflows',
49
+ link: <a href="/workflows">Workflows</a>,
32
50
  onClick: action('Workflows clicked'),
33
51
  },
34
52
  ];