@nuskin/foundation-ui-components 1.0.0-cft-35.11 → 1.0.0-cft-35.13

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 (103) hide show
  1. package/package.json +21 -16
  2. package/src/common/alert/NsAlert.spec.tsx +134 -0
  3. package/src/common/alert/NsAlert.stories.tsx +42 -0
  4. package/src/common/alert/NsAlert.styled.ts +124 -0
  5. package/src/common/alert/NsAlert.tsx +155 -0
  6. package/src/common/alert/index.ts +2 -0
  7. package/src/common/alert/types.d.ts +45 -0
  8. package/src/common/auth-dropdown/NsAuthDropdown.stories.tsx +9 -5
  9. package/src/common/auth-dropdown/NsAuthDropdown.tsx +1 -1
  10. package/src/common/autocomplete/NsAutocomplete.spec.tsx +96 -0
  11. package/src/common/autocomplete/NsAutocomplete.stories.tsx +51 -0
  12. package/src/common/autocomplete/NsAutocomplete.tsx +110 -0
  13. package/src/common/autocomplete/index.ts +1 -0
  14. package/src/common/autocomplete/mock/Mock.styled.tsx +23 -0
  15. package/src/common/autocomplete/mock/MockData.ts +46 -0
  16. package/src/common/autocomplete/mock/MockUI.tsx +24 -0
  17. package/src/common/autocomplete/types.ts +39 -0
  18. package/src/common/banner/NsBanner.spec.tsx +2 -2
  19. package/src/common/banner/NsBanner.stories.tsx +2 -2
  20. package/src/common/banner/NsBanner.styled.tsx +1 -0
  21. package/src/common/banner/NsBanner.tsx +12 -3
  22. package/src/common/brand-components/NsBrand.stories.tsx +2 -2
  23. package/src/common/breadcrumb/NsBreadcrumb.spec.tsx +12 -4
  24. package/src/common/breadcrumb/NsBreadcrumb.stories.tsx +19 -8
  25. package/src/common/breadcrumb/NsBreadcrumb.styled.tsx +1 -1
  26. package/src/common/breadcrumb/NsBreadcrumb.tsx +2 -4
  27. package/src/common/button/NsButton.stories.tsx +2 -2
  28. package/src/common/card/NsFfgCard.tsx +18 -0
  29. package/src/common/card/index.ts +1 -0
  30. package/src/common/card/stories/NsBgCard.stories.tsx +2 -2
  31. package/src/common/card/stories/NsBrandProductCard.stories.tsx +2 -2
  32. package/src/common/card/stories/NsFfgCard.stories.tsx +40 -0
  33. package/src/common/card/styled/NsFfgStyled.tsx +44 -0
  34. package/src/common/card/tests/NsFfgCard.spec.tsx +23 -0
  35. package/src/common/card/types.d.ts +9 -0
  36. package/src/common/carousal/CarousalControl.tsx +3 -5
  37. package/src/common/carousal/IconWrapper.tsx +4 -4
  38. package/src/common/carousal/tests/NsCarousal.spec.tsx +4 -4
  39. package/src/common/cart-icon/NsCartIcon.spec.tsx +10 -4
  40. package/src/common/cart-icon/NsCartIcon.stories.tsx +2 -2
  41. package/src/common/checkbox/NsCheckbox.stories.tsx +12 -16
  42. package/src/common/column-control/NDivs.story.tsx +35 -0
  43. package/src/common/column-control/NsColumnControl.spec.tsx +24 -0
  44. package/src/common/column-control/NsColumnControl.stories.tsx +69 -0
  45. package/src/common/column-control/NsColumnControl.tsx +59 -0
  46. package/src/common/column-control/index.ts +2 -0
  47. package/src/common/column-control/types.d.ts +47 -0
  48. package/src/common/column-control/utils.ts +66 -0
  49. package/src/common/dropdown/NsDropdown.styled.tsx +5 -1
  50. package/src/common/dropdown/NsDropdown.tsx +1 -1
  51. package/src/common/dropdown/stories/NsDropdown.stories.tsx +13 -9
  52. package/src/common/dropdown/stories/NsDropdownCountry.stories.tsx +13 -9
  53. package/src/common/flag/NsFlag.stories.tsx +2 -2
  54. package/src/common/icon/NsIcon.spec.tsx +9 -2
  55. package/src/common/icon/NsIcon.stories.tsx +4 -17
  56. package/src/common/icon/NsIcon.tsx +1 -1
  57. package/src/common/icon/{IconMap.ts → NsIconVariants.ts} +10 -0
  58. package/src/common/icon/icons/AlertErrorIcon.tsx +36 -0
  59. package/src/common/icon/icons/ArrowDown.tsx +1 -1
  60. package/src/common/{carousal/LeftChevron.tsx → icon/icons/ArrowLeft.tsx} +7 -5
  61. package/src/common/{carousal/RightChevron.tsx → icon/icons/ArrowRight.tsx} +3 -3
  62. package/src/common/icon/icons/ArrowUp.tsx +1 -1
  63. package/src/common/icon/icons/Cart.tsx +7 -1
  64. package/src/common/icon/icons/CartBadge.tsx +7 -1
  65. package/src/common/icon/icons/CheckShield.tsx +7 -1
  66. package/src/common/icon/icons/CheckVerified.tsx +7 -1
  67. package/src/common/icon/icons/CloseIcon.tsx +22 -0
  68. package/src/common/icon/icons/ErrorIcon.tsx +1 -1
  69. package/src/common/icon/icons/InfoFilled.tsx +1 -1
  70. package/src/common/icon/icons/InfoOutlined.tsx +7 -1
  71. package/src/common/icon/icons/SearchIcon.tsx +1 -1
  72. package/src/common/icon/icons/SlashIcon.tsx +4 -4
  73. package/src/common/icon/icons/SuccessIcon.tsx +1 -1
  74. package/src/common/icon/icons/TrashIcon.tsx +1 -2
  75. package/src/common/icon/icons/WarningIcon.tsx +36 -0
  76. package/src/common/icon/icons/home.tsx +4 -3
  77. package/src/common/icon/index.ts +1 -0
  78. package/src/common/icon/types.d.ts +2 -15
  79. package/src/common/image/NsImage.stories.tsx +2 -2
  80. package/src/common/image/NsImage.tsx +3 -2
  81. package/src/common/image/NsNextImage.stories.tsx +2 -2
  82. package/src/common/image/NsNextImage.tsx +3 -7
  83. package/src/common/image/types.d.ts +6 -4
  84. package/src/common/index.ts +15 -8
  85. package/src/common/input/InputFieldWrapper.tsx +2 -3
  86. package/src/common/input/InputWrapper.tsx +3 -2
  87. package/src/common/input/NsInputField.spec.tsx +17 -2
  88. package/src/common/link/NsLink.spec.tsx +15 -8
  89. package/src/common/link/NsLink.stories.tsx +10 -2
  90. package/src/common/link/NsLink.styled.tsx +1 -1
  91. package/src/common/link/NsLink.tsx +26 -4
  92. package/src/common/link/types.d.ts +4 -2
  93. package/src/common/nav-product-card/NsNavProductCard.stories.tsx +2 -2
  94. package/src/common/nav-product-card/NsNavProductCard.tsx +3 -2
  95. package/src/common/nav-tab/NsNavTab.stories.tsx +2 -2
  96. package/src/common/typography/NsTypography.stories.tsx +2 -2
  97. package/src/common/videos/NsVideo.spec.tsx +26 -0
  98. package/src/common/videos/NsVideo.stories.tsx +32 -0
  99. package/src/common/videos/NsVideo.tsx +25 -0
  100. package/src/common/videos/index.ts +2 -0
  101. package/src/common/videos/types.d.ts +9 -0
  102. package/CHANGELOG.md +0 -187
  103. /package/src/common/breadcrumb/{types.ts → types.d.ts} +0 -0
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nuskin/foundation-ui-components",
3
- "version": "1.0.0-cft-35.11",
4
- "description": "It is a foundation library written in react, that provides commom components to all UI pages",
3
+ "version": "1.0.0-cft-35.13",
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",
7
7
  "repository": {
@@ -10,8 +10,8 @@
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
- "email": "rpalanisamy@nuskin.com",
14
- "name": "Ruthraj Palanisamy"
13
+ "name": "Ruthraj Palanisamy",
14
+ "email": "rpalanisamy@nuskin.com"
15
15
  },
