@arbor-education/design-system.components 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (245) hide show
  1. package/README.md +1 -1
  2. package/dist/components/button/Button.d.ts +5 -2
  3. package/dist/components/button/Button.d.ts.map +1 -1
  4. package/dist/components/button/Button.js +3 -1
  5. package/dist/components/button/Button.js.map +1 -1
  6. package/dist/components/card/Card.d.ts +1 -2
  7. package/dist/components/card/Card.d.ts.map +1 -1
  8. package/dist/components/card/Card.js +3 -3
  9. package/dist/components/card/Card.js.map +1 -1
  10. package/dist/components/card/Card.test.js +0 -5
  11. package/dist/components/card/Card.test.js.map +1 -1
  12. package/dist/components/formField/FormField.d.ts +4 -0
  13. package/dist/components/formField/FormField.d.ts.map +1 -1
  14. package/dist/components/formField/FormField.js +2 -1
  15. package/dist/components/formField/FormField.js.map +1 -1
  16. package/dist/components/formField/FormField.stories.d.ts.map +1 -1
  17. package/dist/components/formField/FormField.stories.js +3 -1
  18. package/dist/components/formField/FormField.stories.js.map +1 -1
  19. package/dist/components/formField/FormField.test.js +5 -0
  20. package/dist/components/formField/FormField.test.js.map +1 -1
  21. package/dist/components/formField/inputs/checkbox/CheckboxInput.d.ts +7 -0
  22. package/dist/components/formField/inputs/checkbox/CheckboxInput.d.ts.map +1 -0
  23. package/dist/components/formField/inputs/checkbox/CheckboxInput.js +31 -0
  24. package/dist/components/formField/inputs/checkbox/CheckboxInput.js.map +1 -0
  25. package/dist/components/formField/inputs/checkbox/CheckboxInput.stories.d.ts +17 -0
  26. package/dist/components/formField/inputs/checkbox/CheckboxInput.stories.d.ts.map +1 -0
  27. package/dist/components/formField/inputs/checkbox/CheckboxInput.stories.js +19 -0
  28. package/dist/components/formField/inputs/checkbox/CheckboxInput.stories.js.map +1 -0
  29. package/dist/components/formField/inputs/checkbox/CheckboxInput.test.d.ts +2 -0
  30. package/dist/components/formField/inputs/checkbox/CheckboxInput.test.d.ts.map +1 -0
  31. package/dist/components/formField/inputs/checkbox/CheckboxInput.test.js +30 -0
  32. package/dist/components/formField/inputs/checkbox/CheckboxInput.test.js.map +1 -0
  33. package/dist/components/formField/inputs/dropdown/Dropdown.d.ts +11 -0
  34. package/dist/components/formField/inputs/dropdown/Dropdown.d.ts.map +1 -0
  35. package/dist/components/formField/inputs/dropdown/Dropdown.js +43 -0
  36. package/dist/components/formField/inputs/dropdown/Dropdown.js.map +1 -0
  37. package/dist/components/formField/inputs/dropdown/Dropdown.stories.d.ts +161 -0
  38. package/dist/components/formField/inputs/dropdown/Dropdown.stories.d.ts.map +1 -0
  39. package/dist/components/formField/inputs/dropdown/Dropdown.stories.js +172 -0
  40. package/dist/components/formField/inputs/dropdown/Dropdown.stories.js.map +1 -0
  41. package/dist/components/formField/inputs/dropdown/Dropdown.test.d.ts +2 -0
  42. package/dist/components/formField/inputs/dropdown/Dropdown.test.d.ts.map +1 -0
  43. package/dist/components/formField/inputs/dropdown/Dropdown.test.js +93 -0
  44. package/dist/components/formField/inputs/dropdown/Dropdown.test.js.map +1 -0
  45. package/dist/components/formField/inputs/dropdown/buttons/dropdownButton/DropdownButton.d.ts +11 -0
  46. package/dist/components/formField/inputs/dropdown/buttons/dropdownButton/DropdownButton.d.ts.map +1 -0
  47. package/dist/components/formField/inputs/dropdown/buttons/dropdownButton/DropdownButton.js +15 -0
  48. package/dist/components/formField/inputs/dropdown/buttons/dropdownButton/DropdownButton.js.map +1 -0
  49. package/dist/components/formField/inputs/dropdown/items/DropdownItemRenderer.d.ts +10 -0
  50. package/dist/components/formField/inputs/dropdown/items/DropdownItemRenderer.d.ts.map +1 -0
  51. package/dist/components/formField/inputs/dropdown/items/DropdownItemRenderer.js +12 -0
  52. package/dist/components/formField/inputs/dropdown/items/DropdownItemRenderer.js.map +1 -0
  53. package/dist/components/formField/inputs/dropdown/items/dropdownItem/DropdownItem.d.ts +9 -0
  54. package/dist/components/formField/inputs/dropdown/items/dropdownItem/DropdownItem.d.ts.map +1 -0
  55. package/dist/components/formField/inputs/dropdown/items/dropdownItem/DropdownItem.js +17 -0
  56. package/dist/components/formField/inputs/dropdown/items/dropdownItem/DropdownItem.js.map +1 -0
  57. package/dist/components/formField/inputs/dropdown/items/dropdownMultiLineItem/DropdownMultiLineItem.d.ts +7 -0
  58. package/dist/components/formField/inputs/dropdown/items/dropdownMultiLineItem/DropdownMultiLineItem.d.ts.map +1 -0
  59. package/dist/components/formField/inputs/dropdown/items/dropdownMultiLineItem/DropdownMultiLineItem.js +16 -0
  60. package/dist/components/formField/inputs/dropdown/items/dropdownMultiLineItem/DropdownMultiLineItem.js.map +1 -0
  61. package/dist/components/formField/inputs/dropdown/wrapper/DropdownWrapper.d.ts +16 -0
  62. package/dist/components/formField/inputs/dropdown/wrapper/DropdownWrapper.d.ts.map +1 -0
  63. package/dist/components/formField/inputs/dropdown/wrapper/DropdownWrapper.js +73 -0
  64. package/dist/components/formField/inputs/dropdown/wrapper/DropdownWrapper.js.map +1 -0
  65. package/dist/components/formField/inputs/number/NumberInput.d.ts +6 -0
  66. package/dist/components/formField/inputs/number/NumberInput.d.ts.map +1 -0
  67. package/dist/components/formField/inputs/number/NumberInput.js +39 -0
  68. package/dist/components/formField/inputs/number/NumberInput.js.map +1 -0
  69. package/dist/components/formField/inputs/number/NumberInput.stories.d.ts +20 -0
  70. package/dist/components/formField/inputs/number/NumberInput.stories.d.ts.map +1 -0
  71. package/dist/components/formField/inputs/number/NumberInput.stories.js +22 -0
  72. package/dist/components/formField/inputs/number/NumberInput.stories.js.map +1 -0
  73. package/dist/components/formField/inputs/number/NumberInput.test.d.ts +2 -0
  74. package/dist/components/formField/inputs/number/NumberInput.test.d.ts.map +1 -0
  75. package/dist/components/formField/inputs/number/NumberInput.test.js +30 -0
  76. package/dist/components/formField/inputs/number/NumberInput.test.js.map +1 -0
  77. package/dist/components/formField/inputs/radio/RadioButtonInput.d.ts +7 -0
  78. package/dist/components/formField/inputs/radio/RadioButtonInput.d.ts.map +1 -0
  79. package/dist/components/formField/inputs/radio/RadioButtonInput.js +9 -0
  80. package/dist/components/formField/inputs/radio/RadioButtonInput.js.map +1 -0
  81. package/dist/components/formField/inputs/radio/RadioButtonInput.stories.d.ts +46 -0
  82. package/dist/components/formField/inputs/radio/RadioButtonInput.stories.d.ts.map +1 -0
  83. package/dist/components/formField/inputs/radio/RadioButtonInput.stories.js +83 -0
  84. package/dist/components/formField/inputs/radio/RadioButtonInput.stories.js.map +1 -0
  85. package/dist/components/formField/inputs/radio/RadioButtonInput.test.d.ts +2 -0
  86. package/dist/components/formField/inputs/radio/RadioButtonInput.test.d.ts.map +1 -0
  87. package/dist/components/formField/inputs/radio/RadioButtonInput.test.js +34 -0
  88. package/dist/components/formField/inputs/radio/RadioButtonInput.test.js.map +1 -0
  89. package/dist/components/heading/Heading.d.ts +392 -388
  90. package/dist/components/heading/Heading.d.ts.map +1 -1
  91. package/dist/components/heading/Heading.js +8 -1
  92. package/dist/components/heading/Heading.js.map +1 -1
  93. package/dist/components/heading/Heading.stories.d.ts.map +1 -1
  94. package/dist/components/heading/Heading.stories.js +7 -8
  95. package/dist/components/heading/Heading.stories.js.map +1 -1
  96. package/dist/components/heading/HeadingInnerContainer.d.ts +2 -2
  97. package/dist/components/heading/HeadingInnerContainer.js +4 -4
  98. package/dist/components/icon/Icon.d.ts +2 -2
  99. package/dist/components/icon/Icon.d.ts.map +1 -1
  100. package/dist/components/icon/Icon.js.map +1 -1
  101. package/dist/components/icon/allowedIcons.d.ts +1 -0
  102. package/dist/components/icon/allowedIcons.d.ts.map +1 -1
  103. package/dist/components/section/Section.d.ts +18 -0
  104. package/dist/components/section/Section.d.ts.map +1 -0
  105. package/dist/components/section/Section.js +36 -0
  106. package/dist/components/section/Section.js.map +1 -0
  107. package/dist/components/section/Section.stories.d.ts +18 -0
  108. package/dist/components/section/Section.stories.d.ts.map +1 -0
  109. package/dist/components/section/Section.stories.js +27 -0
  110. package/dist/components/section/Section.stories.js.map +1 -0
  111. package/dist/components/section/Section.test.d.ts +2 -0
  112. package/dist/components/section/Section.test.d.ts.map +1 -0
  113. package/dist/components/section/Section.test.js +157 -0
  114. package/dist/components/section/Section.test.js.map +1 -0
  115. package/dist/components/slideover/Slideover.d.ts +11 -0
  116. package/dist/components/slideover/Slideover.d.ts.map +1 -0
  117. package/dist/components/slideover/Slideover.js +11 -0
  118. package/dist/components/slideover/Slideover.js.map +1 -0
  119. package/dist/components/slideover/Slideover.test.d.ts +2 -0
  120. package/dist/components/slideover/Slideover.test.d.ts.map +1 -0
  121. package/dist/components/slideover/Slideover.test.js +33 -0
  122. package/dist/components/slideover/Slideover.test.js.map +1 -0
  123. package/dist/components/slideoverManager/SlideoverManager.d.ts +7 -0
  124. package/dist/components/slideoverManager/SlideoverManager.d.ts.map +1 -0
  125. package/dist/components/slideoverManager/SlideoverManager.js +29 -0
  126. package/dist/components/slideoverManager/SlideoverManager.js.map +1 -0
  127. package/dist/components/slideoverManager/SlideoverManager.stories.d.ts +15 -0
  128. package/dist/components/slideoverManager/SlideoverManager.stories.d.ts.map +1 -0
  129. package/dist/components/slideoverManager/SlideoverManager.stories.js +102 -0
  130. package/dist/components/slideoverManager/SlideoverManager.stories.js.map +1 -0
  131. package/dist/components/slideoverManager/SlideoverManager.test.d.ts +2 -0
  132. package/dist/components/slideoverManager/SlideoverManager.test.d.ts.map +1 -0
  133. package/dist/components/slideoverManager/SlideoverManager.test.js +53 -0
  134. package/dist/components/slideoverManager/SlideoverManager.test.js.map +1 -0
  135. package/dist/index.css +1948 -1334
  136. package/dist/index.css.map +1 -1
  137. package/dist/index.d.ts +7 -1
  138. package/dist/index.d.ts.map +1 -1
  139. package/dist/index.js +7 -1
  140. package/dist/index.js.map +1 -1
  141. package/dist/utils/Constants.d.ts +6 -0
  142. package/dist/utils/Constants.d.ts.map +1 -0
  143. package/dist/utils/Constants.js +6 -0
  144. package/dist/utils/Constants.js.map +1 -0
  145. package/dist/utils/PopupParentContext.d.ts +3 -0
  146. package/dist/utils/PopupParentContext.d.ts.map +1 -0
  147. package/dist/utils/PopupParentContext.js +6 -0
  148. package/dist/utils/PopupParentContext.js.map +1 -0
  149. package/dist/utils/PubSub.d.ts +11 -0
  150. package/dist/utils/PubSub.d.ts.map +1 -0
  151. package/dist/utils/PubSub.js +27 -0
  152. package/dist/utils/PubSub.js.map +1 -0
  153. package/dist/utils/PubSub.test.d.ts +2 -0
  154. package/dist/utils/PubSub.test.d.ts.map +1 -0
  155. package/dist/utils/PubSub.test.js +229 -0
  156. package/dist/utils/PubSub.test.js.map +1 -0
  157. package/dist/utils/SlideoverUtils.d.ts +7 -0
  158. package/dist/utils/SlideoverUtils.d.ts.map +1 -0
  159. package/dist/utils/SlideoverUtils.js +8 -0
  160. package/dist/utils/SlideoverUtils.js.map +1 -0
  161. package/dist/utils/getDefaultPopupParent.d.ts +2 -0
  162. package/dist/utils/getDefaultPopupParent.d.ts.map +1 -0
  163. package/dist/utils/getDefaultPopupParent.js +13 -0
  164. package/dist/utils/getDefaultPopupParent.js.map +1 -0
  165. package/dist/utils/hooks/useComponentDidMount.d.ts +3 -0
  166. package/dist/utils/hooks/useComponentDidMount.d.ts.map +1 -0
  167. package/dist/utils/hooks/useComponentDidMount.js +5 -0
  168. package/dist/utils/hooks/useComponentDidMount.js.map +1 -0
  169. package/dist/utils/hooks/usePubSub.d.ts +2 -0
  170. package/dist/utils/hooks/usePubSub.d.ts.map +1 -0
  171. package/dist/utils/hooks/usePubSub.js +12 -0
  172. package/dist/utils/hooks/usePubSub.js.map +1 -0
  173. package/package.json +3 -3
  174. package/src/components/button/Button.story.tsx +9 -0
  175. package/src/components/button/Button.tsx +10 -2
  176. package/src/components/button/button.scss +75 -33
  177. package/src/components/card/Card.test.tsx +0 -6
  178. package/src/components/card/Card.tsx +12 -7
  179. package/src/components/card/card.scss +32 -18
  180. package/src/components/formField/FormField.stories.tsx +9 -1
  181. package/src/components/formField/FormField.test.tsx +6 -0
  182. package/src/components/formField/FormField.tsx +5 -0
  183. package/src/components/formField/formField.scss +20 -8
  184. package/src/components/formField/inputs/checkbox/CheckboxInput.stories.tsx +22 -0
  185. package/src/components/formField/inputs/checkbox/CheckboxInput.test.tsx +35 -0
  186. package/src/components/formField/inputs/checkbox/CheckboxInput.tsx +79 -0
  187. package/src/components/formField/inputs/checkbox/checkboxInput.scss +96 -0
  188. package/src/components/formField/inputs/dropdown/Dropdown.stories.tsx +185 -0
  189. package/src/components/formField/inputs/dropdown/Dropdown.test.tsx +185 -0
  190. package/src/components/formField/inputs/dropdown/Dropdown.tsx +82 -0
  191. package/src/components/formField/inputs/dropdown/buttons/dropdownButton/DropdownButton.tsx +41 -0
  192. package/src/components/formField/inputs/dropdown/buttons/dropdownButton/dropdownButton.scss +12 -0
  193. package/src/components/formField/inputs/dropdown/dropdown.scss +24 -0
  194. package/src/components/formField/inputs/dropdown/items/DropdownItemRenderer.tsx +38 -0
  195. package/src/components/formField/inputs/dropdown/items/dropdownItem/DropdownItem.tsx +49 -0
  196. package/src/components/formField/inputs/dropdown/items/dropdownItem/dropdownItem.scss +62 -0
  197. package/src/components/formField/inputs/dropdown/items/dropdownMultiLineItem/DropdownMultiLineItem.tsx +48 -0
  198. package/src/components/formField/inputs/dropdown/items/dropdownMultiLineItem/dropdownMultiLineItem.scss +52 -0
  199. package/src/components/formField/inputs/dropdown/wrapper/DropdownWrapper.tsx +138 -0
  200. package/src/components/formField/inputs/dropdown/wrapper/dropdownWrapper.scss +32 -0
  201. package/src/components/formField/inputs/input.scss +25 -26
  202. package/src/components/formField/inputs/number/NumberInput.stories.tsx +25 -0
  203. package/src/components/formField/inputs/number/NumberInput.test.tsx +33 -0
  204. package/src/components/formField/inputs/number/NumberInput.tsx +107 -0
  205. package/src/components/formField/inputs/number/numberInput.scss +68 -0
  206. package/src/components/formField/inputs/radio/RadioButtonInput.stories.tsx +97 -0
  207. package/src/components/formField/inputs/radio/RadioButtonInput.test.tsx +37 -0
  208. package/src/components/formField/inputs/radio/RadioButtonInput.tsx +46 -0
  209. package/src/components/formField/inputs/radio/radioButtonInput.scss +100 -0
  210. package/src/components/formField/label/label.scss +5 -1
  211. package/src/components/heading/Heading.stories.tsx +11 -12
  212. package/src/components/heading/Heading.tsx +21 -2
  213. package/src/components/heading/heading.scss +4 -0
  214. package/src/components/icon/Icon.tsx +2 -2
  215. package/src/components/icon/allowedIcons.tsx +2 -0
  216. package/src/components/pill/pill.scss +7 -7
  217. package/src/components/section/Section.stories.tsx +34 -0
  218. package/src/components/section/Section.test.tsx +308 -0
  219. package/src/components/section/Section.tsx +131 -0
  220. package/src/components/section/section.scss +42 -0
  221. package/src/components/slideover/Slideover.test.tsx +36 -0
  222. package/src/components/slideover/Slideover.tsx +38 -0
  223. package/src/components/slideover/slideover.scss +50 -0
  224. package/src/components/slideoverManager/SlideoverManager.stories.tsx +374 -0
  225. package/src/components/slideoverManager/SlideoverManager.test.tsx +64 -0
  226. package/src/components/slideoverManager/SlideoverManager.tsx +51 -0
  227. package/src/components/slideoverManager/slideoverManager.scss +13 -0
  228. package/src/components/tabs/tabs.scss +8 -7
  229. package/src/global.scss +10 -1
  230. package/src/index.scss +14 -3
  231. package/src/index.ts +9 -3
  232. package/src/tokens.scss +1321 -1239
  233. package/src/utils/Constants.ts +5 -0
  234. package/src/utils/PopupParentContext.ts +6 -0
  235. package/src/utils/PubSub.test.ts +303 -0
  236. package/src/utils/PubSub.ts +34 -0
  237. package/src/utils/SlideoverUtils.ts +9 -0
  238. package/src/utils/getDefaultPopupParent.ts +14 -0
  239. package/src/utils/hooks/useComponentDidMount.ts +5 -0
  240. package/src/utils/hooks/usePubSub.ts +12 -0
  241. package/tokens/export-config.json +32 -0
  242. package/tokens/json/$metadata.json +5 -0
  243. package/tokens/json/$themes.json +1333 -0
  244. package/tokens/json/Arbor.json +6329 -0
  245. package/src/components/heading/HeadingInnerContainer.tsx +0 -18
