@nuskin/foundation-ui-components 1.0.0-develop.3 → 1.0.0-develop.5

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 (95) hide show
  1. package/package.json +9 -4
  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 +93 -0
  10. package/src/common/accordion/specs/NsAccordionHeader.spec.tsx +63 -0
  11. package/src/common/accordion/specs/NsAccordionItem.spec.tsx +62 -0
  12. package/src/common/accordion/specs/NsCollapse.spec.tsx +37 -0
  13. package/src/common/accordion/specs/NsToggleSection.spec.tsx +38 -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.spec.tsx +0 -1
  22. package/src/common/alert/NsAlert.styled.ts +10 -10
  23. package/src/common/alert/NsAlert.tsx +4 -3
  24. package/src/common/alert/types.d.ts +22 -22
  25. package/src/common/auth-dropdown/NsAuthDropdown.styled.ts +12 -11
  26. package/src/common/auth-dropdown/NsAuthDropdown.tsx +2 -1
  27. package/src/common/auth-dropdown/types.d.ts +3 -1
  28. package/src/common/autocomplete/NsAutocomplete.spec.tsx +20 -8
  29. package/src/common/autocomplete/NsAutocomplete.stories.tsx +3 -0
  30. package/src/common/autocomplete/NsAutocomplete.styled.tsx +12 -0
  31. package/src/common/autocomplete/NsAutocomplete.tsx +36 -18
  32. package/src/common/autocomplete/types.d.ts +7 -1
  33. package/src/common/brand-components/NsBrandComponent.tsx +3 -0
  34. package/src/common/breadcrumb/NsBreadcrumb.tsx +4 -2
  35. package/src/common/button/NsButton.spec.tsx +11 -12
  36. package/src/common/button/NsButton.stories.tsx +1 -1
  37. package/src/common/button/NsButton.styled.tsx +25 -23
  38. package/src/common/button/NsButton.tsx +9 -2
  39. package/src/common/button/types.d.ts +1 -0
  40. package/src/common/checkbox/NsCheckbox.styled.tsx +2 -2
  41. package/src/common/common.types.d.ts +2 -0
  42. package/src/common/dropdown/types.d.ts +3 -1
  43. package/src/common/email-simple/NsEmailSimple.spec.tsx +145 -0
  44. package/src/common/email-simple/NsEmailSimple.stories.tsx +61 -0
  45. package/src/common/email-simple/NsEmailSimple.tsx +71 -0
  46. package/src/common/email-simple/index.ts +2 -0
  47. package/src/common/email-simple/types.d.ts +14 -0
  48. package/src/common/flag/NsFlag.spec.tsx +4 -24
  49. package/src/common/flag/NsFlag.styled.tsx +5 -5
  50. package/src/common/flag/NsFlag.tsx +0 -2
  51. package/src/common/icon/types.d.ts +1 -0
  52. package/src/common/image/types.d.ts +1 -0
  53. package/src/common/index.ts +3 -0
  54. package/src/common/input/InputFieldWrapper.tsx +4 -4
  55. package/src/common/input/NsInputField.stories.tsx +11 -9
  56. package/src/common/input/NsInputField.tsx +12 -5
  57. package/src/common/input/getAdornmentProps.tsx +4 -0
  58. package/src/common/input/types.d.ts +3 -1
  59. package/src/common/label/NsLabel.stories.tsx +3 -0
  60. package/src/common/label/NsLabel.tsx +18 -17
  61. package/src/common/label/types.d.ts +2 -1
  62. package/src/common/nav-tab/NsNavTab.spec.tsx +0 -5
  63. package/src/common/nav-tab/NsNavTab.styled.tsx +7 -4
  64. package/src/common/radiogroup/NsRadioGroup.spec.tsx +64 -0
  65. package/src/common/radiogroup/NsRadioGroup.stories.tsx +102 -0
  66. package/src/common/radiogroup/NsRadioGroup.styled.tsx +50 -0
  67. package/src/common/radiogroup/NsRadioGroup.tsx +61 -0
  68. package/src/common/radiogroup/index.ts +2 -0
  69. package/src/common/radiogroup/types.d.ts +20 -0
  70. package/src/common/select/NsSelect.spec.tsx +200 -0
  71. package/src/common/select/NsSelect.styled.tsx +85 -0
  72. package/src/common/select/NsSelect.tsx +117 -0
  73. package/src/common/select/NsSelectOption.tsx +30 -0
  74. package/src/common/select/index.ts +3 -0
  75. package/src/common/select/stories/NsSelect.stories.tsx +134 -0
  76. package/src/common/select/types.d.ts +34 -0
  77. package/src/common/table/NsExpandableRow.tsx +68 -0
  78. package/src/common/table/NsTable.spec.tsx +69 -41
  79. package/src/common/table/NsTable.stories.tsx +45 -7
  80. package/src/common/table/NsTable.styled.ts +106 -12
  81. package/src/common/table/NsTable.tsx +78 -89
  82. package/src/common/table/NsTableHeader.tsx +52 -38
  83. package/src/common/table/NsTablePagination.tsx +21 -13
  84. package/src/common/table/types.d.ts +21 -8
  85. package/src/common/text-strip/NsTextStrip.tsx +10 -7
  86. package/src/common/typography/Typography.styled.tsx +3 -3
  87. package/src/common/validations/regex.ts +3 -0
  88. /package/src/common/card/{tests → specs}/BrandLogo.spec.tsx +0 -0
  89. /package/src/common/card/{tests → specs}/NsBgCard.spec.tsx +0 -0
  90. /package/src/common/card/{tests → specs}/NsBrandProductCard.spec.tsx +0 -0
  91. /package/src/common/card/{tests → specs}/NsFfgCard.spec.tsx +0 -0
  92. /package/src/common/carousal/{tests → specs}/Chevron.spec.tsx +0 -0
  93. /package/src/common/carousal/{tests → specs}/NsCarousal.spec.tsx +0 -0
  94. /package/src/common/carousal/{tests → specs}/NsScrollingCarousal.spec.tsx +0 -0
  95. /package/src/common/carousal/{tests → specs}/RenderBrand.spec.tsx +0 -0
