@mitodl/smoot-design 0.0.0-preview215f7ae3fa

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 (190) hide show
  1. package/LICENSE +28 -0
  2. package/README.md +27 -0
  3. package/dist/bundles/aiChat.es.js +24812 -0
  4. package/dist/bundles/aiChat.umd.js +161 -0
  5. package/dist/cjs/ai.d.ts +2 -0
  6. package/dist/cjs/ai.js +5 -0
  7. package/dist/cjs/bundles/aiChat.d.ts +6 -0
  8. package/dist/cjs/bundles/aiChat.js +13 -0
  9. package/dist/cjs/components/AiChat/AiChat.d.ts +5 -0
  10. package/dist/cjs/components/AiChat/AiChat.js +150 -0
  11. package/dist/cjs/components/AiChat/AiChat.stories.d.ts +11 -0
  12. package/dist/cjs/components/AiChat/AiChat.stories.js +76 -0
  13. package/dist/cjs/components/AiChat/AiChat.test.d.ts +1 -0
  14. package/dist/cjs/components/AiChat/AiChat.test.js +130 -0
  15. package/dist/cjs/components/AiChat/story-utils.d.ts +3 -0
  16. package/dist/cjs/components/AiChat/story-utils.js +100 -0
  17. package/dist/cjs/components/AiChat/types.d.ts +45 -0
  18. package/dist/cjs/components/AiChat/types.js +3 -0
  19. package/dist/cjs/components/AiChat/utils.d.ts +9 -0
  20. package/dist/cjs/components/AiChat/utils.js +31 -0
  21. package/dist/cjs/components/Button/ActionButton.d.ts +30 -0
  22. package/dist/cjs/components/Button/ActionButton.js +73 -0
  23. package/dist/cjs/components/Button/ActionButton.stories.d.ts +15 -0
  24. package/dist/cjs/components/Button/ActionButton.stories.js +116 -0
  25. package/dist/cjs/components/Button/Button.d.ts +56 -0
  26. package/dist/cjs/components/Button/Button.js +273 -0
  27. package/dist/cjs/components/Button/Button.stories.d.ts +17 -0
  28. package/dist/cjs/components/Button/Button.stories.js +138 -0
  29. package/dist/cjs/components/Button/Button.test.d.ts +1 -0
  30. package/dist/cjs/components/Button/Button.test.js +46 -0
  31. package/dist/cjs/components/Input/Input.d.ts +115 -0
  32. package/dist/cjs/components/Input/Input.js +219 -0
  33. package/dist/cjs/components/Input/Input.stories.d.ts +19 -0
  34. package/dist/cjs/components/Input/Input.stories.js +134 -0
  35. package/dist/cjs/components/Input/Input.test.d.ts +1 -0
  36. package/dist/cjs/components/Input/Input.test.js +32 -0
  37. package/dist/cjs/components/LinkAdapter/LinkAdapter.d.ts +23 -0
  38. package/dist/cjs/components/LinkAdapter/LinkAdapter.js +34 -0
  39. package/dist/cjs/components/ScrollSnap/ScrollSnap.d.ts +19 -0
  40. package/dist/cjs/components/ScrollSnap/ScrollSnap.js +59 -0
  41. package/dist/cjs/components/ScrollSnap/ScrollSnap.stories.d.ts +6 -0
  42. package/dist/cjs/components/ScrollSnap/ScrollSnap.stories.js +43 -0
  43. package/dist/cjs/components/SrAnnouncer/SrAnnouncer.d.ts +25 -0
  44. package/dist/cjs/components/SrAnnouncer/SrAnnouncer.js +43 -0
  45. package/dist/cjs/components/SrAnnouncer/SrAnnouncer.stories.d.ts +6 -0
  46. package/dist/cjs/components/SrAnnouncer/SrAnnouncer.stories.js +44 -0
  47. package/dist/cjs/components/SrAnnouncer/SrAnnouncer.test.d.ts +1 -0
  48. package/dist/cjs/components/SrAnnouncer/SrAnnouncer.test.js +62 -0
  49. package/dist/cjs/components/TextField/TextField.d.ts +29 -0
  50. package/dist/cjs/components/TextField/TextField.js +33 -0
  51. package/dist/cjs/components/TextField/TextField.stories.d.ts +10 -0
  52. package/dist/cjs/components/TextField/TextField.stories.js +135 -0
  53. package/dist/cjs/components/TextField/TextField.test.d.ts +1 -0
  54. package/dist/cjs/components/TextField/TextField.test.js +77 -0
  55. package/dist/cjs/components/ThemeProvider/ThemeProvider.d.ts +23 -0
  56. package/dist/cjs/components/ThemeProvider/ThemeProvider.js +90 -0
  57. package/dist/cjs/components/ThemeProvider/ThemeProvider.stories.d.ts +58 -0
  58. package/dist/cjs/components/ThemeProvider/ThemeProvider.stories.js +97 -0
  59. package/dist/cjs/components/ThemeProvider/Typography.stories.d.ts +39 -0
  60. package/dist/cjs/components/ThemeProvider/Typography.stories.js +65 -0
  61. package/dist/cjs/components/ThemeProvider/breakpoints.d.ts +4 -0
  62. package/dist/cjs/components/ThemeProvider/breakpoints.js +20 -0
  63. package/dist/cjs/components/ThemeProvider/buttons.d.ts +7 -0
  64. package/dist/cjs/components/ThemeProvider/buttons.js +20 -0
  65. package/dist/cjs/components/ThemeProvider/chips.d.ts +3 -0
  66. package/dist/cjs/components/ThemeProvider/chips.js +154 -0
  67. package/dist/cjs/components/ThemeProvider/colors.d.ts +32 -0
  68. package/dist/cjs/components/ThemeProvider/colors.js +35 -0
  69. package/dist/cjs/components/ThemeProvider/typography.d.ts +18 -0
  70. package/dist/cjs/components/ThemeProvider/typography.js +174 -0
  71. package/dist/cjs/components/VisuallyHidden/VisuallyHidden.d.ts +24 -0
  72. package/dist/cjs/components/VisuallyHidden/VisuallyHidden.js +33 -0
  73. package/dist/cjs/components/VisuallyHidden/VisuallyHidden.stories.d.ts +6 -0
  74. package/dist/cjs/components/VisuallyHidden/VisuallyHidden.stories.js +13 -0
  75. package/dist/cjs/components/internal/FormHelpers/FormHelpers.d.ts +39 -0
  76. package/dist/cjs/components/internal/FormHelpers/FormHelpers.js +78 -0
  77. package/dist/cjs/components/internal/FormHelpers/FormHelpers.test.d.ts +1 -0
  78. package/dist/cjs/components/internal/FormHelpers/FormHelpers.test.js +93 -0
  79. package/dist/cjs/index.d.ts +16 -0
  80. package/dist/cjs/index.js +28 -0
  81. package/dist/cjs/jest-setup.d.ts +1 -0
  82. package/dist/cjs/jest-setup.js +18 -0
  83. package/dist/cjs/jsdom-extended.d.ts +6 -0
  84. package/dist/cjs/jsdom-extended.js +14 -0
  85. package/dist/cjs/story-utils/index.d.ts +6 -0
  86. package/dist/cjs/story-utils/index.js +17 -0
  87. package/dist/cjs/utils/composeRefs.d.ts +7 -0
  88. package/dist/cjs/utils/composeRefs.js +20 -0
  89. package/dist/cjs/utils/composeRefs.test.d.ts +1 -0
  90. package/dist/cjs/utils/composeRefs.test.js +19 -0
  91. package/dist/cjs/utils/useDevCheckStable.d.ts +8 -0
  92. package/dist/cjs/utils/useDevCheckStable.js +29 -0
  93. package/dist/cjs/utils/useInterval.d.ts +7 -0
  94. package/dist/cjs/utils/useInterval.js +25 -0
  95. package/dist/esm/ai.d.ts +2 -0
  96. package/dist/esm/ai.js +1 -0
  97. package/dist/esm/bundles/aiChat.d.ts +6 -0
  98. package/dist/esm/bundles/aiChat.js +10 -0
  99. package/dist/esm/components/AiChat/AiChat.d.ts +5 -0
  100. package/dist/esm/components/AiChat/AiChat.js +147 -0
  101. package/dist/esm/components/AiChat/AiChat.stories.d.ts +11 -0
  102. package/dist/esm/components/AiChat/AiChat.stories.js +73 -0
  103. package/dist/esm/components/AiChat/AiChat.test.d.ts +1 -0
  104. package/dist/esm/components/AiChat/AiChat.test.js +128 -0
  105. package/dist/esm/components/AiChat/story-utils.d.ts +3 -0
  106. package/dist/esm/components/AiChat/story-utils.js +96 -0
  107. package/dist/esm/components/AiChat/types.d.ts +45 -0
  108. package/dist/esm/components/AiChat/types.js +2 -0
  109. package/dist/esm/components/AiChat/utils.d.ts +9 -0
  110. package/dist/esm/components/AiChat/utils.js +28 -0
  111. package/dist/esm/components/Button/ActionButton.d.ts +30 -0
  112. package/dist/esm/components/Button/ActionButton.js +68 -0
  113. package/dist/esm/components/Button/ActionButton.stories.d.ts +15 -0
  114. package/dist/esm/components/Button/ActionButton.stories.js +113 -0
  115. package/dist/esm/components/Button/Button.d.ts +56 -0
  116. package/dist/esm/components/Button/Button.js +265 -0
  117. package/dist/esm/components/Button/Button.stories.d.ts +17 -0
  118. package/dist/esm/components/Button/Button.stories.js +135 -0
  119. package/dist/esm/components/Button/Button.test.d.ts +1 -0
  120. package/dist/esm/components/Button/Button.test.js +44 -0
  121. package/dist/esm/components/Input/Input.d.ts +115 -0
  122. package/dist/esm/components/Input/Input.js +214 -0
  123. package/dist/esm/components/Input/Input.stories.d.ts +19 -0
  124. package/dist/esm/components/Input/Input.stories.js +131 -0
  125. package/dist/esm/components/Input/Input.test.d.ts +1 -0
  126. package/dist/esm/components/Input/Input.test.js +30 -0
  127. package/dist/esm/components/LinkAdapter/LinkAdapter.d.ts +23 -0
  128. package/dist/esm/components/LinkAdapter/LinkAdapter.js +31 -0
  129. package/dist/esm/components/ScrollSnap/ScrollSnap.d.ts +19 -0
  130. package/dist/esm/components/ScrollSnap/ScrollSnap.js +56 -0
  131. package/dist/esm/components/ScrollSnap/ScrollSnap.stories.d.ts +6 -0
  132. package/dist/esm/components/ScrollSnap/ScrollSnap.stories.js +40 -0
  133. package/dist/esm/components/SrAnnouncer/SrAnnouncer.d.ts +25 -0
  134. package/dist/esm/components/SrAnnouncer/SrAnnouncer.js +40 -0
  135. package/dist/esm/components/SrAnnouncer/SrAnnouncer.stories.d.ts +6 -0
  136. package/dist/esm/components/SrAnnouncer/SrAnnouncer.stories.js +41 -0
  137. package/dist/esm/components/SrAnnouncer/SrAnnouncer.test.d.ts +1 -0
  138. package/dist/esm/components/SrAnnouncer/SrAnnouncer.test.js +60 -0
  139. package/dist/esm/components/TextField/TextField.d.ts +29 -0
  140. package/dist/esm/components/TextField/TextField.js +30 -0
  141. package/dist/esm/components/TextField/TextField.stories.d.ts +10 -0
  142. package/dist/esm/components/TextField/TextField.stories.js +132 -0
  143. package/dist/esm/components/TextField/TextField.test.d.ts +1 -0
  144. package/dist/esm/components/TextField/TextField.test.js +75 -0
  145. package/dist/esm/components/ThemeProvider/ThemeProvider.d.ts +23 -0
  146. package/dist/esm/components/ThemeProvider/ThemeProvider.js +86 -0
  147. package/dist/esm/components/ThemeProvider/ThemeProvider.stories.d.ts +58 -0
  148. package/dist/esm/components/ThemeProvider/ThemeProvider.stories.js +94 -0
  149. package/dist/esm/components/ThemeProvider/Typography.stories.d.ts +39 -0
  150. package/dist/esm/components/ThemeProvider/Typography.stories.js +62 -0
  151. package/dist/esm/components/ThemeProvider/breakpoints.d.ts +4 -0
  152. package/dist/esm/components/ThemeProvider/breakpoints.js +16 -0
  153. package/dist/esm/components/ThemeProvider/buttons.d.ts +7 -0
  154. package/dist/esm/components/ThemeProvider/buttons.js +17 -0
  155. package/dist/esm/components/ThemeProvider/chips.d.ts +3 -0
  156. package/dist/esm/components/ThemeProvider/chips.js +151 -0
  157. package/dist/esm/components/ThemeProvider/colors.d.ts +32 -0
  158. package/dist/esm/components/ThemeProvider/colors.js +32 -0
  159. package/dist/esm/components/ThemeProvider/typography.d.ts +18 -0
  160. package/dist/esm/components/ThemeProvider/typography.js +168 -0
  161. package/dist/esm/components/VisuallyHidden/VisuallyHidden.d.ts +24 -0
  162. package/dist/esm/components/VisuallyHidden/VisuallyHidden.js +30 -0
  163. package/dist/esm/components/VisuallyHidden/VisuallyHidden.stories.d.ts +6 -0
  164. package/dist/esm/components/VisuallyHidden/VisuallyHidden.stories.js +10 -0
  165. package/dist/esm/components/internal/FormHelpers/FormHelpers.d.ts +39 -0
  166. package/dist/esm/components/internal/FormHelpers/FormHelpers.js +73 -0
  167. package/dist/esm/components/internal/FormHelpers/FormHelpers.test.d.ts +1 -0
  168. package/dist/esm/components/internal/FormHelpers/FormHelpers.test.js +91 -0
  169. package/dist/esm/index.d.ts +16 -0
  170. package/dist/esm/index.js +11 -0
  171. package/dist/esm/jest-setup.d.ts +1 -0
  172. package/dist/esm/jest-setup.js +16 -0
  173. package/dist/esm/jsdom-extended.d.ts +6 -0
  174. package/dist/esm/jsdom-extended.js +12 -0
  175. package/dist/esm/story-utils/index.d.ts +6 -0
  176. package/dist/esm/story-utils/index.js +13 -0
  177. package/dist/esm/utils/composeRefs.d.ts +7 -0
  178. package/dist/esm/utils/composeRefs.js +17 -0
  179. package/dist/esm/utils/composeRefs.test.d.ts +1 -0
  180. package/dist/esm/utils/composeRefs.test.js +17 -0
  181. package/dist/esm/utils/useDevCheckStable.d.ts +8 -0
  182. package/dist/esm/utils/useDevCheckStable.js +26 -0
  183. package/dist/esm/utils/useInterval.d.ts +7 -0
  184. package/dist/esm/utils/useInterval.js +22 -0
  185. package/dist/tsconfig.tsbuildinfo +1 -0
  186. package/dist/type-augmentation/TypescriptDocs.mdx +17 -0
  187. package/dist/type-augmentation/index.d.ts +2 -0
  188. package/dist/type-augmentation/theme.d.ts +103 -0
  189. package/dist/type-augmentation/typography.d.ts +54 -0
  190. package/package.json +141 -0
