@nuskin/foundation-ui-components 1.0.0-cft-35.13 → 1.0.0-develop.10

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 (247) hide show
  1. package/package.json +21 -11
  2. package/src/common/accordion/NsAccordion.tsx +69 -0
  3. package/src/common/accordion/NsAccordionHeader.tsx +77 -0
  4. package/src/common/accordion/NsAccordionItem.tsx +59 -0
  5. package/src/common/accordion/NsCollapse.tsx +110 -0
  6. package/src/common/accordion/NsToggleSection.tsx +43 -0
  7. package/src/common/accordion/ToggleSection.styled.tsx +32 -0
  8. package/src/common/accordion/colorMap.ts +117 -0
  9. package/src/common/accordion/enums.ts +8 -0
  10. package/src/common/accordion/index.ts +7 -0
  11. package/src/common/accordion/specs/NsAccordion.spec.tsx +163 -0
  12. package/src/common/accordion/specs/NsAccordionHeader.spec.tsx +130 -0
  13. package/src/common/accordion/specs/NsAccordionItem.spec.tsx +79 -0
  14. package/src/common/accordion/specs/NsCollapse.spec.tsx +129 -0
  15. package/src/common/accordion/specs/NsToggleSection.spec.tsx +74 -0
  16. package/src/common/accordion/stories/NsAccordion.stories.tsx +65 -0
  17. package/src/common/accordion/stories/NsAccordionHeader.stories.tsx +44 -0
  18. package/src/common/accordion/stories/NsAccordionItem.stories.tsx +45 -0
  19. package/src/common/accordion/stories/NsCollapse.stories.tsx +50 -0
  20. package/src/common/accordion/stories/NsToggleSection.stories.tsx +26 -0
  21. package/src/common/accordion/stories/data.tsx +143 -0
  22. package/src/common/accordion/types.d.ts +81 -0
  23. package/src/common/alert/Header.tsx +29 -0
  24. package/src/common/alert/NsAlert.spec.tsx +62 -29
  25. package/src/common/alert/NsAlert.stories.tsx +18 -17
  26. package/src/common/alert/NsAlert.styled.tsx +124 -0
  27. package/src/common/alert/NsAlert.tsx +27 -110
  28. package/src/common/alert/index.ts +2 -2
  29. package/src/common/alert/types.d.ts +23 -23
  30. package/src/common/auth-dropdown/NsAuthDropdown.spec.tsx +24 -6
  31. package/src/common/auth-dropdown/NsAuthDropdown.stories.tsx +2 -2
  32. package/src/common/auth-dropdown/NsAuthDropdown.styled.ts +21 -16
  33. package/src/common/auth-dropdown/NsAuthDropdown.tsx +7 -6
  34. package/src/common/auth-dropdown/index.ts +1 -1
  35. package/src/common/auth-dropdown/types.d.ts +3 -1
  36. package/src/common/autocomplete/NsAutocomplete.spec.tsx +69 -24
  37. package/src/common/autocomplete/NsAutocomplete.stories.tsx +64 -7
  38. package/src/common/autocomplete/NsAutocomplete.styled.tsx +12 -0
  39. package/src/common/autocomplete/NsAutocomplete.tsx +100 -46
  40. package/src/common/autocomplete/index.ts +2 -1
  41. package/src/common/autocomplete/mock/MockData.ts +50 -7
  42. package/src/common/autocomplete/mock/MockUI.tsx +2 -1
  43. package/src/common/autocomplete/{types.ts → types.d.ts} +18 -8
  44. package/src/common/banner/NsBanner.spec.tsx +13 -4
  45. package/src/common/banner/NsBanner.stories.tsx +2 -2
  46. package/src/common/banner/NsBanner.styled.tsx +1 -1
  47. package/src/common/banner/NsBanner.tsx +1 -1
  48. package/src/common/banner/index.ts +1 -1
  49. package/src/common/brand-components/NsBrand.stories.tsx +2 -2
  50. package/src/common/brand-components/NsBrandComponent.tsx +6 -3
  51. package/src/common/brand-components/index.ts +1 -1
  52. package/src/common/breadcrumb/NsBreadcrumb.spec.tsx +8 -9
  53. package/src/common/breadcrumb/NsBreadcrumb.stories.tsx +3 -5
  54. package/src/common/breadcrumb/NsBreadcrumb.tsx +5 -3
  55. package/src/common/breadcrumb/data.ts +10 -0
  56. package/src/common/breadcrumb/index.ts +1 -1
  57. package/src/common/button/NsButton.spec.tsx +66 -51
  58. package/src/common/button/NsButton.stories.tsx +61 -4
  59. package/src/common/button/NsButton.styled.tsx +54 -72
  60. package/src/common/button/NsButton.tsx +9 -3
  61. package/src/common/button/helper.ts +82 -0
  62. package/src/common/button/index.ts +1 -1
  63. package/src/common/button/types.d.ts +3 -0
  64. package/src/common/card/NsFfgCard.tsx +14 -8
  65. package/src/common/card/specs/NsFfgCard.spec.tsx +33 -0
  66. package/src/common/card/stories/NsBgCard.stories.tsx +2 -4
  67. package/src/common/card/stories/NsBrandProductCard.stories.tsx +2 -2
  68. package/src/common/card/stories/NsFfgCard.stories.tsx +49 -16
  69. package/src/common/card/stories/{data.js → data.ts} +1 -25
  70. package/src/common/card/styled/NsFfgStyled.tsx +9 -7
  71. package/src/common/card/types.d.ts +7 -4
  72. package/src/common/carousal/NsScrollingCarousal.tsx +61 -0
  73. package/src/common/carousal/index.ts +3 -0
  74. package/src/common/carousal/{tests → specs}/NsCarousal.spec.tsx +2 -2
  75. package/src/common/carousal/specs/NsScrollingCarousal.spec.tsx +61 -0
  76. package/src/common/carousal/stories/NSCarousal.stories.tsx +2 -2
  77. package/src/common/carousal/stories/NsScrollingCarousal.stories.tsx +52 -0
  78. package/src/common/carousal/types.d.ts +23 -0
  79. package/src/common/cart-icon/NsCartIcon.spec.tsx +1 -1
  80. package/src/common/cart-icon/NsCartIcon.stories.tsx +2 -2
  81. package/src/common/cart-icon/NsCartIcon.tsx +1 -1
  82. package/src/common/cart-icon/index.ts +1 -1
  83. package/src/common/checkbox/NsCheckbox.spec.tsx +2 -2
  84. package/src/common/checkbox/NsCheckbox.stories.tsx +2 -2
  85. package/src/common/checkbox/NsCheckbox.styled.tsx +15 -16
  86. package/src/common/checkbox/NsCheckbox.tsx +2 -2
  87. package/src/common/checkbox/index.ts +1 -1
  88. package/src/common/checkbox/types.d.ts +1 -7
  89. package/src/common/column-control/NsColumnControl.tsx +1 -1
  90. package/src/common/column-control/NsFlexColumns.tsx +22 -0
  91. package/src/common/column-control/NsGridColumns.tsx +22 -0
  92. package/src/common/column-control/index.ts +3 -1
  93. package/src/common/column-control/{NsColumnControl.spec.tsx → specs/NsColumnControl.spec.tsx} +3 -3
  94. package/src/common/column-control/specs/NsFlexColumns.spec.tsx +24 -0
  95. package/src/common/column-control/specs/NsGridColumns.spec.tsx +24 -0
  96. package/src/common/column-control/stories/DivArray.stories.tsx +18 -0
  97. package/src/common/column-control/stories/DivArray.tsx +63 -0
  98. package/src/common/column-control/{NsColumnControl.stories.tsx → stories/NsColumnControl.stories.tsx} +9 -16
  99. package/src/common/column-control/stories/NsFlexColumns.stories.tsx +63 -0
  100. package/src/common/column-control/stories/NsGridColumns.stories.tsx +63 -0
  101. package/src/common/column-control/stories/common.tsx +14 -0
  102. package/src/common/column-control/styled/StyledFlex.tsx +45 -0
  103. package/src/common/column-control/styled/StyledGrid.tsx +40 -0
  104. package/src/common/column-control/styled/common.ts +27 -0
  105. package/src/common/column-control/types.d.ts +15 -16
  106. package/src/common/column-control/utils.ts +5 -5
  107. package/src/common/common.types.d.ts +21 -0
  108. package/src/common/dropdown/NsDropdown.spec.tsx +1 -1
  109. package/src/common/dropdown/NsDropdown.styled.tsx +23 -18
  110. package/src/common/dropdown/NsDropdown.tsx +1 -1
  111. package/src/common/dropdown/NsDropdownOption.tsx +1 -1
  112. package/src/common/dropdown/index.ts +1 -1
  113. package/src/common/dropdown/stories/NsDropdown.stories.tsx +2 -2
  114. package/src/common/dropdown/stories/NsDropdownCountry.stories.tsx +2 -2
  115. package/src/common/dropdown/types.d.ts +3 -1
  116. package/src/common/email-simple/NsEmailSimple.spec.tsx +145 -0
  117. package/src/common/email-simple/NsEmailSimple.stories.tsx +61 -0
  118. package/src/common/email-simple/NsEmailSimple.tsx +71 -0
  119. package/src/common/email-simple/index.ts +2 -0
  120. package/src/common/email-simple/types.d.ts +14 -0
  121. package/src/common/flag/NsFlag.spec.tsx +5 -25
  122. package/src/common/flag/NsFlag.stories.tsx +2 -2
  123. package/src/common/flag/NsFlag.styled.tsx +7 -9
  124. package/src/common/flag/NsFlag.tsx +1 -3
  125. package/src/common/flag/index.ts +1 -1
  126. package/src/common/flag/types.d.ts +0 -2
  127. package/src/common/hooks/index.ts +2 -0
  128. package/src/common/hooks/specs/useWindowSize.spec.tsx +19 -0
  129. package/src/common/hooks/useAccordionMap.tsx +39 -0
  130. package/src/common/hooks/useWindowSize.tsx +30 -0
  131. package/src/common/icon/NsIcon.spec.tsx +1 -1
  132. package/src/common/icon/NsIcon.stories.tsx +2 -2
  133. package/src/common/icon/NsIcon.styled.tsx +1 -1
  134. package/src/common/icon/NsIcon.tsx +1 -1
  135. package/src/common/icon/NsIconVariants.ts +9 -4
  136. package/src/common/icon/icons/AlertErrorIcon.tsx +15 -6
  137. package/src/common/icon/icons/HamburgerIcon.tsx +29 -0
  138. package/src/common/icon/icons/UserIcon.tsx +30 -0
  139. package/src/common/icon/icons/WarningIcon.tsx +14 -5
  140. package/src/common/icon/index.ts +1 -1
  141. package/src/common/icon/types.d.ts +1 -0
  142. package/src/common/image/NsImage.spec.tsx +57 -7
  143. package/src/common/image/NsImage.stories.tsx +2 -2
  144. package/src/common/image/NsImage.tsx +24 -12
  145. package/src/common/image/NsNextImage.spec.tsx +1 -1
  146. package/src/common/image/NsNextImage.stories.tsx +2 -2
  147. package/src/common/image/NsNextImage.tsx +1 -1
  148. package/src/common/image/index.ts +1 -1
  149. package/src/common/image/types.d.ts +1 -0
  150. package/src/common/index.ts +14 -10
  151. package/src/common/input/InputFieldWrapper.tsx +4 -4
  152. package/src/common/input/InputWrapper.tsx +12 -7
  153. package/src/common/input/NsInputField.stories.tsx +13 -10
  154. package/src/common/input/NsInputField.tsx +13 -6
  155. package/src/common/input/getAdornmentProps.tsx +5 -1
  156. package/src/common/input/index.ts +1 -1
  157. package/src/common/input/types.d.ts +18 -1
  158. package/src/common/label/NsLabel.stories.tsx +6 -1
  159. package/src/common/label/NsLabel.tsx +21 -20
  160. package/src/common/label/index.ts +1 -1
  161. package/src/common/label/types.d.ts +2 -1
  162. package/src/common/link/NsLink.spec.tsx +1 -1
  163. package/src/common/link/NsLink.stories.tsx +2 -2
  164. package/src/common/link/NsLink.tsx +1 -1
  165. package/src/common/link/index.ts +1 -1
  166. package/src/common/modal/NsModal.spec.tsx +46 -0
  167. package/src/common/modal/NsModal.styled.tsx +28 -0
  168. package/src/common/modal/NsModal.tsx +37 -0
  169. package/src/common/modal/helper-component/NsModalContentBox.tsx +32 -0
  170. package/src/common/modal/helper-component/NsModalDefault.tsx +25 -0
  171. package/src/common/modal/helper-component/NsModalStatus.tsx +15 -0
  172. package/src/common/modal/helper-component/NsModalStatusIcon.tsx +14 -0
  173. package/src/common/modal/helper-component/NsModalTitle.tsx +26 -0
  174. package/src/common/modal/index.ts +2 -0
  175. package/src/common/modal/model/NsModalVariantMap.tsx +24 -0
  176. package/src/common/modal/stories/NsModal.stories.tsx +86 -0
  177. package/src/common/modal/stories/mock.tsx +46 -0
  178. package/src/common/modal/types.ts +56 -0
  179. package/src/common/nav-product-card/NsNavProductCard.spec.tsx +1 -1
  180. package/src/common/nav-product-card/NsNavProductCard.stories.tsx +2 -2
  181. package/src/common/nav-product-card/NsNavProductCard.tsx +1 -1
  182. package/src/common/nav-product-card/index.ts +1 -1
  183. package/src/common/nav-tab/NsNavTab.spec.tsx +2 -7
  184. package/src/common/nav-tab/NsNavTab.stories.tsx +2 -2
  185. package/src/common/nav-tab/NsNavTab.styled.tsx +7 -4
  186. package/src/common/nav-tab/NsNavTab.tsx +1 -1
  187. package/src/common/nav-tab/index.ts +1 -1
  188. package/src/common/nav-tab/types.d.ts +2 -2
  189. package/src/common/radiogroup/NsRadioGroup.spec.tsx +63 -0
  190. package/src/common/radiogroup/NsRadioGroup.stories.tsx +84 -0
  191. package/src/common/radiogroup/NsRadioGroup.styled.tsx +52 -0
  192. package/src/common/radiogroup/NsRadioGroup.tsx +62 -0
  193. package/src/common/radiogroup/index.ts +2 -0
  194. package/src/common/radiogroup/types.d.ts +20 -0
  195. package/src/common/search-bar/NsSeachBar.spec.tsx +1 -1
  196. package/src/common/search-bar/NsSearchBar.tsx +1 -3
  197. package/src/common/select/NsSelect.spec.tsx +193 -0
  198. package/src/common/select/NsSelect.styled.tsx +104 -0
  199. package/src/common/select/NsSelect.tsx +117 -0
  200. package/src/common/select/NsSelectOption.tsx +30 -0
  201. package/src/common/select/index.ts +3 -0
  202. package/src/common/select/stories/NsSelect.stories.tsx +134 -0
  203. package/src/common/select/types.d.ts +34 -0
  204. package/src/common/spinner/NsSpinner.spec.tsx +21 -0
  205. package/src/common/spinner/NsSpinner.stories.tsx +26 -0
  206. package/src/common/spinner/NsSpinner.styled.tsx +344 -0
  207. package/src/common/spinner/NsSpinner.tsx +14 -0
  208. package/src/common/spinner/icons/Spinner.tsx +161 -0
  209. package/src/common/spinner/index.ts +2 -0
  210. package/src/common/spinner/types.ts +5 -0
  211. package/src/common/table/NsExpandableRow.tsx +68 -0
  212. package/src/common/table/NsTable.spec.tsx +174 -0
  213. package/src/common/table/NsTable.stories.tsx +161 -0
  214. package/src/common/table/NsTable.styled.ts +127 -0
  215. package/src/common/table/NsTable.tsx +133 -0
  216. package/src/common/table/NsTableHeader.tsx +41 -0
  217. package/src/common/table/NsTablePagination.tsx +28 -0
  218. package/src/common/table/helper.ts +33 -0
  219. package/src/common/table/index.ts +2 -0
  220. package/src/common/table/types.d.ts +57 -0
  221. package/src/common/text-strip/NsTextStrip.spec.tsx +30 -0
  222. package/src/common/text-strip/NsTextStrip.stories.tsx +33 -0
  223. package/src/common/text-strip/NsTextStrip.tsx +47 -0
  224. package/src/common/text-strip/index.ts +2 -0
  225. package/src/common/text-strip/types.d.ts +17 -0
  226. package/src/common/typography/NsTypography.stories.tsx +2 -2
  227. package/src/common/typography/NsTypography.tsx +1 -1
  228. package/src/common/typography/Typography.styled.tsx +4 -4
  229. package/src/common/typography/index.ts +1 -1
  230. package/src/common/util.ts +1 -0
  231. package/src/common/utility/Show.tsx +13 -0
  232. package/src/common/utility/index.ts +1 -0
  233. package/src/common/validations/regex.ts +3 -0
  234. package/src/common/videos/NsVideo.stories.tsx +2 -2
  235. package/src/common/videos/NsVideo.tsx +1 -1
  236. package/src/common/videos/index.ts +1 -1
  237. package/src/common/videos/types.d.ts +1 -1
  238. package/src/common/alert/NsAlert.styled.ts +0 -124
  239. package/src/common/card/tests/NsFfgCard.spec.tsx +0 -23
  240. package/src/common/column-control/NDivs.story.tsx +0 -35
  241. package/src/common/common.types.ts +0 -10
  242. /package/src/common/brand-components/{NsBrandContanier.styled.tsx → NsBrandContainer.styled.tsx} +0 -0
  243. /package/src/common/card/{tests → specs}/BrandLogo.spec.tsx +0 -0
  244. /package/src/common/card/{tests → specs}/NsBgCard.spec.tsx +0 -0
  245. /package/src/common/card/{tests → specs}/NsBrandProductCard.spec.tsx +0 -0
  246. /package/src/common/carousal/{tests → specs}/Chevron.spec.tsx +0 -0
  247. /package/src/common/carousal/{tests → specs}/RenderBrand.spec.tsx +0 -0