@@ -0,0 +1,71 @@
1
+ import React, { useState } from 'react';
2
+ import { NsEmailSimpleProps } from './types';
3
+ import { NsInputField } from '../input';
4
+ import { fieldStateType } from '../input/types';
5
+ import { emailPattern } from '../validations/regex';
6
+
7
+ const NsEmailSimple = (props: NsEmailSimpleProps) => {
8
+ const {
9
+ disabled,
10
+ label,
11
+ required,
12
+ maxLength,
13
+ invalidEmailMessage,
14
+ dupedEmailMessage,
15
+ requiredErrorMessage,
16
+ checkEmail,
17
+ additionalProps,
18
+ } = props;
19
+ const [fieldState, setFieldState] = useState<fieldStateType>();
20
+ const [errorMsg, setErrorMessage] = useState('');
21
+
22
+ const handleBlur = async (e: React.FocusEvent<HTMLInputElement>) => {
23
+ const emailInput = e.target.value.toLowerCase().trim();
24
+ let fieldStateValue: fieldStateType;
25
+ let errorMessageValue = '';
26
+ if (required && !emailInput) {
27
+ fieldStateValue = 'error';
28
+ errorMessageValue = requiredErrorMessage;
29
+ } else if (!emailPattern.test(emailInput)) {
30
+ fieldStateValue = 'error';
31
+ errorMessageValue = invalidEmailMessage;
32
+ } else if (typeof checkEmail === 'function') {
33
+ try {
34
+ const [isValid, isAvailable] = await checkEmail();
35
+ if (!isValid) {
36
+ fieldStateValue = 'error';
37
+ errorMessageValue = invalidEmailMessage;
38
+ } else if (!isAvailable) {
39
+ fieldStateValue = 'error';
40
+ errorMessageValue = dupedEmailMessage;
41
+ } else {
42
+ fieldStateValue = undefined;
43
+ errorMessageValue = '';
44
+ }
45
+ } catch (error) {
46
+ console.log('API error', error);
47
+ }
48
+ } else {
49
+ //TODO What happens when user does not pass valid checkEmail function
50
+ }
51
+ setFieldState(fieldStateValue);
52
+ setErrorMessage(errorMessageValue);
53
+ };
54
+ return (
55
+ <NsInputField
56
+ required={required}
57
+ disabled={disabled}
58
+ label={label}
59
+ onBlur={handleBlur}
60
+ inputProps={{ maxLength }}
61
+ additionalProps={{ testid: additionalProps?.testid ?? 'email-field-test' }}
62
+ helperText={errorMsg}
63
+ fieldState={fieldState}
64
+ InputProps={{
65
+ endAdornment: null,
66
+ }}
67
+ />
68
+ );
69
+ };
70
+
71
+ export default NsEmailSimple;
@@ -0,0 +1,2 @@
1
+ export { default as NsEmailSimple } from './NsEmailSimple';
2
+ export type { NsEmailSimpleProps } from './types.d';
@@ -0,0 +1,14 @@
1
+ import { TextFieldProps } from '@mui/material';
2
+ import { AdditionalProps } from '../common.types';
3
+
4
+ export type NsEmailSimpleProps = Pick<TextFieldProps> &
5
+ AdditionalProps & {
6
+ disabled?: boolean;
7
+ label?: string;
8
+ required?: boolean;
9
+ maxLength?: number;
10
+ invalidEmailText?: string;
11
+ dupedEmailText?: string;
12
+ requiredErrorMessage?: string;
13
+ checkEmail?: Function;
14
+ };
@@ -1,35 +1,15 @@
1
- /**
2
- * @author [vijayaprathap Kumar] (vpkumar@nuskin.com)
3
- * Flag.spec.tsx
4
- * @description In this test case,
5
- * we use the render function to render the MyComponent with the desired background color and text.
6
- */
7
-
8
1
  import React from 'react';