16
16
  "publishConfig": {
17
17
  "access": "public"
@@ -27,11 +27,11 @@
27
27
  "build": "next build",
28
28
  "start": "next start",
29
29
  "lint": "next lint",
30
- "storybook": "start-storybook -p 6007",
31
30
  "test": "jest",
32
31
  "test:coverage": "yarn test --coverage",
33
32
  "test:watch": "jest --watch",
34
- "build-storybook": "build-storybook"
33
+ "storybook": "storybook dev -p 6007",
34
+ "build-storybook": "storybook build"
35
35
  },
36
36
  "dependencies": {
37
37
  "@emotion/react": "^11.10.6",
@@ -57,14 +57,16 @@
57
57
  "@babel/preset-typescript": "^7.21.0",
58
58
  "@emotion/jest": "^11.10.5",
59
59
  "@nuskin/eslint-config": "^1.0.0-setup.1",
60
- "@storybook/addon-actions": "^6.5.16",
61
- "@storybook/addon-essentials": "^6.5.16",
62
- "@storybook/addon-interactions": "^6.5.16",
63
- "@storybook/addon-links": "^6.5.16",
64
- "@storybook/builder-webpack5": "^6.5.16",
65
- "@storybook/manager-webpack5": "^6.5.16",
66
- "@storybook/react": "^6.5.16",
67
- "@storybook/testing-library": "^0.0.13",
60
+ "@storybook/addon-actions": "^7.0.7",
61
+ "@storybook/addon-essentials": "^7.0.7",
62
+ "@storybook/addon-interactions": "^7.0.7",
63
+ "@storybook/addon-links": "^7.0.7",
64
+ "@storybook/addon-mdx-gfm": "^7.0.7",
65
+ "@storybook/jest": "^0.1.0",
66
+ "@storybook/nextjs": "^7.0.7",
67
+ "@storybook/react": "^7.0.7",
68
+ "@storybook/test-runner": "^0.10.0",
69
+ "@storybook/testing-library": "^0.1.0",
68
70
  "@testing-library/jest-dom": "^5.16.5",
69
71
  "@testing-library/react": "^14.0.0",
70
72
  "@types/lodash": "^4.14.191",
@@ -77,6 +79,7 @@
77
79
  "babel-jest": "^29.5.0",
78
80
  "babel-loader": "^9.1.2",
79
81
  "babel-plugin-emotion": "^11.0.0",
82
+ "chromatic": "^6.17.3",
80
83
  "eslint": "8.36.0",
81
84
  "eslint-config-next": "13.2.4",
82
85
  "eslint-config-prettier": "^8.7.0",
@@ -84,9 +87,11 @@
84
87
  "eslint-plugin-prettier": "^4.2.1",
85
88
  "eslint-plugin-storybook": "^0.6.11",
86
89
  "jest": "^29.5.0",
87
- "jest-environment-jsdom": "^29.5.0"
90
+ "jest-environment-jsdom": "^29.5.0",
91
+ "storybook": "^7.0.7"
88
92
  },
