adnbn-ui 0.0.1 → 0.0.2

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 (145) hide show
  1. package/.prettierignore +3 -0
  2. package/.prettierrc +28 -0
  3. package/.storybook/main.ts +22 -0
  4. package/.storybook/preview.tsx +100 -0
  5. package/.storybook/styles/custom.scss +59 -0
  6. package/.storybook/styles/preview.css +58 -0
  7. package/.storybook/vitest.setup.ts +9 -0
  8. package/eslint.config.js +39 -0
  9. package/package.json +77 -2
  10. package/src/components/Avatar/Avatar.stories.tsx +118 -0
  11. package/src/components/Avatar/Avatar.tsx +65 -0
  12. package/src/components/Avatar/avatar.module.scss +77 -0
  13. package/src/components/Avatar/index.ts +2 -0
  14. package/src/components/BaseButton/BaseButton.tsx +36 -0
  15. package/src/components/BaseButton/base-button.module.scss +24 -0
  16. package/src/components/BaseButton/index.ts +2 -0
  17. package/src/components/Button/Button.stories.tsx +148 -0
  18. package/src/components/Button/Button.tsx +73 -0
  19. package/src/components/Button/button.module.scss +140 -0
  20. package/src/components/Button/index.ts +2 -0
  21. package/src/components/Checkbox/Checkbox.stories.tsx +180 -0
  22. package/src/components/Checkbox/Checkbox.tsx +71 -0
  23. package/src/components/Checkbox/checkbox.module.scss +82 -0
  24. package/src/components/Checkbox/index.ts +2 -0
  25. package/src/components/Dialog/Dialog.tsx +125 -0
  26. package/src/components/Dialog/dialog.module.scss +55 -0
  27. package/src/components/Dialog/index.ts +2 -0
  28. package/src/components/Drawer/Drawer.stories.tsx +89 -0
  29. package/src/components/Drawer/Drawer.tsx +57 -0
  30. package/src/components/Drawer/drawer.module.scss +170 -0
  31. package/src/components/Drawer/index.ts +2 -0
  32. package/src/components/Footer/Footer.stories.tsx +118 -0
  33. package/src/components/Footer/Footer.tsx +58 -0
  34. package/src/components/Footer/footer.module.scss +44 -0
  35. package/src/components/Footer/index.ts +2 -0
  36. package/src/components/Header/Header.stories.tsx +49 -0
  37. package/src/components/Header/Header.tsx +73 -0
  38. package/src/components/Header/header.module.scss +56 -0
  39. package/src/components/Header/index.ts +2 -0
  40. package/src/components/Highlight/Highlight.stories.tsx +83 -0
  41. package/src/components/Highlight/Highlight.tsx +40 -0
  42. package/src/components/Highlight/highlight.module.scss +47 -0
  43. package/src/components/Highlight/index.ts +2 -0
  44. package/src/components/Icon/Icon.tsx +46 -0
  45. package/src/components/Icon/icon.module.scss +17 -0
  46. package/src/components/Icon/index.ts +2 -0
  47. package/src/components/IconButton/IconButton.stories.tsx +179 -0
  48. package/src/components/IconButton/IconButton.tsx +65 -0
  49. package/src/components/IconButton/icon-button.module.scss +86 -0
  50. package/src/components/IconButton/index.ts +2 -0
  51. package/src/components/Layout/Layout.stories.tsx +88 -0
  52. package/src/components/Layout/Provider.tsx +47 -0
  53. package/src/components/Layout/context.ts +24 -0
  54. package/src/components/Layout/index.ts +2 -0
  55. package/src/components/Layout/layout.module.scss +17 -0
  56. package/src/components/List/List.stories.tsx +81 -0
  57. package/src/components/List/List.tsx +24 -0
  58. package/src/components/List/index.ts +2 -0
  59. package/src/components/List/list.module.scss +8 -0
  60. package/src/components/ListItem/ListItem.tsx +75 -0
  61. package/src/components/ListItem/index.ts +2 -0
  62. package/src/components/ListItem/list-item.module.scss +36 -0
  63. package/src/components/Modal/Modal.stories.tsx +95 -0
  64. package/src/components/Modal/Modal.tsx +94 -0
  65. package/src/components/Modal/index.ts +2 -0
  66. package/src/components/Modal/modal.module.scss +97 -0
  67. package/src/components/Odometer/Odometer.stories.tsx +66 -0
  68. package/src/components/Odometer/Odometer.tsx +45 -0
  69. package/src/components/Odometer/hooks/useOdometer.tsx +24 -0
  70. package/src/components/Odometer/index.ts +3 -0
  71. package/src/components/Odometer/odometer.module.scss +81 -0
  72. package/src/components/Odometer/odometr.d.ts +9 -0
  73. package/src/components/ScrollArea/ScrollArea.stories.tsx +58 -0
  74. package/src/components/ScrollArea/ScrollArea.tsx +63 -0
  75. package/src/components/ScrollArea/index.ts +2 -0
  76. package/src/components/ScrollArea/scroll-area.module.scss +54 -0
  77. package/src/components/SvgSprite/SvgSprite.tsx +21 -0
  78. package/src/components/SvgSprite/index.ts +2 -0
  79. package/src/components/Switch/Switch.stories.tsx +25 -0
  80. package/src/components/Switch/Switch.tsx +23 -0
  81. package/src/components/Switch/index.ts +2 -0
  82. package/src/components/Switch/switch.module.scss +65 -0
  83. package/src/components/Tag/Tag.stories.tsx +157 -0
  84. package/src/components/Tag/Tag.tsx +71 -0
  85. package/src/components/Tag/index.ts +2 -0
  86. package/src/components/Tag/tag.module.scss +118 -0
  87. package/src/components/TextArea/TextArea.stories.tsx +145 -0
  88. package/src/components/TextArea/TextArea.tsx +143 -0
  89. package/src/components/TextArea/index.ts +2 -0
  90. package/src/components/TextArea/text-area.module.scss +88 -0
  91. package/src/components/TextField/TextField.stories.tsx +177 -0
  92. package/src/components/TextField/TextField.tsx +162 -0
  93. package/src/components/TextField/index.ts +2 -0
  94. package/src/components/TextField/text-field.module.scss +129 -0
  95. package/src/components/Toast/Toast.stories.tsx +209 -0
  96. package/src/components/Toast/Toast.tsx +142 -0
  97. package/src/components/Toast/index.ts +2 -0
  98. package/src/components/Toast/toast.module.scss +267 -0
  99. package/src/components/Tooltip/Tooltip.stories.tsx +80 -0
  100. package/src/components/Tooltip/Tooltip.tsx +79 -0
  101. package/src/components/Tooltip/index.ts +2 -0
  102. package/src/components/Tooltip/tooltip.module.scss +93 -0
  103. package/src/components/View/View.stories.tsx +47 -0
  104. package/src/components/View/View.tsx +68 -0
  105. package/src/components/View/index.ts +2 -0
  106. package/src/components/View/view.module.scss +38 -0
  107. package/src/components/ViewDrawer/ViewDrawer.stories.tsx +75 -0
  108. package/src/components/ViewDrawer/ViewDrawer.tsx +24 -0
  109. package/src/components/ViewDrawer/index.ts +2 -0
  110. package/src/components/ViewModal/ViewModal.stories.tsx +68 -0
  111. package/src/components/ViewModal/ViewModal.tsx +24 -0
  112. package/src/components/ViewModal/index.ts +2 -0
  113. package/src/components/index.ts +29 -0
  114. package/src/components/types.ts +65 -0
  115. package/src/config/default.ts +3 -0
  116. package/src/config/index.ts +26 -0
  117. package/src/declaration.d.ts +8 -0
  118. package/src/index.ts +3 -0
  119. package/src/plugin/builder/ConfigBuilder.ts +32 -0
  120. package/src/plugin/builder/StyleBuilder.ts +34 -0
  121. package/src/plugin/builder/virtual.config.ts +7 -0
  122. package/src/plugin/finder/ConfigFinder.ts +26 -0
  123. package/src/plugin/finder/Finder.ts +76 -0
  124. package/src/plugin/finder/StyleFinder.ts +23 -0
  125. package/src/plugin/index.ts +70 -0
  126. package/src/plugin/types.ts +8 -0
  127. package/src/providers/UIProvider.tsx +26 -0
  128. package/src/providers/icons/IconsProvider.tsx +34 -0
  129. package/src/providers/icons/context.ts +22 -0
  130. package/src/providers/icons/index.ts +3 -0
  131. package/src/providers/index.ts +3 -0
  132. package/src/providers/theme/ThemeProvider.tsx +39 -0
  133. package/src/providers/theme/context.ts +30 -0
  134. package/src/providers/theme/index.ts +2 -0
  135. package/src/providers/theme/styles/default.scss +95 -0
  136. package/src/providers/theme/styles/reset.css +111 -0
  137. package/src/styles/mixins.scss +23 -0
  138. package/src/types/theme.ts +4 -0
  139. package/src/utils/index.ts +2 -0
  140. package/src/utils/react.ts +21 -0
  141. package/src/utils/utils.ts +12 -0
  142. package/tsconfig.json +18 -0
  143. package/vite.config.ts +11 -0
  144. package/vitest.workspace.ts +19 -0
  145. package/components/Button/index.ts +0 -0
