@automattic/vip-design-system 2.5.0 → 2.7.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 (83) hide show
  1. package/build/system/Card/Card.d.ts +9 -1
  2. package/build/system/Card/Card.js +25 -4
  3. package/build/system/Card/Card.stories.d.ts +5 -0
  4. package/build/system/Card/Card.stories.js +34 -2
  5. package/build/system/Card/Card.test.js +25 -0
  6. package/build/system/Dropdown/Dropdown.d.ts +25 -36
  7. package/build/system/Dropdown/Dropdown.js +60 -99
  8. package/build/system/Dropdown/Dropdown.stories.d.ts +1 -26
  9. package/build/system/Dropdown/Dropdown.test.js +51 -28
  10. package/build/system/Dropdown/DropdownContent.d.ts +14 -10
  11. package/build/system/Dropdown/DropdownContent.js +43 -47
  12. package/build/system/Dropdown/DropdownItem.d.ts +20 -32
  13. package/build/system/Dropdown/DropdownItem.js +86 -103
  14. package/build/system/Dropdown/DropdownLabel.d.ts +11 -7
  15. package/build/system/Dropdown/DropdownLabel.js +29 -29
  16. package/build/system/Dropdown/DropdownSeparator.d.ts +10 -6
  17. package/build/system/Dropdown/DropdownSeparator.js +28 -28
  18. package/build/system/Dropdown/index.d.ts +17 -39
  19. package/build/system/Dropdown/index.js +23 -50
  20. package/build/system/FilterDropdown/FilterDropdown.d.ts +27 -0
  21. package/build/system/FilterDropdown/FilterDropdown.js +75 -0
  22. package/build/system/FilterDropdown/FilterDropdown.stories.d.ts +18 -0
  23. package/build/system/FilterDropdown/FilterDropdown.stories.js +46 -0
  24. package/build/system/FilterDropdown/FilterDropdown.test.d.ts +1 -0
  25. package/build/system/FilterDropdown/FilterDropdown.test.js +53 -0
  26. package/build/system/Hr/Hr.d.ts +7 -0
  27. package/build/system/Hr/Hr.js +22 -0
  28. package/build/system/Hr/Hr.stories.d.ts +23 -0
  29. package/build/system/Hr/Hr.stories.js +30 -0
  30. package/build/system/Hr/Hr.test.d.ts +1 -0
  31. package/build/system/Hr/Hr.test.js +41 -0
  32. package/build/system/Page/Page.d.ts +2 -0
  33. package/build/system/Page/Page.js +10 -0
  34. package/build/system/Page/Page.test.d.ts +1 -0
  35. package/build/system/Page/Page.test.js +41 -0
  36. package/build/system/index.d.ts +3 -1
  37. package/build/system/index.js +4 -0
  38. package/build/system/theme/index.d.ts +84 -33
  39. package/build/system/theme/index.js +32 -5
  40. package/package.json +1 -1
  41. package/src/system/Card/Card.stories.tsx +19 -1
  42. package/src/system/Card/Card.test.tsx +11 -0
  43. package/src/system/Card/Card.tsx +43 -14
  44. package/src/system/Dropdown/{Dropdown.test.js → Dropdown.test.tsx} +2 -1
  45. package/src/system/Dropdown/Dropdown.tsx +72 -0
  46. package/src/system/Dropdown/DropdownContent.tsx +46 -0
  47. package/src/system/Dropdown/DropdownItem.tsx +112 -0
  48. package/src/system/Dropdown/DropdownLabel.tsx +29 -0
  49. package/src/system/Dropdown/DropdownSeparator.tsx +28 -0
  50. package/src/system/Dropdown/{index.js → index.ts} +1 -3
  51. package/src/system/FilterDropdown/FilterDropdown.stories.tsx +57 -0
  52. package/src/system/FilterDropdown/FilterDropdown.test.tsx +52 -0
  53. package/src/system/FilterDropdown/FilterDropdown.tsx +92 -0
  54. package/src/system/Hr/Hr.stories.tsx +48 -0
  55. package/src/system/Hr/Hr.test.tsx +22 -0
  56. package/src/system/Hr/Hr.tsx +11 -0
  57. package/src/system/Page/Page.test.tsx +22 -0
  58. package/src/system/Page/Page.tsx +3 -0
  59. package/src/system/index.js +4 -0
  60. package/src/system/theme/index.js +32 -5
  61. package/tokens/valet-core/$metadata.json +1 -17
  62. package/tokens/valet-core/$themes.json +0 -2586
  63. package/src/system/Dropdown/Dropdown.js +0 -101
  64. package/src/system/Dropdown/DropdownContent.js +0 -50
  65. package/src/system/Dropdown/DropdownItem.js +0 -108
  66. package/src/system/Dropdown/DropdownLabel.js +0 -31
  67. package/src/system/Dropdown/DropdownSeparator.js +0 -30
  68. package/tokens/valet-core/figma-parsely-web-type.json +0 -1217
  69. package/tokens/valet-core/figma-valet-web-type.json +0 -1217
  70. package/tokens/valet-core/figma-wpvip-services-web-type.json +0 -1267
  71. package/tokens/valet-core/figma-wpvip-web-type.json +0 -1213
  72. package/tokens/valet-core/parsely-web-color.json +0 -729
  73. package/tokens/valet-core/parsely-web-core.json +0 -172
  74. package/tokens/valet-core/parsely-web-type.json +0 -362
  75. package/tokens/valet-core/valet-web-color.json +0 -677
  76. package/tokens/valet-core/valet-web-core.json +0 -172
  77. package/tokens/valet-core/wpvip-services-web-color.json +0 -730
  78. package/tokens/valet-core/wpvip-services-web-core.json +0 -172
  79. package/tokens/valet-core/wpvip-services-web-type.json +0 -412
  80. package/tokens/valet-core/wpvip-web-color-dark.json +0 -735
  81. package/tokens/valet-core/wpvip-web-color.json +0 -730
  82. package/tokens/valet-core/wpvip-web-type.json +0 -412
  83. package/tokens/valet-core/wpvip-web.json +0 -1310
