@mitodl/smoot-design 0.0.0-355a925

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 (247) hide show
  1. package/LICENSE +28 -0
  2. package/README.md +35 -0
  3. package/dist/bundles/remoteTutorDrawer.es.js +38364 -0
  4. package/dist/bundles/remoteTutorDrawer.umd.js +207 -0
  5. package/dist/cjs/ai.d.ts +3 -0
  6. package/dist/cjs/ai.js +9 -0
  7. package/dist/cjs/bundles/RemoteTutorDrawer/FlashcardsScreen.d.ts +9 -0
  8. package/dist/cjs/bundles/RemoteTutorDrawer/FlashcardsScreen.js +87 -0
  9. package/dist/cjs/bundles/RemoteTutorDrawer/RemoteTutorDrawer.d.ts +56 -0
  10. package/dist/cjs/bundles/RemoteTutorDrawer/RemoteTutorDrawer.js +276 -0
  11. package/dist/cjs/bundles/RemoteTutorDrawer/RemoteTutorDrawer.stories.d.ts +16 -0
  12. package/dist/cjs/bundles/RemoteTutorDrawer/RemoteTutorDrawer.stories.js +284 -0
  13. package/dist/cjs/bundles/RemoteTutorDrawer/RemoteTutorDrawer.test.d.ts +1 -0
  14. package/dist/cjs/bundles/RemoteTutorDrawer/RemoteTutorDrawer.test.js +241 -0
  15. package/dist/cjs/bundles/remoteTutorDrawer.d.ts +7 -0
  16. package/dist/cjs/bundles/remoteTutorDrawer.js +40 -0
  17. package/dist/cjs/components/AiChat/AiChat.d.ts +5 -0
  18. package/dist/cjs/components/AiChat/AiChat.js +226 -0
  19. package/dist/cjs/components/AiChat/AiChat.stories.d.ts +21 -0
  20. package/dist/cjs/components/AiChat/AiChat.stories.js +243 -0
  21. package/dist/cjs/components/AiChat/AiChat.test.d.ts +1 -0
  22. package/dist/cjs/components/AiChat/AiChat.test.js +211 -0
  23. package/dist/cjs/components/AiChat/AiChatContext.d.ts +22 -0
  24. package/dist/cjs/components/AiChat/AiChatContext.js +105 -0
  25. package/dist/cjs/components/AiChat/AiChatContext.stories.d.ts +14 -0
  26. package/dist/cjs/components/AiChat/AiChatContext.stories.js +75 -0
  27. package/dist/cjs/components/AiChat/ChatTitle.d.ts +8 -0
  28. package/dist/cjs/components/AiChat/ChatTitle.js +43 -0
  29. package/dist/cjs/components/AiChat/EntryScreen.d.ts +11 -0
  30. package/dist/cjs/components/AiChat/EntryScreen.js +123 -0
  31. package/dist/cjs/components/AiChat/TimLogo.d.ts +5 -0
  32. package/dist/cjs/components/AiChat/TimLogo.js +15 -0
  33. package/dist/cjs/components/AiChat/test-utils/api.d.ts +2 -0
  34. package/dist/cjs/components/AiChat/test-utils/api.js +125 -0
  35. package/dist/cjs/components/AiChat/types.d.ts +86 -0
  36. package/dist/cjs/components/AiChat/types.js +3 -0
  37. package/dist/cjs/components/Alert/Alert.d.ts +15 -0
  38. package/dist/cjs/components/Alert/Alert.js +62 -0
  39. package/dist/cjs/components/Alert/Alert.stories.d.ts +8 -0
  40. package/dist/cjs/components/Alert/Alert.stories.js +53 -0
  41. package/dist/cjs/components/Button/ActionButton.d.ts +30 -0
  42. package/dist/cjs/components/Button/ActionButton.js +73 -0
  43. package/dist/cjs/components/Button/ActionButton.stories.d.ts +15 -0
  44. package/dist/cjs/components/Button/ActionButton.stories.js +113 -0
  45. package/dist/cjs/components/Button/Button.d.ts +54 -0
  46. package/dist/cjs/components/Button/Button.js +240 -0
  47. package/dist/cjs/components/Button/Button.stories.d.ts +17 -0
  48. package/dist/cjs/components/Button/Button.stories.js +135 -0
  49. package/dist/cjs/components/Button/Button.test.d.ts +1 -0
  50. package/dist/cjs/components/Button/Button.test.js +46 -0
  51. package/dist/cjs/components/ImageAdapter/ImageAdapter.d.ts +23 -0
  52. package/dist/cjs/components/ImageAdapter/ImageAdapter.js +30 -0
  53. package/dist/cjs/components/Input/Input.d.ts +116 -0
  54. package/dist/cjs/components/Input/Input.js +237 -0
  55. package/dist/cjs/components/Input/Input.stories.d.ts +19 -0
  56. package/dist/cjs/components/Input/Input.stories.js +135 -0
  57. package/dist/cjs/components/Input/Input.test.d.ts +1 -0
  58. package/dist/cjs/components/Input/Input.test.js +32 -0
  59. package/dist/cjs/components/LinkAdapter/LinkAdapter.d.ts +23 -0
  60. package/dist/cjs/components/LinkAdapter/LinkAdapter.js +34 -0
  61. package/dist/cjs/components/ScrollSnap/ScrollSnap.d.ts +19 -0
  62. package/dist/cjs/components/ScrollSnap/ScrollSnap.js +59 -0
  63. package/dist/cjs/components/ScrollSnap/ScrollSnap.stories.d.ts +6 -0
  64. package/dist/cjs/components/ScrollSnap/ScrollSnap.stories.js +43 -0
  65. package/dist/cjs/components/ScrollSnap/useScrollSnap.d.ts +6 -0
  66. package/dist/cjs/components/ScrollSnap/useScrollSnap.js +36 -0
  67. package/dist/cjs/components/SrAnnouncer/SrAnnouncer.d.ts +25 -0
  68. package/dist/cjs/components/SrAnnouncer/SrAnnouncer.js +43 -0
  69. package/dist/cjs/components/SrAnnouncer/SrAnnouncer.stories.d.ts +6 -0
  70. package/dist/cjs/components/SrAnnouncer/SrAnnouncer.stories.js +44 -0
  71. package/dist/cjs/components/SrAnnouncer/SrAnnouncer.test.d.ts +1 -0
  72. package/dist/cjs/components/SrAnnouncer/SrAnnouncer.test.js +62 -0
  73. package/dist/cjs/components/TabButtons/TabButtonList.d.ts +25 -0
  74. package/dist/cjs/components/TabButtons/TabButtonList.js +97 -0
  75. package/dist/cjs/components/TabButtons/TabButtonList.stories.d.ts +24 -0
  76. package/dist/cjs/components/TabButtons/TabButtonList.stories.js +139 -0
  77. package/dist/cjs/components/TextField/TextField.d.ts +29 -0
  78. package/dist/cjs/components/TextField/TextField.js +33 -0
  79. package/dist/cjs/components/TextField/TextField.stories.d.ts +10 -0
  80. package/dist/cjs/components/TextField/TextField.stories.js +136 -0
  81. package/dist/cjs/components/TextField/TextField.test.d.ts +1 -0
  82. package/dist/cjs/components/TextField/TextField.test.js +77 -0
  83. package/dist/cjs/components/ThemeProvider/ThemeProvider.d.ts +21 -0
  84. package/dist/cjs/components/ThemeProvider/ThemeProvider.js +86 -0
  85. package/dist/cjs/components/ThemeProvider/ThemeProvider.stories.d.ts +63 -0
  86. package/dist/cjs/components/ThemeProvider/ThemeProvider.stories.js +102 -0
  87. package/dist/cjs/components/ThemeProvider/Typography.stories.d.ts +39 -0
  88. package/dist/cjs/components/ThemeProvider/Typography.stories.js +65 -0
  89. package/dist/cjs/components/ThemeProvider/breakpoints.d.ts +4 -0
  90. package/dist/cjs/components/ThemeProvider/breakpoints.js +19 -0
  91. package/dist/cjs/components/ThemeProvider/buttons.d.ts +7 -0
  92. package/dist/cjs/components/ThemeProvider/buttons.js +20 -0
  93. package/dist/cjs/components/ThemeProvider/chips.d.ts +3 -0
  94. package/dist/cjs/components/ThemeProvider/chips.js +154 -0
  95. package/dist/cjs/components/ThemeProvider/colors.d.ts +32 -0
  96. package/dist/cjs/components/ThemeProvider/colors.js +35 -0
  97. package/dist/cjs/components/ThemeProvider/typography.d.ts +18 -0
  98. package/dist/cjs/components/ThemeProvider/typography.js +173 -0
  99. package/dist/cjs/components/VisuallyHidden/VisuallyHidden.d.ts +24 -0
  100. package/dist/cjs/components/VisuallyHidden/VisuallyHidden.js +33 -0
  101. package/dist/cjs/components/VisuallyHidden/VisuallyHidden.stories.d.ts +6 -0
  102. package/dist/cjs/components/VisuallyHidden/VisuallyHidden.stories.js +13 -0
  103. package/dist/cjs/components/internal/FormHelpers/FormHelpers.d.ts +39 -0
  104. package/dist/cjs/components/internal/FormHelpers/FormHelpers.js +78 -0
  105. package/dist/cjs/components/internal/FormHelpers/FormHelpers.test.d.ts +1 -0
  106. package/dist/cjs/components/internal/FormHelpers/FormHelpers.test.js +93 -0
  107. package/dist/cjs/index.d.ts +16 -0
  108. package/dist/cjs/index.js +30 -0
  109. package/dist/cjs/jest-setup.d.ts +1 -0
  110. package/dist/cjs/jest-setup.js +18 -0
  111. package/dist/cjs/jsdom-extended.d.ts +6 -0
  112. package/dist/cjs/jsdom-extended.js +14 -0
  113. package/dist/cjs/story-utils/index.d.ts +6 -0
  114. package/dist/cjs/story-utils/index.js +17 -0
  115. package/dist/cjs/utils/composeRefs.d.ts +7 -0
  116. package/dist/cjs/utils/composeRefs.js +20 -0
  117. package/dist/cjs/utils/composeRefs.test.d.ts +1 -0
  118. package/dist/cjs/utils/composeRefs.test.js +19 -0
  119. package/dist/cjs/utils/useDevCheckStable.d.ts +8 -0
  120. package/dist/cjs/utils/useDevCheckStable.js +29 -0
  121. package/dist/cjs/utils/useInterval.d.ts +7 -0
  122. package/dist/cjs/utils/useInterval.js +25 -0
  123. package/dist/esm/ai.d.ts +3 -0
  124. package/dist/esm/ai.js +2 -0
  125. package/dist/esm/bundles/RemoteTutorDrawer/FlashcardsScreen.d.ts +9 -0
  126. package/dist/esm/bundles/RemoteTutorDrawer/FlashcardsScreen.js +83 -0
  127. package/dist/esm/bundles/RemoteTutorDrawer/RemoteTutorDrawer.d.ts +56 -0
  128. package/dist/esm/bundles/RemoteTutorDrawer/RemoteTutorDrawer.js +273 -0
  129. package/dist/esm/bundles/RemoteTutorDrawer/RemoteTutorDrawer.stories.d.ts +16 -0
  130. package/dist/esm/bundles/RemoteTutorDrawer/RemoteTutorDrawer.stories.js +281 -0
  131. package/dist/esm/bundles/RemoteTutorDrawer/RemoteTutorDrawer.test.d.ts +1 -0
  132. package/dist/esm/bundles/RemoteTutorDrawer/RemoteTutorDrawer.test.js +239 -0
  133. package/dist/esm/bundles/remoteTutorDrawer.d.ts +7 -0
  134. package/dist/esm/bundles/remoteTutorDrawer.js +37 -0
  135. package/dist/esm/components/AiChat/AiChat.d.ts +5 -0
  136. package/dist/esm/components/AiChat/AiChat.js +222 -0
  137. package/dist/esm/components/AiChat/AiChat.stories.d.ts +21 -0
  138. package/dist/esm/components/AiChat/AiChat.stories.js +240 -0
  139. package/dist/esm/components/AiChat/AiChat.test.d.ts +1 -0
  140. package/dist/esm/components/AiChat/AiChat.test.js +209 -0
  141. package/dist/esm/components/AiChat/AiChatContext.d.ts +22 -0
  142. package/dist/esm/components/AiChat/AiChatContext.js +101 -0
  143. package/dist/esm/components/AiChat/AiChatContext.stories.d.ts +14 -0
  144. package/dist/esm/components/AiChat/AiChatContext.stories.js +72 -0
  145. package/dist/esm/components/AiChat/ChatTitle.d.ts +8 -0
  146. package/dist/esm/components/AiChat/ChatTitle.js +40 -0
  147. package/dist/esm/components/AiChat/EntryScreen.d.ts +11 -0
  148. package/dist/esm/components/AiChat/EntryScreen.js +120 -0
  149. package/dist/esm/components/AiChat/TimLogo.d.ts +5 -0
  150. package/dist/esm/components/AiChat/TimLogo.js +13 -0
  151. package/dist/esm/components/AiChat/test-utils/api.d.ts +2 -0
  152. package/dist/esm/components/AiChat/test-utils/api.js +122 -0
  153. package/dist/esm/components/AiChat/types.d.ts +86 -0
  154. package/dist/esm/components/AiChat/types.js +2 -0
  155. package/dist/esm/components/Alert/Alert.d.ts +15 -0
  156. package/dist/esm/components/Alert/Alert.js +59 -0
  157. package/dist/esm/components/Alert/Alert.stories.d.ts +8 -0
  158. package/dist/esm/components/Alert/Alert.stories.js +50 -0
  159. package/dist/esm/components/Button/ActionButton.d.ts +30 -0
  160. package/dist/esm/components/Button/ActionButton.js +68 -0
  161. package/dist/esm/components/Button/ActionButton.stories.d.ts +15 -0
  162. package/dist/esm/components/Button/ActionButton.stories.js +110 -0
  163. package/dist/esm/components/Button/Button.d.ts +54 -0
  164. package/dist/esm/components/Button/Button.js +232 -0
  165. package/dist/esm/components/Button/Button.stories.d.ts +17 -0
  166. package/dist/esm/components/Button/Button.stories.js +132 -0
  167. package/dist/esm/components/Button/Button.test.d.ts +1 -0
  168. package/dist/esm/components/Button/Button.test.js +44 -0
  169. package/dist/esm/components/ImageAdapter/ImageAdapter.d.ts +23 -0
  170. package/dist/esm/components/ImageAdapter/ImageAdapter.js +27 -0
  171. package/dist/esm/components/Input/Input.d.ts +116 -0
  172. package/dist/esm/components/Input/Input.js +232 -0
  173. package/dist/esm/components/Input/Input.stories.d.ts +19 -0
  174. package/dist/esm/components/Input/Input.stories.js +132 -0
  175. package/dist/esm/components/Input/Input.test.d.ts +1 -0
  176. package/dist/esm/components/Input/Input.test.js +30 -0
  177. package/dist/esm/components/LinkAdapter/LinkAdapter.d.ts +23 -0
  178. package/dist/esm/components/LinkAdapter/LinkAdapter.js +31 -0
  179. package/dist/esm/components/ScrollSnap/ScrollSnap.d.ts +19 -0
  180. package/dist/esm/components/ScrollSnap/ScrollSnap.js +56 -0
  181. package/dist/esm/components/ScrollSnap/ScrollSnap.stories.d.ts +6 -0
  182. package/dist/esm/components/ScrollSnap/ScrollSnap.stories.js +40 -0
  183. package/dist/esm/components/ScrollSnap/useScrollSnap.d.ts +6 -0
  184. package/dist/esm/components/ScrollSnap/useScrollSnap.js +33 -0
  185. package/dist/esm/components/SrAnnouncer/SrAnnouncer.d.ts +25 -0
  186. package/dist/esm/components/SrAnnouncer/SrAnnouncer.js +40 -0
  187. package/dist/esm/components/SrAnnouncer/SrAnnouncer.stories.d.ts +6 -0
  188. package/dist/esm/components/SrAnnouncer/SrAnnouncer.stories.js +41 -0
  189. package/dist/esm/components/SrAnnouncer/SrAnnouncer.test.d.ts +1 -0
  190. package/dist/esm/components/SrAnnouncer/SrAnnouncer.test.js +60 -0
  191. package/dist/esm/components/TabButtons/TabButtonList.d.ts +25 -0
  192. package/dist/esm/components/TabButtons/TabButtonList.js +92 -0
  193. package/dist/esm/components/TabButtons/TabButtonList.stories.d.ts +24 -0
  194. package/dist/esm/components/TabButtons/TabButtonList.stories.js +136 -0
  195. package/dist/esm/components/TextField/TextField.d.ts +29 -0
  196. package/dist/esm/components/TextField/TextField.js +30 -0
  197. package/dist/esm/components/TextField/TextField.stories.d.ts +10 -0
  198. package/dist/esm/components/TextField/TextField.stories.js +133 -0
  199. package/dist/esm/components/TextField/TextField.test.d.ts +1 -0
  200. package/dist/esm/components/TextField/TextField.test.js +75 -0
  201. package/dist/esm/components/ThemeProvider/ThemeProvider.d.ts +21 -0
  202. package/dist/esm/components/ThemeProvider/ThemeProvider.js +82 -0
  203. package/dist/esm/components/ThemeProvider/ThemeProvider.stories.d.ts +63 -0
  204. package/dist/esm/components/ThemeProvider/ThemeProvider.stories.js +99 -0
  205. package/dist/esm/components/ThemeProvider/Typography.stories.d.ts +39 -0
  206. package/dist/esm/components/ThemeProvider/Typography.stories.js +62 -0
  207. package/dist/esm/components/ThemeProvider/breakpoints.d.ts +4 -0
  208. package/dist/esm/components/ThemeProvider/breakpoints.js +15 -0
  209. package/dist/esm/components/ThemeProvider/buttons.d.ts +7 -0
  210. package/dist/esm/components/ThemeProvider/buttons.js +17 -0
  211. package/dist/esm/components/ThemeProvider/chips.d.ts +3 -0
  212. package/dist/esm/components/ThemeProvider/chips.js +151 -0
  213. package/dist/esm/components/ThemeProvider/colors.d.ts +32 -0
  214. package/dist/esm/components/ThemeProvider/colors.js +32 -0
  215. package/dist/esm/components/ThemeProvider/typography.d.ts +18 -0
  216. package/dist/esm/components/ThemeProvider/typography.js +167 -0
  217. package/dist/esm/components/VisuallyHidden/VisuallyHidden.d.ts +24 -0
  218. package/dist/esm/components/VisuallyHidden/VisuallyHidden.js +30 -0
  219. package/dist/esm/components/VisuallyHidden/VisuallyHidden.stories.d.ts +6 -0
  220. package/dist/esm/components/VisuallyHidden/VisuallyHidden.stories.js +10 -0
  221. package/dist/esm/components/internal/FormHelpers/FormHelpers.d.ts +39 -0
  222. package/dist/esm/components/internal/FormHelpers/FormHelpers.js +73 -0
  223. package/dist/esm/components/internal/FormHelpers/FormHelpers.test.d.ts +1 -0
  224. package/dist/esm/components/internal/FormHelpers/FormHelpers.test.js +91 -0
  225. package/dist/esm/index.d.ts +16 -0
  226. package/dist/esm/index.js +11 -0
  227. package/dist/esm/jest-setup.d.ts +1 -0
  228. package/dist/esm/jest-setup.js +16 -0
  229. package/dist/esm/jsdom-extended.d.ts +6 -0
  230. package/dist/esm/jsdom-extended.js +12 -0
  231. package/dist/esm/story-utils/index.d.ts +6 -0
  232. package/dist/esm/story-utils/index.js +13 -0
  233. package/dist/esm/utils/composeRefs.d.ts +7 -0
  234. package/dist/esm/utils/composeRefs.js +17 -0
  235. package/dist/esm/utils/composeRefs.test.d.ts +1 -0
  236. package/dist/esm/utils/composeRefs.test.js +17 -0
  237. package/dist/esm/utils/useDevCheckStable.d.ts +8 -0
  238. package/dist/esm/utils/useDevCheckStable.js +26 -0
  239. package/dist/esm/utils/useInterval.d.ts +7 -0
  240. package/dist/esm/utils/useInterval.js +22 -0
  241. package/dist/tsconfig.tsbuildinfo +1 -0
  242. package/dist/type-augmentation/TypescriptDocs.mdx +17 -0
  243. package/dist/type-augmentation/imports.d.ts +3 -0
  244. package/dist/type-augmentation/index.d.ts +3 -0
  245. package/dist/type-augmentation/theme.d.ts +105 -0
  246. package/dist/type-augmentation/typography.d.ts +54 -0
  247. package/package.json +155 -0
