@nuskin/foundation-ui-components 1.1.0 → 1.1.1

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 (135) hide show
  1. package/package.json +15 -11
  2. package/src/common/accordion/NsAccordion.tsx +32 -40
  3. package/src/common/accordion/NsAccordionHeader.tsx +29 -8
  4. package/src/common/accordion/NsAccordionItem.tsx +24 -4
  5. package/src/common/accordion/NsCollapse.tsx +96 -35
  6. package/src/common/accordion/NsToggleSection.tsx +16 -3
  7. package/src/common/accordion/ToggleSection.styled.tsx +11 -7
  8. package/src/common/accordion/colorMap.ts +117 -0
  9. package/src/common/accordion/enums.ts +18 -0
  10. package/src/common/accordion/index.ts +1 -0
  11. package/src/common/accordion/specs/NsAccordion.spec.tsx +101 -31
  12. package/src/common/accordion/specs/NsAccordionHeader.spec.tsx +77 -10
  13. package/src/common/accordion/specs/NsAccordionItem.spec.tsx +27 -10
  14. package/src/common/accordion/specs/NsCollapse.spec.tsx +109 -17
  15. package/src/common/accordion/specs/NsToggleSection.spec.tsx +50 -14
  16. package/src/common/accordion/stories/NsAccordion.stories.tsx +31 -13
  17. package/src/common/accordion/stories/NsAccordionHeader.stories.tsx +5 -1
  18. package/src/common/accordion/stories/NsAccordionItem.stories.tsx +8 -3
  19. package/src/common/accordion/stories/NsCollapse.stories.tsx +19 -4
  20. package/src/common/accordion/stories/NsToggleSection.stories.tsx +6 -3
  21. package/src/common/accordion/stories/data.tsx +140 -19
  22. package/src/common/accordion/types.d.ts +55 -47
  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 +1 -1
  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.styled.ts +9 -2
  31. package/src/common/auth-dropdown/NsAuthDropdown.tsx +4 -4
  32. package/src/common/autocomplete/NsAutocomplete.spec.tsx +34 -11
  33. package/src/common/autocomplete/NsAutocomplete.stories.tsx +18 -2
  34. package/src/common/autocomplete/NsAutocomplete.tsx +63 -24
  35. package/src/common/autocomplete/mock/MockData.ts +50 -7
  36. package/src/common/autocomplete/mock/MockUI.tsx +2 -1
  37. package/src/common/autocomplete/types.d.ts +7 -4
  38. package/src/common/banner/NsBanner.spec.tsx +12 -3
  39. package/src/common/brand-components/NsBrandComponent.tsx +2 -2
  40. package/src/common/breadcrumb/NsBreadcrumb.spec.tsx +8 -3
  41. package/src/common/breadcrumb/data.ts +8 -5
  42. package/src/common/button/NsButton.spec.tsx +65 -49
  43. package/src/common/button/NsButton.stories.tsx +40 -4
  44. package/src/common/button/NsButton.styled.tsx +49 -66
  45. package/src/common/button/NsButton.tsx +1 -2
  46. package/src/common/button/helper.ts +82 -0
  47. package/src/common/card/NsFfgCard.tsx +13 -7
  48. package/src/common/card/specs/NsFfgCard.spec.tsx +18 -8
  49. package/src/common/card/stories/NsFfgCard.stories.tsx +47 -14
  50. package/src/common/card/styled/NsFfgStyled.tsx +10 -7
  51. package/src/common/card/types.d.ts +7 -4
  52. package/src/common/carousal/NsCarousal.tsx +3 -9
  53. package/src/common/cart-icon/NsCartIcon.spec.tsx +5 -16
  54. package/src/common/cart-icon/NsCartIcon.stories.tsx +1 -1
  55. package/src/common/cart-icon/NsCartIcon.styled.ts +7 -33
  56. package/src/common/cart-icon/NsCartIcon.tsx +5 -14
  57. package/src/common/cart-icon/types.d.ts +1 -0
  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/styled/common.ts +1 -1
  61. package/src/common/column-control/utils.ts +4 -4
  62. package/src/common/common.types.d.ts +14 -5
  63. package/src/common/dropdown/NsDropdown.styled.tsx +23 -18
  64. package/src/common/hooks/index.ts +2 -0
  65. package/src/common/hooks/specs/useWindowSize.spec.tsx +19 -0
  66. package/src/common/hooks/useAccordionMap.tsx +39 -0
  67. package/src/common/hooks/useWindowSize.tsx +30 -0
  68. package/src/common/icon/NsIcon.spec.tsx +1 -1
  69. package/src/common/icon/NsIcon.stories.tsx +3 -0
  70. package/src/common/icon/NsIcon.tsx +6 -2
  71. package/src/common/icon/NsIconVariants.ts +4 -1
  72. package/src/common/icon/icons/AlertErrorIcon.tsx +2 -2
  73. package/src/common/icon/icons/ArrowLeft.tsx +3 -6
  74. package/src/common/icon/icons/ArrowRight.tsx +6 -8
  75. package/src/common/icon/icons/Cart.tsx +7 -32
  76. package/src/common/icon/icons/CartBadge.tsx +2 -2
  77. package/src/common/icon/icons/CloseIcon.tsx +1 -1
  78. package/src/common/icon/icons/ErrorIcon.tsx +2 -2
  79. package/src/common/icon/icons/HamburgerIcon.tsx +5 -2
  80. package/src/common/icon/icons/SearchIcon.tsx +1 -1
  81. package/src/common/icon/icons/SuccessIcon.tsx +2 -7
  82. package/src/common/icon/icons/TrashIcon.tsx +1 -1
  83. package/src/common/icon/icons/UserIcon.tsx +3 -6
  84. package/src/common/icon/icons/UserOutline.tsx +24 -0
  85. package/src/common/icon/icons/WarningIcon.tsx +1 -1
  86. package/src/common/icon/icons/home.tsx +1 -1
  87. package/src/common/image/NsImage.spec.tsx +56 -6
  88. package/src/common/image/NsImage.tsx +23 -11
  89. package/src/common/index.ts +6 -2
  90. package/src/common/input/InputWrapper.tsx +12 -7
  91. package/src/common/input/NsInputField.tsx +1 -1
  92. package/src/common/modal/NsModal.spec.tsx +46 -0
  93. package/src/common/modal/NsModal.styled.tsx +28 -0
  94. package/src/common/modal/NsModal.tsx +37 -0
  95. package/src/common/modal/helper-component/NsModalContentBox.tsx +32 -0
  96. package/src/common/modal/helper-component/NsModalDefault.tsx +25 -0
  97. package/src/common/modal/helper-component/NsModalStatus.tsx +15 -0
  98. package/src/common/modal/helper-component/NsModalStatusIcon.tsx +14 -0
  99. package/src/common/modal/helper-component/NsModalTitle.tsx +26 -0
  100. package/src/common/modal/index.ts +2 -0
  101. package/src/common/modal/model/NsModalVariantMap.tsx +24 -0
  102. package/src/common/modal/stories/NsModal.stories.tsx +85 -0
  103. package/src/common/modal/stories/mock.tsx +46 -0
  104. package/src/common/modal/types.ts +56 -0
  105. package/src/common/nav-tab/NavDrawer.tsx +34 -0
  106. package/src/common/nav-tab/NavTitles.tsx +52 -0
  107. package/src/common/nav-tab/NsNavTab.spec.tsx +4 -5
  108. package/src/common/nav-tab/NsNavTab.stories.tsx +3 -3
  109. package/src/common/nav-tab/NsNavTab.styled.tsx +13 -7
  110. package/src/common/nav-tab/NsNavTab.tsx +21 -75
  111. package/src/common/nav-tab/index.ts +1 -1
  112. package/src/common/nav-tab/types.d.ts +3 -3
  113. package/src/common/radiogroup/NsRadioGroup.spec.tsx +24 -25
  114. package/src/common/radiogroup/NsRadioGroup.stories.tsx +13 -31
  115. package/src/common/radiogroup/NsRadioGroup.styled.tsx +20 -19
  116. package/src/common/radiogroup/NsRadioGroup.tsx +6 -5
  117. package/src/common/search-bar/NsSearchBar.tsx +1 -3
  118. package/src/common/select/NsSelect.spec.tsx +10 -17
  119. package/src/common/select/NsSelect.styled.tsx +53 -34
  120. package/src/common/select/stories/NsSelect.stories.tsx +10 -10
  121. package/src/common/select/types.d.ts +3 -3
  122. package/src/common/spinner/NsSpinner.spec.tsx +21 -0
  123. package/src/common/spinner/NsSpinner.stories.tsx +26 -0
  124. package/src/common/spinner/NsSpinner.styled.tsx +344 -0
  125. package/src/common/spinner/NsSpinner.tsx +14 -0
  126. package/src/common/spinner/icons/Spinner.tsx +161 -0
  127. package/src/common/spinner/index.ts +2 -0
  128. package/src/common/spinner/types.ts +5 -0
  129. package/src/common/table/NsTable.tsx +32 -49
  130. package/src/common/table/NsTableHeader.tsx +30 -51
  131. package/src/common/util.ts +1 -0
  132. package/src/common/utility/Show.tsx +13 -0
  133. package/src/common/utility/index.ts +1 -0
  134. package/src/common/videos/types.d.ts +1 -1
  135. /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.1.0",