@@ -0,0 +1,163 @@
1
+ import React from 'react';
2
+ import { render, fireEvent, screen } from '@/test-utils/index';
3
+ import { AccordionItem, AccordionVariant, NsAccordion } from '@/common/index';
4
+
5
+ const generateContentArray = (count: number, isDefaultOpen = true) => {
6
+ const arr = [] as AccordionItem[];
7
+ for (let i = 1; i <= count; i++) {
8
+ arr?.push({
9
+ title: `Title ${i}`,
10
+ content: <div className="p-2">Content {i}</div>,
11
+ isDefaultOpen,
12
+ type:'jsx',
13
+ id: `Test ${i}`,
14
+ });
15
+ }
16
+ return arr;
17
+ };
18
+
19
+ describe('NsAccordion', () => {
20
+ const items = generateContentArray(3);
21
+ const defaultProps = {
22
+ additionalProps: {
23
+ testid: 'test-accordion',
24
+ },
25
+ allowMultipleExpanded: false,
26
+ items,
27
+ variant: AccordionVariant.Basic,
28
+ invert: false,
29
+ level: 0,
30
+ };
31
+
32
+ it('1. renders without error', () => {
33
+ const { getByTestId } = render(<NsAccordion {...defaultProps} />);
34
+ const accordion = getByTestId(defaultProps.additionalProps.testid);
35
+ expect(accordion).toBeInTheDocument();
36
+ });
37
+
38
+ it(`2. only first section should be visible when allowMultipleExpanded prop is false and multiple items have
39
+ isDefaultOpen true`, () => {
40
+ const { getAllByText } = render(<NsAccordion {...defaultProps} />);
41
+ const [title1, title2, title3] = getAllByText(/Title /i);
42
+
43
+ expect(title1.closest('header')).toHaveAttribute('aria-expanded', 'true');
44
+ expect(title2.closest('header')).toHaveAttribute('aria-expanded', 'false');
45
+ expect(title3.closest('header')).toHaveAttribute('aria-expanded', 'false');
46
+ const [c1, c2, c3] = getAllByText(/Content /i);
47
+ expect(c1.parentNode).toHaveStyle('opacity: 1');
48
+ expect(c2.parentNode).toHaveStyle('opacity: 0');
49
+ expect(c3.parentNode).toHaveStyle('opacity: 0');
50
+ });
51
+
52
+ it(`3. expands second section only when allowMultipleExpanded
53
+ prop is false and second title is clicked`, async () => {
54
+ const { getAllByText } = render(<NsAccordion {...defaultProps} />);
55
+ const [title1, title2, title3] = getAllByText(/Title /i);
56
+ const header = title2.closest('header');
57
+ expect(header).toHaveAttribute('aria-expanded', 'false');
58
+ if (header) {
59
+ fireEvent.click(header);
60
+ expect(title1.closest('header')).toHaveAttribute('aria-expanded', 'false');
61
+ expect(title2.closest('header')).toHaveAttribute('aria-expanded', 'true');
62
+ expect(title3.closest('header')).toHaveAttribute('aria-expanded', 'false');
63
+ const [c1, c2, c3] = getAllByText(/Content /i);
64
+ expect(c1.parentNode).toHaveStyle('opacity: 0');
65
+ expect(c2.parentNode).toHaveStyle('opacity: 1');
66
+ expect(c3.parentNode).toHaveStyle('opacity: 0');
67
+ }
68
+ });
69
+
70
+ it('4. expands multiple sections by default when allowMultipleExpanded prop is true', () => {
71
+ const items = generateContentArray(3);
72
+ items[2].isDefaultOpen = false;
73
+ const defaultProps = {
74
+ allowMultipleExpanded: false,
75
+ items,
76
+ variant: AccordionVariant.Basic,
77
+ level: 0,
78
+ invert: false,
79
+ };
80
+ const { getAllByText } = render(<NsAccordion {...defaultProps} allowMultipleExpanded />);
81
+ const accordion = screen.getByTestId('ns-accordion-testid');
82
+ expect(accordion).toBeDefined();
83
+ const [title1, title2, title3] = getAllByText(/Title /i);
84
+
85
+ expect(title1.closest('header')).toHaveAttribute('aria-expanded', 'true');
86
+ expect(title2.closest('header')).toHaveAttribute('aria-expanded', 'true');
87
+ expect(title3.closest('header')).toHaveAttribute('aria-expanded', 'false');
88
+
89
+ const [c1, c2, c3] = getAllByText(/Content /i);
90
+ expect(c1.parentNode).toHaveStyle('opacity: 1');
91
+ expect(c2.parentNode).toHaveStyle('opacity: 1');
92
+ expect(c3.parentNode).toHaveStyle('opacity: 0');
93
+
94
+ fireEvent.click(title3);
95
+
96
+ expect(title1.closest('header')).toHaveAttribute('aria-expanded', 'true');
97
+ expect(title2.closest('header')).toHaveAttribute('aria-expanded', 'true');
98
+ expect(title3.closest('header')).toHaveAttribute('aria-expanded', 'true');
99
+
100
+ const [c11, c12, c13] = getAllByText(/Content /i);
101
+ expect(c11.parentNode).toHaveStyle('opacity: 1');
102
+ expect(c12.parentNode).toHaveStyle('opacity: 1');
103
+ expect(c13.parentNode).toHaveStyle('opacity: 1');
104
+ });
105
+ it(`5. closes second section also when allowMultipleExpanded
106
+ prop is true and second title is clicked`, async () => {
107
+ const items = generateContentArray(3);
108
+ const defaultProps = {
109
+ additionalProps: {
110
+ testid: 'test-accordion',
111
+ },
112
+ allowMultipleExpanded: true,
113
+ items,
114
+ variant: AccordionVariant.Basic,
115
+ invert: false,
116
+ level: 0,
117
+ };
118
+ const { getAllByText } = render(<NsAccordion {...defaultProps} />);
119
+ const [title1, title2, title3] = getAllByText(/Title /i);
120
+ const header = title2.closest('header');
121
+ expect(header).toHaveAttribute('aria-expanded', 'true');
122
+ if (header) {
123
+ fireEvent.click(header);
124
+ expect(title1.closest('header')).toHaveAttribute('aria-expanded', 'true');
125
+ expect(title2.closest('header')).toHaveAttribute('aria-expanded', 'false');
126
+ expect(title3.closest('header')).toHaveAttribute('aria-expanded', 'true');
127
+
128
+ const [c1, c2, c3] = getAllByText(/Content /i);
129
+ expect(c1.parentNode).toHaveStyle('opacity: 1');
130
+ expect(c2.parentNode).toHaveStyle('opacity: 0');
131
+ expect(c3.parentNode).toHaveStyle('opacity: 1');
132
+ }
133
+ });
134
+ it(`6. closes second section also when allowMultipleExpanded
135
+ prop is true and second title is clicked`, async () => {
136
+ const items = generateContentArray(3, false);
137
+ items[1].isDefaultOpen = true;
138
+ const defaultProps = {
139
+ additionalProps: {
140
+ testid: 'test-accordion',
141
+ },
142
+ allowMultipleExpanded: false,
143
+ items,
144
+ variant: AccordionVariant.Compact,
145
+ level: 0,
146
+ invert: false,
147
+ };
148
+ const { getAllByText } = render(<NsAccordion {...defaultProps} />);
149
+ const [title1, title2, title3] = getAllByText(/Title /i);
150
+ const header = title2.closest('header');
151
+ expect(header).toHaveAttribute('aria-expanded', 'true');
152
+ if (header) {
153
+ fireEvent.click(header);
154
+ expect(title1.closest('header')).toHaveAttribute('aria-expanded', 'false');
155
+ expect(title2.closest('header')).toHaveAttribute('aria-expanded', 'false');
156
+ expect(title3.closest('header')).toHaveAttribute('aria-expanded', 'false');
157
+ const [c1, c2, c3] = getAllByText(/Content /i);
158
+ expect(c1.parentNode).toHaveStyle('opacity: 0');
159
+ expect(c2.parentNode).toHaveStyle('opacity: 0');
160
+ expect(c3.parentNode).toHaveStyle('opacity: 0');
161
+ }
162
+ });
163
+ });
@@ -0,0 +1,130 @@
1
+ import React from 'react';
2
+ import { render, fireEvent } from '@/test-utils/index';
3
+ import { NsAccordionHeader, AccordionVariant } from '@/common/index';
4
+
5
+ describe('NsAccordionHeader', () => {
6
+ it('1. renders title correctly', () => {
7
+ const onClick = jest.fn();
8
+ const title = 'Section Header';
9
+ const { getByText } = render(
10
+ <NsAccordionHeader
11
+ variant={AccordionVariant.Basic}
12
+ title={title}
13
+ onClick={onClick}
14
+ invert={false}
15
+ isOpen={true}
16
+ />
17
+ );
18
+ const el = getByText(title);
19
+ expect(el).toBeInTheDocument();
20
+ expect(el.closest('header')).toHaveAttribute('aria-expanded', 'true');
21
+ });
22
+ it('2. renders title correctly', () => {
23
+ const onClick = jest.fn();
24
+ const title = 'Section Header';
25
+ const { getByText } = render(
26
+ <NsAccordionHeader
27
+ variant={AccordionVariant.Compact}
28
+ title={<span>{title}</span>}
29
+ onClick={onClick}
30
+ invert={false}
31
+ isOpen={false}
32
+ />
33
+ );
34
+ const el = getByText(title);
35
+ expect(el).toBeInTheDocument();
36
+ expect(el.closest('header')).toHaveAttribute('aria-expanded', 'false');
37
+ });
38
+ it('3. calls onClick handler when clicked', () => {
39
+ const onClick = jest.fn();
40
+ const { container } = render(
41
+ <NsAccordionHeader
42
+ variant={AccordionVariant.Basic}
43
+ title="Section Header"
44
+ onClick={onClick}
45
+ invert={false}
46
+ isOpen={false}
47
+ />
48
+ );
49
+ const header = container.querySelector('header');
50
+ if (header) {
51
+ fireEvent.click(header);
52
+ expect(onClick).toHaveBeenCalledTimes(1);
53
+ }
54
+ });
55
+
56
+ it('4. renders with additional class name', () => {
57
+ const additionalClassName = 'custom-class';
58
+ const onClick = jest.fn();
59
+ const { container } = render(
60
+ <NsAccordionHeader
61
+ isOpen={false}
62
+ variant={AccordionVariant.Basic}
63
+ title="Section Header"
64
+ additionalProps={{ className: additionalClassName }}
65
+ onClick={onClick}
66
+ invert={false}
67
+ />
68
+ );
69
+ expect(container.querySelector('header')).toHaveClass(`section-header ${additionalClassName}`);
70
+ });
71
+
72
+ it('5. renders with expanded class when isOpen is true', () => {
73
+ const onClick = jest.fn();
74
+ const { container } = render(
75
+ <NsAccordionHeader
76
+ variant={AccordionVariant.Basic}
77
+ title="Section Header"
78
+ isOpen
79
+ onClick={onClick}
80
+ invert={false}
81
+ />
82
+ );
83
+ expect(container.querySelector('header')).toHaveClass('expanded');
84
+ });
85
+
86
+ it('6. renders with header icon', () => {
87
+ const onClick = jest.fn();
88
+ const { getByTestId } = render(
89
+ <NsAccordionHeader
90
+ variant={AccordionVariant.Basic}
91
+ title="Section Header"
92
+ onClick={onClick}
93
+ invert={false}
94
+ isOpen
95
+ />
96
+ );
97
+ // this icon refers to end icon which is either arrowUp or arrowDown
98
+ expect(getByTestId('icon')).toBeInTheDocument();
99
+ });
100
+ it('7. renders with custom start icon', () => {
101
+ const onClick = jest.fn();
102
+ const { getByTestId } = render(
103
+ <NsAccordionHeader
104
+ variant={AccordionVariant.Basic}
105
+ title="Section Header"
106
+ onClick={onClick}
107
+ invert={false}
108
+ isOpen
109
+ startIcon={{ name: 'hamburgerIcon', testId: 'hamburger-test' }}
110
+ />
111
+ );
112
+ expect(getByTestId('hamburger-test')).toBeInTheDocument();
113
+ });
114
+ it('8. does not render start icon, when invalid icon name is passed', () => {
115
+ const onClick = jest.fn();
116
+ const invalidIconName = 'hambur';
117
+ const testId = 'hamburger-test';
118
+ const { queryByTestId } = render(
119
+ <NsAccordionHeader
120
+ variant={AccordionVariant.Basic}
121
+ title="Section Header"
122
+ onClick={onClick}
123
+ invert={false}
124
+ isOpen
125
+ startIcon={{ name: invalidIconName as any, testId }}
126
+ />
127
+ );
128
+ expect(queryByTestId(testId)).toBeNull();
129
+ });
130
+ });
@@ -0,0 +1,79 @@
1
+ import React from 'react';
2
+ import { render, fireEvent } from '@/test-utils/index';
3
+ import { NsAccordionItem, AccordionVariant } from '@/common/index';
4
+
5
+ describe('NsAccordionItem', () => {
6
+ const title = 'Accordion Section Title';
7
+ const content = 'Accordion Section Content';
8
+ const contentElement = <div className="p-2">{content}</div>;
9
+ it('1. renders title correctly', () => {
10
+ const { getByText } = render(
11
+ <NsAccordionItem
12
+ type="jsx"
13
+ variant={AccordionVariant.Basic}
14
+ isOpen={false}
15
+ toggleOpen={() => {}}
16
+ title={title}
17
+ content={contentElement}
18
+ isChild={false}
19
+ invert={false}
20
+ level={1}
21
+ />
22
+ );
23
+ expect(getByText(title)).toBeInTheDocument();
24
+ });
25
+
26
+ it('2. calls toggleOpen function when clicked on the section header', () => {
27
+ const toggleOpen = jest.fn();
28
+ const { getByText } = render(
29
+ <NsAccordionItem
30
+ type="jsx"
31
+ variant={AccordionVariant.Basic}
32
+ isOpen={false}
33
+ toggleOpen={toggleOpen}
34
+ title={title}
35
+ content={contentElement}
36
+ isChild={false}
37
+ invert={false}
38
+ level={1}
39
+ />
40
+ );
41
+ fireEvent.click(getByText(title));
42
+ expect(toggleOpen).toHaveBeenCalledTimes(1);
43
+ });
44
+
45
+ it('3. renders content when isOpen is true', () => {
46
+ const { getByText } = render(
47
+ <NsAccordionItem
48
+ variant={AccordionVariant.Basic}
49
+ isOpen={true}
50
+ toggleOpen={() => {}}
51
+ title={title}
52
+ type="jsx"
53
+ content={contentElement}
54
+ isChild={false}
55
+ invert={false}
56
+ level={1}
57
+ />
58
+ );
59
+ expect(getByText(content)).toBeInTheDocument();
60
+ });
61
+
62
+ it('4. when isOpen is false, renders jsx dom content within container with 0 height', () => {
63
+ const { queryByText } = render(
64
+ <NsAccordionItem
65
+ type="jsx"
66
+ variant={AccordionVariant.Basic}
67
+ isOpen={false}
68
+ toggleOpen={() => {}}
69
+ title={title}
70
+ content={contentElement}
71
+ isChild={false}
72
+ invert={false}
73
+ level={1}
74
+ />
75
+ );
76
+ const bodyElement = queryByText(content);
77
+ expect(bodyElement?.parentNode).toHaveStyle('height:0px;');
78
+ });
79
+ });
@@ -0,0 +1,129 @@
1
+ import React from 'react';
2
+ import { render, screen } from '@/test-utils/index';
3
+ import { NsCollapse, AccordionVariant, AccordionItem } from '@/common/index';
4
+ import { createAccordionItem3_1 } from '../stories/data';
5
+
6
+ describe('NsCollapse', () => {
7
+ it('1. renders children when isOpen is true', () => {
8
+ const { getByText } = render(
9
+ <NsCollapse
10
+ isOpen
11
+ variant={AccordionVariant.Basic}
12
+ content={
13
+ <>
14
+ <div>Child 1</div>
15
+ <div>Child 2</div>
16
+ </>
17
+ }
18
+ type="jsx"
19
+ isChild={false}
20
+ invert={false}
21
+ level={0}
22
+ />
23
+ );
24
+ expect(getByText('Child 1')).toBeInTheDocument();
25
+ expect(getByText('Child 2')).toBeInTheDocument();
26
+ });
27
+ it('2. renders children when isOpen is true and isChild is true', () => {
28
+ const content = 'renders children when isOpen is true and isChild is true';
29
+ const { getByText } = render(
30
+ <NsCollapse
31
+ isOpen
32
+ type="text"
33
+ variant={AccordionVariant.Basic}
34
+ content={content}
35
+ isChild={true}
36
+ invert={false}
37
+ level={0}
38
+ />
39
+ );
40
+ expect(getByText(content)).toBeInTheDocument();
41
+ });
42
+ it('3. renders children when isOpen is true and variant is compact and content is of type accordion', () => {
43
+ const accItem = createAccordionItem3_1();
44
+ const content = accItem.content as AccordionItem[];
45
+ const { getByText } = render(
46
+ <NsCollapse
47
+ isOpen
48
+ variant={AccordionVariant.Compact}
49
+ content={content}
50
+ type={accItem.type}
51
+ isChild={true}
52
+ invert={false}
53
+ level={0}
54
+ />
55
+ );
56
+ expect(getByText(content[0].title)).toBeInTheDocument();
57
+ expect(getByText(content[1].title)).toBeInTheDocument();
58
+ });
59
+
60
+ it('4. does not render children when isOpen is false', () => {
61
+ const content = '<h2>Lorem ipsum dolor sit amet.</h2>';
62
+ render(
63
+ <NsCollapse
64
+ isOpen={false}
65
+ variant={AccordionVariant.Basic}
66
+ type="html"
67
+ content={content}
68
+ isChild={false}
69
+ invert={true}
70
+ level={0}
71
+ />
72
+ );
73
+ expect(screen.queryByText(content)).toBeNull();
74
+ });
75
+ it('5. renders html children when isOpen is true', () => {
76
+ const content = '<h2>Lorem ipsum dolor sit amet.</h2>';
77
+ render(
78
+ <NsCollapse
79
+ isOpen={true}
80
+ variant={AccordionVariant.Compact}
81
+ type="html"
82
+ content={content}
83
+ isChild={false}
84
+ invert={true}
85
+ level={0}
86
+ />
87
+ );
88
+ expect(screen.queryByText(content)).toBeDefined();
89
+ });
90
+
91
+ it('6. renders with additional class name', () => {
92
+ const additionalClassName = 'custom-class';
93
+ const { container } = render(
94
+ <NsCollapse
95
+ type="jsx"
96
+ isOpen
97
+ variant={AccordionVariant.Gray}
98
+ content={
99
+ <>
100
+ <div>Child 1</div>
101
+ <div>Child 2</div>
102
+ </>
103
+ }
104
+ additionalProps={{ className: additionalClassName }}
105
+ isChild={false}
106
+ invert={false}
107
+ level={7}
108
+ />
109
+ );
110
+ expect(container.querySelector('section')).toHaveClass(`ns-collapse ${additionalClassName}`);
111
+ });
112
+ it('7. skipping allowMultipleExpanded in child data', () => {
113
+ const { content, type } = createAccordionItem3_1();
114
+ const additionalClassName = 'custom-class';
115
+ const { container } = render(
116
+ <NsCollapse
117
+ type={type}
118
+ isOpen
119
+ variant={AccordionVariant.Gray}
120
+ content={content}
121
+ additionalProps={{ className: additionalClassName }}
122
+ isChild={false}
123
+ invert={true}
124
+ level={7}
125
+ />
126
+ );
127
+ expect(container.querySelector('section')).toHaveClass(`ns-collapse ${additionalClassName}`);
128
+ });
129
+ });
@@ -0,0 +1,74 @@
1
+ import React from 'react';
2
+
3
+ import { AccordionVariant, NsToggleSection } from '@/common/index';
4
+
5
+ import { render, fireEvent } from '@/test-utils/index';
6
+
7
+ describe('NsToggleSection', () => {
8
+ const title = 'Toggle Section Title';
9
+ const contentText = 'Toggle Section Content';
10
+ const content = <div className="p-2">{contentText}</div>;
11
+ it('1. renders title correctly', () => {
12
+ const { getByText } = render(
13
+ <NsToggleSection
14
+ variant={AccordionVariant.Basic}
15
+ title={title}
16
+ content={content}
17
+ invert={false}
18
+ isChild={false}
19
+ type="jsx"
20
+ />
21
+ );
22
+ expect(getByText(title)).toBeInTheDocument();
23
+ });
24
+ it('2. renders title correctly', () => {
25
+ const { getByText } = render(
26
+ <NsToggleSection
27
+ variant={AccordionVariant.Compact}
28
+ title={title}
29
+ content={content}
30
+ invert={false}
31
+ isChild={false}
32
+ type="jsx"
33
+ />
34
+ );
35
+ expect(getByText(title)).toBeInTheDocument();
36
+ });
37
+
38
+ it('2. toggles content visibility when clicked on the section header', () => {
39
+ const { getByText, queryByText } = render(
40
+ <NsToggleSection
41
+ variant={AccordionVariant.Basic}
42
+ title={title}
43
+ content={content}
44
+ invert={false}
45
+ isChild={false}
46
+ type="jsx"
47
+ />
48
+ );
49
+ const el = queryByText(contentText);
50
+ expect(el?.parentNode).toHaveStyle('opacity: 0;');
51
+
52
+ fireEvent.click(getByText(title));
53
+ expect(el?.parentNode).toHaveStyle('opacity: 1;');
54
+
55
+ fireEvent.click(getByText(title));
56
+ expect(el?.parentNode).toHaveStyle('opacity: 0;');
57
+ });
58
+
59
+ it('3. sets defaultOpen prop correctly', () => {
60
+ const { getByText } = render(
61
+ <NsToggleSection
62
+ variant={AccordionVariant.Basic}
63
+ title={title}
64
+ content={content}
65
+ invert={false}
66
+ isChild={false}
67
+ defaultOpen
68
+ type="jsx"
69
+ />
70
+ );
71
+
72
+ expect(getByText(contentText)).toBeInTheDocument();
73
+ });
74
+ });
@@ -0,0 +1,65 @@
1
+ import type { StoryObj, Meta } from '@storybook/react';
2
+ import { withCenterDecorator } from '@/stories/decorators/withCenterDecorator';
3
+ import { NsAccordion, AccordionVariant } from '../..';
4
+ import { getAccordionData } from './data';
5
+ import { within } from '@storybook/testing-library';
6
+ import { expect } from '@storybook/jest';
7
+ const meta = {
8
+ title: 'Components/Containers/Accordion',
9
+ component: NsAccordion,
10
+ decorators: [withCenterDecorator],
11
+ argTypes: {
12
+ allowMultipleExpanded: {
13
+ control: 'boolean',
14
+ description: `if true, then multiple sections can remain open at a same time, and if false,
15
+ opening a section will close other sections of the accordion`,
16
+ },
17
+ items: {
18
+ description: ` this should be an array of objects, each object should have 3 properties,
19
+ title, body and isDefaultOpen`,
20
+ },
21
+ variant: {
22
+ control: 'select',
23
+ options: [...Object.values(AccordionVariant)],
24
+ },
25
+ level: {
26
+ control: 'number',
27
+ description: `level = 1 means no padding on left from parent to child,
28
+ level = 2 means padding of 16px, level = 3 means padding of 32px and so on ..`,
29
+ },
30
+ },
31
+ args: {
32
+ variant: AccordionVariant.Basic,
33
+ invert: false,
34
+ level: 2,
35
+ },
36
+ } satisfies MetaStory;
37
+
38
+ export default meta;
39
+
40
+ type MetaStory = Meta<typeof NsAccordion>;
41
+ type Story = StoryObj<typeof meta>;
42
+
43
+ export const SingleOpen: Story = {
44
+ args: {
45
+ allowMultipleExpanded: false,
46
+ items: getAccordionData(),
47
+ invert: false,
48
+ },
49
+ play: ({ canvasElement }) => {
50
+ const canvas = within(canvasElement);
51
+ const el1 = canvas.getByText('Example - 1 JSX');
52
+ expect(el1).toBeInTheDocument();
53
+ expect(el1.closest('header')).toHaveAttribute('aria-expanded', 'true');
54
+ const el2 = canvas.getByText('Example - 2');
55
+ expect(el2).toBeInTheDocument();
56
+ expect(el2.closest('header')).toHaveAttribute('aria-expanded', 'false');
57
+ },
58
+ };
59
+
60
+ export const MultipleOpen: Story = {
61
+ args: {
62
+ allowMultipleExpanded: true,
63
+ items: getAccordionData(),
64
+ },
65
+ };
@@ -0,0 +1,44 @@
1
+ import type { StoryObj, Meta } from '@storybook/react';
2
+ import { withCenterDecorator } from '@/stories/decorators/withCenterDecorator';
3
+ import { AccordionVariant, NsAccordionHeader, NsIconVariants } from '../..';
4
+
5
+ type ComponentType = typeof NsAccordionHeader;
6
+ type Story = StoryObj<ComponentType>;
7
+ type MetaStory = Meta<ComponentType>;
8
+
9
+ export default {
10
+ title: 'Components/Containers/Accordion/NsAccordionHeader',
11
+ component: NsAccordionHeader,
12
+ decorators: [withCenterDecorator],
13
+ argTypes: {
14
+ title: { control: 'string' },
15
+ openedIconName: {
16
+ control: 'select',
17
+ options: Object.keys(NsIconVariants),
18
+ },
19
+ closedIconName: {
20
+ control: 'select',
21
+ options: Object.keys(NsIconVariants),
22
+ },
23
+ },
24
+ args: {
25
+ title: 'Nuskin',
26
+ variant: AccordionVariant.Compact,
27
+ onClick: () => {
28
+ console.log('accordion header clicked');
29
+ },
30
+ startIcon: {
31
+ name: 'home',
32
+ },
33
+ openedIconName: 'arrowUp',
34
+ closedIconName: 'arrowDown',
35
+ isOpen: false,
36
+ },
37
+ } as MetaStory;
38
+
39
+ export const ClosedHeader: Story = {};
40
+ export const OpenedHeader: Story = {
41
+ args: {
42
+ isOpen: true,
43
+ },
44
+ };