@nuskin/foundation-ui-components 1.0.0-develop.6 → 1.0.0-develop.7

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 (112) hide show
  1. package/package.json +17 -12
  2. package/src/common/accordion/NsAccordion.tsx +29 -39
  3. package/src/common/accordion/NsAccordionHeader.tsx +32 -17
  4. package/src/common/accordion/NsAccordionItem.tsx +16 -4
  5. package/src/common/accordion/NsCollapse.tsx +73 -35
  6. package/src/common/accordion/NsToggleSection.tsx +14 -3
  7. package/src/common/accordion/ToggleSection.styled.tsx +8 -7
  8. package/src/common/accordion/colorMap.ts +117 -0
  9. package/src/common/accordion/enums.ts +15 -0
  10. package/src/common/accordion/index.ts +1 -0
  11. package/src/common/accordion/specs/NsAccordion.spec.tsx +100 -31
  12. package/src/common/accordion/specs/NsAccordionHeader.spec.tsx +77 -10
  13. package/src/common/accordion/specs/NsAccordionItem.spec.tsx +23 -10
  14. package/src/common/accordion/specs/NsCollapse.spec.tsx +106 -17
  15. package/src/common/accordion/specs/NsToggleSection.spec.tsx +46 -14
  16. package/src/common/accordion/stories/NsAccordion.stories.tsx +27 -14
  17. package/src/common/accordion/stories/NsAccordionHeader.stories.tsx +4 -1
  18. package/src/common/accordion/stories/NsAccordionItem.stories.tsx +3 -3
  19. package/src/common/accordion/stories/NsCollapse.stories.tsx +3 -3
  20. package/src/common/accordion/stories/NsToggleSection.stories.tsx +2 -3
  21. package/src/common/accordion/stories/data.tsx +157 -19
  22. package/src/common/accordion/types.d.ts +56 -49
  23. package/src/common/alert/Header.tsx +29 -0
  24. package/src/common/alert/NsAlert.spec.tsx +46 -13
  25. package/src/common/alert/NsAlert.stories.tsx +3 -3
  26. package/src/common/alert/{NsAlert.styled.ts → NsAlert.styled.tsx} +22 -22
  27. package/src/common/alert/NsAlert.tsx +22 -87
  28. package/src/common/alert/types.d.ts +7 -7
  29. package/src/common/auth-dropdown/NsAuthDropdown.spec.tsx +23 -5
  30. package/src/common/auth-dropdown/NsAuthDropdown.stories.tsx +1 -1
  31. package/src/common/auth-dropdown/NsAuthDropdown.styled.ts +11 -7
  32. package/src/common/auth-dropdown/NsAuthDropdown.tsx +4 -4
  33. package/src/common/autocomplete/NsAutocomplete.spec.tsx +29 -6
  34. package/src/common/autocomplete/NsAutocomplete.stories.tsx +1 -1
  35. package/src/common/autocomplete/NsAutocomplete.tsx +18 -8
  36. package/src/common/autocomplete/mock/MockUI.tsx +1 -0
  37. package/src/common/banner/NsBanner.spec.tsx +12 -3
  38. package/src/common/banner/NsBanner.stories.tsx +1 -1
  39. package/src/common/brand-components/NsBrand.stories.tsx +1 -1
  40. package/src/common/brand-components/NsBrandComponent.tsx +2 -2
  41. package/src/common/breadcrumb/NsBreadcrumb.spec.tsx +8 -3
  42. package/src/common/breadcrumb/NsBreadcrumb.stories.tsx +1 -1
  43. package/src/common/breadcrumb/data.ts +8 -5
  44. package/src/common/button/NsButton.spec.tsx +65 -49
  45. package/src/common/button/NsButton.stories.tsx +59 -2
  46. package/src/common/button/NsButton.styled.tsx +49 -66
  47. package/src/common/button/NsButton.tsx +1 -2
  48. package/src/common/button/helper.ts +82 -0
  49. package/src/common/button/types.d.ts +2 -0
  50. package/src/common/card/stories/NsBgCard.stories.tsx +1 -1
  51. package/src/common/card/stories/NsBrandProductCard.stories.tsx +1 -1
  52. package/src/common/card/stories/NsFfgCard.stories.tsx +5 -2
  53. package/src/common/card/styled/NsFfgStyled.tsx +1 -1
  54. package/src/common/carousal/stories/NSCarousal.stories.tsx +1 -1
  55. package/src/common/carousal/stories/NsScrollingCarousal.stories.tsx +1 -1
  56. package/src/common/cart-icon/NsCartIcon.stories.tsx +1 -1
  57. package/src/common/checkbox/NsCheckbox.stories.tsx +1 -1
  58. package/src/common/checkbox/NsCheckbox.styled.tsx +15 -16
  59. package/src/common/checkbox/NsCheckbox.tsx +1 -1
  60. package/src/common/column-control/stories/DivArray.stories.tsx +1 -1
  61. package/src/common/column-control/stories/NsColumnControl.stories.tsx +1 -1
  62. package/src/common/column-control/stories/NsFlexColumns.stories.tsx +1 -1
  63. package/src/common/column-control/stories/NsGridColumns.stories.tsx +1 -1
  64. package/src/common/column-control/styled/common.ts +1 -1
  65. package/src/common/column-control/utils.ts +4 -4
  66. package/src/common/common.types.d.ts +11 -1
  67. package/src/common/dropdown/NsDropdown.styled.tsx +23 -18
  68. package/src/common/dropdown/stories/NsDropdown.stories.tsx +1 -1
  69. package/src/common/dropdown/stories/NsDropdownCountry.stories.tsx +1 -1
  70. package/src/common/flag/NsFlag.stories.tsx +1 -1
  71. package/src/common/hooks/index.ts +2 -0
  72. package/src/common/hooks/specs/useWindowSize.spec.tsx +19 -0
  73. package/src/common/hooks/useAccordionMap.tsx +39 -0
  74. package/src/common/hooks/useWindowSize.tsx +30 -0
  75. package/src/common/icon/NsIcon.stories.tsx +1 -1
  76. package/src/common/icon/NsIconVariants.ts +1 -0
  77. package/src/common/image/NsImage.spec.tsx +56 -6
  78. package/src/common/image/NsImage.stories.tsx +1 -1
  79. package/src/common/image/NsImage.tsx +23 -11
  80. package/src/common/image/NsNextImage.stories.tsx +1 -1
  81. package/src/common/index.ts +2 -0
  82. package/src/common/input/InputWrapper.tsx +12 -7
  83. package/src/common/input/NsInputField.tsx +1 -1
  84. package/src/common/label/NsLabel.stories.tsx +1 -1
  85. package/src/common/link/NsLink.stories.tsx +1 -1
  86. package/src/common/nav-product-card/NsNavProductCard.stories.tsx +1 -1
  87. package/src/common/nav-tab/NsNavTab.stories.tsx +1 -1
  88. package/src/common/radiogroup/NsRadioGroup.spec.tsx +24 -25
  89. package/src/common/radiogroup/NsRadioGroup.stories.tsx +14 -32
  90. package/src/common/radiogroup/NsRadioGroup.styled.tsx +17 -15
  91. package/src/common/radiogroup/NsRadioGroup.tsx +6 -5
  92. package/src/common/search-bar/NsSearchBar.tsx +1 -3
  93. package/src/common/select/NsSelect.spec.tsx +10 -17
  94. package/src/common/select/NsSelect.styled.tsx +53 -34
  95. package/src/common/select/stories/NsSelect.stories.tsx +11 -11
  96. package/src/common/select/types.d.ts +3 -3
  97. package/src/common/spinner/NsSpinner.spec.tsx +21 -0
  98. package/src/common/spinner/NsSpinner.stories.tsx +26 -0
  99. package/src/common/spinner/NsSpinner.styled.tsx +344 -0
  100. package/src/common/spinner/NsSpinner.tsx +14 -0
  101. package/src/common/spinner/icons/Spinner.tsx +161 -0
  102. package/src/common/spinner/index.ts +2 -0
  103. package/src/common/spinner/types.ts +5 -0
  104. package/src/common/table/NsTable.stories.tsx +1 -1
  105. package/src/common/table/NsTable.tsx +32 -49
  106. package/src/common/table/NsTableHeader.tsx +30 -51
  107. package/src/common/text-strip/NsTextStrip.stories.tsx +1 -1
  108. package/src/common/typography/NsTypography.stories.tsx +1 -1
  109. package/src/common/util.ts +1 -0
  110. package/src/common/videos/NsVideo.stories.tsx +1 -1
  111. package/src/common/videos/types.d.ts +1 -1
  112. /package/src/common/brand-components/{NsBrandContanier.styled.tsx → NsBrandContainer.styled.tsx} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nuskin/foundation-ui-components",