9
- import nuskinTheme from '@nuskin/foundation-theme/src/themes/genome-foundation';
10
2
 
11
3
  import { render } from '@/test-utils/index';
12
- import NsFlag from './NsFlag';
13
-
14
- const { palette } = nuskinTheme;
4
+ import { NsFlag } from '../';
15
5
 
16
- // Test suite for FlagComponent
17
6
  describe('FlagComponent', () => {
18
- // Test case for rendering a div element with background color and text.
19
7
  it('renders a div element with background color and text', () => {
20
- // Render FlagComponent with blue background color and "Nuskin" text
8
+ const text = 'NU SKIN';
21
9
  const { getByText } = render(<NsFlag message="NU SKIN" color="accentColorA" />);
10
+ const divElement = getByText(text);
22
11
 
23
- // Get the rendered div element using its text
24
- const divElement = getByText('NU SKIN');
25
-
26
- // Assert that the div element is in the document
27
12
  expect(divElement).toBeInTheDocument();
28
-
29
- // Assert that the div element has the expected background color
30
- expect(divElement).toHaveStyle(`color: ${palette?.primary?.contrastText}`);
31
-
32
- // Assert that the div element has the expected text content
33
- expect(divElement).toHaveTextContent('NU SKIN');
13
+ expect(divElement).toHaveTextContent(text);
34
14
  });
35
15
  });
@@ -9,6 +9,8 @@ import { styled, ColorUtils, FoundationTheme } from '@nuskin/foundation-theme';
9
9
 
10
10
  import { NsFlagSize } from './types.d';
11
11
 
