@nuskin/foundation-ui-components 1.0.0-develop.2 → 1.0.0-develop.4

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 (123) hide show
  1. package/package.json +1 -1
  2. package/src/common/accordion/NsAccordion.tsx +77 -0
  3. package/src/common/accordion/NsAccordionHeader.tsx +56 -0
  4. package/src/common/accordion/NsAccordionItem.tsx +39 -0
  5. package/src/common/accordion/NsCollapse.tsx +56 -0
  6. package/src/common/accordion/NsToggleSection.tsx +30 -0
  7. package/src/common/accordion/ToggleSection.styled.tsx +28 -0
  8. package/src/common/accordion/index.ts +6 -0
  9. package/src/common/accordion/specs/NsAccordion.spec.tsx +91 -0
  10. package/src/common/accordion/specs/NsAccordionHeader.spec.tsx +47 -0
  11. package/src/common/accordion/specs/NsAccordionItem.spec.tsx +38 -0
  12. package/src/common/accordion/specs/NsCollapse.spec.tsx +37 -0
  13. package/src/common/accordion/specs/NsToggleSection.spec.tsx +33 -0
  14. package/src/common/accordion/stories/NsAccordion.stories.tsx +47 -0
  15. package/src/common/accordion/stories/NsAccordionHeader.stories.tsx +40 -0
  16. package/src/common/accordion/stories/NsAccordionItem.stories.tsx +40 -0
  17. package/src/common/accordion/stories/NsCollapse.stories.tsx +35 -0
  18. package/src/common/accordion/stories/NsToggleSection.stories.tsx +23 -0
  19. package/src/common/accordion/stories/data.tsx +22 -0
  20. package/src/common/accordion/types.d.ts +73 -0
  21. package/src/common/alert/NsAlert.stories.tsx +15 -14
  22. package/src/common/alert/types.d.ts +22 -22
  23. package/src/common/auth-dropdown/NsAuthDropdown.stories.tsx +1 -1
  24. package/src/common/autocomplete/NsAutocomplete.spec.tsx +20 -8
  25. package/src/common/autocomplete/NsAutocomplete.stories.tsx +4 -1
  26. package/src/common/autocomplete/NsAutocomplete.styled.tsx +12 -0
  27. package/src/common/autocomplete/NsAutocomplete.tsx +36 -18
  28. package/src/common/autocomplete/types.d.ts +7 -1
  29. package/src/common/banner/NsBanner.stories.tsx +1 -1
  30. package/src/common/brand-components/NsBrand.stories.tsx +1 -1
  31. package/src/common/breadcrumb/NsBreadcrumb.spec.tsx +1 -7
  32. package/src/common/breadcrumb/NsBreadcrumb.stories.tsx +2 -4
  33. package/src/common/breadcrumb/data.ts +7 -0
  34. package/src/common/button/NsButton.spec.tsx +10 -11
  35. package/src/common/button/NsButton.stories.tsx +1 -1
  36. package/src/common/card/stories/NsBgCard.stories.tsx +1 -3
  37. package/src/common/card/stories/NsBrandProductCard.stories.tsx +1 -1
  38. package/src/common/card/stories/NsFfgCard.stories.tsx +1 -1
  39. package/src/common/card/stories/{data.js → data.ts} +1 -25
  40. package/src/common/carousal/NsScrollingCarousal.tsx +26 -2
  41. package/src/common/carousal/stories/NsScrollingCarousal.stories.tsx +1 -1
  42. package/src/common/carousal/types.d.ts +2 -0
  43. package/src/common/cart-icon/NsCartIcon.stories.tsx +1 -1
  44. package/src/common/checkbox/NsCheckbox.stories.tsx +1 -1
  45. package/src/common/checkbox/NsCheckbox.styled.tsx +2 -2
  46. package/src/common/column-control/NsFlexColumns.tsx +5 -10
  47. package/src/common/column-control/NsGridColumns.tsx +5 -10
  48. package/src/common/column-control/specs/NsColumnControl.spec.tsx +1 -1
  49. package/src/common/column-control/specs/NsFlexColumns.spec.tsx +1 -1
  50. package/src/common/column-control/specs/NsGridColumns.spec.tsx +1 -1
  51. package/src/common/column-control/stories/DivArray.stories.tsx +18 -0
  52. package/src/common/column-control/stories/DivArray.tsx +63 -0
  53. package/src/common/column-control/stories/NsColumnControl.stories.tsx +6 -3
  54. package/src/common/column-control/stories/NsFlexColumns.stories.tsx +13 -9
  55. package/src/common/column-control/stories/NsGridColumns.stories.tsx +12 -8
  56. package/src/common/column-control/stories/common.tsx +1 -1
  57. package/src/common/column-control/styled/StyledFlex.tsx +7 -3
  58. package/src/common/column-control/styled/StyledGrid.tsx +9 -2
  59. package/src/common/column-control/styled/common.ts +2 -2
  60. package/src/common/column-control/types.d.ts +15 -16
  61. package/src/common/common.types.d.ts +1 -0
  62. package/src/common/dropdown/stories/NsDropdown.stories.tsx +1 -1
  63. package/src/common/dropdown/stories/NsDropdownCountry.stories.tsx +1 -1
  64. package/src/common/email-simple/NsEmailSimple.spec.tsx +145 -0
  65. package/src/common/email-simple/NsEmailSimple.stories.tsx +61 -0
  66. package/src/common/email-simple/NsEmailSimple.tsx +71 -0
  67. package/src/common/email-simple/index.ts +2 -0
  68. package/src/common/email-simple/types.d.ts +14 -0
  69. package/src/common/flag/NsFlag.spec.tsx +4 -25
  70. package/src/common/flag/NsFlag.stories.tsx +1 -1
  71. package/src/common/flag/NsFlag.tsx +0 -2
  72. package/src/common/icon/NsIcon.stories.tsx +1 -1
  73. package/src/common/image/NsImage.stories.tsx +1 -1
  74. package/src/common/image/NsNextImage.stories.tsx +1 -1
  75. package/src/common/image/types.d.ts +1 -0
  76. package/src/common/index.ts +3 -0
  77. package/src/common/input/NsInputField.stories.tsx +13 -10
  78. package/src/common/input/NsInputField.tsx +12 -5
  79. package/src/common/input/getAdornmentProps.tsx +4 -0
  80. package/src/common/input/types.d.ts +18 -1
  81. package/src/common/label/NsLabel.stories.tsx +5 -0
  82. package/src/common/label/NsLabel.tsx +16 -19
  83. package/src/common/label/types.d.ts +2 -1
  84. package/src/common/link/NsLink.stories.tsx +1 -1
  85. package/src/common/nav-product-card/NsNavProductCard.stories.tsx +1 -1
  86. package/src/common/nav-tab/NsNavTab.spec.tsx +0 -5
  87. package/src/common/nav-tab/NsNavTab.stories.tsx +1 -1
  88. package/src/common/radiogroup/NsRadioGroup.spec.tsx +63 -0
  89. package/src/common/radiogroup/NsRadioGroup.stories.tsx +101 -0
  90. package/src/common/radiogroup/NsRadioGroup.styled.tsx +56 -0
  91. package/src/common/radiogroup/NsRadioGroup.tsx +46 -0
  92. package/src/common/radiogroup/index.ts +2 -0
  93. package/src/common/radiogroup/types.d.ts +19 -0
  94. package/src/common/select/NsSelect.spec.tsx +200 -0
  95. package/src/common/select/NsSelect.styled.tsx +89 -0
  96. package/src/common/select/NsSelect.tsx +117 -0
  97. package/src/common/select/NsSelectOption.tsx +30 -0
  98. package/src/common/select/index.ts +3 -0
  99. package/src/common/select/stories/NsSelect.stories.tsx +134 -0
  100. package/src/common/select/types.d.ts +34 -0
  101. package/src/common/table/NsExpandableRow.tsx +68 -0
  102. package/src/common/table/NsTable.spec.tsx +69 -41
  103. package/src/common/table/NsTable.stories.tsx +48 -10
  104. package/src/common/table/NsTable.styled.ts +95 -4
  105. package/src/common/table/NsTable.tsx +78 -89
  106. package/src/common/table/NsTableHeader.tsx +52 -38
  107. package/src/common/table/NsTablePagination.tsx +21 -13
  108. package/src/common/table/types.d.ts +21 -8
  109. package/src/common/text-strip/NsTextStrip.stories.tsx +5 -4
  110. package/src/common/text-strip/NsTextStrip.tsx +5 -2
  111. package/src/common/text-strip/types.d.ts +7 -4
  112. package/src/common/typography/NsTypography.stories.tsx +1 -1
  113. package/src/common/validations/regex.ts +3 -0
  114. package/src/common/videos/NsVideo.stories.tsx +1 -1
  115. package/src/common/column-control/stories/NDivs.story.tsx +0 -35
  116. /package/src/common/card/{tests → specs}/BrandLogo.spec.tsx +0 -0
  117. /package/src/common/card/{tests → specs}/NsBgCard.spec.tsx +0 -0
  118. /package/src/common/card/{tests → specs}/NsBrandProductCard.spec.tsx +0 -0
  119. /package/src/common/card/{tests → specs}/NsFfgCard.spec.tsx +0 -0
  120. /package/src/common/carousal/{tests → specs}/Chevron.spec.tsx +0 -0
  121. /package/src/common/carousal/{tests → specs}/NsCarousal.spec.tsx +0 -0
  122. /package/src/common/carousal/{tests → specs}/NsScrollingCarousal.spec.tsx +0 -0
  123. /package/src/common/carousal/{tests → specs}/RenderBrand.spec.tsx +0 -0