@@ -0,0 +1,5 @@
1
+ export const SLIDEOVER = {
2
+ ADD_SLIDEOVER: 'ds-add-slideover',
3
+ REMOVE_SLIDEOVER: 'ds-remove-slideover',
4
+ REMOVE_ALL_SLIDEOVERS: 'ds-remove-all-slideover',
5
+ };
@@ -0,0 +1,6 @@
1
+ import { createContext, type RefObject } from 'react';
2
+ import { getDefaultPopupParent } from './getDefaultPopupParent';
3
+
4
+ export const PopupParentContext = createContext<RefObject<HTMLElement | null>>({
5
+ current: getDefaultPopupParent(),
6
+ });
@@ -0,0 +1,303 @@
1
+ import { expect, test, describe, vi, beforeEach } from 'vitest';
2
+ import PubSub from './PubSub';
3
+
4
+ describe('PubSub Service', () => {
5
+ beforeEach(() => {
6
+ // Clear all subscriptions before each test
7
+ // @ts-expect-error - Accessing private property for testing
8
+ PubSub.events = {};
9
+ });
10
+
11
+ describe('subscribe', () => {
12
+ test('subscribes a function to an event', () => {
13
+ const mockFn = vi.fn();
14
+ const subscriptionId = PubSub.subscribe('test-event', mockFn);
15
+
16
+ expect(subscriptionId).toBeDefined();
17
+ expect(typeof subscriptionId).toBe('string');
18
+ });
19
+
20
+ test('returns a unique subscription ID for each subscription', () => {
21
+ const mockFn1 = vi.fn();
22
+ const mockFn2 = vi.fn();
23
+
24
+ const id1 = PubSub.subscribe('test-event', mockFn1);
25
+ const id2 = PubSub.subscribe('test-event', mockFn2);
26
+
27
+ expect(id1).not.toBe(id2);
28
+ });
29
+
30
+ test('allows multiple subscriptions to the same event', () => {
31
+ const mockFn1 = vi.fn();
32
+ const mockFn2 = vi.fn();
33
+
34
+ PubSub.subscribe('test-event', mockFn1);
35
+ PubSub.subscribe('test-event', mockFn2);
36
+
37
+ PubSub.publish('test-event', 'test data');
38
+
39
+ expect(mockFn1).toHaveBeenCalledTimes(1);
40
+ expect(mockFn2).toHaveBeenCalledTimes(1);
41
+ });
42
+
43
+ test('allows subscriptions to different events', () => {
44
+ const mockFn1 = vi.fn();
45
+ const mockFn2 = vi.fn();
46
+
47
+ PubSub.subscribe('event-1', mockFn1);
48
+ PubSub.subscribe('event-2', mockFn2);
49
+
50
+ PubSub.publish('event-1', 'data-1');
51
+
52
+ expect(mockFn1).toHaveBeenCalledWith('data-1');
53
+ expect(mockFn2).not.toHaveBeenCalled();
54
+ });
55
+ });
56
+
57
+ describe('unsubscribe', () => {
58
+ test('removes a subscription by ID', () => {
59
+ const mockFn = vi.fn();
60
+ const subscriptionId = PubSub.subscribe('test-event', mockFn);
61
+
62
+ PubSub.unsubscribe('test-event', subscriptionId);
63
+ PubSub.publish('test-event', 'test data');
64
+
65
+ expect(mockFn).not.toHaveBeenCalled();
66
+ });
67
+
68
+ test('only removes the specific subscription', () => {
69
+ const mockFn1 = vi.fn();
70
+ const mockFn2 = vi.fn();
71
+
72
+ const id1 = PubSub.subscribe('test-event', mockFn1);
73
+ PubSub.subscribe('test-event', mockFn2);
74
+
75
+ PubSub.unsubscribe('test-event', id1);
76
+ PubSub.publish('test-event', 'test data');
77
+
78
+ expect(mockFn1).not.toHaveBeenCalled();
79
+ expect(mockFn2).toHaveBeenCalledWith('test data');
80
+ });
81
+
82
+ test('does not throw error when unsubscribing non-existent event', () => {
83
+ expect(() => {
84
+ PubSub.unsubscribe('non-existent-event', 'fake-id');
85
+ }).not.toThrow();
86
+ });
87
+
88
+ test('does not throw error when unsubscribing non-existent subscription ID', () => {
89
+ const mockFn = vi.fn();
90
+ PubSub.subscribe('test-event', mockFn);
91
+
92
+ expect(() => {
93
+ PubSub.unsubscribe('test-event', 'non-existent-id');
94
+ }).not.toThrow();
95
+ });
96
+ });
97
+
98
+ describe('publish', () => {
99
+ test('calls subscribed function when event is published', () => {
100
+ const mockFn = vi.fn();
101
+ PubSub.subscribe('test-event', mockFn);
102
+
103
+ PubSub.publish('test-event');
104
+
105
+ expect(mockFn).toHaveBeenCalledTimes(1);
106
+ });
107
+
108
+ test('passes data to subscribed function', () => {
109
+ const mockFn = vi.fn();
110
+ const testData = { message: 'Hello World' };
111
+
112
+ PubSub.subscribe('test-event', mockFn);
113
+ PubSub.publish('test-event', testData);
114
+
115
+ expect(mockFn).toHaveBeenCalledWith(testData);
116
+ });
117
+
118
+ test('handles undefined data parameter', () => {
119
+ const mockFn = vi.fn();
120
+ PubSub.subscribe('test-event', mockFn);
121
+
122
+ PubSub.publish('test-event');
123
+
124
+ expect(mockFn).toHaveBeenCalledWith(undefined);
125
+ });
126
+
127
+ test('calls all subscribed functions for an event', () => {
128
+ const mockFn1 = vi.fn();
129
+ const mockFn2 = vi.fn();
130
+ const mockFn3 = vi.fn();
131
+
132
+ PubSub.subscribe('test-event', mockFn1);
133
+ PubSub.subscribe('test-event', mockFn2);
134
+ PubSub.subscribe('test-event', mockFn3);
135
+
136
+ PubSub.publish('test-event', 'shared data');
137
+
138
+ expect(mockFn1).toHaveBeenCalledWith('shared data');
139
+ expect(mockFn2).toHaveBeenCalledWith('shared data');
140
+ expect(mockFn3).toHaveBeenCalledWith('shared data');
141
+ });
142
+
143
+ test('does not throw error when publishing to non-existent event', () => {
144
+ expect(() => {
145
+ PubSub.publish('non-existent-event', 'some data');
146
+ }).not.toThrow();
147
+ });
148
+
149
+ test('handles various data types', () => {
150
+ const mockFn = vi.fn();
151
+ PubSub.subscribe('test-event', mockFn);
152
+
153
+ // String
154
+ PubSub.publish('test-event', 'string data');
155
+ expect(mockFn).toHaveBeenCalledWith('string data');
156
+
157
+ // Number
158
+ PubSub.publish('test-event', 42);
159
+ expect(mockFn).toHaveBeenCalledWith(42);
160
+
161
+ // Object
162
+ const obj = { key: 'value' };
163
+ PubSub.publish('test-event', obj);
164
+ expect(mockFn).toHaveBeenCalledWith(obj);
165
+
166
+ // Array
167
+ const arr = [1, 2, 3];
168
+ PubSub.publish('test-event', arr);
169
+ expect(mockFn).toHaveBeenCalledWith(arr);
170
+
171
+ // Boolean
172
+ PubSub.publish('test-event', true);
173
+ expect(mockFn).toHaveBeenCalledWith(true);
174
+
175
+ expect(mockFn).toHaveBeenCalledTimes(5);
176
+ });
177
+ });
178
+
179
+ describe('integration scenarios', () => {
180
+ test('subscribe, publish, and unsubscribe workflow', () => {
181
+ const mockFn = vi.fn();
182
+ const subscriptionId = PubSub.subscribe('workflow-event', mockFn);
183
+
184
+ // First publish should trigger the function
185
+ PubSub.publish('workflow-event', 'first');
186
+ expect(mockFn).toHaveBeenCalledTimes(1);
187
+ expect(mockFn).toHaveBeenCalledWith('first');
188
+
189
+ // Second publish should also trigger
190
+ PubSub.publish('workflow-event', 'second');
191
+ expect(mockFn).toHaveBeenCalledTimes(2);
192
+ expect(mockFn).toHaveBeenCalledWith('second');
193
+
194
+ // Unsubscribe
195
+ PubSub.unsubscribe('workflow-event', subscriptionId);
196
+
197
+ // Third publish should not trigger
198
+ PubSub.publish('workflow-event', 'third');
199
+ expect(mockFn).toHaveBeenCalledTimes(2);
200
+ });
201
+
202
+ test('multiple events with multiple subscribers', () => {
203
+ const event1Handler1 = vi.fn();
204
+ const event1Handler2 = vi.fn();
205
+ const event2Handler1 = vi.fn();
206
+
207
+ PubSub.subscribe('event-1', event1Handler1);
208
+ PubSub.subscribe('event-1', event1Handler2);
209
+ PubSub.subscribe('event-2', event2Handler1);
210
+
211
+ PubSub.publish('event-1', 'data-1');
212
+ PubSub.publish('event-2', 'data-2');
213
+
214
+ expect(event1Handler1).toHaveBeenCalledWith('data-1');
215
+ expect(event1Handler2).toHaveBeenCalledWith('data-1');
216
+ expect(event2Handler1).toHaveBeenCalledWith('data-2');
217
+
218
+ expect(event1Handler1).toHaveBeenCalledTimes(1);
219
+ expect(event1Handler2).toHaveBeenCalledTimes(1);
220
+ expect(event2Handler1).toHaveBeenCalledTimes(1);
221
+ });
222
+
223
+ test('handler can modify external state', () => {
224
+ let externalState = 0;
225
+
226
+ const incrementHandler = (amount: unknown) => {
227
+ externalState += amount as number;
228
+ };
229
+
230
+ PubSub.subscribe('increment', incrementHandler);
231
+
232
+ PubSub.publish('increment', 5);
233
+ expect(externalState).toBe(5);
234
+
235
+ PubSub.publish('increment', 3);
236
+ expect(externalState).toBe(8);
237
+ });
238
+
239
+ test('subscription within a handler does not affect current publish', () => {
240
+ const handler1 = vi.fn(() => {
241
+ // Subscribe a new handler during the first handler execution
242
+ PubSub.subscribe('test-event', handler2);
243
+ });
244
+ const handler2 = vi.fn();
245
+
246
+ PubSub.subscribe('test-event', handler1);
247
+ PubSub.publish('test-event', 'first');
248
+
249
+ // handler1 should be called, handler2 should not (wasn't subscribed yet when publish started)
250
+ expect(handler1).toHaveBeenCalledTimes(1);
251
+ expect(handler2).not.toHaveBeenCalled();
252
+
253
+ // On second publish, both should be called
254
+ PubSub.publish('test-event', 'second');
255
+ expect(handler1).toHaveBeenCalledTimes(2);
256
+ expect(handler2).toHaveBeenCalledTimes(1);
257
+ });
258
+ });
259
+
260
+ describe('edge cases', () => {
261
+ test('handles empty event name string', () => {
262
+ const mockFn = vi.fn();
263
+ const subscriptionId = PubSub.subscribe('', mockFn);
264
+
265
+ PubSub.publish('', 'data');
266
+ expect(mockFn).toHaveBeenCalledWith('data');
267
+
268
+ PubSub.unsubscribe('', subscriptionId);
269
+ PubSub.publish('', 'data');
270
+ expect(mockFn).toHaveBeenCalledTimes(1);
271
+ });
272
+
273
+ test('handles function that throws error', () => {
274
+ const errorHandler = vi.fn(() => {
275
+ throw new Error('Handler error');
276
+ });
277
+ const normalHandler = vi.fn();
278
+
279
+ PubSub.subscribe('test-event', errorHandler);
280
+ PubSub.subscribe('test-event', normalHandler);
281
+
282
+ // Publishing should throw since the handler throws
283
+ expect(() => {
284
+ PubSub.publish('test-event', 'data');
285
+ }).toThrow('Handler error');
286
+
287
+ expect(errorHandler).toHaveBeenCalled();
288
+ });
289
+
290
+ test('maintains separate event namespaces', () => {
291
+ const handler1 = vi.fn();
292
+ const handler2 = vi.fn();
293
+
294
+ PubSub.subscribe('user:login', handler1);
295
+ PubSub.subscribe('user:logout', handler2);
296
+
297
+ PubSub.publish('user:login', { userId: 123 });
298
+
299
+ expect(handler1).toHaveBeenCalledWith({ userId: 123 });
300
+ expect(handler2).not.toHaveBeenCalled();
301
+ });
302
+ });
303
+ });
@@ -0,0 +1,34 @@
1
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2
+ type AnyFunction = (...args: any[]) => any;
3
+
4
+ class Pubsub {
5
+ private events: Record<string, Record<string, AnyFunction>>;
6
+ constructor() {
7
+ this.events = {};
8
+ }
9
+
10
+ subscribe(eventName: string, fn: AnyFunction) {
11
+ const subscriptionId = crypto.randomUUID();
12
+
13
+ this.events[eventName] = this.events[eventName] ?? {};
14
+ this.events[eventName][subscriptionId] = fn;
15
+ return subscriptionId;
16
+ }
17
+
18
+ unsubscribe(eventName: string, subscriptionId: string) {
19
+ if (typeof this.events[eventName] !== 'undefined') {
20
+ delete this.events[eventName][subscriptionId];
21
+ }
22
+ }
23
+
24
+ publish(eventName: string, data?: unknown) {
25
+ if (this.events[eventName]) {
26
+ Object.keys(this.events[eventName]).forEach((key) => {
27
+ const subscribedFunction = this.events[eventName]![key];
28
+ subscribedFunction?.(data);
29
+ });
30
+ }
31
+ }
32
+ }
33
+
34
+ export default new Pubsub();
@@ -0,0 +1,9 @@
1
+ import type { SlideoverProps } from 'Components/slideover/Slideover';
2
+ import { SLIDEOVER } from './Constants';
3
+ import PubSub from './PubSub';
4
+
5
+ export const SlideoverUtils = {
6
+ addSlideover: (slideoverConfig: SlideoverProps) => PubSub.publish(SLIDEOVER.ADD_SLIDEOVER, slideoverConfig),
7
+ removeSlideover: () => PubSub.publish(SLIDEOVER.REMOVE_SLIDEOVER),
8
+ removeAllSlideovers: () => PubSub.publish(SLIDEOVER.REMOVE_ALL_SLIDEOVERS),
9
+ };
@@ -0,0 +1,14 @@
1
+ export const getDefaultPopupParent = () => {
2
+ const element = document.getElementById('ds-popup-parent');
3
+ if (element) {
4
+ return element;
5
+ }
6
+
7
+ const newContainer = document.createElement('div');
8
+ newContainer.id = 'ds-popup-parent';
9
+ newContainer.style.zIndex = '1';
10
+ newContainer.style.position = 'relative';
11
+ document.body.appendChild(newContainer);
12
+
13
+ return newContainer;
14
+ };
@@ -0,0 +1,5 @@
1
+ import { useEffect, type EffectCallback } from 'react';
2
+
3
+ export const useComponentDidMount = (callback: EffectCallback) => {
4
+ useEffect(callback, []);
5
+ };
@@ -0,0 +1,12 @@
1
+ import PubSub from 'Utils/PubSub';
2
+ import { useComponentDidMount } from './useComponentDidMount';
3
+
4
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
5
+ export const usePubSub = <T extends (...args: any[]) => any>(eventName: string, handler: T) => {
6
+ useComponentDidMount(() => {
7
+ const token = PubSub.subscribe(eventName, handler);
8
+ return () => {
9
+ PubSub.unsubscribe(eventName, token);
10
+ };
11
+ });
12
+ };
@@ -0,0 +1,32 @@
1
+ {
2
+ "config": {
3
+ "source": [
4
+ "**/*.json"
5
+ ],
6
+ "platforms": {
7
+ "css": {
8
+ "files": [
9
+ {
10
+ "format": "css/variables",
11
+ "options": {
12
+ "outputReferences": true
13
+ },
14
+ "destination": "variables.css"
15
+ }
16
+ ],
17
+ "buildPath": "build/css/",
18
+ "transforms": [
19
+ "name/kebab"
20
+ ],
21
+ "transformGroup": "tokens-studio"
22
+ }
23
+ },
24
+ "preprocessors": [
25
+ "tokens-studio"
26
+ ]
27
+ },
28
+ "functions": "import StyleDictionary from 'style-dictionary';\nimport { register } from '@tokens-studio/sd-transforms';\n\n// sd-transforms, 2nd parameter for options can be added\n// See docs: https://github.com/tokens-studio/sd-transforms\nregister(StyleDictionary);\n",
29
+ "themeOptions": {
30
+ "Arbor": "included"
31
+ }
32
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "tokenSetOrder": [
3
+ "Arbor"
4
+ ]
5
+ }