@@ -0,0 +1,162 @@
1
+ import React, {
2
+ ChangeEventHandler,
3
+ ComponentProps,
4
+ forwardRef,
5
+ memo,
6
+ ReactNode,
7
+ useCallback,
8
+ useEffect,
9
+ useImperativeHandle,
10
+ useRef,
11
+ useState,
12
+ } from "react";
13
+
14
+ import classnames from "classnames";
15
+
16
+ import {cloneOrCreateElement} from "../../utils";
17
+ import {useComponentProps} from "../../providers";
18
+
19
+ import styles from "./text-field.module.scss";
20
+
21
+ export enum TextFieldVariant {
22
+ Regular = "regular",
23
+ Outlined = "outlined",
24
+ Filled = "filled",
25
+ }
26
+
27
+ export enum TextFieldSize {
28
+ Small = "small",
29
+ Medium = "medium",
30
+ Large = "large",
31
+ }
32
+
33
+ export enum TextFieldRadius {
34
+ None = "none",
35
+ Small = "small",
36
+ Medium = "medium",
37
+ Large = "large",
38
+ Full = "full",
39
+ }
40
+
41
+ export enum TextFieldAccent {
42
+ Success = "success",
43
+ Error = "error",
44
+ }
45
+
46
+ export interface TextFieldActions {
47
+ select(): void;
48
+
49
+ focus(): void;
50
+
51
+ getValue(): string | undefined;
52
+
53
+ setValue(value: string | number | undefined): void;
54
+ }
55
+
56
+ export interface TextFieldProps extends ComponentProps<"input"> {
57
+ variant?: TextFieldVariant;
58
+ accent?: TextFieldAccent;
59
+ radius?: TextFieldRadius;
60
+ customSize?: TextFieldSize;
61
+ value?: string | number | undefined;
62
+ defaultValue?: string | number | undefined;
63
+ label?: string;
64
+ fullWidth?: boolean;
65
+ before?: ReactNode;
66
+ after?: ReactNode;
67
+ inputClassName?: string;
68
+ afterClassName?: string;
69
+ beforeClassName?: string;
70
+ }
71
+
72
+ const TextField = forwardRef<TextFieldActions, TextFieldProps>((props, ref) => {
73
+ const {
74
+ variant = TextFieldVariant.Regular,
75
+ accent,
76
+ radius,
77
+ customSize,
78
+ label,
79
+ fullWidth,
80
+ type = "text",
81
+ value: propValue = "",
82
+ defaultValue,
83
+ before,
84
+ after,
85
+ className,
86
+ inputClassName,
87
+ afterClassName,
88
+ beforeClassName,
89
+ onChange,
90
+ ...other
91
+ } = {...useComponentProps("textField"), ...props};
92
+
93
+ const [value, setValue] = useState<string | number | undefined>(defaultValue || propValue);
94
+ const inputRef = useRef<HTMLInputElement | null>(null);
95
+
96
+ useImperativeHandle(
97
+ ref,
98
+ () => ({
99
+ select() {
100
+ inputRef.current?.select();
101
+ },
102
+ focus() {
103
+ inputRef.current?.focus();
104
+ },
105
+ getValue(): string | undefined {
106
+ return inputRef.current?.value;
107
+ },
108
+ setValue(value: string | number | undefined) {
109
+ setValue(value);
110
+ },
111
+ }),
112
+ []
113
+ );
114
+
115
+ const handleChange = useCallback<ChangeEventHandler<HTMLInputElement>>(
116
+ event => {
117
+ onChange?.(event);
118
+ setValue(event.currentTarget.value);
119
+ },
120
+ [onChange]
121
+ );
122
+
123
+ useEffect(() => {
124
+ setValue(propValue);
125
+ }, [propValue]);
126
+
127
+ return (
128
+ <div
129
+ aria-label={label}
130
+ className={classnames(
131
+ styles["text-field"],
132
+ {
133
+ [styles[`text-field--${variant}`]]: variant,
134
+ [styles[`text-field--${accent}`]]: accent,
135
+ [styles[`text-field--${radius}-radius`]]: radius,
136
+ [styles[`text-field--${customSize}-size`]]: customSize,
137
+ [styles["text-field--full-width"]]: fullWidth,
138
+ },
139
+ className
140
+ )}
141
+ >
142
+ {cloneOrCreateElement(
143
+ before,
144
+ {className: classnames(styles["text-field__before"], beforeClassName)},
145
+ "span"
146
+ )}
147
+ <input
148
+ {...other}
149
+ ref={inputRef}
150
+ type={type}
151
+ value={value}
152
+ defaultValue={defaultValue}
153
+ aria-label={label}
154
+ className={classnames(styles["text-field__input"], inputClassName)}
155
+ onChange={handleChange}
156
+ />
157
+ {cloneOrCreateElement(after, {className: classnames(styles["text-field__after"], afterClassName)}, "span")}
158
+ </div>
159
+ );
160
+ });
161
+
162
+ export default memo(TextField);
@@ -0,0 +1,2 @@
1
+ export {default as TextField, TextFieldVariant, TextFieldSize, TextFieldAccent} from "./TextField";
2
+ export type {TextFieldProps, TextFieldActions} from "./TextField";
@@ -0,0 +1,129 @@
1
+ $root: text-field;
2
+
3
+ .#{$root} {
4
+ display: flex;
5
+ align-items: center;
6
+ gap: var(--text-field-gap, 0.3em);
7
+ font-family: var(--text-field-font-family, var(--font-family)), sans-serif;
8
+ font-weight: var(--text-field-font-weight, 400);
9
+ font-size: var(--text-field-font-size, 14px);
10
+ letter-spacing: var(--text-field-letter-spacing, 0.5px);
11
+ line-height: var(--text-field-line-height, 18px);
12
+ padding: var(--text-field-padding, 8px 12px);
13
+ border-radius: var(--text-field-border-radius, 8px);
14
+ transition:
15
+ border-color var(--transition-speed-sm),
16
+ box-shadow var(--transition-speed-sm),
17
+ background var(--transition-speed-sm);
18
+
19
+ &:has(&__input:focus) {
20
+ border-color: var(--text-field-focus-border-color, color-mix(in srgb, white 40%, var(--primary-color)));
21
+ box-shadow: var(--text-field-focus-shadow, 0 0 4px var(--primary-color));
22
+ }
23
+
24
+ &:has(&__input:disabled) {
25
+ opacity: var(--text-field-disabled-opacity, 0.7);
26
+ cursor: not-allowed;
27
+ }
28
+
29
+ &__input {
30
+ width: 100%;
31
+ color: inherit;
32
+ font-size: inherit;
33
+ font-family: inherit;
34
+ padding: 0;
35
+ border: none;
36
+ outline: none;
37
+ background: transparent;
38
+
39
+ &:focus {
40
+ outline: none;
41
+ }
42
+ &:disabled {
43
+ cursor: not-allowed;
44
+ }
45
+ }
46
+
47
+ &__before,
48
+ &__after {
49
+ display: inline;
50
+ cursor: default;
51
+ }
52
+
53
+ &--full-width {
54
+ width: 100%;
55
+ }
56
+
57
+ // Variants
58
+ &--regular {
59
+ color: var(--text-field-regular-color, var(--text-field-color, var(--text-primary-color)));
60
+ background: var(--text-field-regular-bg-color, var(--text-field-bg-color, var(--bg-secondary-color)));
61
+ border-style: solid;
62
+ border-width: var(--text-field-regular-border-width, var(--text-field-border-width, 1px));
63
+ border-color: var(--text-field-regular-border-color, var(--border-color));
64
+ }
65
+
66
+ &--outlined {
67
+ color: var(--text-field-outlined-color, var(--text-field-color, var(--text-primary-color)));
68
+ background: transparent;
69
+ border-style: solid;
70
+ border-width: var(--text-field-outlined-border-width, var(--text-field-border-width, 1px));
71
+ border-color: var(--text-field-outlined-border-color, var(--border-color));
72
+ }
73
+
74
+ &--filled {
75
+ color: var(--text-field-filled-color, var(--text-field-color, var(--text-primary-color)));
76
+ background: var(--text-field-filled-bg-color, var(--text-field-bg-color, var(--bg-secondary-color)));
77
+ border: none;
78
+ }
79
+
80
+ // Radius
81
+ &--none-radius {
82
+ border-radius: 0;
83
+ }
84
+
85
+ &--small-radius {
86
+ border-radius: var(--text-field-border-radius-sm, 5px);
87
+ }
88
+
89
+ &--medium-radius {
90
+ border-radius: var(--text-field-border-radius-md, 10px);
91
+ }
92
+
93
+ &--large-radius {
94
+ border-radius: var(--text-field-border-radius-lg, 15px);
95
+ }
96
+
97
+ &--full-radius {
98
+ border-radius: var(--text-field-border-radius-full, 999px);
99
+ }
100
+
101
+ // Sizes
102
+ &--small-size {
103
+ padding: var(--text-field-padding-sm, 6px 10px);
104
+ font-size: var(--text-field-font-size-sm, 12px);
105
+ }
106
+
107
+ &--medium-size {
108
+ padding: var(--text-field-padding-md, 10px 14px);
109
+ font-size: var(--text-field-font-size-sm, 16px);
110
+ }
111
+
112
+ &--large-size {
113
+ padding: var(--text-field-padding-lg, 12px 16px);
114
+ font-size: var(--text-field-font-size-sm, 18px);
115
+ }
116
+
117
+ // Accents
118
+ &--success {
119
+ border-color: var(--text-field-success-color, var(--success-color)) !important;
120
+ border-width: var(--text-field-accent-border-width, 2px) !important;
121
+ box-shadow: var(--text-field-success-color, 0 0 4px var(--success-color)) !important;
122
+ }
123
+
124
+ &--error {
125
+ border-color: var(--text-field-error-color, var(--error-color)) !important;
126
+ border-width: var(--text-field-accent-border-width, 2px) !important;
127
+ box-shadow: var(--text-field-error-color, 0 0 4px var(--error-color)) !important;
128
+ }
129
+ }
@@ -0,0 +1,209 @@
1
+ import {FC, useState} from "react";
2
+ import {Meta, StoryObj} from "@storybook/react";
3
+
4
+ import {hideInTable} from "../../utils";
5
+
6
+ import {Button, ButtonColor, ButtonVariant} from "../index";
7
+
8
+ import ToastComponent, {ToastColor, ToastProps, ToastRadius, ToastSide} from "./Toast";
9
+
10
+ const sides: ToastSide[] = [
11
+ ToastSide.TopLeft,
12
+ ToastSide.TopCenter,
13
+ ToastSide.TopRight,
14
+ ToastSide.BottomRight,
15
+ ToastSide.BottomCenter,
16
+ ToastSide.BottomLeft,
17
+ ];
18
+ const colors: (ToastColor | "default")[] = ["default", ToastColor.Success, ToastColor.Error];
19
+ const radius: (ToastRadius | "default")[] = [
20
+ ToastRadius.None,
21
+ ToastRadius.Small,
22
+ "default",
23
+ ToastRadius.Medium,
24
+ ToastRadius.Large,
25
+ ];
26
+
27
+ const meta: Meta<typeof ToastComponent> = {
28
+ title: "Components/Toast",
29
+ component: ToastComponent,
30
+ tags: ["autodocs"],
31
+ argTypes: {
32
+ duration: {
33
+ description: "The time in milliseconds that should elapse before automatically closing each toast.",
34
+ },
35
+ swipeDirection: {
36
+ options: ["right", "left", "up", "down"],
37
+ control: {type: "select"},
38
+ description: "The direction of the pointer swipe that should close the toast.",
39
+ },
40
+ swipeThreshold: {
41
+ description: "The distance in pixels that the swipe gesture must travel before a close is triggered.",
42
+ control: {type: "number"},
43
+ },
44
+ side: {
45
+ options: sides,
46
+ control: {type: "select"},
47
+ },
48
+ radius: {
49
+ options: radius,
50
+ control: {type: "select"},
51
+ },
52
+ color: {
53
+ options: colors,
54
+ control: {type: "select"},
55
+ },
56
+
57
+ action: hideInTable,
58
+ closeIcon: hideInTable,
59
+ closeProps: hideInTable,
60
+ onClose: hideInTable,
61
+ children: hideInTable,
62
+ className: hideInTable,
63
+ titleClassName: hideInTable,
64
+ actionClassName: hideInTable,
65
+ viewportClassName: hideInTable,
66
+ descriptionClassName: hideInTable,
67
+ },
68
+ };
69
+
70
+ export default meta;
71
+
72
+ export const Toast: StoryObj<typeof ToastComponent> = {
73
+ args: {
74
+ open: true,
75
+ sticky: false,
76
+ fullWidth: false,
77
+ children: (
78
+ <Button variant={ButtonVariant.Contained} color={ButtonColor.Primary}>
79
+ Show toast
80
+ </Button>
81
+ ),
82
+ title: "New notification",
83
+ description: "Description",
84
+ side: ToastSide.BottomRight,
85
+ duration: 5000,
86
+ onClose: () => undefined,
87
+ },
88
+ };
89
+
90
+ const ToastClickable: FC<ToastProps> = ({children, ...props}) => {
91
+ const [open, setOpen] = useState(false);
92
+ const handleClick = () => setOpen(prev => !prev);
93
+ const handleClose = () => setOpen(false);
94
+
95
+ return (
96
+ <ToastComponent
97
+ open={open}
98
+ title="New notification"
99
+ description="Description"
100
+ onOpenChange={setOpen}
101
+ onClose={handleClose}
102
+ {...props}
103
+ >
104
+ <Button variant={ButtonVariant.Contained} color={ButtonColor.Primary} onClick={handleClick}>
105
+ {children}
106
+ </Button>
107
+ </ToastComponent>
108
+ );
109
+ };
110
+
111
+ export const Side = () => {
112
+ return (
113
+ <div style={{display: "grid", gridTemplateColumns: "repeat(6, auto)", gap: "10px"}}>
114
+ <ToastClickable side={ToastSide.TopLeft} description="Top Left">
115
+ Top Left
116
+ </ToastClickable>
117
+
118
+ <ToastClickable side={ToastSide.TopCenter} description="Top Center">
119
+ Top Center
120
+ </ToastClickable>
121
+
122
+ <ToastClickable side={ToastSide.TopRight} description="Top Right">
123
+ Top Right
124
+ </ToastClickable>
125
+
126
+ <ToastClickable side={ToastSide.BottomLeft} description="Bottom Left">
127
+ Bottom Left
128
+ </ToastClickable>
129
+
130
+ <ToastClickable side={ToastSide.BottomCenter} description="Bottom Center">
131
+ Bottom Center
132
+ </ToastClickable>
133
+
134
+ <ToastClickable side={ToastSide.BottomRight} description="Bottom Right">
135
+ Bottom Right
136
+ </ToastClickable>
137
+ </div>
138
+ );
139
+ };
140
+
141
+ export const Radius = () => {
142
+ return (
143
+ <div style={{display: "flex", gap: "10px"}}>
144
+ <ToastClickable side={ToastSide.TopLeft} radius={ToastRadius.None} description="None Radius">
145
+ None
146
+ </ToastClickable>
147
+
148
+ <ToastClickable side={ToastSide.TopCenter} radius={ToastRadius.Small} description="Small Radius">
149
+ Small
150
+ </ToastClickable>
151
+
152
+ <ToastClickable side={ToastSide.TopRight} description="Default Radius">
153
+ Default
154
+ </ToastClickable>
155
+
156
+ <ToastClickable side={ToastSide.BottomLeft} radius={ToastRadius.Medium} description="Medium Radius">
157
+ Medium
158
+ </ToastClickable>
159
+
160
+ <ToastClickable side={ToastSide.BottomRight} radius={ToastRadius.Large} description="Large Radius">
161
+ Large
162
+ </ToastClickable>
163
+ </div>
164
+ );
165
+ };
166
+
167
+ export const FullWidth = () => {
168
+ return (
169
+ <div style={{display: "flex", flexDirection: "column", gap: "10px"}}>
170
+ <ToastClickable
171
+ side={ToastSide.TopCenter}
172
+ radius={ToastRadius.None}
173
+ fullWidth
174
+ sticky
175
+ description="Top full width without padding"
176
+ >
177
+ Top
178
+ </ToastClickable>
179
+
180
+ <ToastClickable
181
+ side={ToastSide.BottomCenter}
182
+ radius={ToastRadius.None}
183
+ fullWidth
184
+ sticky
185
+ description="Bottom full width without padding"
186
+ >
187
+ Bottom
188
+ </ToastClickable>
189
+ </div>
190
+ );
191
+ };
192
+
193
+ export const Color = () => {
194
+ return (
195
+ <div style={{display: "flex", gap: "10px"}}>
196
+ <ToastClickable side={ToastSide.TopLeft} color={ToastColor.Error} description="Error color">
197
+ Error
198
+ </ToastClickable>
199
+
200
+ <ToastClickable side={ToastSide.TopCenter} description="Default color">
201
+ Default
202
+ </ToastClickable>
203
+
204
+ <ToastClickable side={ToastSide.TopRight} color={ToastColor.Success} description="Success color">
205
+ Success
206
+ </ToastClickable>
207
+ </div>
208
+ );
209
+ };
@@ -0,0 +1,142 @@
1
+ import React, {FC, memo, ReactElement, ReactNode} from "react";
2
+ import classnames from "classnames";
3
+ import {
4
+ Description,
5
+ Provider,
6
+ Root,
7
+ Title,
8
+ ToastProps as ToastRootProps,
9
+ ToastProviderProps,
10
+ Viewport,
11
+ } from "@radix-ui/react-toast";
12
+
13
+ import {IconButton, IconButtonProps} from "../IconButton";
14
+ import {cloneOrCreateElement} from "../../utils";
15
+ import {useComponentProps} from "../../providers";
16
+
17
+ import styles from "./toast.module.scss";
18
+
19
+ export enum ToastSide {
20
+ TopCenter = "top-center",
21
+ TopLeft = "top-left",
22
+ TopRight = "top-right",
23
+ BottomRight = "bottom-right",
24
+ BottomLeft = "bottom-left",
25
+ BottomCenter = "bottom-center",
26
+ }
27
+
28
+ export enum ToastRadius {
29
+ None = "none",
30
+ Small = "small",
31
+ Medium = "medium",
32
+ Large = "large",
33
+ }
34
+
35
+ export enum ToastColor {
36
+ Error = "error",
37
+ Success = "success",
38
+ }
39
+
40
+ const toastSideBySwipeDirectionMap = {
41
+ [ToastSide.TopLeft]: "left",
42
+ [ToastSide.TopCenter]: "up",
43
+ [ToastSide.TopRight]: "right",
44
+ [ToastSide.BottomRight]: "right",
45
+ [ToastSide.BottomCenter]: "down",
46
+ [ToastSide.BottomLeft]: "left",
47
+ } as Record<ToastSide, ToastProviderProps["swipeDirection"]>;
48
+
49
+ export interface ToastProps extends Omit<ToastRootProps, "title">, Omit<ToastProviderProps, "children"> {
50
+ side?: ToastSide;
51
+ color?: ToastColor;
52
+ radius?: ToastRadius;
53
+ title?: ReactNode;
54
+ action?: ReactNode;
55
+ description?: ReactNode;
56
+ closeIcon?: ReactElement;
57
+ closeProps?: IconButtonProps;
58
+ titleClassName?: string;
59
+ actionClassName?: string;
60
+ viewportClassName?: string;
61
+ descriptionClassName?: string;
62
+ onClose?: () => void;
63
+ fullWidth?: boolean;
64
+ sticky?: boolean;
65
+ }
66
+
67
+ const Toast: FC<ToastProps> = props => {
68
+ const defaultProps = useComponentProps("toast");
69
+ const mergedProps = {...defaultProps, ...props};
70
+ const {
71
+ side = ToastSide.BottomRight,
72
+ color,
73
+ radius,
74
+ title,
75
+ action,
76
+ description,
77
+ fullWidth,
78
+ sticky,
79
+ closeIcon = "✖",
80
+ closeProps,
81
+
82
+ label,
83
+ duration,
84
+ swipeDirection = toastSideBySwipeDirectionMap[side],
85
+ swipeThreshold = ["up", "down"].includes(swipeDirection || "") ? 15 : 50,
86
+
87
+ className,
88
+ titleClassName,
89
+ actionClassName,
90
+ viewportClassName,
91
+ descriptionClassName,
92
+ children,
93
+ onClose,
94
+ ...other
95
+ } = mergedProps;
96
+
97
+ const {className: closeClassName, ...otherCloseProps} = closeProps || {};
98
+ return (
99
+ <Provider label={label} duration={duration} swipeDirection={swipeDirection} swipeThreshold={swipeThreshold}>
100
+ {children}
101
+ <Root
102
+ className={classnames(
103
+ styles["toast"],
104
+ {
105
+ [styles[`toast--${side}`]]: side,
106
+ [styles[`toast--${color}-color`]]: color,
107
+ [styles[`toast--${radius}-radius`]]: radius,
108
+ [styles["toast--sticky"]]: sticky,
109
+ [styles["toast--full-width"]]: fullWidth,
110
+ },
111
+ className
112
+ )}
113
+ {...other}
114
+ >
115
+ {title && <Title className={classnames(styles["toast__title"], titleClassName)}>{title}</Title>}
116
+
117
+ {description && (
118
+ <Description className={classnames(styles["toast__description"], descriptionClassName)}>
119
+ {description}
120
+ </Description>
121
+ )}
122
+
123
+ {cloneOrCreateElement(action, {className: classnames(styles["toast__action"], actionClassName)})}
124
+
125
+ {onClose && (
126
+ <IconButton
127
+ aria-label="Close"
128
+ onClick={onClose}
129
+ className={classnames(styles["toast__close"], closeClassName)}
130
+ {...otherCloseProps}
131
+ >
132
+ {closeIcon}
133
+ </IconButton>
134
+ )}
135
+ </Root>
136
+
137
+ <Viewport className={classnames(styles["toast__viewport"], viewportClassName)} />
138
+ </Provider>
139
+ );
140
+ };
141
+
142
+ export default memo(Toast);
@@ -0,0 +1,2 @@
1
+ export {default as Toast, ToastSide, ToastRadius, ToastColor} from "./Toast";
2
+ export type {ToastProps} from "./Toast";