@@ -0,0 +1,237 @@
1
+ "use strict";
2
+ var __rest = (this && this.__rest) || function (s, e) {
3
+ var t = {};
4
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
5
+ t[p] = s[p];
6
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
7
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
8
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
9
+ t[p[i]] = s[p[i]];
10
+ }
11
+ return t;
12
+ };
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.baseInputStyles = exports.Input = exports.AdornmentButton = void 0;
15
+ const React = require("react");
16
+ const styled_1 = require("@emotion/styled");
17
+ const react_1 = require("@emotion/react");
18
+ const InputBase_1 = require("@mui/material/InputBase");
19
+ const classnames_1 = require("classnames");
20
+ const defaultProps = {
21
+ size: "medium",
22
+ multiline: false,
23
+ };
24
+ const responsiveSize = {
25
+ small: "small",
26
+ medium: "small",
27
+ large: "medium",
28
+ chat: "chat",
29
+ hero: "large",
30
+ };
31
+ const sizeStyles = ({ size, theme, multiline }) => (0, react_1.css)([
32
+ (size === "small" || size === "medium") && Object.assign({}, theme.typography.body2),
33
+ (size === "large" || size === "chat" || size === "hero") && Object.assign({ ".remixicon": {
34
+ width: "24px",
35
+ height: "24px",
36
+ } }, theme.typography.body1),
37
+ size === "medium" && {
38
+ paddingLeft: "12px",
39
+ paddingRight: "12px",
40
+ },
41
+ size === "small" &&
42
+ !multiline && {
43
+ height: "32px",
44
+ },
45
+ size === "medium" &&
46
+ !multiline && {
47
+ height: "40px",
48
+ },
49
+ size === "large" &&
50
+ !multiline && {
51
+ height: "48px",
52
+ },
53
+ size === "chat" &&
54
+ !multiline && {
55
+ height: "56px",
56
+ },
57
+ size === "hero" &&
58
+ !multiline && {
59
+ height: "72px",
60
+ },
61
+ size === "small" && {
62
+ padding: "0 8px",
63
+ ".Mit-AdornmentButton": {
64
+ width: "32px",
65
+ ".remixicon": {
66
+ width: "16px",
67
+ height: "16px",
68
+ },
69
+ },
70
+ },
71
+ size === "medium" && {
72
+ padding: "0 12px",
73
+ ".Mit-AdornmentButton": {
74
+ width: "40px",
75
+ ".remixicon": {
76
+ width: "20px",
77
+ height: "20px",
78
+ },
79
+ },
80
+ },
81
+ size === "large" && {
82
+ padding: "0 16px",
83
+ ".Mit-AdornmentButton": {
84
+ width: "48px",
85
+ },
86
+ },
87
+ size === "chat" && {
88
+ padding: "0 16px",
89
+ borderRadius: "8px",
90
+ borderColor: theme.custom.colors.silverGrayLight,
91
+ backgroundColor: theme.custom.colors.white,
92
+ ".Mit-AdornmentButton": {
93
+ padding: "0 16px",
94
+ },
95
+ },
96
+ size === "hero" && {
97
+ padding: "0 24px",
98
+ ".Mit-AdornmentButton": {
99
+ width: "72px",
100
+ },
101
+ },
102
+ ]);
103
+ /**
104
+ * Base styles for Input and Select components. Includes border, color, hover effects.
105
+ */
106
+ const baseInputStyles = (theme) => ({
107
+ backgroundColor: "white",
108
+ color: theme.custom.colors.darkGray2,
109
+ borderColor: theme.custom.colors.silverGrayLight,
110
+ borderWidth: "1px",
111
+ borderStyle: "solid",
112
+ borderRadius: "4px",
113
+ overflow: "hidden",
114
+ "&.Mui-disabled": {
115
+ backgroundColor: theme.custom.colors.lightGray1,
116
+ },
117
+ "&:hover:not(.Mui-disabled):not(.Mui-focused)": {
118
+ borderColor: theme.custom.colors.darkGray2,
119
+ },
120
+ "&.Mui-focused": {
121
+ /**
122
+ * When change border width, it affects either the elements outside of it or
123
+ * inside based on the border-box setting.
124
+ *
125
+ * Instead of changing the border width, we hide the border and change width
126
+ * using outline.
127
+ */
128
+ borderColor: "transparent",
129
+ outline: "2px solid currentcolor",
130
+ outlineOffset: "-2px",
131
+ },
132
+ "&.Mui-error": {
133
+ borderColor: theme.custom.colors.red,
134
+ outlineColor: theme.custom.colors.red,
135
+ },
136
+ "& input::placeholder, textarea::placeholder": {
137
+ color: theme.custom.colors.silverGrayDark,
138
+ opacity: 1, // some browsers apply opacity to placeholder text
139
+ },
140
+ "& input:placeholder-shown, textarea:placeholder-shown": {
141
+ textOverflow: "ellipsis",
142
+ },
143
+ "& textarea": {
144
+ paddingTop: "8px",
145
+ paddingBottom: "8px",
146
+ },
147
+ "&.MuiInputBase-adornedStart": {
148
+ paddingLeft: "0",
149
+ input: {
150
+ paddingLeft: "8px",
151
+ },
152
+ },
153
+ "&.MuiInputBase-adornedEnd": {
154
+ paddingRight: "0",
155
+ input: {
156
+ paddingRight: "8px",
157
+ },
158
+ },
159
+ });
160
+ exports.baseInputStyles = baseInputStyles;
161
+ const noForward = Object.keys({
162
+ responsive: true,
163
+ });
164
+ /**
165
+ * Use `Input` for a visually unlabelled input field. If used, it should still
166
+ * have an accessible label, e.g., provided via `aria-label`.
167
+ * For a labeled input field, use `TextField`. instead.
168
+ *
169
+ * **Note:** This component is a styled version of MUI's `InputBase`. See
170
+ * MUI's documentation for full info.
171
+ *
172
+ * - [Smoot Design Input Documentation](https://mitodl.github.io/smoot-design/?path=/docs/smoot-design-input--docs)
173
+ * - [InputBase Documentation](https://mui.com/api/input-base/)
174
+ */
175
+ const Input = (0, styled_1.default)(InputBase_1.default, {
176
+ shouldForwardProp: (prop) => !noForward.includes(prop),
177
+ })(({ theme, size = defaultProps.size, multiline, responsive }) => [
178
+ baseInputStyles(theme),
179
+ sizeStyles({ size, theme, multiline }),
180
+ responsive && {
181
+ [theme.breakpoints.down("sm")]: sizeStyles({
182
+ size: responsiveSize[size],
183
+ theme,
184
+ multiline,
185
+ }),
186
+ },
187
+ ]);
188
+ exports.Input = Input;
189
+ const AdornmentButtonStyled = styled_1.default.button(({ theme, disabled }) => (Object.assign(Object.assign({}, theme.typography.button), {
190
+ // display
191
+ display: "flex", flexShrink: 0, justifyContent: "center", alignItems: "center",
192
+ // background and border
193
+ border: "none", background: "transparent", transition: `background ${theme.transitions.duration.short}ms`,
194
+ // cursor
195
+ cursor: disabled ? "default" : "pointer", ":disabled": {
196
+ cursor: "default",
197
+ svg: {
198
+ fill: theme.custom.colors.silverGray,
199
+ },
200
+ }, ":hover": {
201
+ background: disabled ? "inherit" : "rgba(0, 0, 0, 0.06)",
202
+ }, color: theme.custom.colors.silverGray, ".MuiInputBase-root:hover &": {
203
+ color: "inherit",
204
+ }, ".MuiInputBase-root.Mui-focused &": {
205
+ color: "inherit",
206
+ }, ".MuiInputBase-root.Mui-disabled &": {
207
+ color: "inherit",
208
+ }, height: "100%" })));
209
+ const noFocus = (e) => e.preventDefault();
210
+ /**
211
+ * Button to be used with `startAdornment` and `endAdornment` props on Input and
212
+ * TextField components. AdornmentButton takes care of positioning and other
213
+ * styling concerns.
214
+ *
215
+ * NOTES:
216
+ * - It is generally expected that the content of the AdornmentButton is a
217
+ * Remix Icon component. https://remixicon.com/
218
+ * - By default, the AdornmentButton calls `preventDefault` on `mouseDown`
219
+ * events. This prevents the button from stealing focus from the input on
220
+ * click. The button is still focusable via keyboard events. You can override
221
+ * this behavior by passing your own `onMouseDown` handler.
222
+ */
223
+ const AdornmentButton = (_a) => {
224
+ var { className } = _a, others = __rest(_a, ["className"]);
225
+ return (React.createElement(AdornmentButtonStyled
226
+ /**
227
+ * If the input is focused and user clicks the AdornmentButton, we don't
228
+ * want to steal focus from the input.
229
+ */
230
+ , Object.assign({
231
+ /**
232
+ * If the input is focused and user clicks the AdornmentButton, we don't
233
+ * want to steal focus from the input.
234
+ */
235
+ onMouseDown: noFocus, className: (0, classnames_1.default)("Mit-AdornmentButton", className) }, others)));
236
+ };
237
+ exports.AdornmentButton = AdornmentButton;
@@ -0,0 +1,19 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { Input } from "./Input";
3
+ declare const meta: Meta<typeof Input>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof Input>;
6
+ export declare const Sizes: Story;
7
+ /**
8
+ * **Note:** Adornments should be wrapped in an `AdornmentButton` component.
9
+ *
10
+ * ```tsx
11
+ * <Input startAdornment={
12
+ * <AdornmentButton>
13
+ * <RiSearchLine />
14
+ * </AdornmentButton>
15
+ * } {...otherProps} />
16
+ * ```
17
+ */
18
+ export declare const Adornments: Story;
19
+ export declare const States: Story;
@@ -0,0 +1,135 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.States = exports.Adornments = exports.Sizes = void 0;
4
+ const React = require("react");
5
+ const Input_1 = require("./Input");
6
+ const Stack_1 = require("@mui/material/Stack");
7
+ const Grid2_1 = require("@mui/material/Grid2");
8
+ const react_1 = require("@remixicon/react");
9
+ const test_1 = require("@storybook/test");
10
+ const story_utils_1 = require("../../story-utils");
11
+ const Typography_1 = require("@mui/material/Typography");
12
+ const SIZES = (0, story_utils_1.enumValues)({
13
+ small: true,
14
+ medium: true,
15
+ large: true,
16
+ chat: true,
17
+ hero: true,
18
+ });
19
+ const ADORNMENTS = {
20
+ None: undefined,
21
+ SearchIcon: (React.createElement(Input_1.AdornmentButton, null,
22
+ React.createElement(react_1.RiSearchLine, null))),
23
+ CalendarTodayIcon: (React.createElement(Input_1.AdornmentButton, null,
24
+ React.createElement(react_1.RiCalendarLine, null))),
25
+ CloseIcon: (React.createElement(Input_1.AdornmentButton, null,
26
+ React.createElement(react_1.RiCloseLine, null))),
27
+ "Close and Calendar": (React.createElement(React.Fragment, null,
28
+ React.createElement(Input_1.AdornmentButton, null,
29
+ React.createElement(react_1.RiCloseLine, null)),
30
+ React.createElement(Input_1.AdornmentButton, null,
31
+ React.createElement(react_1.RiCalendarLine, null)))),
32
+ };
33
+ const meta = {
34
+ title: "smoot-design/Input",
35
+ component: Input_1.Input,
36
+ argTypes: {
37
+ startAdornment: {
38
+ options: Object.keys(ADORNMENTS),
39
+ mapping: ADORNMENTS,
40
+ control: { type: "select" },
41
+ },
42
+ endAdornment: {
43
+ options: Object.keys(ADORNMENTS),
44
+ mapping: ADORNMENTS,
45
+ control: { type: "select" },
46
+ },
47
+ },
48
+ args: {
49
+ onChange: (0, test_1.fn)(),
50
+ value: "some value",
51
+ placeholder: "placeholder",
52
+ },
53
+ };
54
+ exports.default = meta;
55
+ exports.Sizes = {
56
+ render: (args) => {
57
+ return (React.createElement(Stack_1.default, { direction: "row", gap: 1 },
58
+ React.createElement(Input_1.Input, Object.assign({ size: "small" }, args)),
59
+ React.createElement(Input_1.Input, Object.assign({ size: "medium" }, args)),
60
+ React.createElement(Input_1.Input, Object.assign({ size: "large" }, args)),
61
+ React.createElement(Input_1.Input, Object.assign({ size: "hero" }, args))));
62
+ },
63
+ };
64
+ /**
65
+ * **Note:** Adornments should be wrapped in an `AdornmentButton` component.
66
+ *
67
+ * ```tsx
68
+ * <Input startAdornment={
69
+ * <AdornmentButton>
70
+ * <RiSearchLine />
71
+ * </AdornmentButton>
72
+ * } {...otherProps} />
73
+ * ```
74
+ */
75
+ exports.Adornments = {
76
+ render: (args) => {
77
+ const adornments = [
78
+ { startAdornment: ADORNMENTS.SearchIcon },
79
+ { endAdornment: ADORNMENTS.CloseIcon },
80
+ {
81
+ startAdornment: ADORNMENTS.SearchIcon,
82
+ endAdornment: ADORNMENTS["Close and Calendar"],
83
+ },
84
+ ];
85
+ return (React.createElement(Grid2_1.default, { container: true, maxWidth: "1400px", spacing: 2 }, Object.values(adornments).flatMap((props, i) => SIZES.map((size) => {
86
+ return (React.createElement(Grid2_1.default, { size: { xs: 3 }, key: `${i}-${size}` },
87
+ React.createElement(Input_1.Input, Object.assign({}, args, { size: size }, props))));
88
+ }))));
89
+ },
90
+ argTypes: {
91
+ startAdornment: { table: { disable: true } },
92
+ endAdornment: { table: { disable: true } },
93
+ },
94
+ };
95
+ exports.States = {
96
+ render: (args) => {
97
+ return (React.createElement(Grid2_1.default, { container: true, spacing: 2, alignItems: "center", maxWidth: "400px" },
98
+ React.createElement(Grid2_1.default, { size: { xs: 4 } },
99
+ React.createElement(Typography_1.default, null, "Placeholder")),
100
+ React.createElement(Grid2_1.default, { size: { xs: 8 } },
101
+ React.createElement(Input_1.Input, Object.assign({}, args, { value: "" }))),
102
+ React.createElement(Grid2_1.default, { size: { xs: 4 } },
103
+ React.createElement(Typography_1.default, null, "Default")),
104
+ React.createElement(Grid2_1.default, { size: { xs: 8 } },
105
+ React.createElement(Input_1.Input, Object.assign({}, args))),
106
+ React.createElement(Grid2_1.default, { size: { xs: 4 } },
107
+ React.createElement(Typography_1.default, null, "Initially Focused")),
108
+ React.createElement(Grid2_1.default, { size: { xs: 8 } },
109
+ React.createElement(Input_1.Input
110
+ // This is a story just demonstrating the autofocus prop
111
+ // eslint-disable-next-line jsx-a11y/no-autofocus
112
+ , Object.assign({
113
+ // This is a story just demonstrating the autofocus prop
114
+ // eslint-disable-next-line jsx-a11y/no-autofocus
115
+ autoFocus: true }, args))),
116
+ React.createElement(Grid2_1.default, { size: { xs: 4 } },
117
+ React.createElement(Typography_1.default, null, "Error")),
118
+ React.createElement(Grid2_1.default, { size: { xs: 8 } },
119
+ React.createElement(Input_1.Input, Object.assign({}, args, { error: true }))),
120
+ React.createElement(Grid2_1.default, { size: { xs: 4 } },
121
+ React.createElement(Typography_1.default, null, "Disabled")),
122
+ React.createElement(Grid2_1.default, { size: { xs: 8 } },
123
+ React.createElement(Input_1.Input, Object.assign({}, args, { disabled: true })))));
124
+ },
125
+ args: {
126
+ placeholder: "This is placeholder text.",
127
+ value: "Some value",
128
+ },
129
+ argTypes: {
130
+ placeholder: { table: { disable: true } },
131
+ value: { table: { disable: true } },
132
+ error: { table: { disable: true } },
133
+ disabled: { table: { disable: true } },
134
+ },
135
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const React = require("react");
13
+ const react_1 = require("@testing-library/react");
14
+ const user_event_1 = require("@testing-library/user-event");
15
+ const Input_1 = require("./Input");
16
+ const ThemeProvider_1 = require("../ThemeProvider/ThemeProvider");
17
+ describe("AdornmentButton", () => {
18
+ it("Does not steal focus from input when clicked", () => __awaiter(void 0, void 0, void 0, function* () {
19
+ const onClick = jest.fn();
20
+ (0, react_1.render)(React.createElement(Input_1.Input, { endAdornment: React.createElement(Input_1.AdornmentButton, { onClick: onClick }, "Test") }), { wrapper: ThemeProvider_1.ThemeProvider });
21
+ const input = react_1.screen.getByRole("textbox");
22
+ const button = react_1.screen.getByRole("button", { name: "Test" });
23
+ yield user_event_1.default.click(input);
24
+ expect(input).toHaveFocus();
25
+ yield user_event_1.default.click(button);
26
+ expect(input).toHaveFocus();
27
+ expect(onClick).toHaveBeenCalledTimes(1);
28
+ // But it should still be focusable via keyboard
29
+ yield user_event_1.default.tab();
30
+ expect(button).toHaveFocus();
31
+ }));
32
+ });
@@ -0,0 +1,23 @@
1
+ import * as React from "react";
2
+ /**
3
+ * LinkAdapterPropsOverrides can be used with module augmentation to provide
4
+ * extra props to ButtonLink.
5
+ *
6
+ * For example, in a NextJS App, you might set `next/link` as your default
7
+ * Link implementation, and use LinkAdapterPropsOverrides to provide
8
+ * `next/link`-specific props.
9
+ */
10
+ interface LinkAdapterPropsOverrides {
11
+ }
12
+ type LinkAdapterProps = React.ComponentProps<"a"> & {
13
+ Component?: React.ElementType;
14
+ } & LinkAdapterPropsOverrides;
15
+ /**
16
+ * Overrideable link component.
17
+ * - If `Component` is provided, renders as `Component`
18
+ * - else, if `theme.custom.LinkAdapter` is provided, renders as `theme.custom.LinkAdapter`
19
+ * - else, renders as `a` tag
20
+ */
21
+ declare const LinkAdapter: React.ForwardRefExoticComponent<Omit<LinkAdapterProps, "ref"> & React.RefAttributes<HTMLAnchorElement>>;
22
+ export { LinkAdapter };
23
+ export type { LinkAdapterPropsOverrides, LinkAdapterProps };
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ var __rest = (this && this.__rest) || function (s, e) {
3
+ var t = {};
4
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
5
+ t[p] = s[p];
6
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
7
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
8
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
9
+ t[p[i]] = s[p[i]];
10
+ }
11
+ return t;
12
+ };
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.LinkAdapter = void 0;
15
+ const React = require("react");
16
+ const react_1 = require("@emotion/react");
17
+ const styled_1 = require("@emotion/styled");
18
+ const PlainLink = styled_1.default.a({
19
+ color: "inherit",
20
+ textDecoration: "none",
21
+ });
22
+ /**
23
+ * Overrideable link component.
24
+ * - If `Component` is provided, renders as `Component`
25
+ * - else, if `theme.custom.LinkAdapter` is provided, renders as `theme.custom.LinkAdapter`
26
+ * - else, renders as `a` tag
27
+ */
28
+ const LinkAdapter = React.forwardRef(function LinkAdapter(_a, ref) {
29
+ var { Component } = _a, props = __rest(_a, ["Component"]);
30
+ const theme = (0, react_1.useTheme)();
31
+ const LinkComponent = Component !== null && Component !== void 0 ? Component : theme.custom.LinkAdapter;
32
+ return React.createElement(PlainLink, Object.assign({ as: LinkComponent, ref: ref }, props));
33
+ });
34
+ exports.LinkAdapter = LinkAdapter;
@@ -0,0 +1,19 @@
1
+ import * as React from "react";
2
+ type ScrollSnapProps = {
3
+ /**
4
+ * Tolerance within which scroll will be considered "at the bottom" of the element.
5
+ */
6
+ threshold?: number;
7
+ /**
8
+ * Content to be displayed
9
+ */
10
+ children: React.ReactNode;
11
+ className?: string;
12
+ };
13
+ /**
14
+ * Component that automatically scrolls to the bottom of the element when new
15
+ * content is added, unless the user has scrolled up.
16
+ */
17
+ declare const ScrollSnap: React.ForwardRefExoticComponent<ScrollSnapProps & React.RefAttributes<HTMLDivElement>>;
18
+ export { ScrollSnap };
19
+ export type { ScrollSnapProps };
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ScrollSnap = void 0;
4
+ const composeRefs_1 = require("../../utils/composeRefs");
5
+ const styled_1 = require("@emotion/styled");
6
+ const React = require("react");
7
+ /**
8
+ * Returns the distance between visible content and the bottom of the element.
9
+ */
10
+ const distanceFromBottom = (el) => {
11
+ return el.scrollHeight - el.clientHeight - el.scrollTop;
12
+ };
13
+ /**
14
+ * Scrolls to the bottom of the element.
15
+ */
16
+ const scrollToBottom = (el) => {
17
+ el.scrollTop = el.scrollHeight;
18
+ };
19
+ const Scroller = styled_1.default.div({
20
+ overflow: "auto",
21
+ });
22
+ /**
23
+ * Component that automatically scrolls to the bottom of the element when new
24
+ * content is added, unless the user has scrolled up.
25
+ */
26
+ const ScrollSnap = React.forwardRef(function ScrollSnap({ children, threshold = 2, className }, ref) {
27
+ const el = React.useRef(null);
28
+ // `content` a delayed version of children to allow measuring scroll position
29
+ // using the old children.
30
+ const [content, setContent] = React.useState(children);
31
+ const wasAtBottom = React.useRef(null);
32
+ /**
33
+ * The next two effects:
34
+ * 1. Check if the element is at the bottom.
35
+ * 2. Then set children -> content
36
+ * 3. Then scroll to bottom (if needed)
37
+ *
38
+ * In this way, we can measure the scroll position before the new content is set.
39
+ *
40
+ * In React 19, this started requiring useLayoutEffect.
41
+ */
42
+ React.useLayoutEffect(() => {
43
+ if (!el.current)
44
+ return;
45
+ wasAtBottom.current = distanceFromBottom(el.current) < threshold;
46
+ setContent(children);
47
+ }, [children, threshold]);
48
+ React.useLayoutEffect(() => {
49
+ if (!el.current)
50
+ return;
51
+ const atBottom = distanceFromBottom(el.current) < threshold;
52
+ if (wasAtBottom.current && !atBottom) {
53
+ scrollToBottom(el.current);
54
+ wasAtBottom.current = null;
55
+ }
56
+ }, [content, threshold]);
57
+ return (React.createElement(Scroller, { className: className, ref: (0, composeRefs_1.composeRefs)(el, ref) }, content));
58
+ });
59
+ exports.ScrollSnap = ScrollSnap;
@@ -0,0 +1,6 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { ScrollSnap } from "./ScrollSnap";
3
+ declare const meta: Meta<typeof ScrollSnap>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof ScrollSnap>;
6
+ export declare const Chat: Story;
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Chat = void 0;
4
+ const React = require("react");
5
+ const ScrollSnap_1 = require("./ScrollSnap");
6
+ const styled_1 = require("@emotion/styled");
7
+ const en_1 = require("@faker-js/faker/locale/en");
8
+ const useInterval_1 = require("../../utils/useInterval");
9
+ const Slider_1 = require("@mui/material/Slider");
10
+ const Stack_1 = require("@mui/material/Stack");
11
+ const Typography_1 = require("@mui/material/Typography");
12
+ const Button_1 = require("../Button/Button");
13
+ const Scroller = (0, styled_1.default)(ScrollSnap_1.ScrollSnap)({
14
+ width: "200px",
15
+ height: "350px",
16
+ border: "1pt solid black",
17
+ });
18
+ const meta = {
19
+ title: "smoot-design/ScrollSnap",
20
+ component: ScrollSnap_1.ScrollSnap,
21
+ render: function Render(args) {
22
+ const MAX = 3000;
23
+ const [updateInterval, setUpdateInterval] = React.useState(MAX);
24
+ const [children, setChildren] = React.useState(en_1.faker.lorem.sentence());
25
+ const appendText = () => setChildren((current) => {
26
+ return `${current} ${en_1.faker.lorem.sentence()}`;
27
+ });
28
+ (0, useInterval_1.useInterval)(() => {
29
+ appendText();
30
+ }, updateInterval === MAX ? null : updateInterval);
31
+ return (React.createElement(Stack_1.default, { gap: "12px", alignItems: "start" },
32
+ React.createElement(Typography_1.default, null, "Update interval (ms)"),
33
+ React.createElement(Slider_1.default, { sx: { width: "350px" }, marks: [
34
+ { value: 100, label: "0.1s" },
35
+ { value: 2000, label: "2s" },
36
+ { value: MAX, label: "off" },
37
+ ], value: updateInterval, min: 100, max: MAX, onChange: (_e, val) => setUpdateInterval(val) }),
38
+ React.createElement(Scroller, Object.assign({}, args), children),
39
+ React.createElement(Button_1.Button, { onClick: appendText }, "Append Sentence")));
40
+ },
41
+ };
42
+ exports.default = meta;
43
+ exports.Chat = {};
@@ -0,0 +1,6 @@
1
+ declare const useScrollSnap: ({ scrollElement, contentElement, threshold, }: {
2
+ scrollElement: HTMLElement | null;
3
+ contentElement?: HTMLElement | null;
4
+ threshold?: number;
5
+ }) => void;
6
+ export { useScrollSnap };
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useScrollSnap = void 0;
4
+ const react_1 = require("react");
5
+ /**
6
+ * Returns the distance between visible content and the bottom of the element.
7
+ */
8
+ const distanceFromBottom = (el) => {
9
+ return el.scrollHeight - el.clientHeight - el.scrollTop;
10
+ };
11
+ /**
12
+ * Scrolls to the bottom of the element.
13
+ */
14
+ const scrollToBottom = (el) => {
15
+ el.scrollTop = el.scrollHeight;
16
+ };
17
+ const useScrollSnap = ({ scrollElement, contentElement, threshold = 2, }) => {
18
+ (0, react_1.useEffect)(() => {
19
+ const onGrow = () => {
20
+ if (!scrollElement)
21
+ return;
22
+ if (distanceFromBottom(scrollElement) < threshold) {
23
+ scrollToBottom(scrollElement);
24
+ }
25
+ };
26
+ onGrow();
27
+ const resizeObserver = new ResizeObserver(onGrow);
28
+ if (contentElement) {
29
+ resizeObserver.observe(contentElement);
30
+ }
31
+ return () => {
32
+ resizeObserver.disconnect();
33
+ };
34
+ }, [scrollElement, contentElement, threshold]);
35
+ };
36
+ exports.useScrollSnap = useScrollSnap;