@redsift/popovers 9.2.3-patch → 9.2.3

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 (171) hide show
  1. package/coverage/clover.xml +763 -0
  2. package/coverage/coverage-final.json +53 -0
  3. package/coverage/lcov-report/base.css +224 -0
  4. package/coverage/lcov-report/block-navigation.js +87 -0
  5. package/coverage/lcov-report/dialog/Dialog.tsx.html +271 -0
  6. package/coverage/lcov-report/dialog/context.ts.html +97 -0
  7. package/coverage/lcov-report/dialog/index.html +191 -0
  8. package/coverage/lcov-report/dialog/index.ts.html +100 -0
  9. package/coverage/lcov-report/dialog/types.ts.html +241 -0
  10. package/coverage/lcov-report/dialog/useDialog.tsx.html +346 -0
  11. package/coverage/lcov-report/dialog/useDialogContext.tsx.html +121 -0
  12. package/coverage/lcov-report/dialog-content/DialogContent.tsx.html +484 -0
  13. package/coverage/lcov-report/dialog-content/index.html +146 -0
  14. package/coverage/lcov-report/dialog-content/index.ts.html +91 -0
  15. package/coverage/lcov-report/dialog-content/intl/index.html +116 -0
  16. package/coverage/lcov-report/dialog-content/intl/index.ts.html +106 -0
  17. package/coverage/lcov-report/dialog-content/styles.ts.html +256 -0
  18. package/coverage/lcov-report/dialog-content-actions/DialogContentActions.tsx.html +205 -0
  19. package/coverage/lcov-report/dialog-content-actions/index.html +146 -0
  20. package/coverage/lcov-report/dialog-content-actions/index.ts.html +91 -0
  21. package/coverage/lcov-report/dialog-content-actions/styles.ts.html +139 -0
  22. package/coverage/lcov-report/dialog-content-body/DialogContentBody.tsx.html +232 -0
  23. package/coverage/lcov-report/dialog-content-body/index.html +146 -0
  24. package/coverage/lcov-report/dialog-content-body/index.ts.html +91 -0
  25. package/coverage/lcov-report/dialog-content-body/styles.ts.html +259 -0
  26. package/coverage/lcov-report/dialog-content-header/DialogContentHeader.tsx.html +280 -0
  27. package/coverage/lcov-report/dialog-content-header/index.html +146 -0
  28. package/coverage/lcov-report/dialog-content-header/index.ts.html +91 -0
  29. package/coverage/lcov-report/dialog-content-header/styles.ts.html +193 -0
  30. package/coverage/lcov-report/dialog-trigger/DialogTrigger.tsx.html +217 -0
  31. package/coverage/lcov-report/dialog-trigger/index.html +131 -0
  32. package/coverage/lcov-report/dialog-trigger/index.ts.html +91 -0
  33. package/coverage/lcov-report/favicon.png +0 -0
  34. package/coverage/lcov-report/index.html +341 -0
  35. package/coverage/lcov-report/popover/Popover.tsx.html +295 -0
  36. package/coverage/lcov-report/popover/context.ts.html +97 -0
  37. package/coverage/lcov-report/popover/index.html +191 -0
  38. package/coverage/lcov-report/popover/index.ts.html +100 -0
  39. package/coverage/lcov-report/popover/types.ts.html +283 -0
  40. package/coverage/lcov-report/popover/usePopover.tsx.html +415 -0
  41. package/coverage/lcov-report/popover/usePopoverContext.tsx.html +121 -0
  42. package/coverage/lcov-report/popover-content/PopoverContent.tsx.html +229 -0
  43. package/coverage/lcov-report/popover-content/index.html +146 -0
  44. package/coverage/lcov-report/popover-content/index.ts.html +94 -0
  45. package/coverage/lcov-report/popover-content/styles.ts.html +370 -0
  46. package/coverage/lcov-report/popover-trigger/PopoverTrigger.tsx.html +202 -0
  47. package/coverage/lcov-report/popover-trigger/index.html +131 -0
  48. package/coverage/lcov-report/popover-trigger/index.ts.html +91 -0
  49. package/coverage/lcov-report/prettify.css +1 -0
  50. package/coverage/lcov-report/prettify.js +2 -0
  51. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  52. package/coverage/lcov-report/sorter.js +196 -0
  53. package/coverage/lcov-report/toast/Toast.tsx.html +373 -0
  54. package/coverage/lcov-report/toast/index.html +161 -0
  55. package/coverage/lcov-report/toast/index.ts.html +91 -0
  56. package/coverage/lcov-report/toast/intl/index.html +116 -0
  57. package/coverage/lcov-report/toast/intl/index.ts.html +106 -0
  58. package/coverage/lcov-report/toast/styles.ts.html +193 -0
  59. package/coverage/lcov-report/toast/types.ts.html +217 -0
  60. package/coverage/lcov-report/toast-container/ToastContainer.tsx.html +217 -0
  61. package/coverage/lcov-report/toast-container/index.html +161 -0
  62. package/coverage/lcov-report/toast-container/index.ts.html +94 -0
  63. package/coverage/lcov-report/toast-container/styles.ts.html +2284 -0
  64. package/coverage/lcov-report/toast-container/useToast.tsx.html +469 -0
  65. package/coverage/lcov-report/tooltip/Tooltip.tsx.html +250 -0
  66. package/coverage/lcov-report/tooltip/context.ts.html +97 -0
  67. package/coverage/lcov-report/tooltip/index.html +191 -0
  68. package/coverage/lcov-report/tooltip/index.ts.html +100 -0
  69. package/coverage/lcov-report/tooltip/types.ts.html +250 -0
  70. package/coverage/lcov-report/tooltip/useTooltip.tsx.html +358 -0
  71. package/coverage/lcov-report/tooltip/useTooltipContext.tsx.html +121 -0
  72. package/coverage/lcov-report/tooltip-content/TooltipContent.tsx.html +313 -0
  73. package/coverage/lcov-report/tooltip-content/index.html +146 -0
  74. package/coverage/lcov-report/tooltip-content/index.ts.html +91 -0
  75. package/coverage/lcov-report/tooltip-content/styles.ts.html +337 -0
  76. package/coverage/lcov-report/tooltip-trigger/TooltipTrigger.tsx.html +211 -0
  77. package/coverage/lcov-report/tooltip-trigger/index.html +131 -0
  78. package/coverage/lcov-report/tooltip-trigger/index.ts.html +91 -0
  79. package/coverage/lcov.info +1510 -0
  80. package/coverage/storybook/coverage-storybook.json +58724 -0
  81. package/dist/package.json +96 -0
  82. package/index.ts +1 -0
  83. package/jest.config.js +3 -0
  84. package/package.json +2 -3
  85. package/rollup.config.js +13 -0
  86. package/src/components/dialog/Dialog.stories.tsx +264 -0
  87. package/src/components/dialog/Dialog.test.tsx +116 -0
  88. package/src/components/dialog/Dialog.tsx +62 -0
  89. package/src/components/dialog/context.ts +4 -0
  90. package/src/components/dialog/index.ts +5 -0
  91. package/src/components/dialog/types.ts +52 -0
  92. package/src/components/dialog/useDialog.tsx +87 -0
  93. package/src/components/dialog/useDialogContext.tsx +12 -0
  94. package/src/components/dialog-content/DialogContent.stories.tsx +348 -0
  95. package/src/components/dialog-content/DialogContent.tsx +133 -0
  96. package/src/components/dialog-content/index.ts +2 -0
  97. package/src/components/dialog-content/intl/en-US.json +3 -0
  98. package/src/components/dialog-content/intl/fr-FR.json +3 -0
  99. package/src/components/dialog-content/intl/index.ts +7 -0
  100. package/src/components/dialog-content/styles.ts +57 -0
  101. package/src/components/dialog-content/types.ts +10 -0
  102. package/src/components/dialog-content-actions/DialogContentActions.test.tsx +68 -0
  103. package/src/components/dialog-content-actions/DialogContentActions.tsx +40 -0
  104. package/src/components/dialog-content-actions/index.ts +2 -0
  105. package/src/components/dialog-content-actions/styles.ts +18 -0
  106. package/src/components/dialog-content-actions/types.ts +11 -0
  107. package/src/components/dialog-content-body/DialogContentBody.test.tsx +63 -0
  108. package/src/components/dialog-content-body/DialogContentBody.tsx +49 -0
  109. package/src/components/dialog-content-body/index.ts +2 -0
  110. package/src/components/dialog-content-body/styles.ts +58 -0
  111. package/src/components/dialog-content-body/types.ts +14 -0
  112. package/src/components/dialog-content-header/DialogContentHeader.test.tsx +63 -0
  113. package/src/components/dialog-content-header/DialogContentHeader.tsx +65 -0
  114. package/src/components/dialog-content-header/index.ts +2 -0
  115. package/src/components/dialog-content-header/styles.ts +36 -0
  116. package/src/components/dialog-content-header/types.ts +21 -0
  117. package/src/components/dialog-trigger/DialogTrigger.tsx +44 -0
  118. package/src/components/dialog-trigger/index.ts +2 -0
  119. package/src/components/dialog-trigger/types.ts +9 -0
  120. package/src/components/popover/Popover.stories.tsx +129 -0
  121. package/src/components/popover/Popover.test.tsx +102 -0
  122. package/src/components/popover/Popover.tsx +70 -0
  123. package/src/components/popover/context.ts +4 -0
  124. package/src/components/popover/index.ts +5 -0
  125. package/src/components/popover/types.ts +66 -0
  126. package/src/components/popover/usePopover.tsx +110 -0
  127. package/src/components/popover/usePopoverContext.tsx +12 -0
  128. package/src/components/popover-content/PopoverContent.tsx +48 -0
  129. package/src/components/popover-content/index.ts +3 -0
  130. package/src/components/popover-content/styles.ts +95 -0
  131. package/src/components/popover-content/types.ts +11 -0
  132. package/src/components/popover-trigger/PopoverTrigger.tsx +39 -0
  133. package/src/components/popover-trigger/index.ts +2 -0
  134. package/src/components/popover-trigger/types.ts +9 -0
  135. package/src/components/toast/Toast.stories.tsx +68 -0
  136. package/src/components/toast/Toast.test.tsx +63 -0
  137. package/src/components/toast/Toast.tsx +96 -0
  138. package/src/components/toast/index.ts +2 -0
  139. package/src/components/toast/intl/en-US.json +3 -0
  140. package/src/components/toast/intl/fr-FR.json +3 -0
  141. package/src/components/toast/intl/index.ts +7 -0
  142. package/src/components/toast/styles.ts +36 -0
  143. package/src/components/toast/types.ts +44 -0
  144. package/src/components/toast-container/ToastContainer.stories.tsx +349 -0
  145. package/src/components/toast-container/ToastContainer.tsx +44 -0
  146. package/src/components/toast-container/index.ts +3 -0
  147. package/src/components/toast-container/styles.ts +733 -0
  148. package/src/components/toast-container/types.ts +110 -0
  149. package/src/components/toast-container/useToast.test.tsx +111 -0
  150. package/src/components/toast-container/useToast.tsx +128 -0
  151. package/src/components/tooltip/Tooltip.stories.tsx +196 -0
  152. package/src/components/tooltip/Tooltip.test.tsx +119 -0
  153. package/src/components/tooltip/Tooltip.tsx +55 -0
  154. package/src/components/tooltip/context.ts +4 -0
  155. package/src/components/tooltip/index.ts +5 -0
  156. package/src/components/tooltip/types.ts +55 -0
  157. package/src/components/tooltip/useTooltip.tsx +93 -0
  158. package/src/components/tooltip/useTooltipContext.tsx +12 -0
  159. package/src/components/tooltip-content/TooltipContent.tsx +76 -0
  160. package/src/components/tooltip-content/index.ts +2 -0
  161. package/src/components/tooltip-content/styles.ts +84 -0
  162. package/src/components/tooltip-content/types.ts +14 -0
  163. package/src/components/tooltip-trigger/TooltipTrigger.tsx +42 -0
  164. package/src/components/tooltip-trigger/index.ts +2 -0
  165. package/src/components/tooltip-trigger/types.ts +9 -0
  166. package/src/index.ts +16 -0
  167. package/tsconfig.json +3 -0
  168. /package/{CONTRIBUTING.md → dist/CONTRIBUTING.md} +0 -0
  169. /package/{index.d.ts → dist/index.d.ts} +0 -0
  170. /package/{index.js → dist/index.js} +0 -0
  171. /package/{index.js.map → dist/index.js.map} +0 -0