89
93
  "files": [
90
94
  "src/common"
91
- ]
95
+ ],
96
+ "readme": "./README.md"
92
97
  }
@@ -0,0 +1,134 @@
1
+ import React from 'react';
2
+ import { render, fireEvent, screen, act } from '../../../test-utils';
3
+ // import { act } from 'react-dom/test-utils';
4
+ import NsAlert from './NsAlert';
5
+
6
+ const addEventListenerMock = jest.spyOn(window, 'addEventListener');
7
+ const removeEventListenerMock = jest.spyOn(window, 'removeEventListener');
8
+
9
+ describe('NsAlert', () => {
10
+ test('renders alert with provided props', () => {
11
+ render(
12
+ <NsAlert
13
+ context="error"
14
+ title="Error Alert"
15
+ threshhold={800}
16
+ type="banner"
17
+ visible
18
+ head={<span>Alert Head</span>}
19
+ body={<p>Alert Body</p>}
20
+ foot={<span>Dismiss</span>}
21
+ onDismiss={() => {}}
22
+ />
23
+ );
24
+
25
+ expect(screen.getByText('Error Alert')).toBeInTheDocument();
26
+ expect(screen.getByText('Alert Head')).toBeInTheDocument();
27
+ expect(screen.getByText('Alert Body')).toBeInTheDocument();
28
+ expect(screen.getByText('Dismiss')).toBeInTheDocument();
29
+ });
30
+
31
+ test('calls onDismiss function when dismissed', () => {
32
+ const onDismissMock = jest.fn();
33
+ render(
34
+ <NsAlert
35
+ context="info"
36
+ title="Info Alert"
37
+ threshhold={600}
38
+ type="auto"
39
+ visible
40
+ head={<span>Alert Head</span>}
41
+ body={<p>Alert Body</p>}
42
+ onDismiss={onDismissMock}
43
+ />
44
+ );
45
+
46
+ expect(screen.getByTestId('alert-close-button')).toBeInTheDocument();
47
+ const button = screen.getByTestId('alert-close-button');
48
+ fireEvent.click(button);
49
+ expect(onDismissMock).toHaveBeenCalled();
50
+ });
51
+
52
+ test('hides alert when not visible', () => {
53
+ render(
54
+ <NsAlert
55
+ context="success"
56
+ title="Success Alert"
57
+ threshhold={700}
58
+ type="card"
59
+ visible={false}
60
+ head={<span>Alert Head</span>}
61
+ body={<p>Alert Body</p>}
62
+ />
63
+ );
64
+
65
+ expect(screen.getByTestId('alert-container')).toHaveStyle('display: none');
66
+ });
67
+
68
+ test('adds and removes event listener on mount/unmount', () => {
69
+ act(() => {
70
+ render(<NsAlert
71
+ context="notice"
72
+ title="Success Alert"
73
+ threshhold={700}
74
+ type="card"
75
+ visible={false}
76
+ head={<span>Alert Head</span>}
77
+ body={<p>Alert Body</p>}
78
+ />);
79
+ });
80
+
81
+ expect(addEventListenerMock).toHaveBeenCalledWith('resize', expect.any(Function));
82
+
83
+
84
+ expect(removeEventListenerMock).toHaveBeenCalledWith('resize', expect.any(Function));
85
+ });
86
+
87
+ test('updates windowWidth on resize', () => {
88
+ const originalInnerWidth = window.innerWidth;
89
+ window.innerWidth = 500; // Set a desired window width for testing
90
+
91
+ act(() => {
92
+ render(<NsAlert />);
93
+ });
94
+
95
+ // Simulate a resize event by restoring the original innerWidth
96
+ window.innerWidth = originalInnerWidth;
97
+
98
+ act(() => {
99
+ window.dispatchEvent(new Event('resize'));
100
+ });
101
+ });
102
+
103
+ test('get props error in console for types', () => {
104
+ render(
105
+ <NsAlert
106
+ context="warning"
107
+ title="warning Alert"
108
+ threshhold={800}
109
+ type="noCard"
110
+ visible
111
+ head={<span>Alert Head</span>}
112
+ body={<p>Alert Body</p>}
113
+ />
114
+ );
115
+
116
+ expect(screen.getByTestId('alert-container')).toHaveStyle('display: block');
117
+ });
118
+
119
+ test('get props error in console for context', () => {
120
+ render(
121
+ <NsAlert
122
+ context="warningError"
123
+ title="warning Alert"
124
+ threshhold={800}
125
+ type="card"
126
+ visible
127
+ head={<span>Alert Head</span>}
128
+ body={<p>Alert Body</p>}
129
+ />
130
+ );
131
+
132
+ expect(screen.getByTestId('alert-container')).toHaveStyle('display: block');
133
+ });
134
+ });
@@ -0,0 +1,42 @@
1
+ import React from 'react';
2
+ import type { Meta, StoryObj } from '@storybook/react';
3
+ import NsAlert from './NsAlert';
4
+ import { withCenterDecorator } from '../../stories/decorators/withCenterDecorator';
5
+
6
+ type ComponentType = typeof NsAlert;
7
+ type Story = StoryObj<ComponentType>;
8
+ type MetaStory = Meta<ComponentType>;
9
+
10
+ export default {
11
+ title: 'Components/NsAlert',
12
+ component: NsAlert,
13
+ decorators: [withCenterDecorator],
14
+ argTypes: {
15
+ context: {
16
+ control: 'select',
17
+ options: ['error', 'info', 'notice', 'success', 'warning']
18
+ },
19
+ type: {
20
+ control: 'select',
21
+ options: ['auto', 'banner', 'card']
22
+ }
23
+ },
24
+ args: {
25
+ context: 'info',
26
+ title: 'Information',
27
+ threshhold: 600,
28
+ type: 'banner',
29
+ visible: true,
30
+ onDismiss: () => {},
31
+ body:
32
+ <p>{`Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt
33
+ ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
34
+ laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
35
+ reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
36
+ pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa
37
+ qui officia deserunt mollit anim id est laborum.`}</p>,
38
+ foot: <span>Some message goes here.</span>
39
+ }
40
+ } as MetaStory;
41
+
42
+ export const AuthDropdown: Story = {};
@@ -0,0 +1,124 @@
1
+ /* eslint-disable max-len */
2
+ import { styled, css } from '@nuskin/foundation-theme';
3
+ import { getAppColor } from '@nuskin/foundation-theme/src/utils/color-utils';
4
+ import { FoundationTheme } from '@nuskin/foundation-theme/src/themes';
5
+
6
+ import type { AlertContainerParams, AlertType, AlertParams, TypeMapCSS } from './types';
7
+ const gutter_width= '10px';
8
+ const close_button_width = '12px';
9
+ const icon_width = '24px';
10
+
11
+ const TypeMap: TypeMapCSS = {
12
+ banner: {
13
+ 'min-height' : '114px',
14
+ 'padding' : '15px 45px',
15
+ 'content-column-start': 'row-center',
16
+ 'content-column-end': 'row-center',
17
+ 'bar-position': 'top',
18
+ 'foot-visibility': 'block'
19
+ },
20
+ card: {
21
+ 'min-height' : '72px',
22
+ 'padding' : '24px 24px',
23
+ 'content-column-start': 'row-left',
24
+ 'content-column-end': 'row-right',
25
+ 'bar-position': 'left',
26
+ 'foot-display': 'none',
27
+ }
28
+ }
29
+
30
+ const contextType = {
31
+ error: 'red',
32
+ info: 'info',
33
+ notice: 'info',
34
+ success: 'success',
35
+ warning: 'warning'
36
+ }
37
+
38
+ export const AlertContainer = styled.div<AlertContainerParams>`
39
+ display: ${({ visible }) => visible ? 'block' : 'none'};
40
+ * {
41
+ box-sizing: border-box;
42
+ webkit-font-smoothing: antialiased;
43
+ }
44
+ text-align: left;
45
+ `;
46
+
47
+ const fontFamilyStyles = css`
48
+ font-family: "proxima-nova", "OpenSans", "Pridi", "NotoSans", "NotoSansSC", "NotoSansHebrew",
49
+ "NotoSansJapanese", "Hiragino Kaku Gothic Pro", "Yu Gothic Medium", "Yu Gothic", Meiryo, "source-han-sans-japanese",
50
+ "source-han-sans-korean", "source-han-sans-simplified-c", Helvetica, Arial, sans-serif;
51
+ `;
52
+
53
+ export const Alert = styled.div<AlertParams>`
54
+ position: relative;
55
+ display: grid;
56
+ grid-template-columns: [row-left] ${icon_width} [space] ${gutter_width} [row-center] auto [space] ${gutter_width} [row-right] ${close_button_width};
57
+ grid-template-rows: [row1] auto;
58
+ grid-auto-row: auto;
59
+ grid-auto-flow: row;
60
+ background-color: ${({ theme }) => getAppColor(theme, 'primary', 'white')};
61
+ border: 1px solid ${({ theme }) => getAppColor(theme, 'primary', 'black')};
62
+ min-height: ${({ type }) => TypeMap?.[type]?.['min-height']};
63
+ padding: ${({ type }) => TypeMap?.[type]?.['padding']};
64
+ color: ${({ context, theme }) => getAppColor(theme, contextType?.[context] as FoundationTheme.AppColors, '40')} };
65
+ `;
66
+
67
+ export const AlertCloseButton = styled.div`
68
+ grid-column-start: row-right;
69
+ grid-column-end: row-right;
70
+ grid-row-start: row1;
71
+ grid-row-end: row1;
72
+ align-self: center;
73
+ cursor: pointer;
74
+ `;
75
+
76
+ export const AlertIcon = styled.div`
77
+ grid-column-start: row-left;
78
+ grid-column-end: row-left;
79
+ grid-row-start: row1;
80
+ grid-row-end: row1;
81
+ width: ${icon_width};
82
+ height: ${icon_width};
83
+ `;
84
+
85
+ export const AlertHead = styled.div`
86
+ grid-column-start: row-center;
87
+ grid-column-end: row-center;
88
+ grid-row-start: row1;
89
+ grid-row-end: row1;
90
+ display: flex;
91
+ flex-direction: column;
92
+ justify-content: center;
93
+ span {
94
+ ${fontFamilyStyles}
95
+ color: ${({ theme }) => getAppColor(theme, 'primary', 'black')};
96
+ font-weight: 600;
97
+ font-size: 18px;
98
+ line-height: 20px;
99
+ }
100
+ `;
101
+
102
+ export const AlertContent = styled.div<{type: AlertType}>`
103
+ margin-top: 8px;
104
+ color: ${({ theme }) => getAppColor(theme, 'primary', 'black')};
105
+ grid-column-start: ${({ type }) => TypeMap?.[type]?.['content-column-start']};
106
+ grid-column-end: ${({ type }) => TypeMap?.[type]?.['content-column-end']};
107
+ `;
108
+
109
+ export const AlertFoot = styled.div<{type: AlertType}>`
110
+ margin-top: 8px;
111
+ color: ${({ theme }) => getAppColor(theme, 'primary', 'black')};;
112
+ display: ${({ type }) => TypeMap?.[type]?.['foot-display']};
113
+ ${fontFamilyStyles}
114
+ font-weight: 300;
115
+ font-size: 14px;
116
+ line-height: 18px;
117
+ `;
118
+
119
+ export const AlertBody = styled.div`
120
+ ${fontFamilyStyles}
121
+ font-weight: 300;
122
+ font-size: 16px;
123
+ line-height: 21px;
124
+ `;
@@ -0,0 +1,155 @@
1
+ /* eslint-disable react/require-default-props */
2
+ import React, { useEffect, useState } from 'react';
3
+ import {
4
+ AlertContainer,
5
+ Alert,
6
+ AlertIcon,
7
+ AlertHead,
8
+ AlertCloseButton,
9
+ AlertContent,
10
+ AlertFoot,
11
+ AlertBody
12
+ } from './NsAlert.styled'
13
+ import type { NsAlertProps, HeaderProps, ContextType, AlertType } from './types';
14
+ import { NsIcon } from '../icon';
15
+ import { NsIconNameType } from '../icon/types'
16
+ import { FoundationTheme } from '@nuskin/foundation-theme/src/themes';
17
+
18
+ const Header: React.FC<HeaderProps> = ({ children, head }) => (
19
+ <>
20
+ {children}
21
+ {head}
22
+ </>
23
+ );
24
+
25
+ function isValidContextValue(value: string): boolean {
26
+ return (value as ContextType) !== undefined;
27
+ }
28
+
29
+ function isValidTypeValue(value: string):boolean {
30
+ return (value as AlertType) !== undefined;
31
+ }
32
+
33
+ const colorMap:{ [key: string]: FoundationTheme.PaletteColors } = {
34
+ error: 'error',
35
+ notice: 'info',
36
+ success: 'secondary',
37
+ warning: 'warning',
38
+ default: 'info',
39
+ };
40
+
41
+ const iconMap:{ [key: string]: NsIconNameType } = {
42
+ error: 'alertError',
43
+ success: 'success',
44
+ warning: 'warning',
45
+ default: 'infoFilled',
46
+ };
47
+
48
+ export default function NsAlert({
49
+ context = 'info',
50
+ title = 'Information',
51
+ threshhold = 600,
52
+ type = 'banner',
53
+ visible = false,
54
+ head,
55
+ body,
56
+ foot,
57
+ onDismiss = undefined
58
+ }: NsAlertProps) {
59
+ const [alertType, setAlertType] = useState('banner');
60
+ const [windowWidth, setWindowWidth] = useState(window.innerWidth);
61
+
62
+ const hasDismissListener = typeof onDismiss === 'function';
63
+
64
+ const getColor = () => {
65
+ return colorMap[context] || colorMap.default;
66
+ };
67
+
68
+ const getIcon = () => {
69
+ return iconMap[context] || iconMap.default;
70
+ };
71
+
72
+ const getTitleText = () => {
73
+ if (title) {
74
+ return title;
75
+ }
76
+ };
77
+
78
+ const handleDismiss = () => {
79
+ if (hasDismissListener) {
80
+ onDismiss();
81
+ }
82
+ };
83
+
84
+ const handleResize = () => {
85
+ setWindowWidth(window.innerWidth);
86
+ };
87
+
88
+ useEffect(() => {
89
+ let aType = ''
90
+ if (type === 'auto') {
91
+ aType = windowWidth < threshhold ? 'card' : 'banner';
92
+ } else {
93
+ aType = type;
94
+ }
95
+ setAlertType(aType)
96
+ }, [threshhold, type, windowWidth])
97
+
98
+ useEffect(() => {
99
+ if (!isValidContextValue(context)) {
100
+ console.error(`Invalid prop value for 'context': ${context}`);
101
+ }
102
+
103
+ if (!isValidTypeValue(type)) {
104
+ console.error(`Invalid prop value for 'type': ${type}`);
105
+ }
106
+ }, [context, type]);
107
+
108
+ useEffect(() => {
109
+ window.addEventListener('resize', handleResize);
110
+ return () => {
111
+ window.removeEventListener('resize', handleResize);
112
+ };
113
+ }, []);
114
+
115
+ return (
116
+ <AlertContainer visible={visible} data-testid="alert-container">
117
+ <Alert type={alertType as AlertType} context={context as ContextType}>
118
+ <AlertIcon>
119
+ <NsIcon
120
+ name={getIcon()}
121
+ color={getColor()}
122
+ size="large"
123
+ />
124
+ </AlertIcon>
125
+ <AlertHead>
126
+ <Header head={<span>{getTitleText()}</span>}>
127
+ {head}
128
+ </Header>
129
+ </AlertHead>
130
+ {
131
+ hasDismissListener ? (
132
+ <AlertCloseButton data-testid="alert-close-button" onClick={handleDismiss}>
133
+ <NsIcon
134
+ name='close'
135
+ size='small'
136
+ />
137
+ </AlertCloseButton>
138
+ ) : null
139
+ }
140
+ <AlertContent type={alertType as AlertType}>
141
+ <AlertBody>
142
+ {body}
143
+ </AlertBody>
144
+ {
145
+ foot ? (
146
+ <AlertFoot type={alertType as AlertType}>
147
+ {foot}
148
+ </AlertFoot>
149
+ ) : null
150
+ }
151
+ </AlertContent>
152
+ </Alert>
153
+ </AlertContainer>
154
+ );
155
+ }
@@ -0,0 +1,2 @@
1
+ export { default as NsAlert} from './NsAlert';
2
+ export type { NsAlertProps } from './types';
@@ -0,0 +1,45 @@
1
+ import { ReactNode, CSSProperties } from 'react';
2
+
3
+ export interface NsAlertProps {
4
+ context?: string,
5
+ title?: string,
6
+ threshhold?: number,
7
+ type?: string,
8
+ visible?: boolean,
9
+ head?: ReactNode,
10
+ body?: ReactNode,
11
+ onDismiss?: () => void,
12
+ foot?: ReactNode
13
+ }
14
+
15
+ export interface HeaderProps {
16
+ children?: ReactNode; // Default slot content
17
+ head?: ReactNode; // Content for the "head" named slot (optional)
18
+ }
19
+
20
+ export type AlertContainerParams = {
21
+ visible: boolean
22
+ };
23
+
24
+ export type ContextType = 'error' | 'info' | 'notice'| 'success' | 'warning';
25
+ export type AlertType = 'auto' | 'banner' | 'card';
26
+
27
+ export type AlertParams = {
28
+ context: ContextType,
29
+ type: AlertType
30
+ }
31
+
32
+ export type CustomCSSProperties = CSSProperties & {
33
+ 'min-height'?: string;
34
+ 'content-column-start'? : string;
35
+ 'content-column-end'? : string;
36
+ 'bar-position'? : string;
37
+ 'foot-visibility'? : string;
38
+ 'foot-display'? : string;
39
+ };
40
+
41
+ export interface TypeMapCSS {
42
+ banner: CustomCSSProperties,
43
+ card: CustomCSSProperties,
44
+ auto?: CustomCSSProperties
45
+ }
@@ -1,11 +1,15 @@
1
- import React from 'react';
2
- import { ComponentStory, ComponentMeta } from '@storybook/react';
1
+ import type { Meta, StoryObj } from '@storybook/react';
3
2
  import { NsAuthDropdown } from './';