@@ -0,0 +1,45 @@
1
+ type Role = "assistant" | "user";
2
+ type ChatMessage = {
3
+ id: string;
4
+ content: string;
5
+ role: Role;
6
+ };
7
+ type RequestOpts = {
8
+ apiUrl: string;
9
+ /**
10
+ * Transforms array of chat messages into request body. Messages
11
+ * are ordered oldest to newest.
12
+ *
13
+ * JSON.stringify is applied to the return value.
14
+ */
15
+ transformBody?: (messages: ChatMessage[]) => unknown;
16
+ /**
17
+ * Extra options to pass to fetch.
18
+ *
19
+ * If headers are specified, they will override the headersOpts.
20
+ */
21
+ fetchOpts?: RequestInit;
22
+ /**
23
+ * Extra headers to pass to fetch.
24
+ */
25
+ headersOpts?: HeadersInit;
26
+ };
27
+ type AiChatProps = {
28
+ className?: string;
29
+ initialMessages: Omit<ChatMessage, "id">[];
30
+ conversationStarters?: {
31
+ content: string;
32
+ }[];
33
+ requestOpts: RequestOpts;
34
+ parseContent?: (content: unknown) => string;
35
+ /**
36
+ * A message to display while the component is in a loading state.
37
+ *
38
+ * Identical consecutive messages may not be read on some screen readers.
39
+ */
40
+ srLoadingMessages?: {
41
+ delay: number;
42
+ text: string;
43
+ }[];
44
+ };
45
+ export type { RequestOpts, AiChatProps, ChatMessage };
@@ -0,0 +1,2 @@
1
+ // Some of these are based on (compatible, but simplfied / restricted) versions of ai/react types.
2
+ export {};
@@ -0,0 +1,9 @@
1
+ import { UseChatOptions } from "ai/react";
2
+ import type { RequestOpts } from "./types";
3
+ declare const useAiChat: (requestOpts: RequestOpts, opts: UseChatOptions) => import("@ai-sdk/react").UseChatHelpers & {
4
+ addToolResult: ({ toolCallId, result, }: {
5
+ toolCallId: string;
6
+ result: any;
7
+ }) => void;
8
+ };
9
+ export { useAiChat };
@@ -0,0 +1,28 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { useChat } from "ai/react";
11
+ import { useMemo } from "react";
12
+ const identity = (x) => x;
13
+ const getFetcher = (requestOpts) => (url, opts) => __awaiter(void 0, void 0, void 0, function* () {
14
+ var _a;
15
+ if (typeof (opts === null || opts === void 0 ? void 0 : opts.body) !== "string") {
16
+ console.error("Unexpected body type.");
17
+ return window.fetch(url, opts);
18
+ }
19
+ const messages = JSON.parse(opts === null || opts === void 0 ? void 0 : opts.body).messages;
20
+ const transformBody = (_a = requestOpts.transformBody) !== null && _a !== void 0 ? _a : identity;
21
+ const options = Object.assign(Object.assign(Object.assign({}, opts), { body: JSON.stringify(transformBody(messages)), headers: Object.assign(Object.assign(Object.assign({}, opts === null || opts === void 0 ? void 0 : opts.headers), { "Content-Type": "application/json" }), requestOpts.headersOpts) }), requestOpts.fetchOpts);
22
+ return fetch(url, options);
23
+ });
24
+ const useAiChat = (requestOpts, opts) => {
25
+ const fetcher = useMemo(() => getFetcher(requestOpts), [requestOpts]);
26
+ return useChat(Object.assign({ api: requestOpts.apiUrl, streamProtocol: "text", fetch: fetcher }, opts));
27
+ };
28
+ export { useAiChat };
@@ -0,0 +1,30 @@
1
+ import * as React from "react";
2
+ import { DEFAULT_PROPS } from "./Button";
3
+ import type { ButtonStyleProps } from "./Button";
4
+ import type { LinkAdapterPropsOverrides } from "../LinkAdapter/LinkAdapter";
5
+ type ActionButtonStyleProps = Omit<ButtonStyleProps, "startIcon" | "endIcon">;
6
+ type ActionButtonProps = ActionButtonStyleProps & React.ComponentProps<"button">;
7
+ /**
8
+ * A button that should contain a remixicon icon and nothing else.
9
+ * See [ActionButton docs](https://mitodl.github.io/smoot-design/?path=/docs/smoot-design-actionbutton--docs).
10
+ *
11
+ * See also:
12
+ * - [ActionButtonLink](https://mitodl.github.io/smoot-design/?path=/docs/smoot-design-actionbutton--docs#links)
13
+ * - [Button](https://mitodl.github.io/smoot-design/?path=/docs/smoot-design-button--docs) for text buttons
14
+ */
15
+ declare const ActionButton: import("@emotion/styled").StyledComponent<Omit<ActionButtonProps, "ref"> & React.RefAttributes<HTMLButtonElement> & {
16
+ theme?: import("@emotion/react").Theme;
17
+ }, {}, {}>;
18
+ type ActionButtonLinkProps = ActionButtonStyleProps & React.ComponentProps<"a"> & {
19
+ Component?: React.ElementType;
20
+ } & LinkAdapterPropsOverrides;
21
+ /**
22
+ * See [ActionButtonLink docs](https://mitodl.github.io/smoot-design/?path=/docs/smoot-design-actionbutton--docs#links)
23
+ */
24
+ declare const ActionButtonLink: import("@emotion/styled").StyledComponent<Omit<ActionButtonProps, "ref"> & React.RefAttributes<HTMLButtonElement> & {
25
+ theme?: import("@emotion/react").Theme;
26
+ } & ActionButtonStyleProps & React.ClassAttributes<HTMLAnchorElement> & React.AnchorHTMLAttributes<HTMLAnchorElement> & {
27
+ Component?: React.ElementType;
28
+ } & LinkAdapterPropsOverrides, {}, {}>;
29
+ export { ActionButton, ActionButtonLink, DEFAULT_PROPS };
30
+ export type { ActionButtonProps, ActionButtonLinkProps };
@@ -0,0 +1,68 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import * as React from "react";
13
+ import styled from "@emotion/styled";
14
+ import { pxToRem } from "../ThemeProvider/typography";
15
+ import { ButtonRoot, ButtonLinkRoot, RESPONSIVE_SIZES, DEFAULT_PROPS, } from "./Button";
16
+ const actionStyles = (size) => {
17
+ return {
18
+ minWidth: "auto",
19
+ padding: 0,
20
+ height: {
21
+ small: "32px",
22
+ medium: "40px",
23
+ large: "48px",
24
+ }[size],
25
+ width: {
26
+ small: "32px",
27
+ medium: "40px",
28
+ large: "48px",
29
+ }[size],
30
+ "& svg, & .MuiSvgIcon-root": {
31
+ width: "1em",
32
+ height: "1em",
33
+ fontSize: pxToRem({
34
+ small: 20,
35
+ medium: 24,
36
+ large: 32,
37
+ }[size]),
38
+ },
39
+ };
40
+ };
41
+ /**
42
+ * A button that should contain a remixicon icon and nothing else.
43
+ * See [ActionButton docs](https://mitodl.github.io/smoot-design/?path=/docs/smoot-design-actionbutton--docs).
44
+ *
45
+ * See also:
46
+ * - [ActionButtonLink](https://mitodl.github.io/smoot-design/?path=/docs/smoot-design-actionbutton--docs#links)
47
+ * - [Button](https://mitodl.github.io/smoot-design/?path=/docs/smoot-design-button--docs) for text buttons
48
+ */
49
+ const ActionButton = styled(React.forwardRef(function Root(props, ref) {
50
+ return React.createElement(ButtonRoot, Object.assign({ ref: ref, type: "button" }, props));
51
+ }))(({ size = DEFAULT_PROPS.size, responsive, theme }) => {
52
+ return [
53
+ actionStyles(size),
54
+ responsive && {
55
+ [theme.breakpoints.down("sm")]: actionStyles(RESPONSIVE_SIZES[size]),
56
+ },
57
+ ];
58
+ });
59
+ ActionButton.displayName = "ActionButton";
60
+ /**
61
+ * See [ActionButtonLink docs](https://mitodl.github.io/smoot-design/?path=/docs/smoot-design-actionbutton--docs#links)
62
+ */
63
+ const ActionButtonLink = ActionButton.withComponent((_a) => {
64
+ var { Component } = _a, props = __rest(_a, ["Component"]);
65
+ return React.createElement(ButtonLinkRoot, Object.assign({ Component: Component }, props));
66
+ });
67
+ ActionButtonLink.displayName = "ActionButtonLink";
68
+ export { ActionButton, ActionButtonLink, DEFAULT_PROPS };
@@ -0,0 +1,15 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { ActionButton } from "./ActionButton";
3
+ declare const meta: Meta<typeof ActionButton>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof ActionButton>;
6
+ export declare const VariantsAndEdge: Story;
7
+ /**
8
+ * `ActionButtonLink` is styled as a `ActionButton` that renders an anchor tag.
9
+ *
10
+ * To use a custom link component (E.g. `Link` from `react-router` or `next/link`),
11
+ * pass it as the `Component` prop. Alternatively, customize the project-wide
12
+ * default link adapter via [Theme's LinkAdapter](../?path=/docs/smoot-design-themeprovider--docs)
13
+ */
14
+ export declare const Links: Story;
15
+ export declare const Showcase: Story;
@@ -0,0 +1,113 @@
1
+ import * as React from "react";
2
+ import { ActionButton, ActionButtonLink, DEFAULT_PROPS } from "./ActionButton";
3
+ import Grid from "@mui/material/Grid2";
4
+ import Stack from "@mui/material/Stack";
5
+ import { RiArrowLeftLine, RiDeleteBinLine, RiTestTubeLine, } from "@remixicon/react";
6
+ import { fn } from "@storybook/test";
7
+ import { enumValues } from "../../story-utils";
8
+ const ICONS = {
9
+ None: undefined,
10
+ ArrowBackIcon: React.createElement(RiArrowLeftLine, null),
11
+ DeleteIcon: React.createElement(RiDeleteBinLine, null),
12
+ TestTubeIcon: React.createElement(RiTestTubeLine, null),
13
+ };
14
+ const VARIANTS = enumValues({
15
+ primary: true,
16
+ secondary: true,
17
+ tertiary: true,
18
+ bordered: true,
19
+ text: true,
20
+ unstable_noBorder: true,
21
+ unstable_inverted: true,
22
+ unstable_success: true,
23
+ });
24
+ const STABLE_VARIANTS = VARIANTS.filter((v) => !v.startsWith("unstable"));
25
+ const SIZES = enumValues({
26
+ small: true,
27
+ medium: true,
28
+ large: true,
29
+ });
30
+ const EDGES = enumValues({
31
+ circular: true,
32
+ rounded: true,
33
+ none: true,
34
+ });
35
+ const meta = {
36
+ title: "smoot-design/ActionButton",
37
+ component: ActionButton,
38
+ argTypes: {
39
+ variant: {
40
+ control: { type: "select" },
41
+ table: {
42
+ defaultValue: { summary: DEFAULT_PROPS.variant },
43
+ },
44
+ },
45
+ size: {
46
+ control: { type: "select" },
47
+ table: {
48
+ defaultValue: { summary: DEFAULT_PROPS.size },
49
+ },
50
+ },
51
+ edge: {
52
+ control: { type: "select" },
53
+ table: {
54
+ defaultValue: { summary: DEFAULT_PROPS.edge },
55
+ },
56
+ },
57
+ },
58
+ args: {
59
+ onClick: fn(),
60
+ },
61
+ };
62
+ export default meta;
63
+ export const VariantsAndEdge = {
64
+ render: (args) => (React.createElement(React.Fragment, null,
65
+ React.createElement(Stack, { direction: "row", gap: 2, sx: { my: 2 } },
66
+ React.createElement(ActionButton, Object.assign({}, args, { edge: "none", variant: "primary" }), ICONS.DeleteIcon),
67
+ React.createElement(ActionButton, Object.assign({}, args, { edge: "none", variant: "secondary" }), ICONS.DeleteIcon),
68
+ React.createElement(ActionButton, Object.assign({}, args, { edge: "none", variant: "tertiary" }), ICONS.DeleteIcon),
69
+ React.createElement(ActionButton, Object.assign({}, args, { edge: "none", variant: "bordered" }), ICONS.DeleteIcon),
70
+ React.createElement(ActionButton, Object.assign({}, args, { edge: "none", variant: "text" }), ICONS.DeleteIcon)),
71
+ React.createElement(Stack, { direction: "row", gap: 2, sx: { my: 2 } },
72
+ React.createElement(ActionButton, Object.assign({}, args, { edge: "rounded", variant: "primary" }), ICONS.DeleteIcon),
73
+ React.createElement(ActionButton, Object.assign({}, args, { edge: "rounded", variant: "secondary" }), ICONS.DeleteIcon),
74
+ React.createElement(ActionButton, Object.assign({}, args, { edge: "rounded", variant: "tertiary" }), ICONS.DeleteIcon),
75
+ React.createElement(ActionButton, Object.assign({}, args, { edge: "rounded", variant: "bordered" }), ICONS.DeleteIcon),
76
+ React.createElement(ActionButton, Object.assign({}, args, { edge: "rounded", variant: "text" }), ICONS.DeleteIcon)),
77
+ React.createElement(Stack, { direction: "row", gap: 2, sx: { my: 2 } },
78
+ React.createElement(ActionButton, Object.assign({}, args, { edge: "circular", variant: "primary" }), ICONS.DeleteIcon),
79
+ React.createElement(ActionButton, Object.assign({}, args, { edge: "circular", variant: "secondary" }), ICONS.DeleteIcon),
80
+ React.createElement(ActionButton, Object.assign({}, args, { edge: "circular", variant: "tertiary" }), ICONS.DeleteIcon),
81
+ React.createElement(ActionButton, Object.assign({}, args, { edge: "circular", variant: "bordered" }), ICONS.DeleteIcon),
82
+ React.createElement(ActionButton, Object.assign({}, args, { edge: "circular", variant: "text" }), ICONS.DeleteIcon)))),
83
+ tags: ["main"],
84
+ };
85
+ /**
86
+ * `ActionButtonLink` is styled as a `ActionButton` that renders an anchor tag.
87
+ *
88
+ * To use a custom link component (E.g. `Link` from `react-router` or `next/link`),
89
+ * pass it as the `Component` prop. Alternatively, customize the project-wide
90
+ * default link adapter via [Theme's LinkAdapter](../?path=/docs/smoot-design-themeprovider--docs)
91
+ */
92
+ export const Links = {
93
+ render: () => (React.createElement(Stack, { direction: "row", gap: 2, sx: { my: 2 } },
94
+ React.createElement(ActionButtonLink, { href: "#fake", variant: "primary" }, ICONS.DeleteIcon),
95
+ React.createElement(ActionButtonLink, { href: "#fake", variant: "secondary" }, ICONS.DeleteIcon),
96
+ React.createElement(ActionButtonLink, { href: "#fake", variant: "tertiary" }, ICONS.DeleteIcon),
97
+ React.createElement(ActionButtonLink, { href: "#fake", variant: "bordered" }, ICONS.DeleteIcon),
98
+ React.createElement(ActionButtonLink, { href: "#fake", variant: "text" }, ICONS.DeleteIcon))),
99
+ };
100
+ export const Showcase = {
101
+ render: (args) => (React.createElement(Grid, { container: true, sx: { maxWidth: "750px" }, rowGap: 2 }, STABLE_VARIANTS.flatMap((variant) => EDGES.flatMap((edge) => (React.createElement(React.Fragment, { key: `${variant}-${edge}` },
102
+ React.createElement(Grid, { size: { xs: 12, sm: 3 }, alignItems: "center" },
103
+ React.createElement("code", null,
104
+ "variant=",
105
+ variant,
106
+ React.createElement("br", null),
107
+ "edge=",
108
+ edge)),
109
+ SIZES.flatMap((size) => Object.entries(ICONS)
110
+ .filter(([_key, icon]) => icon)
111
+ .map(([iconKey, icon]) => (React.createElement(Grid, { size: { xs: 4, sm: 1 }, key: `${size}-${iconKey}` },
112
+ React.createElement(ActionButton, Object.assign({ variant: variant, edge: edge, size: size }, args), icon))))))))))),
113
+ };
@@ -0,0 +1,56 @@
1
+ import * as React from "react";
2
+ import { LinkAdapterPropsOverrides } from "../LinkAdapter/LinkAdapter";
3
+ type ButtonVariant = "primary" | "secondary" | "tertiary" | "text" | "bordered" | "unstable_noBorder" | "unstable_inverted" | "unstable_success";
4
+ type ButtonSize = "small" | "medium" | "large";
5
+ type ButtonEdge = "circular" | "rounded" | "none";
6
+ type ButtonStyleProps = {
7
+ variant?: ButtonVariant;
8
+ size?: ButtonSize;
9
+ edge?: ButtonEdge;
10
+ /**
11
+ * Display an icon before the button text
12
+ */
13
+ startIcon?: React.ReactNode;
14
+ /**
15
+ * Display an icon after the button text.
16
+ */
17
+ endIcon?: React.ReactNode;
18
+ /**
19
+ * If true (default: `false`), the button will become one size smaller at the
20
+ * `sm` breakpoint.
21
+ * - large -> medium
22
+ * - medium -> small
23
+ * - small -> small
24
+ */
25
+ responsive?: boolean;
26
+ color?: "secondary";
27
+ };
28
+ declare const DEFAULT_PROPS: Required<Omit<ButtonStyleProps, "startIcon" | "endIcon" | "color">>;
29
+ declare const RESPONSIVE_SIZES: Record<ButtonSize, ButtonSize>;
30
+ declare const ButtonRoot: import("@emotion/styled").StyledComponent<{
31
+ theme?: import("@emotion/react").Theme;
32
+ as?: React.ElementType;
33
+ } & ButtonStyleProps, React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, {}>;
34
+ declare const ButtonLinkRoot: import("@emotion/styled").StyledComponent<Omit<React.ClassAttributes<HTMLAnchorElement> & React.AnchorHTMLAttributes<HTMLAnchorElement> & {
35
+ Component?: React.ElementType;
36
+ } & LinkAdapterPropsOverrides, "ref"> & React.RefAttributes<HTMLAnchorElement> & {
37
+ theme?: import("@emotion/react").Theme;
38
+ } & ButtonStyleProps, {}, {}>;
39
+ type ButtonProps = ButtonStyleProps & React.ComponentProps<"button">;
40
+ /**
41
+ * Our standard button component. See [Button Docs](https://mitodl.github.io/smoot-design/?path=/docs/smoot-design-button--docs).
42
+ *
43
+ * See also:
44
+ * - [ButtonLink](https://mitodl.github.io/smoot-design/?path=/docs/smoot-design-button--docs#links)
45
+ * - [ActionButton](https://mitodl.github.io/smoot-design/?path=/docs/smoot-design-actionbutton--docs) for icon-only uses
46
+ */
47
+ declare const Button: React.ForwardRefExoticComponent<Omit<ButtonProps, "ref"> & React.RefAttributes<HTMLButtonElement>>;
48
+ type ButtonLinkProps = ButtonStyleProps & React.ComponentProps<"a"> & {
49
+ Component?: React.ElementType;
50
+ } & LinkAdapterPropsOverrides;
51
+ /**
52
+ * See [ButtonLink docs](https://mitodl.github.io/smoot-design/?path=/docs/smoot-design-button--docs#links)
53
+ */
54
+ declare const ButtonLink: React.ForwardRefExoticComponent<Omit<ButtonLinkProps, "ref"> & React.RefAttributes<HTMLAnchorElement>>;
55
+ export { Button, ButtonLink, ButtonRoot, DEFAULT_PROPS, ButtonLinkRoot, RESPONSIVE_SIZES, };
56
+ export type { ButtonProps, ButtonLinkProps, ButtonStyleProps, ButtonSize };
@@ -0,0 +1,265 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import * as React from "react";
13
+ import styled from "@emotion/styled";
14
+ import { css } from "@emotion/react";
15
+ import { pxToRem } from "../ThemeProvider/typography";
16
+ import { LinkAdapter, } from "../LinkAdapter/LinkAdapter";
17
+ const styleProps = {
18
+ variant: true,
19
+ size: true,
20
+ edge: true,
21
+ startIcon: true,
22
+ endIcon: true,
23
+ responsive: true,
24
+ color: true,
25
+ };
26
+ const shouldForwardButtonProp = (prop) => !styleProps[prop];
27
+ const DEFAULT_PROPS = {
28
+ variant: "primary",
29
+ size: "medium",
30
+ edge: "rounded",
31
+ responsive: false,
32
+ };
33
+ const BORDER_WIDTHS = {
34
+ small: 1,
35
+ medium: 1,
36
+ large: 2,
37
+ };
38
+ const RESPONSIVE_SIZES = {
39
+ small: "small",
40
+ medium: "small",
41
+ large: "medium",
42
+ };
43
+ const sizeStyles = (size, hasBorder, theme) => {
44
+ const paddingAdjust = hasBorder ? BORDER_WIDTHS[size] : 0;
45
+ return [
46
+ {
47
+ boxSizing: "border-box",
48
+ borderWidth: BORDER_WIDTHS[size],
49
+ },
50
+ size === "large" && Object.assign({ padding: `${14 - paddingAdjust}px 24px` }, theme.typography.buttonLarge),
51
+ size === "medium" && Object.assign({ padding: `${11 - paddingAdjust}px 16px` }, theme.typography.button),
52
+ size === "small" && Object.assign({ padding: `${8 - paddingAdjust}px 12px` }, theme.typography.buttonSmall),
53
+ ];
54
+ };
55
+ const buttonStyles = (props) => {
56
+ const { size, variant, edge, theme, color, responsive } = Object.assign(Object.assign({}, DEFAULT_PROPS), props);
57
+ const { colors } = theme.custom;
58
+ const hasBorder = variant === "secondary" || variant === "bordered";
59
+ return css([
60
+ {
61
+ color: theme.palette.text.primary,
62
+ textAlign: "center",
63
+ // display
64
+ display: "inline-flex",
65
+ justifyContent: "center",
66
+ alignItems: "center",
67
+ // transitions
68
+ transition: `background ${theme.transitions.duration.short}ms`,
69
+ // cursor
70
+ cursor: "pointer",
71
+ ":disabled": {
72
+ cursor: "default",
73
+ },
74
+ minWidth: "100px",
75
+ },
76
+ ...sizeStyles(size, hasBorder, theme),
77
+ // responsive
78
+ responsive && {
79
+ [theme.breakpoints.down("sm")]: sizeStyles(RESPONSIVE_SIZES[size], hasBorder, theme),
80
+ },
81
+ // variant
82
+ variant === "primary" && {
83
+ backgroundColor: colors.mitRed,
84
+ color: colors.white,
85
+ border: "none",
86
+ /* Shadow/04dp */
87
+ boxShadow: "0px 2px 4px 0px rgba(37, 38, 43, 0.10), 0px 3px 8px 0px rgba(37, 38, 43, 0.12)",
88
+ ":hover:not(:disabled)": {
89
+ backgroundColor: colors.red,
90
+ boxShadow: "none",
91
+ },
92
+ ":disabled": {
93
+ backgroundColor: colors.silverGray,
94
+ boxShadow: "none",
95
+ },
96
+ },
97
+ variant === "unstable_success" && {
98
+ backgroundColor: colors.darkGreen,
99
+ color: colors.white,
100
+ border: "none",
101
+ /* Shadow/04dp */
102
+ boxShadow: "0px 2px 4px 0px rgba(37, 38, 43, 0.10), 0px 3px 8px 0px rgba(37, 38, 43, 0.12)",
103
+ ":hover:not(:disabled)": {
104
+ backgroundColor: colors.darkGreen,
105
+ boxShadow: "none",
106
+ },
107
+ ":disabled": {
108
+ backgroundColor: colors.silverGray,
109
+ boxShadow: "none",
110
+ },
111
+ },
112
+ variant === "secondary" && {
113
+ color: colors.red,
114
+ backgroundColor: "transparent",
115
+ borderColor: "currentcolor",
116
+ borderStyle: "solid",
117
+ ":hover:not(:disabled)": {
118
+ // brightRed at 0.06 alpha
119
+ backgroundColor: "rgba(255, 20, 35, 0.06)",
120
+ },
121
+ ":disabled": {
122
+ color: colors.silverGray,
123
+ },
124
+ },
125
+ variant === "text" && {
126
+ backgroundColor: "transparent",
127
+ borderStyle: "none",
128
+ color: colors.darkGray2,
129
+ ":hover:not(:disabled)": {
130
+ // darkGray1 at 6% alpha
131
+ backgroundColor: "rgba(64, 70, 76, 0.06)",
132
+ },
133
+ ":disabled": {
134
+ color: colors.silverGray,
135
+ },
136
+ },
137
+ variant === "bordered" && {
138
+ backgroundColor: colors.white,
139
+ color: colors.silverGrayDark,
140
+ border: `1px solid ${colors.silverGrayLight}`,
141
+ ":hover:not(:disabled)": {
142
+ backgroundColor: colors.lightGray1,
143
+ color: colors.darkGray2,
144
+ },
145
+ ":disabled": {
146
+ backgroundColor: colors.lightGray2,
147
+ border: `1px solid ${colors.lightGray2}`,
148
+ color: colors.silverGrayDark,
149
+ },
150
+ },
151
+ variant === "unstable_noBorder" && {
152
+ backgroundColor: colors.white,
153
+ color: colors.darkGray2,
154
+ border: "none",
155
+ ":hover:not(:disabled)": {
156
+ // darkGray1 at 6% alpha
157
+ backgroundColor: "rgba(64, 70, 76, 0.06)",
158
+ },
159
+ ":disabled": {
160
+ color: colors.silverGray,
161
+ },
162
+ },
163
+ variant === "tertiary" && {
164
+ color: colors.darkGray2,
165
+ border: "none",
166
+ backgroundColor: colors.lightGray2,
167
+ ":hover:not(:disabled)": {
168
+ backgroundColor: colors.white,
169
+ },
170
+ ":disabled": {
171
+ backgroundColor: colors.lightGray2,
172
+ color: colors.silverGrayLight,
173
+ },
174
+ },
175
+ variant === "unstable_inverted" && {
176
+ backgroundColor: colors.white,
177
+ color: colors.mitRed,
178
+ borderColor: colors.mitRed,
179
+ borderStyle: "solid",
180
+ },
181
+ // edge
182
+ edge === "rounded" && {
183
+ borderRadius: "4px",
184
+ },
185
+ edge === "circular" && {
186
+ // Pill-shaped buttons... Overlapping border radius get clipped to pill.
187
+ borderRadius: "100vh",
188
+ },
189
+ // color
190
+ color === "secondary" && {
191
+ color: theme.custom.colors.silverGray,
192
+ borderColor: theme.custom.colors.silverGray,
193
+ ":hover:not(:disabled)": {
194
+ backgroundColor: theme.custom.colors.lightGray1,
195
+ },
196
+ },
197
+ ]);
198
+ };
199
+ const ButtonRoot = styled("button", {
200
+ shouldForwardProp: shouldForwardButtonProp,
201
+ })(buttonStyles);
202
+ const ButtonLinkRoot = styled(LinkAdapter, {
203
+ shouldForwardProp: shouldForwardButtonProp,
204
+ })(buttonStyles);
205
+ const IconContainer = styled.span(({ size, side }) => [
206
+ {
207
+ height: "1em",
208
+ display: "flex",
209
+ alignItems: "center",
210
+ },
211
+ side === "start" && {
212
+ /**
213
+ * The negative margin is to counteract the padding on the button itself.
214
+ * Without icons, the left space is 24/16/12 px.
215
+ * With icons, the left space is 20/12/8 px.
216
+ */
217
+ marginLeft: "-4px",
218
+ marginRight: "8px",
219
+ },
220
+ side === "end" && {
221
+ marginLeft: "8px",
222
+ marginRight: "-4px",
223
+ },
224
+ {
225
+ "& svg, & .MuiSvgIcon-root": {
226
+ width: "1em",
227
+ height: "1em",
228
+ fontSize: pxToRem({
229
+ small: 16,
230
+ medium: 20,
231
+ large: 24,
232
+ }[size]),
233
+ },
234
+ },
235
+ ]);
236
+ const ButtonInner = (props) => {
237
+ const { children, size = DEFAULT_PROPS.size } = props;
238
+ return (React.createElement(React.Fragment, null,
239
+ props.startIcon ? (React.createElement(IconContainer, { size: size, side: "start" }, props.startIcon)) : null,
240
+ children,
241
+ props.endIcon ? (React.createElement(IconContainer, { size: size, side: "end" }, props.endIcon)) : null));
242
+ };
243
+ /**
244
+ * Our standard button component. See [Button Docs](https://mitodl.github.io/smoot-design/?path=/docs/smoot-design-button--docs).
245
+ *
246
+ * See also:
247
+ * - [ButtonLink](https://mitodl.github.io/smoot-design/?path=/docs/smoot-design-button--docs#links)
248
+ * - [ActionButton](https://mitodl.github.io/smoot-design/?path=/docs/smoot-design-actionbutton--docs) for icon-only uses
249
+ */
250
+ const Button = React.forwardRef((_a, ref) => {
251
+ var { children } = _a, props = __rest(_a, ["children"]);
252
+ return (React.createElement(ButtonRoot, Object.assign({ ref: ref, type: "button" }, props),
253
+ React.createElement(ButtonInner, Object.assign({}, props), children)));
254
+ });
255
+ Button.displayName = "Button";
256
+ /**
257
+ * See [ButtonLink docs](https://mitodl.github.io/smoot-design/?path=/docs/smoot-design-button--docs#links)
258
+ */
259
+ const ButtonLink = React.forwardRef((_a, ref) => {
260
+ var { children, Component } = _a, props = __rest(_a, ["children", "Component"]);
261
+ return (React.createElement(ButtonLinkRoot, Object.assign({ Component: Component, ref: ref }, props),
262
+ React.createElement(ButtonInner, Object.assign({}, props), children)));
263
+ });
264
+ ButtonLink.displayName = "ButtonLink";
265
+ export { Button, ButtonLink, ButtonRoot, DEFAULT_PROPS, ButtonLinkRoot, RESPONSIVE_SIZES, };
@@ -0,0 +1,17 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { Button } from "./Button";
3
+ declare const meta: Meta<typeof Button>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof Button>;
6
+ export declare const VariantsAndEdge: Story;
7
+ export declare const Sizes: Story;
8
+ export declare const WithIcons: Story;
9
+ /**
10
+ * `ButtonLink` is a styled `Button` that renders an anchor tag.
11
+ *
12
+ * To use a custom link component (E.g. `Link` from `react-router` or `next/link`),
13
+ * pass it as the `Component` prop. Alternatively, customize the project-wide
14
+ * default link adapter via [Theme's LinkAdapter](../?path=/docs/smoot-design-themeprovider--docs)
15
+ */
16
+ export declare const Links: Story;
17
+ export declare const Showcase: Story;