3
- "version": "1.0.0-develop.6",
3
+ "version": "1.0.0-develop.7",
4
4
  "description": "It is a foundation library written in react, that provides common components to all UI pages",
5
5
  "private": false,
6
6
  "main": "src/common/index.ts",
@@ -10,8 +10,7 @@
10
10
  },
11
11
  "homepage": "https://code.tls.nuskin.io/ns-am/content-foundation/foundation-ui-components/blob/master/README.md",
12
12
  "author": {
13
- "name": "Ruthraj Palanisamy",
14
- "email": "rpalanisamy@nuskin.com"
13
+ "name": "Josh Porter"
15
14
  },
16
15
  "publishConfig": {
17
16
  "access": "public"
@@ -23,17 +22,22 @@
23
22
  ],
24
23
  "license": "MIT",
25
24
  "scripts": {
26
- "dev": "next dev",
25
+ "build-storybook": "storybook build -o dist",
26
+ "build-dev": "yarn build-storybook",
27
+ "build-prod": "yarn build-storybook --mode=production",
28
+ "build-test": "yarn build-storybook",
27
29
  "build": "next build",
28
- "start": "next start",
30
+ "dev": "next dev",
31
+ "export": "next export",
29
32
  "lint": "next lint",
30
- "test": "jest",
31
- "test:coverage": "yarn test --coverage",
32
- "test:watch": "jest --watch",
33
33
  "storybook": "storybook dev -p 6007",
34
- "build-storybook": "storybook build",
35
- "export": "next export",
36
- "prepare": "husky install",
34
+ "sb": "yarn storybook",
35
+ "start": "next start",
36
+ "test": "next build && jest --coverage",
37
+ "test:pattern": "jest --coverage --testNamePattern accordion/*",
38
+ "test:watch": "jest --watch",
39
+ "test:failed": "npx jest --onlyFailures",
40
+ "test:coverage": "yarn test --coverage",
37
41
  "types:check": "tsc --pretty --noEmit"
38
42
  },