@@ -0,0 +1,96 @@
1
+ {
2
+ "author": {
3
+ "name": "Red Sift"
4
+ },
5
+ "bugs": {
6
+ "url": "https://github.com/redsift/design-system/issues"
7
+ },
8
+ "description": "Popover component library as part of Red Sift's Design System. This package is based on @floating-ui/react and react-toastify.",
9
+ "homepage": "https://github.com/redsift/design-system",
10
+ "license": "MIT",
11
+ "main": "index.js",
12
+ "module": "index.js",
13
+ "name": "@redsift/popovers",
14
+ "publishConfig": {
15
+ "directory": "dist"
16
+ },
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/redsift/design-system"
20
+ },
21
+ "sideEffects": false,
22
+ "scripts": {
23
+ "build": "rollup -c",
24
+ "check-types": "tsc && tsc-strict",
25
+ "lint": "eslint --ext .js,.jsx,.ts,.tsx src/",
26
+ "prepare": "install-peers || exit 0",
27
+ "prepublishOnly": "yarn build",
28
+ "test:unit": "NODE_ENV=test jest --verbose",
29
+ "test:storybook": "test-storybook -c ../../.storybook --url http://localhost:9000/ --coverage",
30
+ "test": "yarn test:unit && yarn test:storybook"
31
+ },
32
+ "types": "index.d.ts",
33
+ "version": "9.2.3",
34
+ "dependencies": {
35
+ "@floating-ui/react": "^0.19.2",
36
+ "@react-aria/i18n": "3.7.2",
37
+ "classnames": "^2.3.1",
38
+ "react-toastify": "^9.1.1"
39
+ },
40
+ "devDependencies": {
41
+ "@babel/core": "^7.8.3",
42
+ "@babel/plugin-proposal-class-properties": "^7.16.7",
43
+ "@babel/plugin-proposal-export-default-from": "^7.16.7",
44
+ "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7",
45
+ "@babel/plugin-proposal-object-rest-spread": "^7.17.3",
46
+ "@babel/plugin-proposal-optional-chaining": "^7.16.7",
47
+ "@babel/plugin-proposal-private-methods": "^7.16.11",
48
+ "@babel/plugin-proposal-private-property-in-object": "^7.16.7",
49
+ "@babel/preset-env": "^7.17.10",
50
+ "@babel/preset-react": "^7.17.12",
51
+ "@babel/preset-typescript": "^7.16.7",
52
+ "@rollup/plugin-babel": "^6.0.2",
53
+ "@rollup/plugin-commonjs": "^24.0.0",
54
+ "@rollup/plugin-json": "^6.0.0",
55
+ "@rollup/plugin-node-resolve": "^13.3.0",
56
+ "@svgr/rollup": "^6.2.1",
57
+ "@testing-library/dom": "^8.5.0",
58
+ "@testing-library/jest-dom": "^5.16.4",
59
+ "@testing-library/react": "^13.4.0",
60
+ "@testing-library/user-event": "14.2.1",
61
+ "@types/jest": "^27.5.1",
62
+ "@types/react": "18.0.12",
63
+ "@types/react-dom": "18.0.5",
64
+ "@types/react-transition-group": "^4.4.5",
65
+ "@types/styled-components": "^5.1.25",
66
+ "@typescript-eslint/eslint-plugin": "^5.48.0",
67
+ "@typescript-eslint/parser": "^5.26.0",
68
+ "autoprefixer": "^9.7.4",
69
+ "babel-plugin-require-context-hook": "^1.0.0",
70
+ "changelog-verify": "^1.1.2",
71
+ "identity-obj-proxy": "^3.0.0",
72
+ "install-peers-cli": "^2.2.0",
73
+ "jest": "^28.1.0",
74
+ "jest-environment-jsdom": "^29.3.0",
75
+ "react": "18.2.0",
76
+ "react-dom": "18.2.0",
77
+ "rollup": "^2.72.1",
78
+ "rollup-plugin-analyzer": "^4.0.0",
79
+ "rollup-plugin-auto-external": "^2.0.0",
80
+ "rollup-plugin-cleaner": "^1.0.0",
81
+ "rollup-plugin-copy": "^3.4.0",
82
+ "rollup-plugin-dts": "^5.0.0",
83
+ "rollup-plugin-execute": "^1.1.0",
84
+ "rollup-plugin-svg": "^2.0.0",
85
+ "rollup-plugin-ts-paths-resolve": "^1.7.1",
86
+ "rollup-plugin-typescript-paths": "^1.3.1",
87
+ "ts-jest": "^28.0.3"
88
+ },
89
+ "peerDependencies": {
90
+ "@redsift/design-system": ">=9.0.0-alpha.0",
91
+ "@redsift/icons": ">=9.0.0-alpha.0",
92
+ "react": ">=17",
93
+ "react-dom": ">=17",
94
+ "styled-components": "^5.3.5"
95
+ }
96
+ }
package/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './src';
package/jest.config.js ADDED
@@ -0,0 +1,3 @@
1
+ var JEST_CONFIG = require('../../configs/jest.config');
2
+
3
+ module.exports = { ...JEST_CONFIG };
package/package.json CHANGED
@@ -30,7 +30,7 @@
30
30
  "test": "yarn test:unit && yarn test:storybook"