3
+ "version": "1.1.1",
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",
@@ -22,19 +22,22 @@
22
22
  ],
23
23
  "license": "MIT",
24
24
  "scripts": {
25
- "dev": "next dev",
26
- "start": "next start",
27
- "lint": "next lint",
28
- "test": "next build && jest --coverage",
29
- "test:watch": "jest --watch",
30
- "storybook": "storybook dev -p 6007",
31
- "sb": "yarn storybook",
25
+ "build-storybook": "storybook build -o dist",
32
26
  "build-dev": "yarn build-storybook",
33
27
  "build-prod": "yarn build-storybook --mode=production",
34
28
  "build-test": "yarn build-storybook",
35
- "build-storybook": "storybook build -o dist",
29
+ "build": "next build",
30
+ "dev": "next dev",
36
31
  "export": "next export",
37
- "prepare": "husky install",
32
+ "lint": "next lint",
33
+ "storybook": "storybook dev -p 6007",
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",
38
41
  "types:check": "tsc --pretty --noEmit"
39
42
  },
40
43
  "dependencies": {
@@ -42,6 +45,7 @@
42
45
  "@emotion/styled": "^11.10.6",
43
46
  "@mui/icons-material": "^5.11.11",
44
47
  "@mui/material": "5.4.2",
48
+ "@mui/utils": "^5.14.1",
45
49
  "@next/font": "13.2.4",
46
50
  "@nuskin/foundation-theme": "1.0.0-develop.5",
47
51
  "framer-motion": "^10.8.5",
@@ -72,6 +76,7 @@
72
76
  "@storybook/testing-library": "^0.1.0",
73
77
  "@testing-library/jest-dom": "^5.16.5",
74
78
  "@testing-library/react": "^14.0.0",
79
+ "@testing-library/react-hooks": "^8.0.1",
75
80
  "@types/jest": "^29.5.0",
76
81
  "@types/lodash": "^4.14.191",
77
82
  "@types/node": "18.15.0",
@@ -91,7 +96,6 @@
91
96
  "eslint-plugin-json": "^3.1.0",
92
97
  "eslint-plugin-prettier": "^4.2.1",
93
98
  "eslint-plugin-storybook": "^0.6.11",
94
- "husky": "^8.0.0",
95
99
  "jest": "^29.5.0",
96
100
  "jest-environment-jsdom": "^29.5.0",
97
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
  /**
@@ -9,44 +8,30 @@ import { StyledAccordionWrapper } from './ToggleSection.styled';
9
8
  * multiple sections of accordion can remain open at a time
10
9
  *
11
10
  * we can define certain section to remain open by default using `isDefaultOpen` in the
12
- * contentArray item
11
+ * items
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,26 @@ 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}
47
+ allowMultipleExpanded={item.allowMultipleExpanded}
48
+ type={item.type}
63
49
  closedIconName={closedIconName}
64
- openedIconName={openedIconName}
65
- key={index}
50
+ content={item.content}
51
+ headerTypographyVariant={headerTypographyVariant}
52
+ invert={invert}
66
53
  isOpen={isOpen}
67
- toggleOpen={() => toggleOpen(index, isOpen)}
68
- content={content?.body}
69
- title={content?.title}
54
+ isChild={isChild}
55
+ key={key}
56
+ level={level}
57
+ openedIconName={openedIconName}
58
+ startIcon={item.icon}
59
+ toggleOpen={() => toggleOpen(createKey(item, index))}
60
+ title={<div className="nsa-item-title">{item.title}</div>}
61
+ variant={variant}
70
62
  />
71
63
  );
72
64
  })}
@@ -1,18 +1,28 @@
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';
5
+ const options = {
6
+ shouldForwardProp: (propKey: string) => !['variant', 'invert'].includes(propKey),
7
+ };
8
+ type StyledType = { variant: AccordionVariantType; invert: boolean };
4
9
 
5
- const StyledHeader = styled('header')<{ variant: AccordionVariant }>(({ theme, variant }) => {
6
- const backgroundColor = getPaletteColor(theme, 'primary', 'contrastText') as string;
10
+ const StyledHeader = styled(
11
+ 'header',
12
+ options
13
+ )<StyledType>(({ theme, variant, invert }) => {
14
+ const { headBg, headText } = getAccordionColor({ theme, variant, invert, keys: ['headBg', 'headText'] });
7
15
  let borderBottom = 'none';
8
16
  if (variant === AccordionVariant.Compact) {
9
17
  borderBottom = '1px solid rgb(0,0,0,0.125)';
10
18
  }
11
19
  return {
12
- backgroundColor,
20
+ backgroundColor: headBg,
21
+ color: headText,
13
22
  cursor: 'pointer',
14
23
  display: 'grid',
15
- gridTemplateColumns: '1fr 24px',
24
+ gap: '4px',
25
+ gridTemplateColumns: 'auto 1fr 24px',
16
26
  padding: '9px 16px',
17
27
  borderBottom,
18
28
  } as any;
@@ -31,17 +41,22 @@ const NsAccordionHeader = ({
31
41
  closedIconName,
32
42
  variant,
33
43
  headerTypographyVariant,
44
+ startIcon,
45
+ invert,
46
+ cslp,
34
47
  }: NsAccordionHeaderProps) => {
35
48
  return (
36
49
  <StyledHeader
50
+ invert={invert}
37
51
  role="button"
38
52
  aria-expanded={isOpen ? 'true' : 'false'}
39
53
  className={`section-header ${isOpen ? 'expanded' : ''} ${additionalProps?.className ?? ''}`}
40
54
  onClick={onClick}
41
55
  variant={variant}
42
56
  >
57
+ <HeaderIcon {...startIcon} />
43
58
  {typeof title === 'string' ? (
44
- <NsTypography variant={headerTypographyVariant ?? 'h4'} weight="bold">
59
+ <NsTypography variant={headerTypographyVariant ?? 'h4'} weight="bold" {...(cslp?.header ?? {})}>
45
60
  {title}
46
61
  </NsTypography>
47
62
  ) : (
@@ -54,3 +69,9 @@ const NsAccordionHeader = ({
54
69
  );
55
70
  };
56
71
  export default NsAccordionHeader;
72
+
73
+ const HeaderIcon = (props: Partial<NsIconProps>) => {
74
+ const hasIcon = props?.name ? isValidIconName(props?.name) : false;
75
+ if (!hasIcon) return <span />;
76
+ return <NsIcon {...(props as NsIconProps)} />;
77
+ };
@@ -6,9 +6,11 @@ import { StyledToggleSection } from './ToggleSection.styled';
6
6
  /**
7
7
  * this component is used by accordion to pass title
8
8
  * and content
9
+ * cslp:{header:CslpTag, content:CslpTag}
9
10
  */
10
11
  const NsAccordionItem = ({
11
12
  isOpen,
13
+ isChild,
12
14
  toggleOpen,
13
15
  title,
14
16
  content,
@@ -16,11 +18,19 @@ const NsAccordionItem = ({
16
18
  headerTypographyVariant,
17
19
  closedIconName,
18
20
  openedIconName,
21
+ startIcon,
22
+ level,
23
+ additionalProps,
24
+ invert,
25
+ type,
26
+ cslp,
27
+ allowMultipleExpanded,
19
28
  }: NsAccordionItemProps) => {
20
29
  return (
21
30
  <StyledToggleSection variant={variant}>
22
31
  <NsAccordionHeader
23
- additionalProps={{ className: 'accordion-section' }}
32
+ invert={invert}
33
+ additionalProps={{ ...additionalProps, className: 'accordion-section ' + additionalProps?.className }}
24
34
  closedIconName={closedIconName}
25
35
  headerTypographyVariant={headerTypographyVariant}
26
36
  isOpen={isOpen}
@@ -28,10 +38,20 @@ const NsAccordionItem = ({
28
38
  onClick={toggleOpen}
29
39
  title={title}
30
40
  variant={variant}
41
+ startIcon={startIcon}
42
+ cslp={cslp}
43
+ />
44
+ <NsCollapse
45
+ type={type}
46
+ isChild={isChild}
47
+ isOpen={isOpen}
48
+ variant={variant}
49
+ level={level}
50
+ invert={invert}
51
+ content={content}
52
+ cslp={cslp}
53
+ allowMultipleExpanded={allowMultipleExpanded}
31
54
  />
32
- <NsCollapse isOpen={isOpen} variant={variant}>
33
- {content}
34
- </NsCollapse>
35
55
  </StyledToggleSection>
36
56
  );
37
57
  };
@@ -1,55 +1,116 @@
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 {
3
+ AccordionVariant,
4
+ AccordionVariantType,
5
+ NsCollapseProps,
6
+ AccordionItem,
7
+ NsAccordion,
8
+ AccordionContentTypeObject,
9
+ } from '../';
10
+ import { getAccordionColor } from './colorMap';
11
+ import { ReactElement, isValidElement, useMemo } from 'react';
12
+
13
+ const getLevelOffset = (level: number) => {
14
+ return level > 1 ? (level - 1) * 16 : 0;
7
15
  };
16
+
8
17
  const options = {
9
- shouldForwardProp: (key: string) => key !== 'variant',
18
+ shouldForwardProp: (key: string) => !['variant', 'level'].includes(key),
10
19
  };
20
+
11
21
  export const StyledCollapse = styled(
12
22
  'section',
13
23
  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)';
24
+ )<{ variant: AccordionVariantType; level: number; invert: boolean; isChild: boolean }>(
25
+ ({ theme, variant, level, invert, isChild }) => {
26
+ const { contentBg, contentText } = getAccordionColor({
27
+ theme,
28
+ invert,
29
+ variant,
30
+ keys: ['contentBg', 'contentText'],
31
+ });
32
+
33
+ let borderBottom = 'none';
34
+ if (variant === AccordionVariant.Compact) {
35
+ borderBottom = isChild ? 'none' : '1px solid rgb(0,0,0,0.125)';
36
+ }
37
+ return {
38
+ backgroundColor: contentBg,
39
+ color: contentText,
40
+ opacity: 0,
41
+ padding: '0 16px',
42
+ height: 0,
43
+ overflow: 'hidden',
44
+ transition: '0.3s',
45
+ '&.expanded': {
46
+ padding: `9px 0 9px ${getLevelOffset(level)}px`,
47
+ height: 'auto',
48
+ opacity: 1,
49
+ borderBottom,
50
+ },
51
+ '.nsa-content-padded': {
52
+ padding: '0 16px 16px',
53
+ },
54
+ };
24
55
  }
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
- });
56
+ );
41
57
 
42
58
  /**
43
59
  * NsCollapse component adds css animation while showing children items if prop `isOpen` is true,
44
60
  * and while removing children if prop `isOpen` is false
45
61
  */
46
- const NsCollapse = ({ isOpen, children, additionalProps, variant }: NsCollapseProps) => {
62
+ const NsCollapse = ({
63
+ isOpen,
64
+ content,
65
+ additionalProps,
66
+ variant,
67
+ level,
68
+ invert,
69
+ isChild,
70
+ type,
71
+ cslp,
72
+ allowMultipleExpanded,
73
+ }: NsCollapseProps) => {
74
+ const body = useMemo(() => {
75
+ if (isValidElement(content)) {
76
+ return content as ReactElement;
77
+ }
78
+ if (type === AccordionContentTypeObject.html) {
79
+ return (
80
+ <div
81
+ className="nsa-content-padded"
82
+ dangerouslySetInnerHTML={{ __html: content as string }}
83
+ {...(cslp?.content ?? {})}
84
+ />
85
+ );
86
+ } else if (type === AccordionContentTypeObject.text) {
87
+ return (
88
+ <div className="p-4" {...(cslp?.content ?? {})}>
89
+ {content as string}
90
+ </div>
91
+ );
92
+ } else if (type === AccordionContentTypeObject.accordion) {
93
+ return (
94
+ <NsAccordion
95
+ isChild={true}
96
+ invert={invert}
97
+ level={level}
98
+ variant={AccordionVariant.Gray}
99
+ items={content as AccordionItem[]}
100
+ allowMultipleExpanded={allowMultipleExpanded ?? false}
101
+ />
102
+ );
103
+ }
104
+ }, [allowMultipleExpanded, content, cslp?.content, invert, level, type]);
47
105
  return (
48
106
  <StyledCollapse
107
+ isChild={isChild}
108
+ level={level}
49
109
  className={`ns-collapse ${isOpen ? 'expanded' : ''} ${additionalProps?.className ?? ''}`}
50
110
  variant={variant}
111
+ invert={invert}
51
112
  >
52
- {isOpen ? children : null}
113
+ {body}
53
114
  </StyledCollapse>
54
115
  );
55
116
  };
@@ -9,7 +9,16 @@ 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
+ type,
21
+ }: NsToggleSectionProps) => {
13
22
  const [isExpanded, setIsExpanded] = useState(defaultOpen ?? false);
14
23
 
15
24
  const toggleAccordion = () => {
@@ -17,12 +26,16 @@ const NsToggleSection = ({ title, children, additionalProps, defaultOpen, varian
17
26
  };
18
27
  return (
19
28
  <NsAccordionItem
29
+ type={type}
30
+ level={2}
20
31
  variant={variant}
21
- additionalProps={{ ...additionalProps, className: 'toggle-section ' + additionalProps?.className ?? '' }}
32
+ additionalProps={additionalProps}
22
33
  isOpen={isExpanded}
23
34
  title={title}
24
- content={children}
35
+ content={content}
25
36
  toggleOpen={toggleAccordion}
37
+ invert={invert}
38
+ isChild={isChild}
26
39
  />
27
40
  );
28
41
  };
@@ -1,23 +1,27 @@
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
+
6
+ type StyledType = { variant: AccordionVariantType };
7
+
8
+ export const StyledToggleSection = styled('section')<StyledType>(({ variant }) => {
5
9
  if (variant === AccordionVariant.Compact) {
6
- return { borderRight: '1px solid rgb(0,0,0,0.125)' };
10
+ return { borderRight: border };
7
11
  }
8
12
  return {
9
- margin: '5px',
13
+ margin: '5px 0',
10
14
  };
11
15
  });
12
16
 
13
- export const StyledAccordionWrapper = styled('div')<{ variant: AccordionVariant }>(({ variant }) => {
17
+ export const StyledAccordionWrapper = styled('div')<StyledType>(({ variant }) => {
14
18
  if (variant === AccordionVariant.Compact) {
15
19
  return {
16
20
  display: 'flex',
17
21
  flexDirection: 'column',
18
22
  gap: '0',
19
- borderTop: '1px solid rgb(0,0,0,0.125)',
20
- borderLeft: '1px solid rgb(0,0,0,0.125)',
23
+ borderTop: border,
24
+ borderLeft: border,
21
25
  };
22
26
  }
23
27
  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,18 @@
1
+ export const AccordionVariant = {
2
+ Basic: 'basic',
3
+ Compact: 'compact',
4
+ Gray: 'gray',
5
+ Stripe: 'stripe',
6
+ } as const;
7
+ const variantValues = Object.values(AccordionVariant);
8
+ export type AccordionVariantType = (typeof variantValues)[number];
9
+
10
+ export const AccordionContentTypeObject = {
11
+ text: 'text',
12
+ html: 'html',
13
+ accordion: 'accordion',
14
+ jsx: 'jsx',
15
+ };
16
+
17
+ const contentValues = Object.values(AccordionContentTypeObject);
18
+ export type AccordionContentType = (typeof contentValues)[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';