@goodhood-web/ui 0.0.3 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (291) hide show
  1. package/.babelrc +12 -0
  2. package/.eslintrc.json +25 -0
  3. package/.storybook/main.ts +31 -0
  4. package/.storybook/manager-head.html +1 -0
  5. package/.storybook/manager.ts +7 -0
  6. package/.storybook/nebenanTheme.ts +17 -0
  7. package/.storybook/preview.ts +9 -0
  8. package/.stylelintrc.json +14 -0
  9. package/README.md +7 -0
  10. package/__mocks__/svg.js +2 -0
  11. package/images/favicon.ico +0 -0
  12. package/images/logo.svg +11 -0
  13. package/jest.config.ts +16 -0
  14. package/package.json +1 -1
  15. package/project.json +88 -0
  16. package/{index.d.ts → src/index.ts} +25 -1
  17. package/src/lib/BaseButton/BaseButton.module.scss +11 -0
  18. package/src/lib/BaseButton/BaseButton.spec.tsx +12 -0
  19. package/src/lib/BaseButton/BaseButton.stories.tsx +26 -0
  20. package/src/lib/BaseButton/BaseButton.tsx +39 -0
  21. package/src/lib/Card/Card.module.scss +15 -0
  22. package/src/lib/Card/Card.spec.tsx +15 -0
  23. package/src/lib/Card/Card.stories.tsx +159 -0
  24. package/src/lib/Card/Card.tsx +31 -0
  25. package/src/lib/Card/Card.types.ts +12 -0
  26. package/src/lib/Card/Card.utils.spec.tsx +51 -0
  27. package/src/lib/Card/Card.utils.ts +23 -0
  28. package/src/lib/Card/CardBody/CardBody.module.scss +4 -0
  29. package/src/lib/Card/CardBody/CardBody.spec.tsx +15 -0
  30. package/src/lib/Card/CardBody/CardBody.stories.tsx +108 -0
  31. package/src/lib/Card/CardBody/CardBody.tsx +9 -0
  32. package/src/lib/Card/CardBody/CardBody.types.ts +4 -0
  33. package/src/lib/Card/CardHeader/CardHeader.module.scss +12 -0
  34. package/src/lib/Card/CardHeader/CardHeader.spec.tsx +72 -0
  35. package/src/lib/Card/CardHeader/CardHeader.stories.tsx +77 -0
  36. package/src/lib/Card/CardHeader/CardHeader.tsx +29 -0
  37. package/src/lib/Card/CardHeader/CardHeader.type.ts +14 -0
  38. package/src/lib/ContentCreatorButton/ContentCreatorButton.module.scss +13 -0
  39. package/src/lib/ContentCreatorButton/ContentCreatorButton.spec.tsx +14 -0
  40. package/src/lib/ContentCreatorButton/ContentCreatorButton.stories.tsx +29 -0
  41. package/src/lib/ContentCreatorButton/ContentCreatorButton.tsx +35 -0
  42. package/{lib/ContentCreatorButton/ContentCreatorButton.types.d.ts → src/lib/ContentCreatorButton/ContentCreatorButton.types.ts} +3 -2
  43. package/src/lib/Divider/Divider.module.scss +10 -0
  44. package/src/lib/Divider/Divider.spec.tsx +46 -0
  45. package/src/lib/Divider/Divider.stories.tsx +35 -0
  46. package/src/lib/Divider/Divider.tsx +17 -0
  47. package/src/lib/Divider/Divider.types.ts +6 -0
  48. package/src/lib/Fieldset/Fieldset.module.scss +3 -0
  49. package/src/lib/Fieldset/Fieldset.spec.tsx +68 -0
  50. package/src/lib/Fieldset/Fieldset.stories.tsx +60 -0
  51. package/src/lib/Fieldset/Fieldset.tsx +28 -0
  52. package/src/lib/Fieldset/Fieldset.types.ts +7 -0
  53. package/src/lib/Form/Form.spec.tsx +15 -0
  54. package/src/lib/Form/Form.stories.tsx +53 -0
  55. package/src/lib/Form/Form.tsx +14 -0
  56. package/src/lib/Form/Form.types.ts +11 -0
  57. package/src/lib/Icon/Icon.module.scss +7 -0
  58. package/src/lib/Icon/Icon.spec.tsx +28 -0
  59. package/src/lib/Icon/Icon.stories.tsx +88 -0
  60. package/src/lib/Icon/Icon.tsx +29 -0
  61. package/src/lib/Icon/Icon.types.ts +23 -0
  62. package/src/lib/Icon/icons/24x24/index.ts +89 -0
  63. package/src/lib/Icon/icons/24x24/svg/arrow_left.svg +1 -0
  64. package/src/lib/Icon/icons/24x24/svg/arrow_right.svg +1 -0
  65. package/src/lib/Icon/icons/24x24/svg/bookmark.svg +1 -0
  66. package/src/lib/Icon/icons/24x24/svg/bookmarked.svg +1 -0
  67. package/src/lib/Icon/icons/24x24/svg/burger_menu.svg +1 -0
  68. package/src/lib/Icon/icons/24x24/svg/camera.svg +1 -0
  69. package/src/lib/Icon/icons/24x24/svg/checkmark.svg +1 -0
  70. package/src/lib/Icon/icons/24x24/svg/checkmark_circle.svg +1 -0
  71. package/src/lib/Icon/icons/24x24/svg/chevron_down.svg +1 -0
  72. package/src/lib/Icon/icons/24x24/svg/chevron_left.svg +1 -0
  73. package/src/lib/Icon/icons/24x24/svg/chevron_right.svg +1 -0
  74. package/src/lib/Icon/icons/24x24/svg/chevron_up.svg +1 -0
  75. package/src/lib/Icon/icons/24x24/svg/comment_bubble.svg +1 -0
  76. package/src/lib/Icon/icons/24x24/svg/cross.svg +1 -0
  77. package/src/lib/Icon/icons/24x24/svg/cross_circle.svg +1 -0
  78. package/src/lib/Icon/icons/24x24/svg/envelope.svg +1 -0
  79. package/src/lib/Icon/icons/24x24/svg/event_calendar.svg +1 -0
  80. package/src/lib/Icon/icons/24x24/svg/external_link.svg +1 -0
  81. package/src/lib/Icon/icons/24x24/svg/eye.svg +1 -0
  82. package/src/lib/Icon/icons/24x24/svg/eye_crossed.svg +1 -0
  83. package/src/lib/Icon/icons/24x24/svg/filter.svg +1 -0
  84. package/src/lib/Icon/icons/24x24/svg/globe.svg +1 -0
  85. package/src/lib/Icon/icons/24x24/svg/heart.svg +1 -0
  86. package/src/lib/Icon/icons/24x24/svg/image.svg +1 -0
  87. package/src/lib/Icon/icons/24x24/svg/loudspeaker.svg +1 -0
  88. package/src/lib/Icon/icons/24x24/svg/marketplace.svg +1 -0
  89. package/src/lib/Icon/icons/24x24/svg/more_dots.svg +1 -0
  90. package/src/lib/Icon/icons/24x24/svg/more_dots_alt.svg +1 -0
  91. package/src/lib/Icon/icons/24x24/svg/mute.svg +1 -0
  92. package/src/lib/Icon/icons/24x24/svg/notification_bell.svg +1 -0
  93. package/src/lib/Icon/icons/24x24/svg/paperclip.svg +1 -0
  94. package/src/lib/Icon/icons/24x24/svg/pencil.svg +1 -0
  95. package/src/lib/Icon/icons/24x24/svg/pin.svg +1 -0
  96. package/src/lib/Icon/icons/24x24/svg/plus.svg +1 -0
  97. package/src/lib/Icon/icons/24x24/svg/plus_circle.svg +1 -0
  98. package/src/lib/Icon/icons/24x24/svg/privacy_lock.svg +1 -0
  99. package/src/lib/Icon/icons/24x24/svg/search.svg +1 -0
  100. package/src/lib/Icon/icons/24x24/svg/share_arrow.svg +1 -0
  101. package/src/lib/Icon/icons/24x24/svg/share_arrow_outline.svg +1 -0
  102. package/src/lib/Icon/icons/24x24/svg/sort.svg +1 -0
  103. package/src/lib/Icon/icons/24x24/svg/thanks.svg +1 -0
  104. package/src/lib/Icon/icons/24x24/svg/trash_can.svg +1 -0
  105. package/src/lib/Icon/icons/32x32/index.ts +179 -0
  106. package/src/lib/Icon/icons/32x32/svg/address_book.svg +1 -0
  107. package/src/lib/Icon/icons/32x32/svg/baby_toy.svg +1 -0
  108. package/src/lib/Icon/icons/32x32/svg/bicycle.svg +1 -0
  109. package/src/lib/Icon/icons/32x32/svg/bookmark.svg +1 -0
  110. package/src/lib/Icon/icons/32x32/svg/books.svg +1 -0
  111. package/src/lib/Icon/icons/32x32/svg/bubble_heart_filled.svg +1 -0
  112. package/src/lib/Icon/icons/32x32/svg/bubble_heart_outline.svg +1 -0
  113. package/src/lib/Icon/icons/32x32/svg/buildings.svg +1 -0
  114. package/src/lib/Icon/icons/32x32/svg/burger_menu.svg +1 -0
  115. package/src/lib/Icon/icons/32x32/svg/business.svg +1 -0
  116. package/src/lib/Icon/icons/32x32/svg/business_profile.svg +1 -0
  117. package/src/lib/Icon/icons/32x32/svg/camera.svg +1 -0
  118. package/src/lib/Icon/icons/32x32/svg/camera_crossed.svg +1 -0
  119. package/src/lib/Icon/icons/32x32/svg/car.svg +1 -0
  120. package/src/lib/Icon/icons/32x32/svg/carrot.svg +1 -0
  121. package/src/lib/Icon/icons/32x32/svg/chat.svg +1 -0
  122. package/src/lib/Icon/icons/32x32/svg/checkmark_circle.svg +1 -0
  123. package/src/lib/Icon/icons/32x32/svg/christmas_tree.svg +1 -0
  124. package/src/lib/Icon/icons/32x32/svg/clipboard.svg +1 -0
  125. package/src/lib/Icon/icons/32x32/svg/clothing.svg +1 -0
  126. package/src/lib/Icon/icons/32x32/svg/cocktail.svg +1 -0
  127. package/src/lib/Icon/icons/32x32/svg/comment_bubble.svg +1 -0
  128. package/src/lib/Icon/icons/32x32/svg/compass.svg +1 -0
  129. package/src/lib/Icon/icons/32x32/svg/computer.svg +1 -0
  130. package/src/lib/Icon/icons/32x32/svg/couch.svg +1 -0
  131. package/src/lib/Icon/icons/32x32/svg/credit_card.svg +1 -0
  132. package/src/lib/Icon/icons/32x32/svg/cross_circle.svg +1 -0
  133. package/src/lib/Icon/icons/32x32/svg/cutlery.svg +1 -0
  134. package/src/lib/Icon/icons/32x32/svg/drill_tool.svg +1 -0
  135. package/src/lib/Icon/icons/32x32/svg/email.svg +1 -0
  136. package/src/lib/Icon/icons/32x32/svg/envelope.svg +1 -0
  137. package/src/lib/Icon/icons/32x32/svg/event_calendar_check.svg +1 -0
  138. package/src/lib/Icon/icons/32x32/svg/event_calendar_date.svg +1 -0
  139. package/src/lib/Icon/icons/32x32/svg/event_calendar_plus.svg +1 -0
  140. package/src/lib/Icon/icons/32x32/svg/exchange.svg +1 -0
  141. package/src/lib/Icon/icons/32x32/svg/eye.svg +1 -0
  142. package/src/lib/Icon/icons/32x32/svg/eye_crossed.svg +1 -0
  143. package/src/lib/Icon/icons/32x32/svg/gift.svg +1 -0
  144. package/src/lib/Icon/icons/32x32/svg/group.svg +1 -0
  145. package/src/lib/Icon/icons/32x32/svg/healthcare.svg +1 -0
  146. package/src/lib/Icon/icons/32x32/svg/heart.svg +1 -0
  147. package/src/lib/Icon/icons/32x32/svg/house.svg +1 -0
  148. package/src/lib/Icon/icons/32x32/svg/image.svg +1 -0
  149. package/src/lib/Icon/icons/32x32/svg/info.svg +1 -0
  150. package/src/lib/Icon/icons/32x32/svg/invite_neighbour.svg +1 -0
  151. package/src/lib/Icon/icons/32x32/svg/key.svg +1 -0
  152. package/src/lib/Icon/icons/32x32/svg/kitchen_pot.svg +1 -0
  153. package/src/lib/Icon/icons/32x32/svg/list.svg +1 -0
  154. package/src/lib/Icon/icons/32x32/svg/log_out.svg +1 -0
  155. package/src/lib/Icon/icons/32x32/svg/loudspeaker.svg +1 -0
  156. package/src/lib/Icon/icons/32x32/svg/map.svg +1 -0
  157. package/src/lib/Icon/icons/32x32/svg/marketplace.svg +1 -0
  158. package/src/lib/Icon/icons/32x32/svg/miscellaneous_other.svg +1 -0
  159. package/src/lib/Icon/icons/32x32/svg/more_dots.svg +1 -0
  160. package/src/lib/Icon/icons/32x32/svg/more_dots_alt.svg +1 -0
  161. package/src/lib/Icon/icons/32x32/svg/music.svg +1 -0
  162. package/src/lib/Icon/icons/32x32/svg/nebenan.de.svg +1 -0
  163. package/src/lib/Icon/icons/32x32/svg/neighbour.svg +1 -0
  164. package/src/lib/Icon/icons/32x32/svg/notification_bell.svg +1 -0
  165. package/src/lib/Icon/icons/32x32/svg/organisation.svg +1 -0
  166. package/src/lib/Icon/icons/32x32/svg/paper_form_empty.svg +1 -0
  167. package/src/lib/Icon/icons/32x32/svg/paper_form_filled.svg +1 -0
  168. package/src/lib/Icon/icons/32x32/svg/paperclip.svg +1 -0
  169. package/src/lib/Icon/icons/32x32/svg/paw.svg +1 -0
  170. package/src/lib/Icon/icons/32x32/svg/pencil.svg +1 -0
  171. package/src/lib/Icon/icons/32x32/svg/pin.svg +1 -0
  172. package/src/lib/Icon/icons/32x32/svg/pins.svg +1 -0
  173. package/src/lib/Icon/icons/32x32/svg/plant.svg +1 -0
  174. package/src/lib/Icon/icons/32x32/svg/plus.svg +1 -0
  175. package/src/lib/Icon/icons/32x32/svg/plus_circle.svg +1 -0
  176. package/src/lib/Icon/icons/32x32/svg/post.svg +1 -0
  177. package/src/lib/Icon/icons/32x32/svg/privacy_lock.svg +1 -0
  178. package/src/lib/Icon/icons/32x32/svg/qr_code.svg +1 -0
  179. package/src/lib/Icon/icons/32x32/svg/search.svg +1 -0
  180. package/src/lib/Icon/icons/32x32/svg/settings_cog.svg +1 -0
  181. package/src/lib/Icon/icons/32x32/svg/shopping_bag.svg +1 -0
  182. package/src/lib/Icon/icons/32x32/svg/shopping_cart.svg +1 -0
  183. package/src/lib/Icon/icons/32x32/svg/special_place.svg +1 -0
  184. package/src/lib/Icon/icons/32x32/svg/suitcase.svg +1 -0
  185. package/src/lib/Icon/icons/32x32/svg/supporter.svg +1 -0
  186. package/src/lib/Icon/icons/32x32/svg/tennis_ball.svg +1 -0
  187. package/src/lib/Icon/icons/32x32/svg/thanks.svg +1 -0
  188. package/src/lib/Icon/icons/32x32/svg/trash_can.svg +1 -0
  189. package/src/lib/Icon/icons/32x32/svg/truck.svg +1 -0
  190. package/src/lib/Icon/icons/32x32/svg/user.svg +1 -0
  191. package/src/lib/Icon/icons/32x32/svg/user_profile.svg +1 -0
  192. package/src/lib/Icon/icons/32x32/svg/wellness.svg +1 -0
  193. package/src/lib/Icon/icons/index.ts +9 -0
  194. package/src/lib/IconButton/IconButton.module.scss +36 -0
  195. package/src/lib/IconButton/IconButton.spec.tsx +56 -0
  196. package/src/lib/IconButton/IconButton.stories.tsx +36 -0
  197. package/src/lib/IconButton/IconButton.tsx +25 -0
  198. package/{lib/IconButton/IconButton.types.d.ts → src/lib/IconButton/IconButton.types.ts} +10 -10
  199. package/src/lib/IconButton/utils.ts +6 -0
  200. package/src/lib/Image/Image.spec.tsx +10 -0
  201. package/src/lib/Image/Image.tsx +7 -0
  202. package/src/lib/Image/Image.type.tsx +5 -0
  203. package/src/lib/LabelPill/LabelPill.module.scss +33 -0
  204. package/src/lib/LabelPill/LabelPill.spec.tsx +23 -0
  205. package/src/lib/LabelPill/LabelPill.stories.tsx +31 -0
  206. package/src/lib/LabelPill/LabelPill.tsx +16 -0
  207. package/src/lib/LabelPill/LabelPill.types.ts +4 -0
  208. package/src/lib/Legend/Legend.module.scss +9 -0
  209. package/src/lib/Legend/Legend.spec.tsx +39 -0
  210. package/src/lib/Legend/Legend.stories.ts +39 -0
  211. package/src/lib/Legend/Legend.tsx +19 -0
  212. package/src/lib/Legend/Legend.types.ts +5 -0
  213. package/src/lib/MenuItem/MenuItem.module.scss +70 -0
  214. package/src/lib/MenuItem/MenuItem.spec.tsx +47 -0
  215. package/src/lib/MenuItem/MenuItem.stories.tsx +97 -0
  216. package/src/lib/MenuItem/MenuItem.tsx +34 -0
  217. package/src/lib/MenuItem/MenuItem.types.ts +10 -0
  218. package/src/lib/NotificationBubble/NotificationBubble.module.scss +30 -0
  219. package/src/lib/NotificationBubble/NotificationBubble.spec.tsx +36 -0
  220. package/src/lib/NotificationBubble/NotificationBubble.stories.tsx +56 -0
  221. package/src/lib/NotificationBubble/NotificationBubble.tsx +34 -0
  222. package/{lib/NotificationBubble/NotificationBubble.types.d.ts → src/lib/NotificationBubble/NotificationBubble.types.tsx} +3 -2
  223. package/src/lib/Thumbnail/Thumbnail.module.scss +67 -0
  224. package/src/lib/Thumbnail/Thumbnail.spec.tsx +51 -0
  225. package/src/lib/Thumbnail/Thumbnail.stories.tsx +242 -0
  226. package/src/lib/Thumbnail/Thumbnail.tsx +28 -0
  227. package/src/lib/Thumbnail/Thumbnail.type.tsx +18 -0
  228. package/src/lib/Toggle/Toggle.module.scss +53 -0
  229. package/src/lib/Toggle/Toggle.spec.tsx +23 -0
  230. package/src/lib/Toggle/Toggle.stories.tsx +38 -0
  231. package/src/lib/Toggle/Toggle.tsx +32 -0
  232. package/{lib/Toggle/Toggle.types.d.ts → src/lib/Toggle/Toggle.types.ts} +3 -2
  233. package/src/lib/ToggleInput/ToggleInput.module.scss +33 -0
  234. package/src/lib/ToggleInput/ToggleInput.spec.tsx +45 -0
  235. package/src/lib/ToggleInput/ToggleInput.stories.tsx +62 -0
  236. package/src/lib/ToggleInput/ToggleInput.tsx +40 -0
  237. package/{lib/ToggleInput/ToggleInput.types.d.ts → src/lib/ToggleInput/ToggleInput.types.ts} +5 -3
  238. package/src/lib/Typography/Typography.module.scss +61 -0
  239. package/src/lib/Typography/Typography.spec.tsx +60 -0
  240. package/src/lib/Typography/Typography.stories.tsx +45 -0
  241. package/src/lib/Typography/Typography.tsx +26 -0
  242. package/src/lib/Typography/Typography.types.ts +28 -0
  243. package/src/styles/_design-tokens.scss +1 -0
  244. package/src/styles/_fonts.scss +0 -0
  245. package/src/styles/_functions.scss +17 -0
  246. package/src/styles/_mixins.scss +33 -0
  247. package/src/styles/index.scss +3 -0
  248. package/src/styles/reset.scss +65 -0
  249. package/tsconfig.json +24 -0
  250. package/tsconfig.lib.json +35 -0
  251. package/tsconfig.spec.json +20 -0
  252. package/tsconfig.storybook.json +31 -0
  253. package/vite.config.ts +57 -0
  254. package/index.js +0 -93
  255. package/index.mjs +0 -4258
  256. package/lib/BaseButton/BaseButton.d.ts +0 -11
  257. package/lib/Card/Card.d.ts +0 -3
  258. package/lib/Card/Card.types.d.ts +0 -10
  259. package/lib/Card/Card.utils.d.ts +0 -3
  260. package/lib/Card/CardBody/CardBody.d.ts +0 -3
  261. package/lib/Card/CardBody/CardBody.types.d.ts +0 -5
  262. package/lib/Card/CardHeader/CardHeader.d.ts +0 -3
  263. package/lib/Card/CardHeader/CardHeader.type.d.ts +0 -10
  264. package/lib/ContentCreatorButton/ContentCreatorButton.d.ts +0 -3
  265. package/lib/Divider/Divider.d.ts +0 -3
  266. package/lib/Divider/Divider.types.d.ts +0 -6
  267. package/lib/Fieldset/Fieldset.d.ts +0 -3
  268. package/lib/Fieldset/Fieldset.types.d.ts +0 -8
  269. package/lib/Form/Form.d.ts +0 -3
  270. package/lib/Form/Form.types.d.ts +0 -10
  271. package/lib/Icon/Icon.d.ts +0 -4
  272. package/lib/Icon/Icon.types.d.ts +0 -18
  273. package/lib/Icon/icons/24x24/index.d.ts +0 -130
  274. package/lib/Icon/icons/32x32/index.d.ts +0 -265
  275. package/lib/Icon/icons/index.d.ts +0 -395
  276. package/lib/IconButton/IconButton.d.ts +0 -3
  277. package/lib/IconButton/utils.d.ts +0 -3
  278. package/lib/Image/Image.d.ts +0 -3
  279. package/lib/Image/Image.type.d.ts +0 -5
  280. package/lib/LabelPill/LabelPill.d.ts +0 -3
  281. package/lib/LabelPill/LabelPill.types.d.ts +0 -4
  282. package/lib/Legend/Legend.d.ts +0 -3
  283. package/lib/Legend/Legend.types.d.ts +0 -5
  284. package/lib/MenuItem/MenuItem.d.ts +0 -3
  285. package/lib/MenuItem/MenuItem.types.d.ts +0 -9
  286. package/lib/NotificationBubble/NotificationBubble.d.ts +0 -3
  287. package/lib/Toggle/Toggle.d.ts +0 -3
  288. package/lib/ToggleInput/ToggleInput.d.ts +0 -3
  289. package/lib/Typography/Typography.d.ts +0 -3
  290. package/lib/Typography/Typography.types.d.ts +0 -8
  291. package/style.css +0 -1
