@soul-refiner/design-system 0.0.10 → 0.0.11

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 (267) hide show
  1. package/dist/custom.d.ts +4 -0
  2. package/dist/index.d.ts +1 -0
  3. package/dist/{design-system.umd.cjs → index.umd.cjs} +1 -1
  4. package/dist/src/actions/Button/Button.module.scss +205 -0
  5. package/dist/src/actions/Button/Button.spec.js +56 -0
  6. package/dist/src/actions/Button/Button.tsx +143 -0
  7. package/dist/src/actions/Button/index.ts +1 -0
  8. package/dist/src/actions/Dropdown/Dropdown.module.scss +77 -0
  9. package/dist/src/actions/Dropdown/Dropdown.spec.js +149 -0
  10. package/dist/src/actions/Dropdown/Dropdown.tsx +224 -0
  11. package/dist/src/actions/Dropdown/index.ts +6 -0
  12. package/dist/src/actions/Dropzone/Dropzone.module.scss +48 -0
  13. package/dist/src/actions/Dropzone/Dropzone.spec.js +60 -0
  14. package/dist/src/actions/Dropzone/Dropzone.tsx +191 -0
  15. package/dist/src/actions/Dropzone/index.ts +1 -0
  16. package/dist/src/actions/Rate/Rate.module.scss +17 -0
  17. package/dist/src/actions/Rate/Rate.tsx +53 -0
  18. package/dist/src/actions/Rate/index.ts +1 -0
  19. package/dist/src/actions/Switch/Switch.module.scss +35 -0
  20. package/dist/src/actions/Switch/Switch.spec.js +31 -0
  21. package/dist/src/actions/Switch/Switch.tsx +34 -0
  22. package/dist/src/actions/Switch/index.ts +1 -0
  23. package/dist/src/actions/index.ts +5 -0
  24. package/dist/src/cards/CourseCard/CourseCard.module.scss +219 -0
  25. package/dist/src/cards/CourseCard/CourseCard.spec.js +60 -0
  26. package/dist/src/cards/CourseCard/CourseCard.tsx +145 -0
  27. package/dist/src/cards/CourseCard/index.ts +1 -0
  28. package/dist/src/cards/EpisodeCard/EpisodeCard.module.scss +69 -0
  29. package/dist/src/cards/EpisodeCard/EpisodeCard.tsx +53 -0
  30. package/dist/src/cards/EpisodeCard/index.ts +1 -0
  31. package/dist/src/cards/FeatureCard/FeatureCard.module.scss +116 -0
  32. package/dist/src/cards/FeatureCard/FeatureCard.spec.js +70 -0
  33. package/dist/src/cards/FeatureCard/FeatureCard.tsx +123 -0
  34. package/dist/src/cards/FeatureCard/index.ts +1 -0
  35. package/dist/src/cards/index.ts +3 -0
  36. package/dist/src/data/Bar/Bar.module.scss +105 -0
  37. package/dist/src/data/Bar/Bar.tsx +161 -0
  38. package/dist/src/data/Bar/index.ts +1 -0
  39. package/dist/src/data/Line/Line.module.scss +102 -0
  40. package/dist/src/data/Line/Line.tsx +162 -0
  41. package/dist/src/data/Line/index.ts +1 -0
  42. package/dist/src/data/Pie/Pie.module.scss +56 -0
  43. package/dist/src/data/Pie/Pie.spec.js +72 -0
  44. package/dist/src/data/Pie/Pie.tsx +111 -0
  45. package/dist/src/data/Pie/index.ts +1 -0
  46. package/dist/src/data/index.ts +3 -0
  47. package/dist/src/editor/Editor.module.scss +125 -0
  48. package/dist/src/editor/Editor.tsx +327 -0
  49. package/dist/src/editor/common/elements.ts +50 -0
  50. package/dist/src/editor/common/index.ts +2 -0
  51. package/dist/src/editor/common/marks.ts +27 -0
  52. package/dist/src/editor/components/MediaDrawer/MediaDrawer.module.scss +316 -0
  53. package/dist/src/editor/components/MediaDrawer/MediaDrawer.tsx +457 -0
  54. package/dist/src/editor/components/MediaDrawer/index.ts +1 -0
  55. package/dist/src/editor/components/index.ts +1 -0
  56. package/dist/src/editor/config/default.ts +213 -0
  57. package/dist/src/editor/config/index.ts +2 -0
  58. package/dist/src/editor/config/props.ts +9 -0
  59. package/dist/src/editor/index.ts +2 -0
  60. package/dist/src/editor/plateUI.ts +82 -0
  61. package/dist/src/editor/plugins/blocks.tsx +71 -0
  62. package/dist/src/editor/plugins/custom/assets/DefaultThumbnail.tsx +57 -0
  63. package/dist/src/editor/plugins/custom/assets/index.ts +1 -0
  64. package/dist/src/editor/plugins/custom/buttons.tsx +289 -0
  65. package/dist/src/editor/plugins/custom/example.tsx +64 -0
  66. package/dist/src/editor/plugins/custom/exitBreak.ts +41 -0
  67. package/dist/src/editor/plugins/custom/footnote.tsx +185 -0
  68. package/dist/src/editor/plugins/custom/index.ts +14 -0
  69. package/dist/src/editor/plugins/custom/paywall.tsx +156 -0
  70. package/dist/src/editor/plugins/custom/qa.tsx +390 -0
  71. package/dist/src/editor/plugins/custom/resetBlockType.ts +29 -0
  72. package/dist/src/editor/plugins/custom/selectOnBackspace.ts +7 -0
  73. package/dist/src/editor/plugins/custom/softBreak.ts +20 -0
  74. package/dist/src/editor/plugins/custom/styles/Button.module.scss +51 -0
  75. package/dist/src/editor/plugins/custom/styles/Footnote.module.scss +58 -0
  76. package/dist/src/editor/plugins/custom/styles/Paywall.module.scss +67 -0
  77. package/dist/src/editor/plugins/custom/styles/QA.module.scss +140 -0
  78. package/dist/src/editor/plugins/custom/styles/Video.module.scss +79 -0
  79. package/dist/src/editor/plugins/custom/video.tsx +163 -0
  80. package/dist/src/editor/plugins/index.ts +18 -0
  81. package/dist/src/editor/plugins/inline.ts +46 -0
  82. package/dist/src/editor/plugins/marks.ts +25 -0
  83. package/dist/src/editor/plugins/utils.ts +22 -0
  84. package/dist/src/feedback/Chip/Chip.module.scss +23 -0
  85. package/dist/src/feedback/Chip/Chip.tsx +58 -0
  86. package/dist/src/feedback/Chip/index.ts +1 -0
  87. package/dist/src/feedback/Loader/Loader.module.scss +18 -0
  88. package/dist/src/feedback/Loader/Loader.spec.js +18 -0
  89. package/dist/src/feedback/Loader/Loader.tsx +53 -0
  90. package/dist/src/feedback/Loader/index.ts +1 -0
  91. package/dist/src/feedback/ProgressBar/ProgressBar.module.scss +13 -0
  92. package/dist/src/feedback/ProgressBar/ProgressBar.tsx +32 -0
  93. package/dist/src/feedback/ProgressBar/index.ts +1 -0
  94. package/dist/src/feedback/Toast/Toast.module.scss +44 -0
  95. package/dist/src/feedback/Toast/Toast.tsx +76 -0
  96. package/dist/src/feedback/Toast/index.ts +1 -0
  97. package/dist/src/feedback/Tooltip/Tooltip.module.scss +47 -0
  98. package/dist/src/feedback/Tooltip/Tooltip.tsx +10 -0
  99. package/dist/src/feedback/Tooltip/index.ts +1 -0
  100. package/dist/src/feedback/index.ts +5 -0
  101. package/dist/src/global.d.ts +6 -0
  102. package/dist/src/iconography/Avatar/Avatar.module.scss +90 -0
  103. package/dist/src/iconography/Avatar/Avatar.spec.js +75 -0
  104. package/dist/src/iconography/Avatar/Avatar.tsx +96 -0
  105. package/dist/src/iconography/Avatar/DefaultIcon.svg +4 -0
  106. package/dist/src/iconography/Avatar/DefaultIcon.tsx +12 -0
  107. package/dist/src/iconography/Avatar/iconHelpers.tsx +186 -0
  108. package/dist/src/iconography/Avatar/index.ts +1 -0
  109. package/dist/src/iconography/ColoredIcon/ColoredIcon.module.scss +40 -0
  110. package/dist/src/iconography/ColoredIcon/ColoredIcon.tsx +30 -0
  111. package/dist/src/iconography/ColoredIcon/index.ts +5 -0
  112. package/dist/src/iconography/DevicePreview/DevicePreview.module.scss +143 -0
  113. package/dist/src/iconography/DevicePreview/DevicePreview.tsx +592 -0
  114. package/dist/src/iconography/DevicePreview/index.ts +1 -0
  115. package/dist/src/iconography/IconHeader/IconHeader.module.scss +42 -0
  116. package/dist/src/iconography/IconHeader/IconHeader.tsx +42 -0
  117. package/dist/src/iconography/IconHeader/index.ts +1 -0
  118. package/dist/src/iconography/StarRating/StarRating.tsx +99 -0
  119. package/dist/src/iconography/StarRating/index.ts +1 -0
  120. package/dist/src/iconography/index.ts +5 -0
  121. package/dist/src/implementations/BodyContent/BodyContent.module.scss +38 -0
  122. package/dist/src/implementations/BodyContent/BodyContent.tsx +78 -0
  123. package/dist/src/implementations/BodyContent/index.ts +2 -0
  124. package/dist/src/implementations/JoinGroupModal/JoinGroupModal.module.scss +83 -0
  125. package/dist/src/implementations/JoinGroupModal/JoinGroupModal.tsx +176 -0
  126. package/dist/src/implementations/JoinGroupModal/index.ts +1 -0
  127. package/dist/src/implementations/index.ts +2 -0
  128. package/dist/src/index.ts +149 -0
  129. package/dist/src/inputs/CalendarInput/CalendarInput.module.scss +38 -0
  130. package/dist/src/inputs/CalendarInput/CalendarInput.spec.js +19 -0
  131. package/dist/src/inputs/CalendarInput/CalendarInput.tsx +29 -0
  132. package/dist/src/inputs/CalendarInput/index.ts +1 -0
  133. package/dist/src/inputs/CheckboxInput/CheckboxInput.module.scss +23 -0
  134. package/dist/src/inputs/CheckboxInput/CheckboxInput.tsx +39 -0
  135. package/dist/src/inputs/CheckboxInput/index.ts +1 -0
  136. package/dist/src/inputs/FeedInput/FeedInput.module.scss +48 -0
  137. package/dist/src/inputs/FeedInput/FeedInput.spec.js +16 -0
  138. package/dist/src/inputs/FeedInput/FeedInput.tsx +197 -0
  139. package/dist/src/inputs/FeedInput/index.ts +1 -0
  140. package/dist/src/inputs/InboxInput/InboxInput.module.scss +48 -0
  141. package/dist/src/inputs/InboxInput/InboxInput.spec.js +19 -0
  142. package/dist/src/inputs/InboxInput/InboxInput.tsx +97 -0
  143. package/dist/src/inputs/InboxInput/index.ts +1 -0
  144. package/dist/src/inputs/PostInput/PostInput.module.scss +49 -0
  145. package/dist/src/inputs/PostInput/PostInput.spec.js +19 -0
  146. package/dist/src/inputs/PostInput/PostInput.tsx +54 -0
  147. package/dist/src/inputs/PostInput/index.ts +1 -0
  148. package/dist/src/inputs/RadioInput/RadioInput.module.scss +68 -0
  149. package/dist/src/inputs/RadioInput/RadioInput.tsx +55 -0
  150. package/dist/src/inputs/RadioInput/index.ts +1 -0
  151. package/dist/src/inputs/SearchInput/SearchInput.module.scss +40 -0
  152. package/dist/src/inputs/SearchInput/SearchInput.tsx +61 -0
  153. package/dist/src/inputs/SearchInput/index.ts +1 -0
  154. package/dist/src/inputs/SelectInput/SelectInput.module.scss +66 -0
  155. package/dist/src/inputs/SelectInput/SelectInput.tsx +145 -0
  156. package/dist/src/inputs/SelectInput/index.ts +1 -0
  157. package/dist/src/inputs/TagInput/TagInput.module.scss +75 -0
  158. package/dist/src/inputs/TagInput/TagInput.tsx +115 -0
  159. package/dist/src/inputs/TagInput/index.ts +1 -0
  160. package/dist/src/inputs/TextInput/TextInput.module.scss +35 -0
  161. package/dist/src/inputs/TextInput/TextInput.tsx +46 -0
  162. package/dist/src/inputs/TextInput/index.ts +1 -0
  163. package/dist/src/inputs/index.ts +10 -0
  164. package/dist/src/lists/ContactDetails/ContactDetails.module.scss +70 -0
  165. package/dist/src/lists/ContactDetails/ContactDetails.spec.js +69 -0
  166. package/dist/src/lists/ContactDetails/ContactDetails.tsx +185 -0
  167. package/dist/src/lists/ContactDetails/index.ts +1 -0
  168. package/dist/src/lists/index.ts +1 -0
  169. package/dist/src/navigation/Breadcrumbs/Breadcrumbs.module.scss +18 -0
  170. package/dist/src/navigation/Breadcrumbs/Breadcrumbs.spec.js +38 -0
  171. package/dist/src/navigation/Breadcrumbs/Breadcrumbs.tsx +43 -0
  172. package/dist/src/navigation/Breadcrumbs/index.ts +1 -0
  173. package/dist/src/navigation/Drawer/Drawer.module.scss +104 -0
  174. package/dist/src/navigation/Drawer/Drawer.tsx +177 -0
  175. package/dist/src/navigation/Drawer/index.ts +1 -0
  176. package/dist/src/navigation/EditorBar/EditorBar.module.scss +118 -0
  177. package/dist/src/navigation/EditorBar/EditorBar.tsx +416 -0
  178. package/dist/src/navigation/EditorBar/components/AlignmentDropdown/AlignmentDropdown.tsx +106 -0
  179. package/dist/src/navigation/EditorBar/components/AlignmentDropdown/index.ts +1 -0
  180. package/dist/src/navigation/EditorBar/components/ButtonModal/ButtonModal.module.scss +85 -0
  181. package/dist/src/navigation/EditorBar/components/ButtonModal/ButtonModal.tsx +314 -0
  182. package/dist/src/navigation/EditorBar/components/ButtonModal/assets/Comment.tsx +28 -0
  183. package/dist/src/navigation/EditorBar/components/ButtonModal/assets/GiftSubscription.tsx +28 -0
  184. package/dist/src/navigation/EditorBar/components/ButtonModal/assets/Link.tsx +28 -0
  185. package/dist/src/navigation/EditorBar/components/ButtonModal/assets/Share.tsx +28 -0
  186. package/dist/src/navigation/EditorBar/components/ButtonModal/assets/ShareCommunity.tsx +42 -0
  187. package/dist/src/navigation/EditorBar/components/ButtonModal/assets/Signup.tsx +68 -0
  188. package/dist/src/navigation/EditorBar/components/ButtonModal/assets/Special.tsx +24 -0
  189. package/dist/src/navigation/EditorBar/components/ButtonModal/assets/Subscribe.tsx +28 -0
  190. package/dist/src/navigation/EditorBar/components/ButtonModal/assets/index.ts +8 -0
  191. package/dist/src/navigation/EditorBar/components/ButtonModal/index.ts +1 -0
  192. package/dist/src/navigation/EditorBar/components/FontDropdown/FontDropdown.module.scss +16 -0
  193. package/dist/src/navigation/EditorBar/components/FontDropdown/FontDropdown.tsx +137 -0
  194. package/dist/src/navigation/EditorBar/components/FontDropdown/index.ts +1 -0
  195. package/dist/src/navigation/EditorBar/components/MoreDropdown/MoreDropdown.module.scss +43 -0
  196. package/dist/src/navigation/EditorBar/components/MoreDropdown/MoreDropdown.tsx +124 -0
  197. package/dist/src/navigation/EditorBar/components/MoreDropdown/index.ts +1 -0
  198. package/dist/src/navigation/EditorBar/components/OutlineDropdown/OutlineDropdown.module.scss +21 -0
  199. package/dist/src/navigation/EditorBar/components/OutlineDropdown/OutlineDropdown.tsx +37 -0
  200. package/dist/src/navigation/EditorBar/components/OutlineDropdown/index.ts +1 -0
  201. package/dist/src/navigation/EditorBar/components/TextTypeDropdown/TextTypeDropdown.module.scss +51 -0
  202. package/dist/src/navigation/EditorBar/components/TextTypeDropdown/TextTypeDropdown.tsx +80 -0
  203. package/dist/src/navigation/EditorBar/components/TextTypeDropdown/index.ts +1 -0
  204. package/dist/src/navigation/EditorBar/components/VideoModal/VideoModal.module.scss +150 -0
  205. package/dist/src/navigation/EditorBar/components/VideoModal/VideoModal.tsx +163 -0
  206. package/dist/src/navigation/EditorBar/components/VideoModal/index.ts +1 -0
  207. package/dist/src/navigation/EditorBar/components/index.ts +7 -0
  208. package/dist/src/navigation/EditorBar/index.ts +1 -0
  209. package/dist/src/navigation/MenuTabs/MenuTabs.module.scss +34 -0
  210. package/dist/src/navigation/MenuTabs/MenuTabs.spec.js +36 -0
  211. package/dist/src/navigation/MenuTabs/MenuTabs.tsx +52 -0
  212. package/dist/src/navigation/MenuTabs/index.ts +1 -0
  213. package/dist/src/navigation/Navigation/Navigation.module.scss +92 -0
  214. package/dist/src/navigation/Navigation/Navigation.spec.js +144 -0
  215. package/dist/src/navigation/Navigation/Navigation.tsx +111 -0
  216. package/dist/src/navigation/Navigation/SubNavigation.module.scss +255 -0
  217. package/dist/src/navigation/Navigation/SubNavigation.spec.js +112 -0
  218. package/dist/src/navigation/Navigation/SubNavigation.tsx +443 -0
  219. package/dist/src/navigation/Navigation/index.ts +15 -0
  220. package/dist/src/navigation/Pagination/Pagination.module.scss +49 -0
  221. package/dist/src/navigation/Pagination/Pagination.tsx +115 -0
  222. package/dist/src/navigation/Pagination/index.ts +1 -0
  223. package/dist/src/navigation/index.ts +21 -0
  224. package/dist/src/surfaces/Comment/Comment.module.scss +106 -0
  225. package/dist/src/surfaces/Comment/Comment.spec.js +105 -0
  226. package/dist/src/surfaces/Comment/Comment.tsx +157 -0
  227. package/dist/src/surfaces/Comment/index.ts +1 -0
  228. package/dist/src/surfaces/Faq/Faq.module.scss +91 -0
  229. package/dist/src/surfaces/Faq/Faq.spec.js +38 -0
  230. package/dist/src/surfaces/Faq/Faq.tsx +156 -0
  231. package/dist/src/surfaces/Faq/index.ts +1 -0
  232. package/dist/src/surfaces/Message/Message.module.scss +37 -0
  233. package/dist/src/surfaces/Message/Message.spec.js +47 -0
  234. package/dist/src/surfaces/Message/Message.tsx +54 -0
  235. package/dist/src/surfaces/Message/index.ts +1 -0
  236. package/dist/src/surfaces/Modal/Modal.module.scss +52 -0
  237. package/dist/src/surfaces/Modal/Modal.spec.js +38 -0
  238. package/dist/src/surfaces/Modal/Modal.tsx +131 -0
  239. package/dist/src/surfaces/Modal/index.ts +5 -0
  240. package/dist/src/surfaces/Plan/Plan.module.scss +79 -0
  241. package/dist/src/surfaces/Plan/Plan.tsx +75 -0
  242. package/dist/src/surfaces/Plan/index.ts +1 -0
  243. package/dist/src/surfaces/Post/Post.module.scss +46 -0
  244. package/dist/src/surfaces/Post/Post.spec.js +103 -0
  245. package/dist/src/surfaces/Post/Post.tsx +185 -0
  246. package/dist/src/surfaces/Post/index.ts +1 -0
  247. package/dist/src/surfaces/Post/postHelpers.ts +20 -0
  248. package/dist/src/surfaces/ProfileHeader/ProfileHeader.module.scss +202 -0
  249. package/dist/src/surfaces/ProfileHeader/ProfileHeader.tsx +103 -0
  250. package/dist/src/surfaces/ProfileHeader/index.ts +1 -0
  251. package/dist/src/surfaces/RatingsOverview/RatingsOverview.module.scss +54 -0
  252. package/dist/src/surfaces/RatingsOverview/RatingsOverview.tsx +69 -0
  253. package/dist/src/surfaces/RatingsOverview/index.ts +1 -0
  254. package/dist/src/surfaces/Review/Review.module.scss +73 -0
  255. package/dist/src/surfaces/Review/Review.tsx +88 -0
  256. package/dist/src/surfaces/Review/index.ts +1 -0
  257. package/dist/src/surfaces/index.ts +9 -0
  258. package/dist/src/tables/Filter/Filter.module.scss +34 -0
  259. package/dist/src/tables/Filter/Filter.tsx +30 -0
  260. package/dist/src/tables/Filter/index.ts +1 -0
  261. package/dist/src/tables/Table/Table.module.scss +126 -0
  262. package/dist/src/tables/Table/Table.spec.js +113 -0
  263. package/dist/src/tables/Table/Table.tsx +251 -0
  264. package/dist/src/tables/Table/index.ts +7 -0
  265. package/dist/src/tables/index.ts +7 -0
  266. package/package.json +3 -2
  267. /package/dist/{design-system.js → index.js} +0 -0