@@ -0,0 +1,57 @@
1
+ /** @jsxImportSource theme-ui */
2
+
3
+ import { FilterDropdown } from './FilterDropdown';
4
+
5
+ import type { StoryObj } from '@storybook/react';
6
+
7
+ export default {
8
+ title: 'FilterDropdown',
9
+ component: FilterDropdown,
10
+ parameters: {
11
+ docs: {
12
+ description: {
13
+ component: `
14
+
15
+ A Dropdown component that acts as a filter for a list of items.
16
+
17
+ ## Guidance
18
+
19
+ ### When to use the FilterDropdown component
20
+
21
+ - When you want a Dropdown option that sticks with the selected value on the trigger button;
22
+
23
+ ### When to consider something else
24
+
25
+ - When you want to display a list of options that does not require to stick with the selected value on the trigger button;
26
+
27
+ ## Component Properties
28
+ `,
29
+ },
30
+ },
31
+ },
32
+ };
33
+
34
+ type Story = StoryObj< typeof FilterDropdown >;
35
+
36
+ const filterTypes = [ 'all', 'hasUpdate', 'isVulnerable' ] as const;
37
+ type FilterType = ( typeof filterTypes )[ number ];
38
+
39
+ const FILTER_OPTIONS: Record< FilterType, { value: FilterType; label: string } > = {
40
+ all: { value: 'all', label: 'All' },
41
+ hasUpdate: { value: 'hasUpdate', label: 'Update Available' },
42
+ isVulnerable: { value: 'isVulnerable', label: 'Known Vulnerabilities' },
43
+ };
44
+
45
+ export const Default: Story = {
46
+ render: () => (
47
+ <>
48
+ <FilterDropdown
49
+ className="vip-plugins-filter-dropdown"
50
+ label="Filter:"
51
+ filters={ FILTER_OPTIONS }
52
+ onSelect={ () => {} }
53
+ defaultValue={ FILTER_OPTIONS.all.value }
54
+ />
55
+ </>
56
+ ),
57
+ };
@@ -0,0 +1,52 @@
1
+ import { render, screen } from '@testing-library/react';
2
+ import React from 'react';
3
+ import '@testing-library/jest-dom';
4
+
5
+ import { FilterDropdown } from './FilterDropdown';
6
+
7
+ function getMenu() {
8
+ return screen.getByRole( 'button', { name: 'Filter: Auth Method All checked' } );
9
+ }
10
+
11
+ const props = {
12
+ filters: {
13
+ ALL_USERS: {
14
+ label: 'All',
15
+ authMethod: '',
16
+ },
17
+ WP_USERS: {
18
+ label: 'WP.com',
19
+ authMethod: 'wpcom',
20
+ },
21
+ GH_USERS: {
22
+ label: 'GitHub',
23
+ authMethod: 'github',
24
+ },
25
+ SSO_USERS: {
26
+ label: 'SSO',
27
+ authMethod: 'organization_sso',
28
+ },
29
+ SSO_OTHER_USERS: {
30
+ label: 'SSO (third-party)',
31
+ authMethod: 'other_sso',
32
+ },
33
+ BLOCKED_USERS: {
34
+ label: 'Blocked Auth Methods',
35
+ authMethod: 'restricted',
36
+ },
37
+ },
38
+ label: 'Auth Method',
39
+ onSelect: jest.fn(),
40
+ };
41
+
42
+ describe( '<FilterDropdown />', () => {
43
+ it( 'render with all props passed', () => {
44
+ render( <FilterDropdown { ...props } /> );
45
+
46
+ const menu = getMenu();
47
+
48
+ expect( menu ).toBeInTheDocument();
49
+ expect( menu ).toHaveTextContent( /Filter:/ );
50
+ expect( menu ).toHaveTextContent( /Auth Method/ );
51
+ } );
52
+ } );
@@ -0,0 +1,92 @@
1
+ /** @jsxImportSource theme-ui */
2
+
3
+ import classNames from 'classnames';
4
+ import { useTranslate } from 'i18n-calypso';
5
+ import React, { useState } from 'react';
6
+ import { MdCheck, MdKeyboardArrowDown } from 'react-icons/md';
7
+
8
+ import { Button } from '../Button';
9
+ import * as Dropdown from '../Dropdown';
10
+ import { DropdownCheckboxItemProps } from '../Dropdown/DropdownItem';
11
+ import ScreenReaderText from '../ScreenReaderText';
12
+
13
+ export type FilterDropdownCheckItemProps = DropdownCheckboxItemProps & {
14
+ checked: boolean;
15
+ item: {
16
+ label: string;
17
+ size?: number | string;
18
+ };
19
+ onClick: () => void;
20
+ };
21
+
22
+ const FilterDropdownCheckItem = ( { checked, item, onClick }: FilterDropdownCheckItemProps ) => (
23
+ <Dropdown.CheckboxItem checked={ checked } onClick={ onClick }>
24
+ <Dropdown.ItemIndicator>
25
+ <MdCheck size={ 14 } sx={ { mr: 2 } } fill="brand" />
26
+ </Dropdown.ItemIndicator>
27
+ { item.label } { item?.size ? `(${ item?.size })` : null }
28
+ </Dropdown.CheckboxItem>
29
+ );
30
+ export type FilterDropDownFilterProp = {
31
+ label: string;
32
+ size?: number | string;
33
+ value?: number | string;
34
+ };
35
+
36
+ export interface FilterDropdownFiltersProp {
37
+ [ key: string ]: FilterDropDownFilterProp;
38
+ }
39
+
40
+ export type FilterDropdownProps = {
41
+ className?: string;
42
+ filters: FilterDropdownFiltersProp;
43
+ label?: React.ReactNode | string;
44
+ onSelect: ( filter: FilterDropDownFilterProp, key: string ) => void;
45
+ defaultValue?: string | null;
46
+ };
47
+
48
+ export const FilterDropdown = ( {
49
+ className,
50
+ filters,
51
+ label,
52
+ onSelect,
53
+ defaultValue = null,
54
+ }: FilterDropdownProps ) => {
55
+ const translate = useTranslate();
56
+ const filterKeys = Object.keys( filters );
57
+ const firstFilter = filterKeys[ 0 ];
58
+ const [ filter, setFilter ] = useState( defaultValue || firstFilter );
59
+
60
+ return (
61
+ <Dropdown.Root
62
+ trigger={
63
+ <Button
64
+ className={ classNames( 'vip-filter-dropdown-trigger', className ) }
65
+ variant="secondary"
66
+ >
67
+ <ScreenReaderText>{ translate( 'Filter:' ) } </ScreenReaderText>
68
+
69
+ { label }
70
+
71
+ <strong sx={ { mx: 2 } }> { filters[ filter ].label } </strong>
72
+
73
+ <ScreenReaderText>{ translate( 'checked' ) }</ScreenReaderText>
74
+
75
+ <MdKeyboardArrowDown />
76
+ </Button>
77
+ }
78
+ >
79
+ { filterKeys.map( key => (
80
+ <FilterDropdownCheckItem
81
+ key={ key }
82
+ checked={ filter === key }
83
+ onClick={ () => {
84
+ setFilter( key );
85
+ onSelect( filters[ key ], key );
86
+ } }
87
+ item={ filters[ key ] }
88
+ />
89
+ ) ) }
90
+ </Dropdown.Root>
91
+ );
92
+ };
@@ -0,0 +1,48 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import { Hr } from './Hr';
5
+
6
+ import type { StoryObj } from '@storybook/react';
7
+
8
+ /**
9
+ * Internal dependencies
10
+ */
11
+
12
+ export default {
13
+ title: 'Hr',
14
+ component: Hr,
15
+ parameters: {
16
+ docs: {
17
+ description: {
18
+ component: `
19
+
20
+ Horizontal Line.
21
+
22
+ ## Guidance
23
+
24
+ ### When to use the link component
25
+
26
+ - When you want to separate sections with a horizontal line.
27
+
28
+ ### When to consider something else
29
+
30
+ - When you want to display a vertical line;
31
+
32
+ ## Component Properties
33
+ `,
34
+ },
35
+ },
36
+ },
37
+ };
38
+
39
+ type Story = StoryObj< typeof Hr >;
40
+
41
+ export const Default: Story = {
42
+ render: () => (
43
+ <>
44
+ Horizontal Line:
45
+ <Hr />
46
+ </>
47
+ ),
48
+ };
@@ -0,0 +1,22 @@
1
+ /** @jsxImportSource theme-ui */
2
+ /* eslint-disable @typescript-eslint/ban-ts-comment */
3
+ // @ts-nocheck
4
+ import { render } from '@testing-library/react';
5
+ import { axe } from 'jest-axe';
6
+ import { ThemeUIProvider } from 'theme-ui';
7
+
8
+ import { Hr } from './Hr';
9
+ import theme from '../theme';
10
+
11
+ const renderWithTheme = children =>
12
+ render( <ThemeUIProvider theme={ theme }>{ children }</ThemeUIProvider> );
13
+
14
+ const renderComponent = () => renderWithTheme( <Hr /> );
15
+
16
+ describe( '<Hr />', () => {
17
+ it( 'renders the Hr component', async () => {
18
+ const { container } = renderComponent();
19
+
20
+ expect( await axe( container ) ).toHaveNoViolations();
21
+ } );
22
+ } );
@@ -0,0 +1,11 @@
1
+ /** @jsxImportSource theme-ui */
2
+
3
+ import { ThemeUIStyleObject } from 'theme-ui';
4
+
5
+ export type HrProps = {
6
+ sx?: ThemeUIStyleObject;
7
+ };
8
+
9
+ export const Hr = ( { sx, ...rest }: HrProps ) => (
10
+ <hr sx={ { my: 4, border: 0, height: '1px', backgroundColor: 'borders.2', ...sx } } { ...rest } />
11
+ );
@@ -0,0 +1,22 @@
1
+ /** @jsxImportSource theme-ui */
2
+ /* eslint-disable @typescript-eslint/ban-ts-comment */
3
+ // @ts-nocheck
4
+ import { render } from '@testing-library/react';
5
+ import { axe } from 'jest-axe';
6
+ import { ThemeUIProvider } from 'theme-ui';
7
+
8
+ import { Page } from './Page';
9
+ import theme from '../theme';
10
+
11
+ const renderWithTheme = children =>
12
+ render( <ThemeUIProvider theme={ theme }>{ children }</ThemeUIProvider> );
13
+
14
+ const renderComponent = () => renderWithTheme( <Page /> );
15
+
16
+ describe( '<Page />', () => {
17
+ it( 'renders the Page component', async () => {
18
+ const { container } = renderComponent();
19
+
20
+ expect( await axe( container ) ).toHaveNoViolations();
21
+ } );
22
+ } );
@@ -0,0 +1,3 @@
1
+ import { Box } from '../Box';
2
+
3
+ export const Page = props => <Box { ...props } />;
@@ -21,6 +21,7 @@ import {
21
21
  } from './Dialog';