@@ -0,0 +1,89 @@
1
+ import { styled, ColorUtils, FoundationTheme } from '@nuskin/foundation-theme';
2
+ const { getPaletteColor, getAppColor } = ColorUtils;
3
+
4
+ export const SelectContainer = styled.div<{ disabled: boolean }>`
5
+ position: relative;
6
+ display: inline-block;
7
+ opacity: ${({ disabled }) => (disabled ? '0.5' : '1')};
8
+ `;
9
+
10
+ export const SelectHead = styled.div<{ type: string; disabled: boolean }>`
11
+ cursor: ${({ disabled }) => (disabled ? 'inherit' : 'pointer')};
12
+ padding: 5px 10px;
13
+ display: flex;
14
+ justify-content: space-between;
15
+ align-items: center;
16
+ border: ${({ type, theme }) =>
17
+ type === 'outlined' ? `1px solid ${getAppColor(theme, 'primary', 'black')}` : 'none'};
18
+ color: ${({ theme }) => getPaletteColor(theme, 'primary')};
19
+ width: 207px;
20
+ position: relative;
21
+ z-index: 2;
22
+ `;
23
+
24
+ export const SelectButton = styled.div`
25
+ padding-right: 10px;
26
+ `;
27
+
28
+ export const SelectList = styled.div<{ borderColor: FoundationTheme.PaletteColors }>`
29
+ position: absolute;
30
+ z-index: 100;
31
+ border: 1px solid ${({ borderColor, theme }) => getPaletteColor(theme, borderColor)};
32
+ padding: 0;
33
+ margin: 0;
34
+ width: -webkit-fill-available;
35
+ color: ${({ theme }) => getPaletteColor(theme, 'primary', 'main')};
36
+ background-color: ${({ theme }) => getPaletteColor(theme, 'primary', 'contrastText')};
37
+ `;
38
+ const getIsLight = (theme: FoundationTheme.Theme) => {
39
+ const { palette = { primary: { main: '', contrastText: '' } } } = theme;
40
+ return palette.primary.main === getAppColor(theme, 'primary', 'black');
41
+ };
42
+
43
+ const getDividerColor = (theme: FoundationTheme.Theme) => {
44
+ const isLight = getIsLight(theme);
45
+ const dividerColor = isLight ? getAppColor(theme, 'neutral', '30') : getAppColor(theme, 'neutral', '20');
46
+ return dividerColor;
47
+ };
48
+ const getListBgColor = (theme: FoundationTheme.Theme) => {
49
+ const isLight = getIsLight(theme);
50
+ const bgColor = isLight ? getAppColor(theme, 'accentColorB', '10') : getAppColor(theme, 'accentColorB', '50');
51
+ return bgColor;
52
+ };
53
+ export const ListItemContainer = styled.div<{ showListDivider: boolean; isSelected: boolean }>`
54
+ ${({ showListDivider, isSelected, theme }) => `
55
+ cursor: pointer;
56
+ padding: 5px 0;
57
+ border-bottom: 1px solid ${showListDivider ? getDividerColor(theme) : 'none'};
58
+ background-color: ${isSelected ? getPaletteColor(theme, 'primary') : 'white'};
59
+ color: ${isSelected ? 'white' : 'black'};
60
+
61
+ &:hover {
62
+ background-color: ${getListBgColor(theme)};
63
+ }
64
+
65
+ &:last-child {
66
+ border-bottom: none;
67
+ }
68
+ `}
69
+ `;
70
+
71
+ export const ListItem = styled.div<{ isSelected: boolean}>`
72
+ padding: 5px 10px;
73
+ border-left: ${({ isSelected, theme }) =>
74
+ isSelected ? `2px solid ${getPaletteColor(theme, 'primary')}` : 'none'};
75
+ background-color: ${({ isSelected, theme }) =>
76
+ isSelected ? getPaletteColor(theme, 'primary', 'main') : 'white'};
77
+ color: ${({ isSelected }) => (isSelected ? 'white' : 'black')};
78
+ &:hover {
79
+ background-color: ${({ isSelected, theme }) =>
80
+ isSelected ? getPaletteColor(theme, 'primary', 'main') : getListBgColor(theme)};
81
+ font-weight: bold;
82
+ }
83
+ `;
84
+
85
+ export const SelectLabel = styled.label`
86
+ display: block;
87
+ margin-bottom: 5px;
88
+ color: ${({ theme }) => getPaletteColor(theme, 'primary')};
89
+ `;
@@ -0,0 +1,117 @@
1
+ import React, { useState, useRef, useEffect } from 'react';
2
+ import { SelectContainer, SelectButton, SelectList, SelectHead, SelectLabel } from './NsSelect.styled';
3
+ import { NsIcon } from '../icon';
4
+ import { SelectProps } from './types.d';
5
+
6
+ const NsSelect: React.FC<SelectProps> = ({
7
+ selectedValue,
8
+ selectedLabel,
9
+ onSelect,
10
+ children,
11
+ disabled = false,
12
+ type = 'outlined',
13
+ placeholder = '',
14
+ selectBorderColor = 'accentColorB',
15
+ closeOnMouseLeave = false,
16
+ showListDivider = true,
17
+ label,
18
+ readOnly = false,
19
+ errorMessage,
20
+ }) => {
21
+ const [isOpen, setIsOpen] = useState(false);
22
+ const [value, setValue] = useState(selectedValue || '');
23
+ const selectContainerRef = useRef<HTMLDivElement>(null);
24
+ const selectHeadRef = useRef<HTMLDivElement>(null);
25
+
26
+ const closeSelect = () => {
27
+ if (closeOnMouseLeave) {
28
+ setIsOpen(false);
29
+ }
30
+ };
31
+
32
+ const handleSelect = (input: string) => {
33
+ onSelect(input);
34
+ setIsOpen(false);
35
+ setValue(input);
36
+ };
37
+
38
+ // eslint-disable-next-line react-hooks/exhaustive-deps
39
+ const handleClickOutside = (event: MouseEvent) => {
40
+ if (
41
+ selectContainerRef.current &&
42
+ !selectContainerRef.current.contains(event.target as Node) &&
43
+ isOpen
44
+ ) {
45
+ setIsOpen(false);
46
+ }
47
+ };
48
+
49
+ const handleMouseClick = () => {
50
+ if (disabled) return;
51
+ setIsOpen(!isOpen);
52
+ if (!isOpen) {
53
+ setTimeout(() => {
54
+ selectHeadRef.current?.focus();
55
+ }, 0);
56
+ }
57
+ };
58
+
59
+ useEffect(() => {
60
+ document.addEventListener('click', handleClickOutside);
61
+ return () => {
62
+ document.removeEventListener('click', handleClickOutside);
63
+ };
64
+ }, [handleClickOutside, isOpen]);
65
+
66
+ return (
67
+ <SelectContainer
68
+ data-testid="select-container"
69
+ disabled={disabled || readOnly}
70
+ ref={selectContainerRef}
71
+ style={{
72
+ borderColor: errorMessage ? 'red' : undefined,
73
+ color: errorMessage ? 'red' : 'inherit',
74
+ }}
75
+ >
76
+ {label && <SelectLabel style={{ color: errorMessage ? 'red' : 'inherit' }}>{label}</SelectLabel>}
77
+ <SelectHead
78
+ data-testid="select-head"
79
+ disabled={disabled || readOnly}
80
+ type={type}
81
+ onMouseDown={handleMouseClick}
82
+ tabIndex={0}
83
+ ref={selectHeadRef}
84
+ >
85
+ <SelectButton>{selectedLabel || placeholder}</SelectButton>
86
+ {!readOnly && (
87
+ <NsIcon testId="chevron-icon" name={isOpen ? 'arrowUp' : 'arrowDown'} color="primary" />
88
+ )}
89
+ </SelectHead>
90
+ {isOpen ? (
91
+ <SelectList
92
+ data-testid="select-list"
93
+ onMouseLeave={closeSelect}
94
+ borderColor={selectBorderColor}
95
+ className='selectList'
96
+ >
97
+ <div style={{ maxHeight: '200px', overflowY: 'auto' }}>
98
+ {React.Children.map(children, (child) => {
99
+ if (React.isValidElement(child)) {
100
+ return React.cloneElement(child, {
101
+ // @ts-ignore
102
+ onSelect: handleSelect,
103
+ selectedValue: value,
104
+ showListDivider,
105
+ });
106
+ }
107
+ return null;
108
+ })}
109
+ </div>
110
+ </SelectList>
111
+ ) : null}
112
+ {errorMessage && <div style={{ color: 'red' }}>{errorMessage}</div>}
113
+ </SelectContainer>
114
+ );
115
+ };
116
+
117
+ export default NsSelect;
@@ -0,0 +1,30 @@
1
+ import React from 'react';
2
+ import { ListItem, ListItemContainer } from './NsSelect.styled';
3
+ import { SelectOptionProps } from './types.d';
4
+
5
+ export const NsSelectOption: React.FC<SelectOptionProps> = ({
6
+ value,
7
+ label,
8
+ onSelect,
9
+ selectedValue,
10
+ showListDivider = true,
11
+ }) => {
12
+ const handleClick = () => {
13
+ if (onSelect && typeof onSelect === 'function') {
14
+ onSelect(value);
15
+ }
16
+ };
17
+
18
+ return (
19
+ <ListItemContainer
20
+ data-testid={`option-${value}`}
21
+ isSelected={value === selectedValue}
22
+ showListDivider={showListDivider}
23
+ onClick={handleClick}
24
+ >
25
+ <ListItem isSelected={value === selectedValue}>{label}</ListItem>
26
+ </ListItemContainer>
27
+
28
+ );
29
+ };
30
+ export default NsSelectOption;
@@ -0,0 +1,3 @@
1
+ export { default as NsSelect } from './NsSelect';
2
+ export { default as NsSelectOption } from './NsSelectOption';
3
+ export type { SelectOptionProps, SelectProps } from './types.d';
@@ -0,0 +1,134 @@
1
+ import React, { useState } from 'react';
2
+ import { ComponentStory, ComponentMeta } from '@storybook/react';
3
+ import NsSelect from '../NsSelect';
4
+ import NsSelectOption from '../NsSelectOption';
5
+
6
+ export default {
7
+ title: 'Components/NsSelect',
8
+ decorators: [
9
+ (story) => <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>{story()}</div>,
10
+ ],
11
+ component: NsSelect,
12
+ argTypes: {
13
+ type: { control: 'select', options: ['unfilled', 'outlined'] },
14
+ disabled: { control: 'boolean' },
15
+ selectBorderColor: {
16
+ control: 'select',
17
+ options: ['primary', 'secondary', 'accentColorA', 'accentColorB', 'accentColorC'],
18
+ },
19
+ placeholder: { control: 'text' },
20
+ closeOnMouseLeave: { control: 'boolean' },
21
+ showListDivider: { control: 'boolean' },
22
+ label: { control: 'text' },
23
+ name: { control: 'text' },
24
+ menuProps:{ control: 'text' },
25
+ reverseArrowControls:{ control: 'boolean' },
26
+ validateOnBlur:{ control: 'boolean' },
27
+ autoComplete: { control: 'text' },
28
+ rules: {control: 'array'},
29
+ },
30
+ parameters: {
31
+ options: [
32
+ { label: 'Alabama', value: 'AL' },
33
+ { label: 'Alaska', value: 'AK' },
34
+ { label: 'Arizona', value: 'AZ' },
35
+ { label: 'Arkansas', value: 'AR' },
36
+ { label: 'California', value: 'CA' },
37
+ { label: 'Colorado', value: 'CO' },
38
+ { label: 'Connecticut', value: 'CT' },
39
+ { label: 'Delaware', value: 'DE' },
40
+ { label: 'District of Columbia', value: 'DC' },
41
+ { label: 'Florida', value: 'FL' },
42
+ { label: 'Georgia', value: 'GA' },
43
+ { label: 'Hawaii', value: 'HI' },
44
+ { label: 'Idaho', value: 'ID' },
45
+ { label: 'Illinois', value: 'IL' },
46
+ { label: 'Indiana', value: 'IN' },
47
+ { label: 'Iowa', value: 'IA' },
48
+ { label: 'Kansas', value: 'KA' },
49
+ { label: 'Kentucky', value: 'KY' },
50
+ { label: 'Louisiana', value: 'LA' },
51
+ { label: 'Maine', value: 'ME' },
52
+ { label: 'Maryland', value: 'MY' },
53
+ { label: 'Massachusetts', value: 'MA' },
54
+ { label: 'Michigan', value: 'MC' },
55
+ { label: 'Minnesota', value: 'MN' },
56
+ { label: 'Mississippi', value: 'MI' },
57
+ { label: 'Missouri', value: 'MO' },
58
+ { label: 'Montana', value: 'MT' },
59
+ { label: 'Nebraska', value: 'NE' },
60
+ { label: 'Nevada', value: 'NA' },
61
+ { label: 'New Hampshire', value: 'NH' },
62
+ { label: 'New Jersey', value: 'NJ' },
63
+ { label: 'New Mexico', value: 'NM' },
64
+ { label: 'New York', value: 'NY' },
65
+ { label: 'North Carolina', value: 'NC' },
66
+ { label: 'North Dakota', value: 'CD' },
67
+ { label: 'Ohio', value: 'OH' },
68
+ { label: 'Oklahoma', value: 'OK' },
69
+ { label: 'Oregon', value: 'OR' },
70
+ { label: 'Pennsylvania', value: 'PA' },
71
+ { label: 'Rhode Island', value: 'RI' },
72
+ { label: 'South Carolina', value: 'SC' },
73
+ { label: 'South Dakota', value: 'SD' },
74
+ { label: 'Tennessee', value: 'TN' },
75
+ { label: 'Texas', value: 'TX' },
76
+ { label: 'Utah', value: 'UT' },
77
+ { label: 'Vermont', value: 'VT' },
78
+ { label: 'Virginia', value: 'VA' },
79
+ { label: 'Washington', value: 'WA' },
80
+ { label: 'West Virginia', value: 'WV' },
81
+ { label: 'Wisconsin', value: 'WN' },
82
+ { label: 'Wyoming', value: 'WY' },
83
+ ],
84
+ },
85
+ args: {
86
+ type: 'outlined',
87
+ disabled: false,
88
+ selectBorderColor: 'primary',
89
+ closeOnMouseLeave: false,
90
+ showListDivider: true,
91
+ selectedValue: '',
92
+ selectedLabel: '',
93
+ label: 'State',
94
+ placeholder:'',
95
+ name:'',
96
+ menuProps:'auto',
97
+ reverseArrowControls: false,
98
+ itemText:'Text',
99
+ itemValue:'Value',
100
+ validateOnBlur: false,
101
+ autoComplete: '',
102
+ rules:[]
103
+ },
104
+ } as ComponentMeta<typeof NsSelect>;
105
+
106
+ export const Select: ComponentStory<typeof NsSelect> = (args, context) => {
107
+ const [selectedLabel, setSelectedLabel] = useState(args.selectedLabel);
108
+ const [selectedValue, setSelectedValue] = useState(args.selectedValue);
109
+
110
+ const options = context.parameters.options;
111
+ const handleSelect = (value: string) => {
112
+ setSelectedValue(value);
113
+ options.find((option: any) => {
114
+ if (option.value === value) {
115
+ setSelectedLabel(option.label);
116
+ }
117
+ });
118
+ console.log('Selected:', value);
119
+ };
120
+
121
+ return (
122
+ <NsSelect
123
+ {...args}
124
+ selectedValue={selectedValue}
125
+ selectedLabel={selectedLabel}
126
+ onSelect={handleSelect}
127
+ label={args.label}
128
+ >
129
+ {options.map((option: any) => (
130
+ <NsSelectOption key={option.value} value={option.value} label={option.label} />
131
+ ))}
132
+ </NsSelect>
133
+ );
134
+ };
@@ -0,0 +1,34 @@
1
+ import { ReactNode } from 'react';
2
+ import { FoundationTheme } from '@nuskin/foundation-theme';
3
+
4
+ export interface SelectProps {
5
+ selectedValue: string;
6
+ selectedLabel: string;
7
+ onSelect: (arg: string) => void; // eslint-disable-line
8
+ children: ReactNode;
9
+ disabled?: boolean;
10
+ type?: 'outlined' | 'unfilled';
11
+ placeholder?: string;
12
+ selectBorderColor?: FoundationTheme.PaletteColors;
13
+ closeOnMouseLeave?: boolean;
14
+ showListDivider?: boolean;
15
+ label?: string;
16
+ readOnly?: boolean;
17
+ name?: string;
18
+ errorMessage?: string;
19
+ menuProps?: string | object;
20
+ reverseArrowControls?: boolean;
21
+ itemText?: string;
22
+ itemValue?: string;
23
+ validateOnBlur?: boolean;
24
+ autoComplete?: string;
25
+ rules?: any[];
26
+ }
27
+
28
+ export interface SelectOptionProps {
29
+ value: string;
30
+ label: string;
31
+ selectedValue?: string;
32
+ onSelect?: (arg: string) => void; // eslint-disable-line
33
+ showListDivider?: boolean;
34
+ }
@@ -0,0 +1,68 @@
1
+ import React from 'react';
2
+ import { TableRow } from '@mui/material';
3
+ import {
4
+ StyledTableRow,
5
+ StyledTableLastCell,
6
+ StyledExpandCell,
7
+ StyledOriginalTableCell
8
+ } from './NsTable.styled'
9
+ import type {
10
+ NsTableRowProps
11
+ } from './types'
12
+ import Box from '@mui/material/Box';
13
+ import Collapse from '@mui/material/Collapse';
14
+
15
+ export default function ExpandableRow({
16
+ expandableContent,
17
+ isExpand,
18
+ handleClick,
19
+ row,
20
+ itemKeyList,
21
+ index,
22
+ showActions,
23
+ showExpandedContent,
24
+ actionClick
25
+ }: NsTableRowProps) {
26
+ const tableRowTestId = `table-row-${index}`;
27
+
28
+ return (
29
+ <React.Fragment>
30
+ <StyledTableRow
31
+ hover
32
+ onClick={() => handleClick(index)}
33
+ tabIndex={-1}
34
+ key={index}
35
+ className='cursor-pointer'
36
+ data-testid={tableRowTestId}
37
+ >
38
+ {
39
+ itemKeyList.map((id, i) => {
40
+ return ((i === itemKeyList.length - 1) && showActions) ? (
41
+ <StyledTableLastCell align="justify" key={id}>
42
+ <span>{row[id]}</span>
43
+ <span className='action'>{actionClick(row)}</span>
44
+ </StyledTableLastCell>
45
+ ) : (
46
+ <StyledOriginalTableCell align="left" key={id}>{row[id]}</StyledOriginalTableCell>
47
+ )
48
+ })
49
+ }
50
+ </StyledTableRow>
51
+ {
52
+ showExpandedContent ? (
53
+ <TableRow>
54
+ <StyledExpandCell colSpan={itemKeyList.length} className={!isExpand ? 'remove' : ''}>
55
+ <Collapse in={isExpand} unmountOnExit>
56
+ <Box className='m-px'>
57
+ {
58
+ expandableContent(row, index)
59
+ }
60
+ </Box>
61
+ </Collapse>
62
+ </StyledExpandCell>
63
+ </TableRow>
64
+ ) : null
65
+ }
66
+ </React.Fragment>
67
+ )
68
+ }
@@ -1,11 +1,45 @@
1
1
  import React from 'react';