31
31
  },
32
32
  "types": "index.d.ts",
33
- "version": "9.2.3-patch",
33
+ "version": "9.2.3",
34
34
  "dependencies": {
35
35
  "@floating-ui/react": "^0.19.2",
36
36
  "@react-aria/i18n": "3.7.2",
@@ -92,6 +92,5 @@
92
92
  "react": ">=17",
93
93
  "react-dom": ">=17",
94
94
  "styled-components": "^5.3.5"
95
- },
96
- "gitHead": "44635b1b3181bd68befd7efc0c3519a81342ad7b"
95
+ }
97
96
  }
@@ -0,0 +1,13 @@
1
+ import { rollupConfig } from '../../configs/rollup.base.config';
2
+
3
+ import pkg from './package.json';
4
+
5
+ const baseRollupConfig = rollupConfig(__dirname, pkg);
6
+
7
+ // Bundle JS code
8
+ const bundleJS = { ...baseRollupConfig.bundleJS };
9
+
10
+ // Bundle TS types in D.TS files
11
+ const bundleType = { ...baseRollupConfig.bundleType };
12
+
13
+ export default [bundleJS, bundleType];
@@ -0,0 +1,264 @@
1
+ import React, { RefObject, useRef, useState } from 'react';
2
+ import { Flexbox, Button, Number, Text, Checkbox } from '@redsift/design-system';
3
+ import { Dialog, DialogProps } from '.';
4
+
5
+ export default {
6
+ title: 'Popovers/Dialog',
7
+ component: Dialog,
8
+ };
9
+
10
+ export const Uncontrolled = () => {
11
+ const nextButtonRef = useRef<HTMLButtonElement>(null);
12
+
13
+ return (
14
+ <Dialog initialFocus={nextButtonRef} defaultOpen={false}>
15
+ <Dialog.Trigger>
16
+ <Button variant="secondary">Button</Button>
17
+ </Dialog.Trigger>
18
+ <Dialog.Content>
19
+ <Dialog.Content.Header header="Dialog Header">
20
+ <Text>
21
+ <Number value={102} as="b" /> mails have been detected from this domain.
22
+ </Text>
23
+ </Dialog.Content.Header>
24
+ <Dialog.Content.Body>
25
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore
26
+ magna aliqua.
27
+ </Dialog.Content.Body>
28
+ <Dialog.Content.Actions justifyContent="space-between">
29
+ <Button variant="unstyled">Previous</Button>
30
+ <Flexbox>
31
+ <Button variant="secondary">Cancel</Button>
32
+ <Button ref={nextButtonRef as RefObject<HTMLButtonElement>}>Next</Button>
33
+ </Flexbox>
34
+ </Dialog.Content.Actions>
35
+ </Dialog.Content>
36
+ </Dialog>
37
+ );
38
+ };
39
+
40
+ export const Controlled = () => {
41
+ const [isOpen, setIsOpen] = useState(false);
42
+ const nextButtonRef = useRef<HTMLButtonElement>(null);
43
+
44
+ return (
45
+ <>
46
+ <Button variant="secondary" onClick={() => setIsOpen(!isOpen)}>
47
+ External trigger
48
+ </Button>
49
+ <Dialog isOpen={isOpen} onOpen={setIsOpen} initialFocus={nextButtonRef}>
50
+ <Dialog.Trigger>
51
+ <Button variant="secondary">Trigger</Button>
52
+ </Dialog.Trigger>
53
+ <Dialog.Content>
54
+ <Dialog.Content.Header header="Dialog Header">
55
+ <Text>
56
+ <Number value={102} as="b" /> mails have been detected from this domain.
57
+ </Text>
58
+ </Dialog.Content.Header>
59
+ <Dialog.Content.Body>
60
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et
61
+ dolore magna aliqua.
62
+ </Dialog.Content.Body>
63
+ <Dialog.Content.Actions justifyContent="space-between">
64
+ <Button variant="unstyled">Previous</Button>
65
+ <Flexbox>
66
+ <Button variant="secondary">Cancel</Button>
67
+ <Button ref={nextButtonRef as RefObject<HTMLButtonElement>}>Next</Button>
68
+ </Flexbox>
69
+ </Dialog.Content.Actions>
70
+ </Dialog.Content>
71
+ </Dialog>
72
+ </>
73
+ );
74
+ };
75
+
76
+ export const CheckboxAsTrigger = () => {
77
+ const nextButtonRef = useRef<HTMLButtonElement>(null);
78
+ const [isOpen, setIsOpen] = useState(false);
79
+ const [selected, setSelected] = useState(false);
80
+
81
+ return (
82
+ <Dialog isOpen={isOpen} onOpen={setIsOpen} initialFocus={nextButtonRef} defaultOpen={false}>
83
+ <Dialog.Trigger>
84
+ <Checkbox isSelected={selected} onChange={() => {}}>
85
+ I accept the terms and conditions
86
+ </Checkbox>
87
+ </Dialog.Trigger>
88
+ <Dialog.Content>
89
+ <Dialog.Content.Header header="Terms and conditions" />
90
+ <Dialog.Content.Body display="flex" flexDirection="column" gap="8px">
91
+ <p>
92
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent ligula est, volutpat sit amet lectus
93
+ condimentum, laoreet imperdiet dolor. Sed eu enim vitae orci egestas blandit id non orci. Mauris blandit
94
+ quis erat sit amet suscipit. Proin congue, leo vitae rutrum accumsan, leo diam consectetur sapien, fermentum
95
+ vestibulum elit turpis et metus. Nulla id magna a enim pulvinar accumsan sit amet sit amet dui. Fusce
96
+ fermentum accumsan odio molestie convallis. Mauris faucibus ex bibendum, condimentum risus eget, ullamcorper
97
+ diam. Nullam at ullamcorper felis. Donec diam ante, gravida a ex non, semper interdum orci.
98
+ </p>
99
+ <p>
100
+ Aliquam rhoncus dui ut odio accumsan, a suscipit ex posuere. Quisque faucibus, justo at consequat malesuada,
101
+ tellus nunc tempus mi, in consequat justo metus ac urna. Suspendisse ut augue at arcu aliquam porttitor. Nam
102
+ vestibulum sit amet nulla quis lobortis. Aenean id odio ut ex ultrices egestas. Nulla luctus fringilla nibh,
103
+ eu accumsan massa mollis eget. Pellentesque eleifend sit amet ante ut lobortis. Curabitur imperdiet ex
104
+ gravida lacus fringilla mollis. Phasellus quis metus elit. Praesent lobortis nec ipsum suscipit congue.
105
+ Aliquam in congue felis.
106
+ </p>
107
+ <p>
108
+ Donec a ante eget leo aliquet congue. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices
109
+ posuere cubilia curae; Nunc id libero vitae ante interdum pharetra. Phasellus ipsum diam, sagittis eget
110
+ feugiat in, faucibus ut quam. Sed ac urna interdum, convallis libero vel, fringilla ipsum. Suspendisse
111
+ blandit fringilla augue, in fringilla nulla. Quisque aliquet mi in fermentum sagittis. Vestibulum eu feugiat
112
+ est. Proin tristique, turpis commodo elementum ultricies, elit ipsum lobortis ex, sed porta orci dolor at
113
+ mi.
114
+ </p>
115
+ <p>
116
+ Donec in dolor blandit, egestas nunc sed, mollis ligula. Class aptent taciti sociosqu ad litora torquent per
117
+ conubia nostra, per inceptos himenaeos. Etiam tempor ipsum id tincidunt pharetra. Nulla orci tortor,
118
+ tristique semper vulputate nec, pharetra sit amet quam. Pellentesque habitant morbi tristique senectus et
119
+ netus et malesuada fames ac turpis egestas. Nam suscipit lacus odio, at vestibulum orci viverra in.
120
+ Phasellus interdum dictum congue. Nulla erat turpis, fermentum sit amet placerat eu, condimentum nec augue.
121
+ Donec eget tortor in massa vehicula ultrices.
122
+ </p>
123
+ <p>
124
+ Sed quis turpis turpis. Ut tincidunt justo ligula, a fermentum nisl venenatis vitae. Vestibulum sodales
125
+ consequat diam, venenatis placerat libero dignissim ac. Vestibulum placerat venenatis pretium. Suspendisse
126
+ potenti. Etiam at pretium magna, non pulvinar risus. Nulla in enim felis. Proin at luctus ipsum. Nunc a
127
+ tristique odio, et dictum quam. Donec a commodo ante, eget fringilla augue. Proin luctus neque vitae est
128
+ congue, et volutpat libero luctus. Nulla luctus placerat accumsan. Aliquam tristique urna est, nec volutpat
129
+ nisl varius at.
130
+ </p>
131
+ </Dialog.Content.Body>
132
+ <Dialog.Content.Actions justifyContent="space-between">
133
+ <Button
134
+ variant="secondary"
135
+ onClick={() => {
136
+ setSelected(false);
137
+ setIsOpen(false);
138
+ }}
139
+ >
140
+ Decline
141
+ </Button>
142
+ <Button
143
+ ref={nextButtonRef as RefObject<HTMLButtonElement>}
144
+ onClick={() => {
145
+ setSelected(true);
146
+ setIsOpen(false);
147
+ }}
148
+ >
149
+ Accept
150
+ </Button>
151
+ </Dialog.Content.Actions>
152
+ </Dialog.Content>
153
+ </Dialog>
154
+ );
155
+ };
156
+
157
+ export const TriggerIsInvalid = () => (
158
+ <Dialog>
159
+ <Dialog.Trigger>
160
+ This text has a dialog but this will never be displayed because the trigger is not a button.
161
+ </Dialog.Trigger>
162
+ <Dialog.Content>
163
+ <Text margin="16px">
164
+ Cupcake ipsum dolor sit amet blueie jujubes topping sesame snaps. Liquorice marzipan jelly-o carrot cake icing
165
+ croissant carrot cake. Tart soufflé sweet roll halvah croissant wafer cotton candy. Candy halvah marzipan bear
166
+ claw donut.
167
+ </Text>
168
+ </Dialog.Content>
169
+ </Dialog>
170
+ );
171
+
172
+ export const EmptyDialog = () => (
173
+ <Flexbox
174
+ flexDirection="row"
175
+ flexWrap="wrap"
176
+ justifyContent="center"
177
+ alignItems="center"
178
+ padding="32px"
179
+ style={{ backgroundColor: '#EFEFEF' }}
180
+ >
181
+ <Dialog>
182
+ <Dialog.Trigger>
183
+ <Button variant="secondary">Button</Button>
184
+ </Dialog.Trigger>
185
+ </Dialog>
186
+ </Flexbox>
187
+ );
188
+
189
+ export const DialogOnDisabledButton = () => (
190
+ <Flexbox
191
+ flexDirection="row"
192
+ flexWrap="wrap"
193
+ justifyContent="center"
194
+ alignItems="center"
195
+ padding="32px"
196
+ style={{ backgroundColor: '#EFEFEF' }}
197
+ >
198
+ <Dialog>
199
+ <Dialog.Trigger>
200
+ <Button variant="secondary" isDisabled>
201
+ Disabled
202
+ </Button>
203
+ </Dialog.Trigger>
204
+ <Dialog.Content>
205
+ <Text margin="16px">
206
+ Cupcake ipsum dolor sit amet blueie jujubes topping sesame snaps. Liquorice marzipan jelly-o carrot cake icing
207
+ croissant carrot cake. Tart soufflé sweet roll halvah croissant wafer cotton candy. Candy halvah marzipan bear
208
+ claw donut.
209
+ </Text>
210
+ </Dialog.Content>
211
+ </Dialog>
212
+ </Flexbox>
213
+ );
214
+
215
+ export const InitialFocus = () => {
216
+ const nextButtonRef = useRef<HTMLButtonElement>(null);
217
+
218
+ const renderDialog = ({ title, initialFocus }: { title: string; initialFocus?: DialogProps['initialFocus'] }) => (
219
+ <Dialog initialFocus={initialFocus}>
220
+ <Dialog.Trigger>
221
+ <Button variant="secondary">{title}</Button>
222
+ </Dialog.Trigger>
223
+ <Dialog.Content>
224
+ <Dialog.Content.Header header="Dialog Header">
225
+ <Text>
226
+ <Number value={102} as="b" /> mails have been detected from this domain.
227
+ </Text>
228
+ </Dialog.Content.Header>
229
+ <Dialog.Content.Body>
230
+ {Array.from({ length: 100 }).map((e, i) => (
231
+ <p key={i}>
232
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et
233
+ dolore magna aliqua.
234
+ </p>
235
+ ))}
236
+ </Dialog.Content.Body>
237
+ <Dialog.Content.Actions justifyContent="space-between">
238
+ <Button variant="unstyled">Previous</Button>
239
+ <Flexbox>
240
+ <Button variant="secondary">Cancel</Button>
241
+ <Button ref={nextButtonRef as RefObject<HTMLButtonElement>}>Next</Button>
242
+ </Flexbox>
243
+ </Dialog.Content.Actions>
244
+ </Dialog.Content>
245
+ </Dialog>
246
+ );
247
+
248
+ return (
249
+ <Flexbox
250
+ flexDirection="row"
251
+ flexWrap="wrap"
252
+ justifyContent="center"
253
+ alignItems="center"
254
+ padding="32px"
255
+ style={{ backgroundColor: '#EFEFEF' }}
256
+ >
257
+ {renderDialog({ title: 'Default' })}
258
+ {renderDialog({ title: 'Next', initialFocus: nextButtonRef })}
259
+ {renderDialog({ title: 'Header', initialFocus: 'header' })}
260
+ {renderDialog({ title: 'Body', initialFocus: 'body' })}
261
+ {renderDialog({ title: 'Actions', initialFocus: 'actions' })}
262
+ </Flexbox>
263
+ );
264
+ };
@@ -0,0 +1,116 @@
1
+ import React from 'react';
2
+ import {
3
+ act,
4
+ fireEvent,
5
+ render,
6
+ screen,
7
+ waitFor,
8
+ } from '@testing-library/react';
9
+
10
+ import { Button } from '@redsift/design-system';
11
+ import { DialogContent } from '../dialog-content';
12
+ import { DialogTrigger } from '../dialog-trigger';
13
+ import { DialogContentHeader } from '../dialog-content-header';
14
+ import { DialogContentBody } from '../dialog-content-body';
15
+ import { Dialog } from '.';
16
+
17
+ describe('Dialog', () => {
18
+ const onOpenSpy = jest.fn();
19
+ const realError = console.error;
20
+
21
+ beforeEach(() => {
22
+ console.error = jest.fn();
23
+ });
24
+
25
+ afterEach(() => {
26
+ onOpenSpy.mockClear();
27
+ console.error = realError;
28
+ });
29
+
30
+ it.each`
31
+ Name | Component | props
32
+ ${'DialogTrigger'} | ${DialogTrigger} | ${{}}
33
+ ${'DialogContent'} | ${DialogContent} | ${{}}
34
+ ${'DialogContentHeader'} | ${DialogContentHeader} | ${{}}
35
+ `(
36
+ '$Name should throw error when not wrapped inside `Dialog`',
37
+ function ({ Component, props }) {
38
+ expect(() => render(<Component {...props} />)).toThrow(
39
+ 'Dialog components must be wrapped in <Dialog />'
40
+ );
41
+ }
42
+ );
43
+
44
+ it.each`
45
+ Name | Component | props
46
+ ${'Controlled Dialog'} | ${Dialog} | ${{ onOpen: onOpenSpy, isOpen: false }}
47
+ ${'Uncontrolled Dialog'} | ${Dialog} | ${{ onOpen: onOpenSpy, defaultOpen: false }}
48
+ `(
49
+ '$Name can be closed by default and then open',
50
+ async function ({ Name, Component, props }) {
51
+ const { getByText } = render(
52
+ <Component {...props}>
53
+ <DialogTrigger>
54
+ <Button variant="secondary">Trigger</Button>
55
+ </DialogTrigger>
56
+ <DialogContent>
57
+ <DialogContentBody>Content</DialogContentBody>
58
+ </DialogContent>
59
+ </Component>
60
+ );
61
+
62
+ expect(screen.queryByText('Content')).not.toBeInTheDocument();
63
+ expect(onOpenSpy).not.toHaveBeenCalled();
64
+
65
+ const triggerButton = getByText('Trigger');
66
+ fireEvent.click(triggerButton);
67
+
68
+ expect(onOpenSpy).toHaveBeenCalled();
69
+ if (Name.includes('Uncontrolled')) {
70
+ await act(async () => {});
71
+ await waitFor(() => {
72
+ expect(screen.queryByText('Content')).toBeInTheDocument();
73
+ });
74
+ expect(getByText('Content')).toBeVisible();
75
+ }
76
+ }
77
+ );
78
+
79
+ it.each`
80
+ Name | Component | props
81
+ ${'Controlled Dialog'} | ${Dialog} | ${{ onOpen: onOpenSpy, isOpen: true }}
82
+ ${'Uncontrolled Dialog'} | ${Dialog} | ${{ onOpen: onOpenSpy, defaultOpen: true }}
83
+ `(
84
+ '$Name can be open by default and then closed',
85
+ async function ({ Name, Component, props }) {
86
+ render(
87
+ <Component {...props}>
88
+ <DialogTrigger>
89
+ <Button variant="secondary">Trigger</Button>
90
+ </DialogTrigger>
91
+ <DialogContent>
92
+ <DialogContentBody>Content</DialogContentBody>
93
+ </DialogContent>
94
+ </Component>
95
+ );
96
+ await act(async () => {});
97
+ await waitFor(() => {
98
+ expect(screen.queryByText('Content')).toBeInTheDocument();
99
+ });
100
+
101
+ expect(screen.queryByText('Content')).toBeVisible();
102
+ expect(onOpenSpy).not.toHaveBeenCalled();
103
+
104
+ const closeButton = screen.getByLabelText('Close');
105
+ fireEvent.click(closeButton);
106
+
107
+ expect(onOpenSpy).toHaveBeenCalled();
108
+ if (Name.includes('Uncontrolled')) {
109
+ await act(async () => {});
110
+ await waitFor(() => {
111
+ expect(screen.queryByText('Content')).not.toBeInTheDocument();
112
+ });
113
+ }
114
+ }
115
+ );
116
+ });
@@ -0,0 +1,62 @@
1
+ import React from 'react';
2
+ import { partitionComponents, isComponent } from '@redsift/design-system';
3
+ import { DialogContent } from '../dialog-content';
4
+ import { DialogTrigger } from '../dialog-trigger';
5
+
6
+ import { DialogContext } from './context';
7
+ import { DialogProps, DialogSize } from './types';
8
+ import { useDialog } from './useDialog';
9
+
10
+ const COMPONENT_NAME = 'Dialog';
11
+ const CLASSNAME = 'redsift-dialog';
12
+ const DEFAULT_PROPS: Partial<DialogProps> = {
13
+ hasCloseButton: true,
14
+ size: DialogSize.medium,
15
+ };
16
+
17
+ /**
18
+ * The Dialog component.
19
+ */
20
+ export const BaseDialog: React.FC<DialogProps> & {
21
+ displayName?: string;
22
+ className?: string;
23
+ } = (props) => {
24
+ const {
25
+ children,
26
+ defaultOpen,
27
+ hasCloseButton = DEFAULT_PROPS.hasCloseButton,
28
+ initialFocus,
29
+ isOpen,
30
+ onOpen,
31
+ size,
32
+ } = props;
33
+
34
+ const dialog = useDialog({
35
+ defaultOpen,
36
+ hasCloseButton,
37
+ initialFocus,
38
+ isOpen,
39
+ onOpen,
40
+ size,
41
+ });
42
+
43
+ const [[trigger], [content]] = partitionComponents(
44
+ React.Children.toArray(children),
45
+ [isComponent('DialogTrigger'), isComponent('DialogContent')]
46
+ );
47
+
48
+ return (
49
+ <DialogContext.Provider value={dialog}>
50
+ {trigger}
51
+ {content}
52
+ </DialogContext.Provider>
53
+ );
54
+ };
55
+ BaseDialog.className = CLASSNAME;
56
+ BaseDialog.defaultProps = DEFAULT_PROPS;
57
+ BaseDialog.displayName = COMPONENT_NAME;
58
+
59
+ export const Dialog = Object.assign(BaseDialog, {
60
+ Trigger: DialogTrigger,
61
+ Content: DialogContent,
62
+ });
@@ -0,0 +1,4 @@
1
+ import React from 'react';
2
+ import { DialogState } from './types';
3
+
4
+ export const DialogContext = React.createContext<DialogState | null>(null);
@@ -0,0 +1,5 @@
1
+ export * from './context';
2
+ export * from './types';
3
+ export * from './Dialog';
4
+ export * from './useDialog';
5
+ export * from './useDialogContext';
@@ -0,0 +1,52 @@
1
+ import { Dispatch, ReactNode, SetStateAction } from 'react';
2
+ import { ValueOf } from '@redsift/design-system';
3
+ import { useDialog } from './useDialog';
4
+
5
+ /**
6
+ * Context props.
7
+ */
8
+ export type DialogState =
9
+ | (ReturnType<typeof useDialog> & {
10
+ setLabelId: Dispatch<SetStateAction<string | undefined>>;
11
+ setDescriptionId: Dispatch<SetStateAction<string | undefined>>;
12
+ })
13
+ | null;
14
+
15
+ /**
16
+ * Component variant.
17
+ */
18
+ export const DialogSize = {
19
+ small: 'small',
20
+ medium: 'medium',
21
+ large: 'large',
22
+ xlarge: 'xlarge',
23
+ } as const;
24
+ export type DialogSize = ValueOf<typeof DialogSize>;
25
+
26
+ /**
27
+ * Component props.
28
+ */
29
+ export interface DialogProps {
30
+ /** Children. Can only be DialogTrigger and DialogContent. */
31
+ children: ReactNode;
32
+ /**
33
+ * Default open status.
34
+ * Used for uncontrolled version.
35
+ */
36
+ defaultOpen?: boolean;
37
+ /** Whether the Close icon button is displayed or not. */
38
+ hasCloseButton?: boolean;
39
+ /** Which element to initially focus. Can be either a number (tabbable index), a ref to en element, or a shortcut pointing towards a section of the dialog. See the accessibility section in the documentation to know which one to use. */
40
+ initialFocus?: number | React.MutableRefObject<HTMLElement | null> | 'header' | 'body' | 'actions';
41
+ /**
42
+ * Whether the component is opened or not.
43
+ * Used for controlled version.
44
+ */
45
+ isOpen?: boolean;
46
+ /** Method to handle component change. */
47
+ onOpen?: (open: boolean) => void;
48
+ /** Dialog size. */
49
+ size?: DialogSize | { width: string };
50
+ }
51
+
52
+ export type StyledDialogProps = DialogProps;