39
43
  "dependencies": {
@@ -41,6 +45,7 @@
41
45
  "@emotion/styled": "^11.10.6",
42
46
  "@mui/icons-material": "^5.11.11",
43
47
  "@mui/material": "5.4.2",
48
+ "@mui/utils": "^5.14.1",
44
49
  "@next/font": "13.2.4",
45
50
  "@nuskin/foundation-theme": "1.0.0-develop.5",
46
51
  "framer-motion": "^10.8.5",
@@ -71,6 +76,7 @@
71
76
  "@storybook/testing-library": "^0.1.0",
72
77
  "@testing-library/jest-dom": "^5.16.5",
73
78
  "@testing-library/react": "^14.0.0",
79
+ "@testing-library/react-hooks": "^8.0.1",
74
80
  "@types/jest": "^29.5.0",
75
81
  "@types/lodash": "^4.14.191",
76
82
  "@types/node": "18.15.0",
@@ -90,7 +96,6 @@
90
96
  "eslint-plugin-json": "^3.1.0",
91
97
  "eslint-plugin-prettier": "^4.2.1",
92
98
  "eslint-plugin-storybook": "^0.6.11",
93
- "husky": "^8.0.0",
94
99
  "jest": "^29.5.0",
95
100
  "jest-environment-jsdom": "^29.5.0",
96
101
  "storybook": "^7.0.7"
@@ -1,6 +1,5 @@
1
- import { useState, useEffect, useMemo } from 'react';
2
- import NsAccordionItem from './NsAccordionItem';
3
- import { NsAccordionProps } from './types';
1
+ import React, { FC, useMemo } from 'react';
2
+ import { NsAccordionItem, useAccordionMap, NsAccordionProps, AccordionItem } from '..';
4
3
  import { StyledAccordionWrapper } from './ToggleSection.styled';
5
4
 
6
5
  /**
@@ -13,40 +12,26 @@ import { StyledAccordionWrapper } from './ToggleSection.styled';
13
12
  * if there are multiple items available for default open, but `allowMultipleExpanded`
14
13
  * is false then only first item of default open is made open
15
14
  */
16
- const NsAccordion = ({
17
- additionalProps,
15
+ const createKey = (item: AccordionItem, index: number) => item?.id + index;
16
+ const NsAccordion: FC<NsAccordionProps> = ({
18
17
  allowMultipleExpanded,
19
- contentArray,
18
+ invert,
19
+ level,
20
20
  variant,
21
+ items,
21
22
  headerTypographyVariant,
22
23
  closedIconName,
23
24
  openedIconName,
24
- }: NsAccordionProps) => {
25
+ additionalProps,
26
+ isChild = false,
27
+ }) => {
25
28
  const defaultOpenIds = useMemo(() => {
26
- return contentArray
27
- .map((content, index) => (content?.isDefaultOpen ? index : null))
28
- .filter((e) => typeof e === 'number') as number[];
29
- }, [contentArray]);
30
- const [expandedIds, setExpandedIds] = useState<Array<number>>(defaultOpenIds);
29
+ return items
30
+ ?.map?.((content, index) => (content?.isDefaultOpen ? createKey(content, index) : null))
31
+ .filter((e) => e !== null) as string[];
32
+ }, [items]);
31
33
 
32
- const toggleOpen = (sectionNumber: number, isExpanded: boolean) => {
33
- if (allowMultipleExpanded) {
34
- if (isExpanded) {
35
- setExpandedIds(expandedIds.filter((existingNumber) => existingNumber !== sectionNumber));
36
- } else {
37
- setExpandedIds([...expandedIds, sectionNumber]);
38
- }
39
- } else {
40
- if (isExpanded) {
41
- setExpandedIds([]);
42
- } else {
43
- setExpandedIds([sectionNumber]);
44
- }
45
- }
46
- };
47
- useEffect(() => {
48
- setExpandedIds(allowMultipleExpanded ? defaultOpenIds : [defaultOpenIds[0]]);
49
- }, [allowMultipleExpanded, defaultOpenIds]);
34
+ const { toggleOpen, itemStateMap } = useAccordionMap({ allowMultipleExpanded, defaultOpenIds });
50
35
 
51
36
  return (
52
37
  <StyledAccordionWrapper
@@ -54,19 +39,24 @@ const NsAccordion = ({
54
39
  className="ns-accordion"
55
40
  data-testid={additionalProps?.testid ?? 'ns-accordion-testid'}
56
41
  >
57
- {contentArray.map((content, index) => {
58
- const isOpen = expandedIds.includes(index);
42
+ {items?.map?.((item, index) => {
43
+ const key = createKey(item, index);
44
+ const isOpen = itemStateMap[key] ?? false;
59
45
  return (
60
46
  <NsAccordionItem
61
- variant={variant}
62
- headerTypographyVariant={headerTypographyVariant}
63
47
  closedIconName={closedIconName}
64
- openedIconName={openedIconName}
65
- key={index}
48
+ content={item.content}
49
+ headerTypographyVariant={headerTypographyVariant}
50
+ invert={invert}
66
51
  isOpen={isOpen}
67
- toggleOpen={() => toggleOpen(index, isOpen)}
68
- content={content?.body}
69
- title={content?.title}
52
+ isChild={isChild}
53
+ key={key}
54
+ level={level}
55
+ openedIconName={openedIconName}
56
+ startIcon={item.icon}
57
+ toggleOpen={() => toggleOpen(createKey(item, index))}
58
+ title={<div className="nsa-item-title">{item.title}</div>}
59
+ variant={variant}
70
60
  />
71
61
  );
72
62
  })}
@@ -1,22 +1,27 @@
1
- import { NsTypography, NsIcon, NsAccordionHeaderProps, AccordionVariant } from '..';
2
- import { styled, ColorUtils } from '@nuskin/foundation-theme';
3
- const { getPaletteColor } = ColorUtils;
1
+ import { NsTypography, NsIcon, NsAccordionHeaderProps, AccordionVariant, NsIconProps, AccordionVariantType } from '..';
2
+ import { styled } from '@nuskin/foundation-theme';
3
+ import { isValidIconName } from '../icon/NsIconVariants';
4
+ import { getAccordionColor } from './colorMap';
4
5
 
5
- const StyledHeader = styled('header')<{ variant: AccordionVariant }>(({ theme, variant }) => {
6
- const backgroundColor = getPaletteColor(theme, 'primary', 'contrastText') as string;
7
- let borderBottom = 'none';
8
- if (variant === AccordionVariant.Compact) {
9
- borderBottom = '1px solid rgb(0,0,0,0.125)';
6
+ const StyledHeader = styled('header')<{ variant: AccordionVariantType; invert: boolean }>(
7
+ ({ theme, variant, invert }) => {
8
+ const { headBg, headText } = getAccordionColor({ theme, variant, invert, keys: ['headBg', 'headText'] });
9
+ let borderBottom = 'none';
10
+ if (variant === AccordionVariant.Compact) {
11
+ borderBottom = '1px solid rgb(0,0,0,0.125)';
12
+ }
13
+ return {
14
+ backgroundColor: headBg,
15
+ color: headText,
16
+ cursor: 'pointer',
17
+ display: 'grid',
18
+ gap: '4px',
19
+ gridTemplateColumns: 'auto 1fr 24px',
20
+ padding: '9px 16px',
21
+ borderBottom,
22
+ } as any;
10
23
  }
11
- return {
12
- backgroundColor,
13
- cursor: 'pointer',
14
- display: 'grid',
15
- gridTemplateColumns: '1fr 24px',
16
- padding: '9px 16px',
17
- borderBottom,
18
- } as any;
19
- });
24
+ );
20
25
 
21
26
  /**
22
27
  * NsAccordionHeader is primarily used by NsToggleSection and NsAccordionItem
@@ -31,15 +36,19 @@ const NsAccordionHeader = ({
31
36
  closedIconName,
32
37
  variant,
33
38
  headerTypographyVariant,
39
+ startIcon,
40
+ invert,
34
41
  }: NsAccordionHeaderProps) => {
35
42
  return (
36
43
  <StyledHeader
44
+ invert={invert}
37
45
  role="button"
38
46
  aria-expanded={isOpen ? 'true' : 'false'}
39
47
  className={`section-header ${isOpen ? 'expanded' : ''} ${additionalProps?.className ?? ''}`}
40
48
  onClick={onClick}
41
49
  variant={variant}
42
50
  >
51
+ <HeaderIcon {...startIcon} />
43
52
  {typeof title === 'string' ? (
44
53
  <NsTypography variant={headerTypographyVariant ?? 'h4'} weight="bold">
45
54
  {title}
@@ -54,3 +63,9 @@ const NsAccordionHeader = ({
54
63
  );
55
64
  };
56
65
  export default NsAccordionHeader;
66
+
67
+ const HeaderIcon = (props: Partial<NsIconProps>) => {
68
+ const hasIcon = props?.name ? isValidIconName(props?.name) : false;
69
+ if (!hasIcon) return <span />;
70
+ return <NsIcon {...(props as NsIconProps)} />;
71
+ };
@@ -9,6 +9,7 @@ import { StyledToggleSection } from './ToggleSection.styled';
9
9
  */
10
10
  const NsAccordionItem = ({
11
11
  isOpen,
12
+ isChild,
12
13
  toggleOpen,
13
14
  title,
14
15
  content,
@@ -16,11 +17,16 @@ const NsAccordionItem = ({
16
17
  headerTypographyVariant,
17
18
  closedIconName,
18
19
  openedIconName,
20
+ startIcon,
21
+ level,
22
+ additionalProps,
23
+ invert,
19
24
  }: NsAccordionItemProps) => {
20
25
  return (
21
26
  <StyledToggleSection variant={variant}>
22
27
  <NsAccordionHeader
23
- additionalProps={{ className: 'accordion-section' }}
28
+ invert={invert}
29
+ additionalProps={{ ...additionalProps, className: 'accordion-section ' + additionalProps?.className }}
24
30
  closedIconName={closedIconName}
25
31
  headerTypographyVariant={headerTypographyVariant}
26
32
  isOpen={isOpen}
@@ -28,10 +34,16 @@ const NsAccordionItem = ({
28
34
  onClick={toggleOpen}
29
35
  title={title}
30
36
  variant={variant}
37
+ startIcon={startIcon}
38
+ />
39
+ <NsCollapse
40
+ isChild={isChild}
41
+ isOpen={isOpen}
42
+ variant={variant}
43
+ level={level}
44
+ invert={invert}
45
+ content={content}
31
46
  />
32
- <NsCollapse isOpen={isOpen} variant={variant}>
33
- {content}
34
- </NsCollapse>
35
47
  </StyledToggleSection>
36
48
  );
37
49
  };
@@ -1,55 +1,93 @@
1
- import { styled, ColorUtils, FoundationTheme } from '@nuskin/foundation-theme';
2
- import { AccordionVariant, NsCollapseProps } from './types.d';
3
- const { getAppColor, getPaletteColor } = ColorUtils;
4
- const getIsLight = (theme: FoundationTheme.Theme) => {
5
- const { palette = { primary: { main: '', contrastText: '' } } } = theme;
6
- return palette.primary.main === getAppColor(theme, 'primary', 'black');
1
+ import { styled } from '@nuskin/foundation-theme';
2
+ import { AccordionVariant, AccordionVariantType, NsCollapseProps, ItemContent, AccordionItem, NsAccordion } from '../';
3
+ import { getAccordionColor } from './colorMap';
4
+ import { ReactElement, isValidElement, useMemo } from 'react';
5
+
6
+ const getLevelOffset = (level: number) => {
7
+ return level > 1 ? (level - 1) * 16 : 0;
7
8
  };
9
+
8
10
  const options = {
9
- shouldForwardProp: (key: string) => key !== 'variant',
11
+ shouldForwardProp: (key: string) => !['variant', 'level'].includes(key),
10
12
  };
13
+
11
14
  export const StyledCollapse = styled(
12
15
  'section',
13
16
  options
14
- )<{ variant: AccordionVariant }>(({ theme, variant }) => {
15
- let backgroundColor = getIsLight(theme)
16
- ? (getAppColor(theme, 'primary', 'gray') as string)
17
- : (getAppColor(theme, 'primary', 'dark') as string);
18
- let borderBottom = 'none';
19
- if (variant === AccordionVariant.Compact) {
20
- backgroundColor = getIsLight(theme)
21
- ? (getAppColor(theme, 'primary', 'white') as string)
22
- : (getAppColor(theme, 'primary', 'dark') as string);
23
- borderBottom = '1px solid rgb(0,0,0,0.125)';
17
+ )<{ variant: AccordionVariantType; level: number; invert: boolean; isChild: boolean }>(
18
+ ({ theme, variant, level, invert, isChild }) => {
19
+ const { contentBg, contentText } = getAccordionColor({
20
+ theme,
21
+ invert,
22
+ variant,
23
+ keys: ['contentBg', 'contentText'],
24
+ });
25
+
26
+ let borderBottom = 'none';
27
+ if (variant === AccordionVariant.Compact) {
28
+ borderBottom = isChild ? 'none' : '1px solid rgb(0,0,0,0.125)';
29
+ }
30
+ return {
31
+ backgroundColor: contentBg,
32
+ color: contentText,
33
+ opacity: 0,
34
+ padding: '0 16px',
35
+ height: 0,
36
+ overflow: 'hidden',
37
+ transition: '0.3s',
38
+ '&.expanded': {
39
+ padding: `9px 0 9px ${getLevelOffset(level)}px`,
40
+ height: 'auto',
41
+ opacity: 1,
42
+ borderBottom,
43
+ },
44
+ '.nsa-content-padded': {
45
+ padding: '0 16px 16px',
46
+ },
47
+ };
24
48
  }
25
- return {
26
- backgroundColor,
27
- color: getPaletteColor(theme, 'primary', 'main') as string,
28
- opacity: 0,
29
- padding: '0 16px',
30
- height: 0,
31
- overflow: 'hidden',
32
- transition: '0.3s',
33
- '&.expanded': {
34
- padding: '9px 16px',
35
- height: 'auto',
36
- opacity: 1,
37
- borderBottom,
38
- },
39
- };
40
- });
49
+ );
41
50
 
42
51
  /**
43
52
  * NsCollapse component adds css animation while showing children items if prop `isOpen` is true,
44
53
  * and while removing children if prop `isOpen` is false
45
54
  */
46
- const NsCollapse = ({ isOpen, children, additionalProps, variant }: NsCollapseProps) => {
55
+ const NsCollapse = ({ isOpen, content, additionalProps, variant, level, invert, isChild }: NsCollapseProps) => {
56
+ const body = useMemo(() => {
57
+ if (isValidElement(content)) {
58
+ return content as ReactElement;
59
+ }
60
+ if (content?.type === 'html') {
61
+ return (
62
+ <div
63
+ className="nsa-content-padded"
64
+ dangerouslySetInnerHTML={{ __html: (content as ItemContent)?.data as string }}
65
+ />
66
+ );
67
+ } else if (content?.type === 'text') {
68
+ return <div className="p-4">{(content as ItemContent)?.data as string}</div>;
69
+ } else if (content?.type === 'accordion') {
70
+ return (
71
+ <NsAccordion
72
+ isChild={true}
73
+ invert={invert}
74
+ level={level}
75
+ variant={AccordionVariant.Gray}
76
+ items={(content as ItemContent)?.data as AccordionItem[]}
77
+ allowMultipleExpanded={(content as ItemContent)?.allowMultipleExpanded ?? false}
78
+ />
79
+ );
80
+ }
81
+ }, [content, invert, level]);
47
82
  return (
48
83
  <StyledCollapse
84
+ isChild={isChild}
85
+ level={level}
49
86
  className={`ns-collapse ${isOpen ? 'expanded' : ''} ${additionalProps?.className ?? ''}`}
50
87
  variant={variant}
88
+ invert={invert}
51
89
  >
52
- {isOpen ? children : null}
90
+ {body}
53
91
  </StyledCollapse>
54
92
  );
55
93
  };
@@ -9,7 +9,15 @@ import { NsToggleSectionProps, NsAccordionItem } from '../';
9
9
  * by default, otherwise children is hidden by default and toggles between visible
10
10
  * and hidden on clicking title
11
11
  */
12
- const NsToggleSection = ({ title, children, additionalProps, defaultOpen, variant }: NsToggleSectionProps) => {
12
+ const NsToggleSection = ({
13
+ title,
14
+ content,
15
+ additionalProps,
16
+ defaultOpen,
17
+ variant,
18
+ invert,
19
+ isChild,
20
+ }: NsToggleSectionProps) => {
13
21
  const [isExpanded, setIsExpanded] = useState(defaultOpen ?? false);
14
22
 
15
23
  const toggleAccordion = () => {
@@ -17,12 +25,15 @@ const NsToggleSection = ({ title, children, additionalProps, defaultOpen, varian
17
25
  };
18
26
  return (
19
27
  <NsAccordionItem
28
+ level={2}
20
29
  variant={variant}
21
- additionalProps={{ ...additionalProps, className: 'toggle-section ' + additionalProps?.className ?? '' }}
30
+ additionalProps={additionalProps}
22
31
  isOpen={isExpanded}
23
32
  title={title}
24
- content={children}
33
+ content={content}
25
34
  toggleOpen={toggleAccordion}
35
+ invert={invert}
36
+ isChild={isChild}
26
37
  />
27
38
  );
28
39
  };
@@ -1,23 +1,24 @@
1
1
  import { styled } from '@nuskin/foundation-theme';
2
- import { AccordionVariant } from './types.d';
2
+ import { AccordionVariant, AccordionVariantType } from '../';
3
3
 
4
- export const StyledToggleSection = styled('section')<{ variant: AccordionVariant }>(({ variant }) => {
4
+ const border = '1px solid rgb(0,0,0,0.125)';
5
+ export const StyledToggleSection = styled('section')<{ variant: AccordionVariantType }>(({ variant }) => {
5
6
  if (variant === AccordionVariant.Compact) {
6
- return { borderRight: '1px solid rgb(0,0,0,0.125)' };
7
+ return { borderRight: border };
7
8
  }
8
9
  return {
9
- margin: '5px',
10
+ margin: '5px 0',
10
11
  };
11
12
  });
12
13
 
13
- export const StyledAccordionWrapper = styled('div')<{ variant: AccordionVariant }>(({ variant }) => {
14
+ export const StyledAccordionWrapper = styled('div')<{ variant: AccordionVariantType }>(({ variant }) => {
14
15
  if (variant === AccordionVariant.Compact) {
15
16
  return {
16
17
  display: 'flex',
17
18
  flexDirection: 'column',
18
19
  gap: '0',
19
- borderTop: '1px solid rgb(0,0,0,0.125)',
20
- borderLeft: '1px solid rgb(0,0,0,0.125)',
20
+ borderTop: border,
21
+ borderLeft: border,
21
22
  };
22
23
  }
23
24
  return {
@@ -0,0 +1,117 @@
1
+ import {Themed} from '../common.types';
2
+ import {AccordionVariantType} from './enums';
3
+ import {ColorUtils, FoundationTheme} from '@nuskin/foundation-theme';
4
+ const {isDarkMode, color} = ColorUtils;
5
+ const compKeys = ['contentBg', 'contentText', 'headBg', 'headText'];
6
+ type CompKeys = (typeof compKeys)[number];
7
+ type VariantColors = Record<
8
+ CompKeys,
9
+ {
10
+ light: [FoundationTheme.AppColors, string];
11
+ dark: [FoundationTheme.AppColors, string];
12
+ }
13
+ >;
14
+
15
+ const colorObject: Record<string, [FoundationTheme.AppColors, string]> = {
16
+ n10: ['primary', 'dark'], // #121212
17
+ n20: ['primary', 'black'], // #252525
18
+ n40: ['neutral', '80'], // #444444
19
+ n45: ['neutral', '70'], // #5f5f5f
20
+ n50: ['neutral', '60'], // #8c8c8c
21
+ n80: ['neutral', '50'], // #b2b2b2
22
+ n85: ['neutral', '40'], // #e0e0e0
23
+ n90: ['neutral', '30'], // #ededed
24
+ n95: ['primary', 'gray'], // #f5f5f5
25
+ n100: ['primary', 'white'], // #fff
26
+ };
27
+ export const colorMap: Record<AccordionVariantType, VariantColors> = {
28
+ basic: {
29
+ contentBg: {
30
+ light: colorObject.n95,
31
+ dark: colorObject.n20,
32
+ },
33
+ contentText: {
34
+ light: colorObject.n10,
35
+ dark: colorObject.n95,
36
+ },
37
+ headBg: {
38
+ light: colorObject.n100,
39
+ dark: colorObject.n20,
40
+ },
41
+ headText: {
42
+ light: colorObject.n10,
43
+ dark: colorObject.n95,
44
+ },
45
+ },
46
+ compact: {
47
+ contentBg: {
48
+ light: colorObject.n100,
49
+ dark: colorObject.n10,
50
+ },
51
+ contentText: {
52
+ light: colorObject.n10,
53
+ dark: colorObject.n90,
54
+ },
55
+ headBg: {
56
+ light: colorObject.n100,
57
+ dark: colorObject.n10,
58
+ },
59
+ headText: {
60
+ light: colorObject.n10,
61
+ dark: colorObject.n90,
62
+ },
63
+ },
64
+ gray: {
65
+ contentBg: {
66
+ light: colorObject.n85,
67
+ dark: colorObject.n40,
68
+ },
69
+ contentText: {
70
+ light: colorObject.n40,
71
+ dark: colorObject.n85,
72
+ },
73
+ headBg: {
74
+ light: colorObject.n90,
75
+ dark: colorObject.n45,
76
+ },
77
+ headText: {
78
+ light: colorObject.n45,
79
+ dark: colorObject.n90,
80
+ },
81
+ },
82
+ stripe: {
83
+ contentBg: {
84
+ light: colorObject.n90,
85
+ dark: colorObject.n45,
86
+ },
87
+ contentText: {
88
+ light: colorObject.n45,
89
+ dark: colorObject.n90,
90
+ },
91
+ headBg: {
92
+ light: colorObject.n100,
93
+ dark: colorObject.n40,
94
+ },
95
+ headText: {
96
+ light: colorObject.n40,
97
+ dark: colorObject.n100,
98
+ },
99
+ },
100
+ };
101
+
102
+ type GetAccordionColor = {
103
+ variant: AccordionVariantType;
104
+ invert: boolean;
105
+ keys: CompKeys[];
106
+ } & Themed;
107
+ export const getAccordionColor = ({theme, variant, invert, keys}: GetAccordionColor): Record<CompKeys, string> => {
108
+ const isDark = invert ? !isDarkMode({theme}) : isDarkMode({theme});
109
+ const darkLabel = isDark ? 'dark' : 'light';
110
+ const result: Record<string, string> = {};
111
+ for (const colorKey of keys) {
112
+ const [appColorBg, appSubColorBg] = colorMap[variant][colorKey][darkLabel];
113
+ const colorValue = color(appColorBg, appSubColorBg)({theme});
114
+ result[colorKey] = colorValue;
115
+ }
116
+ return result;
117
+ };
@@ -0,0 +1,15 @@
1
+ /* eslint-disable no-unused-vars */
2
+ // export enum AccordionVariant {
3
+ // Basic = 'basic', // basic is as per figma
4
+ // Compact = 'compact', // compact is as per test.nuskin.com
5
+ // Gray = 'gray',
6
+ // Stripe = 'stripe',
7
+ // }
8
+ export const AccordionVariant = {
9
+ Basic: 'basic',
10
+ Compact: 'compact',
11
+ Gray: 'gray',
12
+ Stripe: 'stripe',
13
+ } as const;
14
+ const variantValues = Object.values(AccordionVariant);
15
+ export type AccordionVariantType = (typeof variantValues)[number];
@@ -4,3 +4,4 @@ export { default as NsToggleSection } from './NsToggleSection';
4
4
  export { default as NsAccordionItem } from './NsAccordionItem';
5
5
  export { default as NsAccordion } from './NsAccordion';
6
6
  export * from './types.d';
7
+ export * from './enums';