@@ -0,0 +1,224 @@
1
+ import React from "react";
2
+ import dropdownStyles from "./Dropdown.module.scss";
3
+
4
+ export interface DropdownProps
5
+ extends Partial<Omit<HTMLSelectElement, "options" | "style" | "children">>,
6
+ React.PropsWithChildren {
7
+ className?: string;
8
+ closeOnChange?: boolean;
9
+ closeOnBlur?: boolean;
10
+ defaultValue?: string;
11
+ disabled?: boolean;
12
+ maintainState?: boolean;
13
+ offset?: [number, number];
14
+ onChange?: (event: React.MouseEvent, value: string) => void;
15
+ open?: "right" | "left";
16
+ options?: React.ReactNode[] | Omit<DropdownOptionProps, "selected">[];
17
+ style?: React.CSSProperties;
18
+ trigger: React.ReactElement;
19
+ }
20
+
21
+ const Dropdown = ({
22
+ className,
23
+ children,
24
+ closeOnChange = true,
25
+ closeOnBlur = true,
26
+ defaultValue = "",
27
+ disabled = false,
28
+ maintainState = true,
29
+ offset,
30
+ onChange,
31
+ open: openDirection = "right",
32
+ options,
33
+ style,
34
+ trigger,
35
+ }: DropdownProps) => {
36
+ const wrapperRef = React.useRef<HTMLDivElement>(null);
37
+ const optionsRef = React.useRef<HTMLDivElement>(null);
38
+ const [open, setOpen] = React.useState(false);
39
+ const [selected, setSelected] = React.useState(defaultValue);
40
+
41
+ const handleOpen = () => {
42
+ if (disabled) {
43
+ return;
44
+ }
45
+ setOpen((prev) => !prev);
46
+ };
47
+
48
+ const handleChange = (event: React.MouseEvent) => {
49
+ event.stopPropagation();
50
+ const value =
51
+ (event.target as HTMLOptionElement).getAttribute("data-value") ?? "";
52
+ if (selected !== value) {
53
+ setSelected(value);
54
+ } else {
55
+ setSelected("");
56
+ }
57
+ if (closeOnChange) {
58
+ setOpen(false);
59
+ }
60
+ if (onChange) onChange(event, value);
61
+ };
62
+
63
+ const handleBlur = (event: React.FocusEvent) => {
64
+ if (
65
+ closeOnBlur &&
66
+ wrapperRef?.current &&
67
+ !wrapperRef?.current?.contains(event.relatedTarget)
68
+ ) {
69
+ setOpen(false);
70
+ }
71
+ };
72
+
73
+ React.useEffect(() => {
74
+ if (disabled) {
75
+ setOpen(false);
76
+ }
77
+ }, [disabled]);
78
+
79
+ let dropdownElements;
80
+ if (
81
+ !children &&
82
+ options &&
83
+ !(
84
+ typeof (options[0] as unknown as { $$typeof: symbol | undefined })
85
+ .$$typeof === "symbol"
86
+ )
87
+ ) {
88
+ dropdownElements = (
89
+ options as Omit<DropdownOptionProps, "selected" | "onClick">[]
90
+ ).map(({ value, ...rest }, index) => {
91
+ return (
92
+ <Option
93
+ key={index + (value ?? "")}
94
+ selected={value === selected}
95
+ onClick={handleChange}
96
+ value={value}
97
+ {...rest}
98
+ />
99
+ );
100
+ });
101
+ } else if (!children) {
102
+ dropdownElements = React.Children.map(
103
+ options as unknown as React.ReactElement[],
104
+ (child, index) => (
105
+ <Option
106
+ key={index + child.props.value}
107
+ selected={child.props.value === selected}
108
+ onClick={handleChange}
109
+ {...child.props}
110
+ />
111
+ )
112
+ );
113
+ }
114
+
115
+ return (
116
+ <div
117
+ className={`dropdown ${dropdownStyles.dropdown} ${
118
+ disabled ? "disabled" : ""
119
+ } ${className ? className : ""}`}
120
+ tabIndex={0}
121
+ ref={wrapperRef}
122
+ style={style}
123
+ onBlurCapture={handleBlur}
124
+ >
125
+ {React.cloneElement(
126
+ trigger,
127
+ typeof trigger.type === "string"
128
+ ? { onClick: handleOpen }
129
+ : { dropdownOpen: open, onClick: handleOpen }
130
+ )}
131
+ {open && (
132
+ <div
133
+ className={`options${openDirection === "left" ? " open-left" : ""}`}
134
+ data-testid="options-wrapper"
135
+ ref={optionsRef}
136
+ >
137
+ {!children && (dropdownElements as React.ReactElement[])}
138
+ {children &&
139
+ React.Children.map(children, (child, index) => {
140
+ let props = {};
141
+ if (React.isValidElement(child)) {
142
+ const { className, onClick, ...possibleProps } = child.props;
143
+ props = possibleProps;
144
+ }
145
+ return (
146
+ <div
147
+ key={index + (child as React.ReactElement).props.value}
148
+ className={`${dropdownStyles.option} ${
149
+ maintainState &&
150
+ (child as React.ReactElement).props["data-value"] ===
151
+ selected
152
+ ? "selected"
153
+ : ""
154
+ }`}
155
+ data-value={(child as React.ReactElement).props["data-value"]}
156
+ onClick={onChange ? handleChange : undefined}
157
+ {...props}
158
+ >
159
+ {child as React.ReactElement}
160
+ </div>
161
+ );
162
+ })}
163
+ </div>
164
+ )}
165
+ </div>
166
+ );
167
+ };
168
+
169
+ export interface DropdownOptionProps
170
+ extends Partial<Omit<HTMLOptionElement, "className" | "style" | "selected">> {
171
+ checkbox?: boolean;
172
+ color?: string;
173
+ icon?: React.ReactNode;
174
+ onClick: (event: React.MouseEvent) => void;
175
+ selected?: boolean;
176
+ style?: React.CSSProperties;
177
+ }
178
+
179
+ const Option = ({
180
+ checkbox,
181
+ color,
182
+ disabled,
183
+ icon,
184
+ label,
185
+ onClick,
186
+ selected,
187
+ style,
188
+ value,
189
+ }: DropdownOptionProps) => {
190
+ return (
191
+ <div
192
+ className={`${dropdownStyles.option} ${disabled ? "disabled" : ""} ${
193
+ selected ? "selected" : ""
194
+ }`}
195
+ data-value={value}
196
+ onClick={onClick}
197
+ style={
198
+ {
199
+ "--option-color": color,
200
+ ...style,
201
+ } as React.CSSProperties
202
+ }
203
+ >
204
+ {checkbox ? <input readOnly type="checkbox" checked={selected} /> : icon}
205
+ {label}
206
+ </div>
207
+ );
208
+ };
209
+
210
+ Option.displayName = "Dropdown.Option";
211
+ Dropdown.Option = Option;
212
+
213
+ export interface DropdownSpacerProps {
214
+ style?: React.CSSProperties;
215
+ }
216
+
217
+ const Spacer = ({ style }: DropdownSpacerProps) => {
218
+ return <div className={dropdownStyles.spacer} style={style} />;
219
+ };
220
+
221
+ Spacer.displayName = "Dropdown.Spacer";
222
+ Dropdown.Spacer = Spacer;
223
+
224
+ export { Dropdown };
@@ -0,0 +1,6 @@
1
+ export {
2
+ Dropdown,
3
+ type DropdownProps,
4
+ type DropdownOptionProps,
5
+ type DropdownSpacerProps,
6
+ } from "./Dropdown";
@@ -0,0 +1,48 @@
1
+ @use "@soul-refiner/styles/mixins";
2
+
3
+ .dropzone {
4
+ display: flex;
5
+ flex-direction: column;
6
+ place-items: center;
7
+ place-content: center;
8
+ gap: 16px;
9
+ padding: 32px;
10
+ border-radius: var(--border-radius-normal);
11
+ border: 2px dashed var(--border);
12
+ background-color: var(--background);
13
+ width: 100%;
14
+
15
+ &[class~="dragover"] {
16
+ border: 2px solid var(--icon);
17
+ }
18
+
19
+ input[type="file"] {
20
+ display: none;
21
+ }
22
+
23
+ .textContainer {
24
+ @include mixins.font(400, 16px, 24px);
25
+ display: flex;
26
+ justify-items: center;
27
+ flex-flow: row wrap;
28
+ gap: 8px;
29
+ place-items: center;
30
+ & > button {
31
+ @include mixins.font(700, 16px, 24px);
32
+ color: var(--icon);
33
+ }
34
+ }
35
+
36
+ p {
37
+ justify-content: center;
38
+ }
39
+
40
+ [class~="icon"] {
41
+ max-width: fit-content;
42
+ max-height: fit-content;
43
+
44
+ svg {
45
+ fill: var(--icon);
46
+ }
47
+ }
48
+ }
@@ -0,0 +1,60 @@
1
+ import React from "react";
2
+ import "@testing-library/jest-dom";
3
+ import { fireEvent, render, screen, waitFor } from "@testing-library/react";
4
+
5
+ import { Dropzone } from "./Dropzone";
6
+
7
+ const generateMockProps = props => ({
8
+ ...props,
9
+ });
10
+
11
+ describe("Dropzone", () => {
12
+ it("restricts the acceptable file type to images", () => {
13
+ const props = generateMockProps({
14
+ fileType: "image",
15
+ });
16
+ render(<Dropzone {...props} />);
17
+ const input = screen.getByTestId("dropzone-upload-input");
18
+ expect(input).toHaveAttribute("accept", "image/*");
19
+ });
20
+
21
+ it("restricts the acceptable file type to videos", () => {
22
+ const props = generateMockProps({
23
+ fileType: "video",
24
+ });
25
+ render(<Dropzone {...props} />);
26
+ const input = screen.getByTestId("dropzone-upload-input");
27
+ expect(input).toHaveAttribute("accept", "video/*");
28
+ });
29
+
30
+ it("restricts the acceptable file type audio", () => {
31
+ const props = generateMockProps({
32
+ fileType: "audio",
33
+ });
34
+ render(<Dropzone {...props} />);
35
+ const input = screen.getByTestId("dropzone-upload-input");
36
+ expect(input).toHaveAttribute("accept", "audio/*");
37
+ });
38
+
39
+ it("restricts the acceptable file type to documents", () => {
40
+ const props = generateMockProps({
41
+ fileType: "document",
42
+ });
43
+ render(<Dropzone {...props} />);
44
+ const input = screen.getByTestId("dropzone-upload-input");
45
+ expect(input).toHaveAttribute("accept", ".xlsx, .xls, .doc, .docx, .ppt, .pptx, .txt, .pdf, application/msword, application/vnd.ms-excel, application/vnd.ms-powerpoint, text/plain, application/pdf,");
46
+ });
47
+
48
+ it("calls the onDrop handler", async () => {
49
+ const file = new File(["test"], "test.png", { type: "image/png" });
50
+ const props = generateMockProps({
51
+ onDrop: jest.fn(),
52
+ });
53
+ render(<Dropzone {...props} />);
54
+ const input = screen.getByTestId("dropzone-upload-input");
55
+ await waitFor(() => {
56
+ fireEvent.change(input, { target: { files: [file] } });
57
+ });
58
+ expect(props.onDrop).toHaveBeenCalled();
59
+ });
60
+ });
@@ -0,0 +1,191 @@
1
+ import React, { DragEvent, useState, useRef, CSSProperties } from "react";
2
+ import dropStyles from "./Dropzone.module.scss";
3
+ import { Button } from "../Button";
4
+ import {
5
+ UploadAudio,
6
+ UploadDocument,
7
+ UploadImage,
8
+ UploadVideo,
9
+ } from "@soul-refiner/icons/src";
10
+
11
+ export interface DropzoneProps extends React.PropsWithChildren {
12
+ color?:
13
+ | "turquoise"
14
+ | "green"
15
+ | "blue"
16
+ | "purple"
17
+ | "yellow"
18
+ | "orange"
19
+ | "red"
20
+ | "grey";
21
+ id?: string;
22
+ fileType?: "video" | "audio" | "image" | "document";
23
+ multiple?: boolean;
24
+ showGraphic?: boolean;
25
+ subtext?: string;
26
+ text?: React.ReactNode;
27
+ fluid?: boolean;
28
+ style?: CSSProperties;
29
+ onDrop?: (files: FileList) => void;
30
+ ref?: React.RefObject<HTMLInputElement>;
31
+ showBrowse?: boolean;
32
+ }
33
+
34
+ export const Dropzone = ({
35
+ children,
36
+ id,
37
+ color = "purple",
38
+ fileType,
39
+ multiple = false,
40
+ showGraphic = true,
41
+ subtext,
42
+ text,
43
+ style,
44
+ onDrop,
45
+ showBrowse = true,
46
+ ...rest
47
+ }: DropzoneProps) => {
48
+ const filesRef = useRef<HTMLInputElement>(null);
49
+ const [draggingOver, setDraggingOver] = useState(false);
50
+
51
+ const acceptableFiletypes = () => {
52
+ switch (fileType) {
53
+ case "video":
54
+ return "video/*";
55
+ case "audio":
56
+ return "audio/*";
57
+ case "image":
58
+ return "image/*";
59
+ case "document":
60
+ return ".xlsx, .xls, .doc, .docx, .ppt, .pptx, .txt, .pdf, application/msword, application/vnd.ms-excel, application/vnd.ms-powerpoint, text/plain, application/pdf,";
61
+ }
62
+ };
63
+
64
+ const getImage = () => {
65
+ switch (fileType) {
66
+ case "video":
67
+ return (
68
+ <UploadVideo iconColor="transparent" iconSize={146} size={146} />
69
+ );
70
+ case "audio":
71
+ return (
72
+ <UploadAudio iconColor="transparent" iconSize={146} size={146} />
73
+ );
74
+ case "image":
75
+ return (
76
+ <UploadImage iconColor="transparent" iconSize={146} size={146} />
77
+ );
78
+ case "document":
79
+ return (
80
+ <UploadDocument iconColor="transparent" iconSize={146} size={146} />
81
+ );
82
+ }
83
+ };
84
+
85
+ const handleDragOver = (e: DragEvent<HTMLDivElement>) => {
86
+ e.preventDefault();
87
+ setDraggingOver(true);
88
+ };
89
+
90
+ const handleDragLeave = (e: DragEvent<HTMLDivElement>) => {
91
+ e.preventDefault();
92
+ setDraggingOver(false);
93
+ };
94
+
95
+ const handleDrop = (e: DragEvent<HTMLDivElement>) => {
96
+ e.preventDefault();
97
+ setDraggingOver(false);
98
+
99
+ const files = e.dataTransfer.files;
100
+ const dataTransfer: DataTransfer = new DataTransfer();
101
+
102
+ for (let i = 0; i < files.length; i++) {
103
+ const file: File | null = files.item(i);
104
+
105
+ if (file !== null) {
106
+ dataTransfer.items.add(file);
107
+ }
108
+ }
109
+
110
+ const fileInput: HTMLInputElement | null = filesRef.current;
111
+
112
+ if (fileInput !== null) {
113
+ fileInput.files = dataTransfer.files;
114
+
115
+ if (onDrop) {
116
+ onDrop(fileInput.files);
117
+ }
118
+ }
119
+ };
120
+
121
+ const handleFileChange = () => {
122
+ const fileInput: HTMLInputElement | null = filesRef.current;
123
+
124
+ if (fileInput !== null) {
125
+ if (onDrop && fileInput.files && fileInput.files.length) {
126
+ onDrop(fileInput.files);
127
+ }
128
+ }
129
+ };
130
+
131
+ const removeFileFromState = () => {
132
+ if (filesRef.current) filesRef.current.value = "";
133
+ };
134
+
135
+ return (
136
+ <>
137
+ <div
138
+ style={
139
+ {
140
+ "--background": `var(--color-${color}-10)`,
141
+ "--border": `var(--color-${color}-7)`,
142
+ "--icon": `var(--color-${color}-5)`,
143
+ ...style,
144
+ } as React.CSSProperties
145
+ }
146
+ className={`${dropStyles.dropzone} ${draggingOver ? "dragover" : ""}`}
147
+ id={id}
148
+ onDragOver={handleDragOver}
149
+ onDragLeave={handleDragLeave}
150
+ onDrop={handleDrop}
151
+ {...rest}
152
+ >
153
+ {showGraphic && <div className={dropStyles.graphic}>{getImage()}</div>}
154
+ <div>
155
+ <div className={dropStyles.textContainer}>
156
+ {text}
157
+ {showBrowse && (
158
+ <Button
159
+ size="small"
160
+ buttonColor="transparent"
161
+ onClick={() => filesRef.current?.click()}
162
+ padded={false}
163
+ >
164
+ Browse
165
+ </Button>
166
+ )}
167
+ </div>
168
+ {subtext && <p className={dropStyles.textContainer}>{subtext}</p>}
169
+ </div>
170
+ <input
171
+ data-testid="dropzone-upload-input"
172
+ ref={filesRef}
173
+ type="file"
174
+ multiple={multiple}
175
+ accept={acceptableFiletypes()}
176
+ name="Files"
177
+ onChange={handleFileChange}
178
+ />
179
+ </div>
180
+ {React.Children.map(children, (child) => {
181
+ if (React.isValidElement(child)) {
182
+ return React.cloneElement(child, {
183
+ handleUpload: () => filesRef.current?.click(),
184
+ removeFileFromState,
185
+ } as Partial<unknown> & React.Attributes);
186
+ }
187
+ return child;
188
+ })}
189
+ </>
190
+ );
191
+ };
@@ -0,0 +1 @@
1
+ export { Dropzone, type DropzoneProps } from "./Dropzone"
@@ -0,0 +1,17 @@
1
+ .rate {
2
+ display: flex;
3
+ flex-direction: row;
4
+ place-content: center;
5
+ place-items: center;
6
+
7
+ font-size: var(--size-12);
8
+ font-weight: var(--weight-inter-semibold);
9
+ color: var(--color-grey-5);
10
+
11
+ .stars {
12
+ cursor: pointer;
13
+ display: flex;
14
+ flex-direction: row;
15
+ gap: 2px;
16
+ }
17
+ }
@@ -0,0 +1,53 @@
1
+ import React, { CSSProperties, useState } from "react";
2
+ import { Star } from "@soul-refiner/icons/src";
3
+ import rateStyles from "./Rate.module.scss";
4
+
5
+ export interface RateProps {
6
+ ownRating?: number;
7
+ label?: string;
8
+ direction?: "vertical" | "horizontal";
9
+ onClickRating: (rating: number) => void;
10
+ }
11
+
12
+ export const Rate = ({
13
+ ownRating = 0,
14
+ label,
15
+ direction = "vertical",
16
+ onClickRating,
17
+ }: RateProps) => {
18
+ const [starsHover, setStarsHover] = useState<number>(ownRating);
19
+
20
+ const stars: number[] = [1, 2, 3, 4, 5];
21
+
22
+ const style: CSSProperties = {
23
+ flexDirection: direction === "vertical" ? "column" : "row",
24
+ };
25
+
26
+ return (
27
+ <div
28
+ className={rateStyles.rate}
29
+ style={style}
30
+ onMouseLeave={() => setStarsHover(ownRating)}
31
+ >
32
+ {label && label}
33
+ <div className={rateStyles.stars}>
34
+ {stars.map((star, index) => {
35
+ const active = index + 1 <= starsHover;
36
+ const fills = active
37
+ ? `hsl(${40 - star * 2.3}deg 100% 50%)`
38
+ : undefined;
39
+ return (
40
+ <Star
41
+ key={index}
42
+ style={{ height: "auto", width: "auto", padding: 0 }}
43
+ fill={fills}
44
+ className={index + 1 <= starsHover ? "hover" : ""}
45
+ onMouseOver={() => setStarsHover(star)}
46
+ onClick={() => onClickRating(star)}
47
+ />
48
+ );
49
+ })}
50
+ </div>
51
+ </div>
52
+ );
53
+ };
@@ -0,0 +1 @@
1
+ export { Rate, type RateProps } from "./Rate"
@@ -0,0 +1,35 @@
1
+ .switch {
2
+ display: flex;
3
+ flex-direction: row;
4
+ padding: 4px;
5
+ border-radius: 35px;
6
+ background-color: var(--color-blue-9);
7
+
8
+ &> div {
9
+ padding: 4px 16px;
10
+ border-radius: 1vw;
11
+ font-weight: var(--weight-inter-semibold);
12
+ user-select: none;
13
+ flex-grow: 1;
14
+ display: flex;
15
+ justify-content: center;
16
+
17
+ }
18
+
19
+ [class~=active] {
20
+ background-color: #FFF;
21
+ color: var(--color-blue-3);
22
+ }
23
+
24
+ [class~=inactive] {
25
+ color: var(--color-blue-6);
26
+ cursor: pointer;
27
+ }
28
+
29
+
30
+ }
31
+
32
+ .fluid {
33
+ align-self: stretch;
34
+ place-content: center;
35
+ }
@@ -0,0 +1,31 @@
1
+ import React from "react";
2
+ import "@testing-library/jest-dom";
3
+ import { render, screen } from "@testing-library/react";
4
+
5
+ import { Switch } from "./Switch";
6
+
7
+ const generateMockProps = props => ({
8
+ ...props,
9
+ });
10
+
11
+ describe("Switch", () => {
12
+ it("renders the switch", () => {
13
+ const props = generateMockProps({
14
+ optionA: "Option A",
15
+ optionB: "Option B"
16
+ });
17
+ render(<Switch {...props} />);
18
+ expect(screen.getByText("Option A"));
19
+ expect(screen.getByText("Option B"));
20
+ });
21
+
22
+ it("changes the active index", () => {
23
+ const props = generateMockProps({
24
+ optionA: "Option A",
25
+ optionB: "Option B",
26
+ active: 1,
27
+ });
28
+ render(<Switch {...props} />);
29
+ expect(screen.getByText("Option B")).toHaveClass("active");
30
+ });
31
+ });