2
2
  import { render, fireEvent, screen } from '@/test-utils/index';
3
3
  import NsTable from './NsTable';
4
+ import { Item } from './types';
5
+ import { NsIcon } from '../icon';
6
+
7
+ const expandableContent = (selectedItem: Item, index: number) => {
8
+ return (
9
+ <div key={index}>
10
+ <p>
11
+ Data: {selectedItem.name} , {selectedItem.calories}
12
+ </p>
13
+ <p>
14
+ Index: {index}
15
+ </p>
16
+ <p>
17
+ Expandable: True
18
+ </p>
19
+ </div>
20
+ )
21
+ }
22
+
23
+ const actionClick = (row: Item) => {
24
+ const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
25
+ event.stopPropagation();
26
+ console.log(row)
27
+ }
28
+
29
+ return (
30
+ <button onClick={handleClick}>
31
+ <NsIcon
32
+ name='cart'
33
+ size='medium'
34
+ />
35
+ </button>
36
+ )
37
+ }
4
38
 
5
39
  describe('NsTable', () => {
6
40
  const headers = [
7
- { id: 'name', label: 'Name', numeric: false },
8
- { id: 'age', label: 'Age', numeric: true },
41
+ { id: 'name', label: 'Name', numeric: false, sortable: true },
42
+ { id: 'age', label: 'Age', numeric: true, sortable: true },
9
43
  ];
10
44
 
11
45
  const items = [
@@ -20,7 +54,6 @@ describe('NsTable', () => {
20
54
  ];
21
55
 
22
56
  const rows = 5;
23
- const isShowSelector = true;
24
57
  const rowsPerPageOptions = [5, 10, 15];
25
58
  const itemKey = 'name';
26
59
 
@@ -30,10 +63,14 @@ describe('NsTable', () => {
30
63
  headers={headers}
31
64
  items={items}
32
65
  rows={rows}
33
- isShowSelector={isShowSelector}
34
66
  rowsPerPageOptions={rowsPerPageOptions}
35
67
  itemKey={itemKey}
36
- isPagination
68
+ isExpandableAll={true}
69
+ loading={true}
70
+ showActions={false}
71
+ showExpandedContent={false}
72
+ expandableContent={expandableContent}
73
+ actionClick={actionClick}
37
74
  />
38
75
  );
39
76
 
@@ -43,82 +80,72 @@ describe('NsTable', () => {
43
80
  expect(screen.getByText('Maria')).toBeInTheDocument();
44
81
  expect(screen.getByText('28')).toBeInTheDocument();
45
82
  expect(screen.getByText('31')).toBeInTheDocument();
46
- expect(screen.getByRole('button', { name: 'Rows per page: 5' })).toBeInTheDocument();
47
83
  });
48
84
 
49
- it('selects and deselects rows on click', () => {
85
+ it('expandable true click', () => {
50
86
  render(
51
87
  <NsTable
52
88
  headers={headers}
53
89
  items={items}
54
90
  rows={rows}
55
- isShowSelector={isShowSelector}
56
91
  rowsPerPageOptions={rowsPerPageOptions}
57
92
  itemKey={itemKey}
58
- isPagination
93
+ isExpandableAll={true}
94
+ expandableContent={expandableContent}
95
+ actionClick={actionClick}
59
96
  />
60
97
  );
61
98
 
62
- expect(screen.getByText('Kevin')).toBeInTheDocument();
63
- const button = screen.getByText('Kevin');
64
- fireEvent.click(button);
99
+
100
+ expect(screen.getByTestId('table-row-0')).toBeInTheDocument();
65
101
 
66
- expect(screen.getByTestId('table-row-3')).toHaveAttribute('aria-checked', 'true');
67
- fireEvent.click(button);
68
- expect(screen.getByTestId('table-row-3')).toHaveAttribute('aria-checked', 'false');
69
- });
102
+ const button = screen.getByTestId('table-row-0');
70
103
 
71
- it('hide selectors', () => {
72
- render(
73
- <NsTable
74
- headers={headers}
75
- items={items}
76
- rows={rows}
77
- isShowSelector={!isShowSelector}
78
- rowsPerPageOptions={rowsPerPageOptions}
79
- itemKey={itemKey}
80
- isPagination
81
- />
82
- );
104
+ fireEvent.click(button);
105
+ expect(screen.getByText('Expandable: True')).toBeInTheDocument();
106
+ fireEvent.click(button);
83
107
  });
84
108
 
85
- it('selects all rows', () => {
109
+ it('expandable false click', () => {
86
110
  render(
87
111
  <NsTable
88
112
  headers={headers}
89
113
  items={items}
90
114
  rows={rows}
91
- isShowSelector={isShowSelector}
92
115
  rowsPerPageOptions={rowsPerPageOptions}
93
116
  itemKey={itemKey}
94
- isPagination
117
+ isExpandableAll={false}
118
+ expandableContent={expandableContent}
119
+ actionClick={actionClick}
95
120
  />
96
121
  );
97
122
 
98
- expect(screen.getByTestId('header-checkbox')).toBeInTheDocument();
123
+ expect(screen.getByTestId('table-row-0')).toBeInTheDocument();
99
124
 
100
- const button = screen.getByTestId('header-checkbox');
125
+ const button = screen.getByTestId('table-row-0');
101
126
 
102
127
  fireEvent.click(button);
103
- expect(screen.getByTestId('table-checkbox-0')).toHaveClass('PrivateSwitchBase-input');
128
+ expect(screen.getByText('Expandable: True')).toBeInTheDocument();
129
+ fireEvent.click(button);
104
130
  });
105
131
 
106
- it('selects all rows when click all values', async () => {
132
+ it('pagination next button click event', async () => {
107
133
  render(
108
134
  <NsTable
109
135
  headers={headers}
110
136
  items={items}
111
137
  rows={rows}
112
- isShowSelector={isShowSelector}
113
138
  rowsPerPageOptions={rowsPerPageOptions}
114
139
  itemKey={itemKey}
115
- isPagination
140
+ isExpandableAll={true}
141
+ expandableContent={expandableContent}
142
+ actionClick={actionClick}
116
143
  />
117
144
  );
118
145
 
119
- expect(screen.getByTestId('KeyboardArrowRightIcon')).toBeInTheDocument();
146
+ expect(screen.getByTestId('NavigateNextIcon')).toBeInTheDocument();
120
147
 
121
- const button = screen.getByTestId('KeyboardArrowRightIcon');
148
+ const button = screen.getByTestId('NavigateNextIcon');
122
149
  fireEvent.click(button);
123
150
  expect(screen.getByText('Sandy')).toBeInTheDocument();
124
151
  });
@@ -129,10 +156,11 @@ describe('NsTable', () => {
129
156
  headers={headers}
130
157
  items={items}
131
158
  rows={rows}
132
- isShowSelector={isShowSelector}
133
159
  rowsPerPageOptions={rowsPerPageOptions}
134
160
  itemKey={itemKey}
135
- isPagination
161
+ isExpandableAll={true}
162
+ expandableContent={expandableContent}
163
+ actionClick={actionClick}
136
164
  />
137
165
  );
138
166