@@ -0,0 +1,51 @@
1
+ import React from 'react';
2
+
3
+ import { filterAllowedElements, findAllowedElement } from './Card.utils';
4
+
5
+ describe('findAllowedElement', () => {
6
+ it('should find an allowed element among children', () => {
7
+ const children = [<div key="1" />, <React.Fragment key="2" />, <span key="3" />];
8
+ const result = findAllowedElement(children, React.Fragment);
9
+ expect(result).toBeDefined();
10
+ expect((result as React.ReactElement).type).toBe(React.Fragment);
11
+ });
12
+
13
+ it('should return undefined if no allowed elements are found', () => {
14
+ const children = [<div key={0} />, <span key={1} />];
15
+ expect(findAllowedElement(children, React.Fragment)).toBeUndefined();
16
+ expect(findAllowedElement(null, React.Fragment)).toBeUndefined();
17
+ expect(findAllowedElement(undefined, React.Fragment)).toBeUndefined();
18
+ });
19
+ });
20
+
21
+ describe('filterAllowedElements', () => {
22
+ let originalEnv: typeof process.env;
23
+
24
+ beforeEach(() => {
25
+ originalEnv = { ...process.env };
26
+ });
27
+
28
+ afterEach(() => {
29
+ process.env = originalEnv; // Restore original environment variables
30
+ jest.restoreAllMocks(); // Restore all mocks
31
+ });
32
+
33
+ it('should filter out disallowed elements', () => {
34
+ const children = [
35
+ <div key="1" />,
36
+ <React.Fragment key="2">Child</React.Fragment>,
37
+ <span key="3" />,
38
+ ];
39
+ const allowedElements = [React.Fragment];
40
+ const result = filterAllowedElements(children, allowedElements);
41
+ expect(result.length).toBe(1);
42
+ expect((result[0] as React.ReactElement).type).toBe(React.Fragment);
43
+ });
44
+
45
+ it('should return an empty array if no allowed elements are present', () => {
46
+ const children = [<div key={0} />, <span key={1} />];
47
+ const allowedElements = [React.Fragment];
48
+ const result = filterAllowedElements(children, allowedElements);
49
+ expect(result.length).toBe(0);
50
+ });
51
+ });
@@ -0,0 +1,23 @@
1
+ import React from 'react';
2
+
3
+ const isAllowedElement = (
4
+ element: React.ReactNode,
5
+ allowedElementsList: React.ElementType[],
6
+ ): boolean =>
7
+ React.isValidElement(element) &&
8
+ typeof element.type !== 'string' &&
9
+ allowedElementsList.includes(element.type);
10
+
11
+ export const findAllowedElement = (
12
+ elements: React.ReactNode,
13
+ type: React.ElementType,
14
+ ): React.ReactNode =>
15
+ React.Children.toArray(elements).find((el) => isAllowedElement(el, [type]));
16
+
17
+ export const filterAllowedElements = (
18
+ elements: React.ReactNode,
19
+ allowedElements: React.ElementType[],
20
+ ): React.ReactNode[] =>
21
+ React.Children.toArray(elements).filter((el) => {
22
+ return isAllowedElement(el, allowedElements);
23
+ });
@@ -0,0 +1,4 @@
1
+ .root {
2
+ padding: getSpacing('sm') 0;
3
+ color: inherit;
4
+ }
@@ -0,0 +1,15 @@
1
+ import '@testing-library/jest-dom';
2
+ import { render } from '@testing-library/react';
3
+
4
+ import CardBody from './CardBody';
5
+
6
+ describe('CardBody', () => {
7
+ it('should render successfully', () => {
8
+ const { baseElement } = render(
9
+ <CardBody>
10
+ <p>render successfully</p>
11
+ </CardBody>,
12
+ );
13
+ expect(baseElement).toBeTruthy();
14
+ });
15
+ });
@@ -0,0 +1,108 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+
3
+ import CardBody from './CardBody';
4
+
5
+ const meta: Meta<typeof CardBody> = {
6
+ component: CardBody,
7
+ title: 'Components/Card/CardBody',
8
+ };
9
+ export default meta;
10
+ type Story = StoryObj<typeof CardBody>;
11
+
12
+ const CardBodyComponent = () => {
13
+ return (
14
+ <>
15
+ <CardBody>
16
+ <p
17
+ style={{
18
+ color: '#201649',
19
+ fontFamily: 'sans-serif',
20
+ fontSize: '14px',
21
+ marginBottom: '16px',
22
+ }}
23
+ >
24
+ Warum hältst du den Inhalt für problematisch?
25
+ </p>
26
+ <div
27
+ style={{
28
+ border: 'solid 1px #A6A2B6',
29
+ borderRadius: '16px',
30
+ fontFamily: 'sans-serif',
31
+ padding: '16px',
32
+ }}
33
+ >
34
+ <p
35
+ style={{
36
+ color: '#201649',
37
+ fontFamily: 'sans-serif',
38
+ fontSize: '16px',
39
+ fontWeight: 500,
40
+ }}
41
+ >
42
+ Haustiere & Zubehör
43
+ </p>
44
+ </div>
45
+ </CardBody>
46
+ <CardBody>
47
+ <p
48
+ style={{
49
+ color: '#635C80',
50
+ fontFamily: 'sans-serif',
51
+ fontSize: '12px',
52
+ fontWeight: 500,
53
+ lineHeight: '16px',
54
+ }}
55
+ >
56
+ Mit Klick auf &quot;Absenden&quot; bestätigst du, in gutem Glauben davon
57
+ überzeugt zu sein, dass die in der Meldung enthaltenen Angaben und Anführungen
58
+ richtig und vollständig sind.
59
+ </p>
60
+ <p
61
+ style={{
62
+ color: '#635C80',
63
+ fontFamily: 'sans-serif',
64
+ fontSize: '12px',
65
+ fontWeight: 500,
66
+ lineHeight: '16px',
67
+ }}
68
+ >
69
+ Weitere Informationen zum Meldeprozess und Beschwerdegründen in den{' '}
70
+ <span
71
+ style={{
72
+ color: '#01819C',
73
+ fontFamily: 'sans-serif',
74
+ fontWeight: 700,
75
+ }}
76
+ >
77
+ Beitragsrichtlinien
78
+ </span>{' '}
79
+ und zur Verarbeitung personenbezogener Daten in den{' '}
80
+ <span
81
+ style={{
82
+ color: '#01819C',
83
+ fontFamily: 'sans-serif',
84
+ fontWeight: 700,
85
+ }}
86
+ >
87
+ Datenschutzbestimmungen
88
+ </span>
89
+ .
90
+ </p>
91
+ </CardBody>
92
+ </>
93
+ );
94
+ };
95
+
96
+ export const Primary: Story = {
97
+ argTypes: {
98
+ children: {
99
+ control: { readonly: true, type: 'string' },
100
+ description: `"children" prop is a versatile way to include various components and content within the CardBody, allowing you to customize and structure the content according to your needs.`,
101
+ },
102
+ className: {
103
+ control: { readonly: true, type: 'string' },
104
+ description: `"className" prop used to assign one or more CSS class names to the HTML element.`,
105
+ },
106
+ },
107
+ render: () => CardBodyComponent(),
108
+ };
@@ -0,0 +1,9 @@
1
+ import clsx from 'clsx';
2
+
3
+ import styles from './CardBody.module.scss';
4
+ import { CardBodyProps } from './CardBody.types';
5
+
6
+ const CardBody = ({ children, className }: CardBodyProps) => (
7
+ <div className={clsx(styles.root, className)}>{children}</div>
8
+ );
9
+ export default CardBody;
@@ -0,0 +1,4 @@
1
+ export interface CardBodyProps {
2
+ children: React.ReactNode;
3
+ className?: string;
4
+ }
@@ -0,0 +1,12 @@
1
+ .root {
2
+ display: flex;
3
+ align-items: center;
4
+ padding-bottom: getSpacing('md');
5
+ color: inherit;
6
+ gap: getSpacing('sm');
7
+ }
8
+
9
+ .title {
10
+ flex-grow: 1;
11
+ margin: 0;
12
+ }
@@ -0,0 +1,72 @@
1
+ import '@testing-library/jest-dom';
2
+ import { render, screen } from '@testing-library/react';
3
+
4
+ import { BaseButton, Icon } from '@goodhood-web/ui';
5
+
6
+ import CardHeader from './CardHeader';
7
+
8
+ describe('CardHeader', () => {
9
+ it('renders headline with default heading type', () => {
10
+ render(<CardHeader headline="Test Headline" />);
11
+ const heading = screen.getByRole('heading', { name: 'Test Headline' });
12
+ expect(heading).toBeInTheDocument();
13
+ expect(heading.tagName).toBe('H3');
14
+ expect(heading).toHaveTextContent('Test Headline');
15
+ });
16
+
17
+ it('renders left and right elements when provided', () => {
18
+ const leftElement = <Icon name="arrow_left" size="24" />;
19
+ const rightElement = (
20
+ <BaseButton
21
+ onClick={() => {
22
+ console.log('Right button clicked');
23
+ }}
24
+ >
25
+ Right Button
26
+ </BaseButton>
27
+ );
28
+
29
+ render(
30
+ <CardHeader
31
+ headline="Test Headline"
32
+ leftElement={leftElement}
33
+ rightElement={rightElement}
34
+ />,
35
+ );
36
+
37
+ expect(screen.getByRole('presentation')).toBeInTheDocument();
38
+ expect(screen.getByRole('button', { name: 'Right Button' })).toBeInTheDocument();
39
+ });
40
+
41
+ it('does not render left or right elements if they are not allowed', () => {
42
+ const leftElement = <div>Unallowed Element</div>;
43
+ const rightElement = <span>Another Unallowed Element</span>;
44
+
45
+ render(
46
+ <CardHeader
47
+ headline="Test Headline"
48
+ leftElement={leftElement}
49
+ rightElement={rightElement}
50
+ />,
51
+ );
52
+
53
+ expect(screen.queryByText('Unallowed Element')).not.toBeInTheDocument();
54
+ expect(screen.queryByText('Another Unallowed Element')).not.toBeInTheDocument();
55
+ });
56
+
57
+ it('does not render elements that are not specified as allowed', () => {
58
+ const leftElement = <div data-testid="unallowed-left">Unallowed Left</div>;
59
+ const rightElement = <div data-testid="unallowed-right">Unallowed Right</div>;
60
+
61
+ render(
62
+ <CardHeader
63
+ headline="No Unallowed Elements"
64
+ leftElement={leftElement}
65
+ rightElement={rightElement}
66
+ />,
67
+ );
68
+
69
+ expect(screen.queryByTestId('unallowed-left')).not.toBeInTheDocument();
70
+ expect(screen.queryByTestId('unallowed-right')).not.toBeInTheDocument();
71
+ });
72
+ });
@@ -0,0 +1,77 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+
3
+ import { BaseButton, Icon } from '@goodhood-web/ui';
4
+
5
+ import CardHeader from './CardHeader';
6
+
7
+ const meta: Meta<typeof CardHeader> = {
8
+ component: CardHeader,
9
+ title: 'Components/Card/CardHeader',
10
+ };
11
+ export default meta;
12
+ type Story = StoryObj<typeof CardHeader>;
13
+
14
+ const typesOptions = [
15
+ 'h2',
16
+ 'h3',
17
+ 'h4',
18
+ 'h5',
19
+ 'h6',
20
+ 'h7',
21
+ 'h8',
22
+ 'body-large',
23
+ 'body-regular',
24
+ 'body-semibold',
25
+ 'body-italic',
26
+ 'detail-medium',
27
+ 'detail-bold',
28
+ 'detail-upper-case',
29
+ ];
30
+
31
+ const asOptions = ['h2', 'h3', 'h4', 'h5', 'h6', 'h7', 'h8'];
32
+
33
+ export const Primary: Story = {
34
+ argTypes: {
35
+ as: {
36
+ control: { type: 'select' },
37
+ defaultValue: { summary: 'h3' },
38
+ description: `'headerAs': An optional prop to specify the HTML tag (element) to be used for the header. If not provided, it defaults to the 'h3' specified in the type prop.`,
39
+ options: asOptions,
40
+ },
41
+ headline: {
42
+ defaultValue: { summary: '""' },
43
+ description: `'headline': This is the main text content of the header.`,
44
+ },
45
+ leftElement: {
46
+ control: { readonly: true, type: 'string' },
47
+ defaultValue: { summary: 'undefined' },
48
+ description: `'leftElement': prop in the CardHeader component can accept components, such as Icon and IconButton.`,
49
+ },
50
+ rightElement: {
51
+ control: { readonly: true, type: 'string' },
52
+ defaultValue: { summary: 'undefined' },
53
+ description: `'rightElement' props in the CardHeader component can accept components, such as Button.`,
54
+ },
55
+
56
+ type: {
57
+ control: { type: 'select' },
58
+ defaultValue: { summary: 'h3' },
59
+ description: `'type': A string that specifies the type of the headline (default is 'h3').`,
60
+ options: typesOptions,
61
+ },
62
+ },
63
+ args: {
64
+ as: 'h3',
65
+ headline: 'Headline',
66
+ leftElement: <Icon name="chevron_left" size="24" />,
67
+ rightElement: <BaseButton onClick={() => console.log('clicked')}>Action</BaseButton>,
68
+ type: 'h2',
69
+ },
70
+
71
+ parameters: {
72
+ design: {
73
+ type: 'figma',
74
+ url: 'https://www.figma.com/file/hN7xJ3rRAemUJT9T0uEfUS/Product-Design-System?node-id=6105%3A12944&mode=dev',
75
+ },
76
+ },
77
+ };
@@ -0,0 +1,29 @@
1
+ import { BaseButton, Icon, Typography } from '@goodhood-web/ui';
2
+
3
+ import { filterAllowedElements } from '../Card.utils';
4
+
5
+ import styles from './CardHeader.module.scss';
6
+ import { CardHeaderProps } from './CardHeader.type';
7
+
8
+ const CardHeader = ({
9
+ as,
10
+ headline,
11
+ leftElement,
12
+ rightElement,
13
+ type = 'h3',
14
+ }: CardHeaderProps) => {
15
+ const currentLeftElement = filterAllowedElements(leftElement, [Icon, BaseButton]);
16
+ const currentRightElement = filterAllowedElements(rightElement, [BaseButton]);
17
+
18
+ return (
19
+ <header className={styles.root}>
20
+ {currentLeftElement && currentLeftElement}
21
+ <Typography type={type} as={as} className={styles.title}>
22
+ {headline}
23
+ </Typography>
24
+ {currentRightElement && currentRightElement}
25
+ </header>
26
+ );
27
+ };
28
+
29
+ export default CardHeader;
@@ -0,0 +1,14 @@
1
+ import { ComponentProps, ReactElement } from 'react';
2
+
3
+ import { BaseButton, Icon } from '@goodhood-web/ui';
4
+
5
+ import { TypographyProps } from '../../Typography/Typography.types';
6
+
7
+ export type CardHeaderProps = {
8
+ as?: Exclude<TypographyProps['as'], 'h1' | 'p' | 'span'>;
9
+ headline: string;
10
+ // TODO Update to IconButton when it's ready
11
+ leftElement?: ReactElement<ComponentProps<typeof Icon | typeof BaseButton>>;
12
+ rightElement?: ReactElement<ComponentProps<typeof BaseButton>>;
13
+ type?: Exclude<TypographyProps['type'], 'h1'>;
14
+ };
@@ -0,0 +1,13 @@
1
+ .ccBtn {
2
+ display: flex;
3
+ height: 40px;
4
+ align-items: center;
5
+ align-self: stretch;
6
+ padding: getSpacing('sm') getSpacing('lg');
7
+ border-color: transparent;
8
+ border-radius: mapGet($tokens, borderRadius, md);
9
+ background-color: getSemanticColor('surface', 'surfaceContainer');
10
+ color: getSemanticColor('surface', 'onSurface');
11
+ cursor: pointer;
12
+ font-size: 14px;
13
+ }
@@ -0,0 +1,14 @@
1
+ import { render } from '@testing-library/react';
2
+
3
+ import ContentCreatorButton from './ContentCreatorButton';
4
+
5
+ describe('ContentCreatorButton', () => {
6
+ it('should render successfully', () => {
7
+ const { baseElement } = render(
8
+ <ContentCreatorButton onClick={() => console.log('clicked')}>
9
+ Render successfully
10
+ </ContentCreatorButton>,
11
+ );
12
+ expect(baseElement).toBeTruthy();
13
+ });
14
+ });
@@ -0,0 +1,29 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+
3
+ import ContentCreatorButton from './ContentCreatorButton';
4
+
5
+ const meta: Meta<typeof ContentCreatorButton> = {
6
+ argTypes: {
7
+ children: {
8
+ control: 'text',
9
+ description: 'Text on the button',
10
+ },
11
+ onClick: { action: 'clicked', description: 'On click event callback' },
12
+ },
13
+ component: ContentCreatorButton,
14
+ title: 'Components/ContentCreatorButton',
15
+ };
16
+ export default meta;
17
+ type Story = StoryObj<typeof ContentCreatorButton>;
18
+
19
+ export const Primary: Story = {
20
+ args: {
21
+ children: 'Neuen Beitrag erstellen',
22
+ },
23
+ parameters: {
24
+ design: {
25
+ type: 'figma',
26
+ url: 'https://www.figma.com/file/hN7xJ3rRAemUJT9T0uEfUS/Product-Design-System?node-id=397%3A6149',
27
+ },
28
+ },
29
+ };
@@ -0,0 +1,35 @@
1
+ import { useButton } from '@mui/base';
2
+ import clsx from 'clsx';
3
+
4
+ import BaseButton from '../BaseButton/BaseButton';
5
+ import Typography from '../Typography/Typography';
6
+
7
+ import styles from './ContentCreatorButton.module.scss';
8
+ import { ContentCreatorButtonProps } from './ContentCreatorButton.types';
9
+
10
+ const ContentCreatorButton = ({
11
+ children,
12
+ onClick,
13
+ ...baseButtonProps
14
+ }: ContentCreatorButtonProps) => {
15
+ const { active, focusVisible } = useButton();
16
+
17
+ const classes = {
18
+ [styles['ccBtn--active']]: active,
19
+ [styles['ccBtn--focusVisible']]: focusVisible,
20
+ };
21
+
22
+ return (
23
+ <BaseButton
24
+ {...baseButtonProps}
25
+ className={clsx(styles.ccBtn, classes)}
26
+ onClick={onClick}
27
+ >
28
+ <Typography type="body-regular" as="span">
29
+ {children}
30
+ </Typography>
31
+ </BaseButton>
32
+ );
33
+ };
34
+
35
+ export default ContentCreatorButton;
@@ -1,5 +1,6 @@
1
1
  import { BaseButtonProps } from '../BaseButton/BaseButton';