3
+ import { withCenterDecorator } from '../../stories/decorators/withCenterDecorator';
4
+
5
+ type ComponentType = typeof NsAuthDropdown;
6
+ type Story = StoryObj<ComponentType>;
7
+ type MetaStory = Meta<ComponentType>;
4
8
 
5
9
  export default {
6
10
  title: 'Components/NsAuthDropdown',
7
11
  component: NsAuthDropdown,
8
- decorators: [(story) => <div style={{ textAlign: 'center', marginTop: '20px' }}>{story()}</div>],
12
+ decorators: [withCenterDecorator],
9
13
  argTypes: {},
10
14
  args: {
11
15
  signInRedirectLink: '/signIn',
@@ -16,6 +20,6 @@ export default {
16
20
  titleText: 'SIGN UP / SIGN IN',
17
21
  closeOnMouseLeave: true,
18
22
  },
19
- } as ComponentMeta<typeof NsAuthDropdown>;
23
+ } as MetaStory;
20
24
 
21
- export const AuthDropdown: ComponentStory<typeof NsAuthDropdown> = (args) => <NsAuthDropdown {...args} />;
25
+ export const AuthDropdown: Story = {};
@@ -37,7 +37,7 @@ const NsAuthDropdown = ({
37
37
  <AuthDropdownContainer>
38
38
  <AuthHead data-testid="auth-head" onClick={handleToggle}>
39
39
  <Button>{titleText}</Button>
40
- <NsIcon testId="chevron-icon" name={isOpen ? 'arrowDown' : 'arrowUp'} color="primary" />
40
+ <NsIcon testId="chevron-icon" name={isOpen ? 'arrowUp' : 'arrowDown'} color="primary" />
41
41
  {isOpen ? (
42
42
  <div onMouseLeave={closeDropdown}>
43
43
  <Triangle />