12
+ const { paletteColor } = ColorUtils;
13
+
12
14
  type NsFlagThemeParams = {
13
15
  $size: NsFlagSize;
14
16
  $bgColor?: FoundationTheme.PaletteColors;
@@ -33,11 +35,9 @@ const makeFlagSize = ({ $size }: { $size: NsFlagSize }) => {
33
35
  return sizeValue / FLAG_SCALE_VALUE;
34
36
  };
35
37
 
36
- const { getPaletteColor } = ColorUtils;
37
-
38
38
  const makeFlagBorder = ({ $size, $bgColor = 'accentColorA', theme }: NsFlagThemeParams) => {
39
39
  if (theme) {
40
- return `${makeFlagSize({ $size })}px solid ${getPaletteColor(theme, $bgColor)}`;
40
+ return `${makeFlagSize({ $size })}px solid ${paletteColor($bgColor)({ theme })}`;
41
41
  }
42
42
  return '';
43
43
  };
@@ -45,8 +45,8 @@ const makeFlagBorder = ({ $size, $bgColor = 'accentColorA', theme }: NsFlagTheme
45
45
  export const StyledFlag = styled('span')<NsFlagThemeParams>`
46
46
  min-width: 29px;
47
47
  height: ${getFlagHeight}px;
48
- color: ${({ $bgColor = 'accentColorA', theme }) => getPaletteColor(theme, $bgColor, 'contrastText')};
49
- background: ${({ $bgColor = 'accentColorA', theme }) => getPaletteColor(theme, $bgColor)};
48
+ color: ${({ $bgColor = 'accentColorA', theme }) => paletteColor($bgColor, 'contrastText')({ theme })};
49
+ background: ${({ $bgColor = 'accentColorA', theme }) => paletteColor($bgColor)({ theme })};
50
50
  position: relative;
51
51
  padding: 0 15px;
52
52
  display: inline-grid;
@@ -5,9 +5,7 @@
5
5
  */
6
6
 
7
7
  import React, { PropsWithChildren } from 'react';
8
-
9
8
  import { StyledFlag } from './NsFlag.styled';
10
-
11
9
  import { NsFlagProps } from './types.d';
12
10
 
13
11
  const NsFlag = (props: PropsWithChildren<NsFlagProps>) => {
@@ -4,6 +4,7 @@ import { NsIconVariants } from '.';
4
4
  export type NsIconSizeType = 'small' | 'medium' | 'large' | 'xLarge';
5
5
 
6
6
  export type NsIconNameType = keyof typeof NsIconVariants;
7
+
7
8
  export type NsIconProps = {
8
9
  name: NsIconNameType;
9
10
  size?: NsIconSizeType;
@@ -15,6 +15,7 @@ export type NsNextImageProps = Pick<
15
15
  | 'blurDataURL'
16
16
  | 'fill'
17
17
  | 'unoptimized'
18
+ | 'loader'
18
19
  > & { id?: string; className?: string };
19
20
 
20
21
  export type NsImageProps = {
@@ -1,3 +1,4 @@
1
+ export * from './accordion';
1
2
  export * from './alert';
2
3
  export * from './auth-dropdown';
3
4
  export * from './autocomplete';
@@ -23,3 +24,5 @@ export * from './nav-product-card';
23
24
  export * from './text-strip';
24
25
  export * from './table';
25
26
  export * from './typography';
27
+ export * from './email-simple';
28
+ export * from './radiogroup';
@@ -1,6 +1,6 @@
1
1
  import { Stack } from '@mui/material';
2
2
  import { styled, ColorUtils } from '@nuskin/foundation-theme';
3
- const { getPaletteColor, getAppColor } = ColorUtils;
3
+ const { color, paletteColor } = ColorUtils;
4
4
 
5
5
  const InputFieldWrapper = styled(Stack)(({ theme }: any) => {
6
6
  return {
@@ -10,12 +10,12 @@ const InputFieldWrapper = styled(Stack)(({ theme }: any) => {
10
10
  '.MuiFormHelperText-root': {
11
11
  fontSize: '11px',
12
12
  marginTop: 0,
13
- color: getPaletteColor(theme, 'primary', 'main'),
13
+ color: paletteColor('primary', 'main')({ theme }),
14
14
  '&.success': {
15
- color: getAppColor(theme, 'success', '40') as string,
15
+ color: color('success', '40')({ theme }),
16
16
  },
17
17
  '&.error': {
18
- color: getPaletteColor(theme, 'error', 'main'),
18
+ color: paletteColor('error', 'main')({ theme }),
19
19
  },
20
20
  },
21
21
  };
@@ -8,31 +8,33 @@ type Story = StoryObj<ComponentType>;
8
8
  type MetaStory = Meta<ComponentType>;
9
9
 
10
10
  export default {
11
- title: 'Components/NsInputField',
11
+ title: 'Components/Inputs/NsInputField',
12
12
  component: NsInputField,
13
13
  decorators: [withCenterDecorator],
14
-
15
- args: {},
14
+ args: {
15
+ helperText: '',
16
+ iconSide: <NsIcon name="trash" />,
17
+ focused: false,
18
+ placeholder: 'enter text',
19
+ disabled: false,
20
+ fullWidth: false,
21
+ },
16
22
  argTypes: {
17
23
  fieldState: { control: 'select', options: ['default', 'success', 'error'] },
18
24
  value: { control: 'text' },
25
+ helperText: { control: 'text', description: 'text shown below input' },
19
26
  required: { control: 'boolean' },
20
27
  disabled: { control: 'boolean' },
21
28
  fullWidth: { control: 'boolean' },
22
- showOptional: { control: 'boolean' },
29
+ showOptional: { control: 'boolean', description: 'if true, an optional text is shown along with label' },
23
30
  focused: { control: 'boolean' },
24
31
  },
25
32
  } as MetaStory;
26
33
 
27
34
  export const Default: Story = {
28
35
  args: {
29
- focused: false,
30
- placeholder: 'enter text',
31
- disabled: false,
32
- fullWidth: false,
33
36
  value: 'Input value',
34
37
  fieldState: 'success',
35
- iconSide: <NsIcon name="trash" />,
36
38
  },
37
39
  };
38
40
 
@@ -3,7 +3,7 @@ import InputWrapper from './InputWrapper';
3
3
  import { NsInputFieldProps } from './types.d';
4
4
  import { NsLabel } from '../label';
5
5
  import InputFieldWrapper from './InputFieldWrapper';
6
- import { getAdornmentProps } from './getAdornmentProps';
6
+ import { AdornmentPropsType, getAdornmentProps } from './getAdornmentProps';
7
7
 
8
8
  /**
9
9
  * we are using fieldState in place of error prop
@@ -14,6 +14,7 @@ const NsInputField = (props: NsInputFieldProps) => {
14
14
  const {
15
15
  autoComplete,
16
16
  autoFocus,
17
+ additionalProps,
17
18
  defaultValue,
18
19
  disabled,
19
20
  fullWidth,
@@ -54,16 +55,22 @@ const NsInputField = (props: NsInputFieldProps) => {
54
55
  } = props;
55
56
  /** EndIcon is created so that we can automatically add success and error icon based of fieldState,
56
57
  * it will override iconEnd. Also to note, InputProps is given to override both iconStart, iconEnd and EndIcon */
57
- let EndIcon: any = getAdornmentProps({ disabled, fieldState, iconEnd, iconStart });
58
+ let EndIcon: AdornmentPropsType = getAdornmentProps({ disabled, fieldState, iconEnd, iconStart });
58
59
 
59
60
  return (
60
61
  <InputFieldWrapper>
61
62
  {label ? (
62
- <NsLabel {...InputLabelProps} showOptional={showOptional} required={required} disabled={disabled}>
63
+ <NsLabel
64
+ {...InputLabelProps}
65
+ showOptional={showOptional}
66
+ required={required}
67
+ disabled={disabled}
68
+ error={fieldState === 'error' && !disabled}
69
+ >
63
70
  {label}
64
71
  </NsLabel>
65
72
  ) : null}
66
- <InputWrapper fieldState={fieldState} data-testid="ns-input-field">
73
+ <InputWrapper fieldState={fieldState} data-testid={additionalProps?.testid ?? 'ns-input-field'}>
67
74
  <TextField
68
75
  {...rest}
69
76
  InputProps={{
@@ -97,7 +104,7 @@ const NsInputField = (props: NsInputFieldProps) => {
97
104
  />
98
105
  {iconSide}
99
106
  </InputWrapper>
100
- {helperText ? (
107
+ {helperText && !disabled ? (
101
108
  <FormHelperText {...FormHelperTextProps} className={fieldState}>
102
109
  {helperText}
103
110
  </FormHelperText>
@@ -22,6 +22,10 @@ type props = {
22
22
  * @param param0
23
23
  * @returns
24
24
  */
25
+ export type AdornmentPropsType = {
26
+ startAdornment?: ReactNode;
27
+ endAdornment?: ReactNode;
28
+ }
25
29
  export const getAdornmentProps = ({ disabled, fieldState, iconStart, iconEnd }: props) => {
26
30
  const icons = {
27
31
  startAdornment: iconStart ? <InputAdornment position="start">{iconStart}</InputAdornment> : null,
@@ -1,6 +1,8 @@
1
1
  import { ReactNode } from 'react';
2
2
  import { TextFieldProps } from '@mui/material';
3
+ import { AdditionalProps } from '../common.types';
3
4
 
5
+ // TODO: check if fieldStateType could be converted to enum, since we also have to account for undefined
4
6
  export type fieldStateType = undefined | 'error' | 'success';
5
7
  export type NsInputFieldProps = Omit<
6
8
  TextFieldProps,
@@ -39,4 +41,4 @@ export type NsInputFieldProps = Omit<
39
41
  defaultValue?: string;
40
42
  rows?: number;
41
43
  id?: string;
42
- };
44
+ } & AdditionalProps;
@@ -16,6 +16,7 @@ export const Default: Story = {
16
16
  args: {
17
17
  children: 'Label',
18
18
  required: false,
19
+ size: 16,
19
20
  },
20
21
  };
21
22
 
@@ -23,6 +24,7 @@ export const Optional: Story = {
23
24
  args: {
24
25
  children: 'Label',
25
26
  showOptional: true,
27
+ size: 16,
26
28
  },
27
29
  };
28
30
 
@@ -31,5 +33,6 @@ export const Required: Story = {
31
33
  children: 'Label',
32
34
  showOptional: true,
33
35
  required: true,
36
+ size: 16,
34
37
  },
35
38
  };
@@ -1,33 +1,34 @@
1
+ import { CSSProperties } from 'react';
2
+
1
3
  import { FormLabel } from '@mui/material';
4
+
5
+ import { styled, ColorUtils } from '@nuskin/foundation-theme';
6
+
2
7
  import { NsLabelProps } from './types.d';
3
- import { styled, nuskinTheme } from '@nuskin/foundation-theme';
4
8
 
5
- const { colors } = nuskinTheme;
9
+ const { paletteColor, isDarkMode, color } = ColorUtils;
6
10
 
7
- const StyledLabel = styled(FormLabel)<{ fontSize?: number }>(({ theme, fontSize }) => {
8
- const isLight = theme.palette?.primary?.main === '#252525';
11
+ const StyledLabel = styled(FormLabel)<{ fontSize?: number; style?: CSSProperties }>(({ theme, fontSize, style }) => {
12
+ const isLight = !isDarkMode({ theme });
9
13
  return {
10
14
  fontSize: fontSize ? `${fontSize}px` : '14px',
11
- color: theme.palette?.primary?.main ?? '#252525',
15
+ textAlign: style?.textAlign ?? 'left',
16
+ color: paletteColor('primary', 'main')({ theme }),
12
17
  '.optional-label': {
13
- color: isLight ? colors?.neutral?.[60] : colors?.neutral?.[50],
18
+ color: isLight ? color('neutral', '60')({ theme }) : color('neutral', '50')({ theme }),
14
19
  },
15
20
  '.MuiInputLabel-asterisk': {
16
- color: isLight ? colors?.red?.[40] : colors?.red?.[20],
21
+ color: isLight ? color('error', '40')({ theme }) : color('error', '20')({ theme }),
17
22
  },
18
- };
23
+ ...(style || {}),
24
+ } as any; // TODO: may be this "any" has to be fixed from foundation-theme
19
25
  });
20
- /**
21
- * NOTE: we are passing error = false, in props, because
22
- * we do not want to change the color of label to red, in case of error
23
- * @param props
24
- * @returns
25
- */
26
+
26
27
  const NsLabel = (props: NsLabelProps) => {
27
- const { required, showOptional } = props;
28
+ const { required, showOptional, children, size } = props;
28
29
  return (
29
- <StyledLabel {...props} required={required} error={false}>
30
- {props.children}
30
+ <StyledLabel {...props} fontSize={size} required={required}>
31
+ {children}
31
32
  {!required && showOptional ? <span className="optional-label">{' (Optional)'}</span> : null}
32
33
  </StyledLabel>
33
34
  );
@@ -2,8 +2,9 @@ import { InputLabelProps } from '@mui/material';
2
2
  import { PropsWithChildren } from 'react';
3
3
 
4
4
  export type NsLabelProps = PropsWithChildren &
5
- Omit<InputLabelProps, 'sx' | 'classes' | 'color' | 'margin' | 'variant' | 'classes' | 'error'> & {
5
+ Omit<InputLabelProps, 'sx' | 'classes' | 'color' | 'margin' | 'variant' | 'classes'> & {
6
6
  /** purpose of showOptional props is to show additional text 'optional' in the label,
7
7
  * if required = false and this flag is true */
8
8
  showOptional?: boolean;
9
+ size?: number;
9
10
  };
@@ -1,11 +1,8 @@
1
1
  import { fireEvent } from '@testing-library/react';
2
- import nuskinTheme from '@nuskin/foundation-theme/src/themes/genome-foundation';
3
2
  import { NsNavTabComponent } from './NsNavTab';
4
3
  import { NavTabs } from './types.d';
5
4
  import { render } from '@/test-utils/index';
6
5
 
7
- const { palette } = nuskinTheme;
8
-
9
6
  const tabs: NavTabs[] = [
10
7
  {
11
8
  tabName: 'Skin & Beauty',
@@ -54,7 +51,6 @@ describe('Nav Bar Component', () => {
54
51
  expect(li.length).toBe(4);
55
52
  li.forEach((list, i) => expect(list).toHaveTextContent(tabs[i].tabName));
56
53
  expect(container).toBeInTheDocument();
57
- expect(getByTestId('Skin & Beauty-list').firstChild).toHaveStyle(`color: ${palette.primary.main}`);
58
54
  fireEvent.mouseOver(getByTestId('Skin & Beauty'));
59
55
  expect(getByTestId('nav-drawer')).toBeInTheDocument();
60
56
  fireEvent.mouseLeave(getByTestId('Skin & Beauty'));
@@ -65,6 +61,5 @@ describe('Nav Bar Component', () => {
65
61
  const { getByTestId } = render(<NsNavTabComponent showDrawer={false} className="mb-2" tabs={tabs} />);
66
62
  fireEvent.mouseOver(getByTestId('Skin & Beauty'));
67
63
  expect(getByTestId('underline')).toBeInTheDocument();
68
- expect(getByTestId('underline')).toHaveStyle(`background-color: ${palette.success.main}`);
69
64
  });
70
65
  });
@@ -1,6 +1,9 @@
1
- import { FoundationTheme, styled } from '@nuskin/foundation-theme';
1
+ import { FoundationTheme, styled, ColorUtils } from '@nuskin/foundation-theme';
2
2
  import { motion } from 'framer-motion';
3
3
 
4
+ const { paletteColor } = ColorUtils;
5
+
6
+
4
7
  export const NavTabContainer = styled.div`
5
8
  .shadow {
6
9
  box-shadow: 0 2px 3px 0 rgba(0, 0, 0, 0.15);
@@ -23,7 +26,7 @@ export const NavTabUnderLine = styled(motion.div)<{ color?: FoundationTheme.Pale
23
26
  position: absolute;
24
27
  bottom: -2px;
25
28
  height: 2px;
26
- background-color: ${({ theme: { palette }, color = 'primary' }) => palette?.[color]?.main};
29
+ background-color: ${({ theme, color = 'primary' }) => paletteColor(color)({ theme })};
27
30
  `;
28
31
 
29
32
  export const NavDrawer = styled.div`
@@ -37,7 +40,7 @@ export const NavDrawer = styled.div`
37
40
  width: 100%;
38
41
  max-height: 590px;
39
42
 
40
- background-color: ${({ theme }) => theme?.palette?.primary.contrastText};
43
+ background-color: ${paletteColor('primary', 'contrastText')};
41
44
  box-shadow: 0 2px 3px 0 rgba(0, 0, 0, 0.15);
42
45
  transition: all 0.15s ease-in-out;
43
46
  overflow: hidden;
@@ -54,7 +57,7 @@ export const NavDrawerContainer = styled(motion.div)`
54
57
  z-index: 1;
55
58
  }
56
59
  box-shadow: 0 2px 3px 0 rgba(0, 0, 0, 0.15);
57
- background-color: ${({ theme }) => theme?.palette?.primary.contrastText};
60
+ background-color: ${paletteColor('primary', 'contrastText')};
58
61
  width: 100%;
59
62
  text-align: left;
60
63
  max-height: 590px;
@@ -0,0 +1,64 @@
1
+ import React from 'react';
2
+ import { render, fireEvent, screen } from '@testing-library/react';
3
+ import { NsRadioGroup } from './';
4
+ import { FoundationTheme } from '@nuskin/foundation-theme';
5
+
6
+
7
+ describe('NsRadioGroup', () => {
8
+
9
+ const options = [
10
+ { id: 'Option1', label: 'Option 1', value: 'Option1' },
11
+ { id: 'Option2', label: 'Option 2', value: 'Option2' },
12
+ { id: 'Option3', label: 'Option 3', value: 'Option3' },
13
+ ]
14
+
15
+ const props = {
16
+ disable: false,
17
+ items: options,
18
+ name: 'test',
19
+ label: 'I choose to signup as',
20
+ color: '#272525' as FoundationTheme.PaletteColors,
21
+ additionalSlot: 'An additional slot allows for more text',
22
+ size: 24,
23
+ labelFontSize: 16,
24
+ additionalProps: {
25
+ testid: 'radio-group',
26
+ },
27
+ };
28
+ const onChange = jest.fn();
29
+
30
+ it('renders options correctly', () => {
31
+ render(
32
+ <NsRadioGroup {...props} onChange={onChange}
33
+ />,
34
+ );
35
+
36
+ options.forEach((option) => {
37
+ const radioOption = screen.getByLabelText(option.label) as HTMLInputElement;
38
+ expect(radioOption).toBeInTheDocument();
39
+ expect(radioOption.value).toBe(option.value)
40
+ })
41
+
42
+ })
43
+
44
+ it('calls OnChange when selecting option', () => {
45
+
46
+ render(<NsRadioGroup {...props} onChange={onChange} />)
47
+
48
+ const radioOption = screen.getByLabelText('Option 2') as HTMLInputElement
49
+ fireEvent.click(radioOption);
50
+ expect(onChange).toHaveBeenCalledTimes(1);
51
+
52
+ })
53
+
54
+ it('does not call Onchange when the same option is clicked', () => {
55
+ const onChange = jest.fn();
56
+ render(<NsRadioGroup {...props} onChange={onChange} />)
57
+
58
+ const radioOption = screen.getByLabelText('Option 1') as HTMLInputElement
59
+ fireEvent.click(radioOption)
60
+ expect(onChange).not.toHaveBeenCalled();
61
+ })
62
+
63
+
64
+ })