2
+
2
3
  export interface ContentCreatorButtonProps extends BaseButtonProps {
3
- children: string;
4
- onClick: () => void;
4
+ children: string;
5
+ onClick: () => void;
5
6
  }
@@ -0,0 +1,10 @@
1
+ .dividerContainer {
2
+ display: flex;
3
+ align-items: center;
4
+ }
5
+
6
+ .dividerLine {
7
+ height: 1px;
8
+ flex-grow: 1;
9
+ background-color: getSemanticColor('outline', 'outlineVariant');
10
+ }
@@ -0,0 +1,46 @@
1
+ import { render, screen } from '@testing-library/react';
2
+
3
+ import Divider from './Divider';
4
+
5
+ describe('Divider', () => {
6
+ it('should render with default full width', () => {
7
+ const { container } = render(<Divider />);
8
+
9
+ const dividerLine = container.querySelector('.dividerLine');
10
+
11
+ expect(dividerLine).not.toBeNull();
12
+ expect(dividerLine?.getAttribute('style')).toBe(
13
+ 'margin-left: 0px; margin-right: 0px;',
14
+ );
15
+ });
16
+
17
+ it('should render with 8 offset on the left', () => {
18
+ const { container } = render(<Divider offsetLeft={8} />);
19
+
20
+ const dividerLine = container.querySelector('.dividerLine');
21
+
22
+ expect(dividerLine).not.toBeNull();
23
+ expect(dividerLine?.getAttribute('style')).toBe(
24
+ 'margin-left: 8px; margin-right: 0px;',
25
+ );
26
+ });
27
+
28
+ it('should render with 16 offset on the right', () => {
29
+ const { container } = render(<Divider offsetRight={16} />);
30
+
31
+ const dividerLine = container.querySelector('.dividerLine');
32
+
33
+ expect(dividerLine).not.toBeNull();
34
+ expect(dividerLine?.getAttribute('style')).toBe(
35
+ 'margin-left: 0px; margin-right: 16px;',
36
+ );
37
+ });
38
+
39
+ it('should render with role "separator"', () => {
40
+ render(<Divider />);
41
+
42
+ const divider = screen.getByRole('separator');
43
+
44
+ expect(divider).toBeVisible();
45
+ });
46
+ });
@@ -0,0 +1,35 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+
3
+ import Divider from './Divider';
4
+
5
+ const meta: Meta<typeof Divider> = {
6
+ argTypes: {
7
+ offsetLeft: {
8
+ control: { type: 'select' },
9
+ options: [0, 8, 16],
10
+ },
11
+ offsetRight: {
12
+ control: { type: 'select' },
13
+ options: [0, 8, 16],
14
+ },
15
+ },
16
+ component: Divider,
17
+ title: 'Components/Divider',
18
+ };
19
+
20
+ export default meta;
21
+
22
+ type Story = StoryObj<typeof Divider>;
23
+
24
+ export const Primary: Story = {
25
+ args: {
26
+ offsetLeft: 0,
27
+ offsetRight: 0,
28
+ },
29
+ parameters: {
30
+ design: {
31
+ type: 'figma',
32
+ url: 'https://www.figma.com/file/hN7xJ3rRAemUJT9T0uEfUS/Product-Design-System?node-id=231%3A3089&mode=dev',
33
+ },
34
+ },
35
+ };
@@ -0,0 +1,17 @@
1
+ import styles from './Divider.module.scss';
2
+ import { DividerProps } from './Divider.types';
3
+
4
+ const Divider = ({ offsetLeft = 0, offsetRight = 0 }: DividerProps) => (
5
+ <div className={styles.dividerContainer}>
6
+ <div
7
+ className={styles.dividerLine}
8
+ style={{
9
+ marginLeft: `${offsetLeft}px`,
10
+ marginRight: `${offsetRight}px`,
11
+ }}
12
+ role="separator"
13
+ />
14
+ </div>
15
+ );
16
+
17
+ export default Divider;
@@ -0,0 +1,6 @@
1
+ type OffsetType = 0 | 8 | 16;
2
+
3
+ export interface DividerProps {
4
+ offsetLeft?: OffsetType;
5
+ offsetRight?: OffsetType;
6
+ }
@@ -0,0 +1,3 @@
1
+ .fieldset {
2
+ border: none;
3
+ }