22
22
  import * as Drawer from './Drawer/Drawer';
23
23
  import * as Dropdown from './Dropdown';
24
+ import { FilterDropdown } from './FilterDropdown/FilterDropdown';
24
25
  import { Flex } from './Flex';
25
26
  import {
26
27
  Input,
@@ -35,6 +36,7 @@ import {
35
36
  } from './Form';
36
37
  import { Grid } from './Grid';
37
38
  import { Heading } from './Heading';
39
+ import { Hr } from './Hr/Hr';
38
40
  import { Link } from './Link';
39
41
  import LinkExternal from './LinkExternal/LinkExternal';
40
42
  import { MobileMenuWrapper, MobileMenuTrigger, MobileMenu } from './MobileMenu/MobileMenu';
@@ -84,10 +86,12 @@ export {
84
86
  MobileMenuWrapper,
85
87
  NewConfirmationDialog,
86
88
  Grid,
89
+ FilterDropdown,
87
90
  Flex,
88
91
  Notice,
89
92
  OptionRow,
90
93
  Heading,
94
+ Hr,
91
95
  Input,
92
96
  Label,
93
97
  Spinner,
@@ -250,23 +250,50 @@ export default {
250
250
 
251
251
  cards: {
252
252
  primary: {
253
- padding: 3,
254
253
  borderRadius: 2,
255
254
  backgroundColor: 'layer.2',
256
255
  boxShadow: 'low',
256
+ header: {
257
+ backgroundColor: 'layer.1',
258
+ borderTopLeftRadius: 2,
259
+ borderTopRightRadius: 2,
260
+ p: 3,
261
+ fontWeight: 'bold',
262
+ display: 'flex',
263
+ },
264
+ children: {
265
+ p: 3,
266
+ },
257
267
  },
258
268
  secondary: {
259
269
  borderRadius: 2,
260
- p: 3,
261
270
  boxShadow: 'none',
262
271
  border: '1px solid',
263
272
  borderColor: 'borders.2',
273
+ header: {
274
+ backgroundColor: 'layer.1',
275
+ borderTopLeftRadius: 2,
276
+ borderTopRightRadius: 2,
277
+ p: 3,
278
+ fontWeight: 'bold',
279
+ display: 'flex',
280
+ },
281
+ children: {
282
+ p: 3,
283
+ },
264
284
  },
265
285
  indent: {
266
286
  borderRadius: 2,
267
- p: 3,
268
287
  boxShadow: 'none',
269
288
  backgroundColor: 'backgroundMuted',
289
+ header: {
290
+ display: 'flex',
291
+ fontWeight: 'bold',
292
+ p: 3,
293
+ },
294
+ children: {
295
+ p: 3,
296
+ },
270
297
  },
271
298
  },
272
299
 
@@ -525,8 +552,8 @@ export default {
525
552
  fontWeight: 'body',
526
553
  color: 'text',
527
554
  backgroundColor: 'backgrounds.primary',
528
- '-webkit-font-smoothing': 'antialiased',
529
- '-moz-osx-font-smoothing': 'grayscale',
555
+ webkitFontSmoothing: 'antialiased',
556
+ mozOsxFontmoothing: 'grayscale',
530
557
  a: {
531
558
  '&:hover': {
532
559
  textDecorationLine: 'underline',
@@ -1,23 +1,7 @@
1
1
  {
2
2
  "tokenSetOrder": [
3
3
  "valet-core",
4
- "valet-web-core",
5
- "valet-web-color",
6
4
  "wpvip-product-core",
7
- "wpvip-product-dark",
8
- "wpvip-web",
9
- "wpvip-web-color-dark",
10
- "wpvip-web-color",
11
- "wpvip-web-type",
12
- "parsely-web-core",
13
- "parsely-web-color",
14
- "parsely-web-type",
15
- "wpvip-services-web-core",
16
- "wpvip-services-web-color",
17
- "wpvip-services-web-type",
18
- "figma-valet-web-type",
19
- "figma-wpvip-web-type",
20
- "figma-wpvip-services-web-type",
21
- "figma-parsely-web-type"
5
+ "wpvip-product-dark"
22
6
  ]
23
7
  }