@mitodl/smoot-design 0.0.0-7bc0c0f
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.
- package/LICENSE +28 -0
- package/README.md +31 -0
- package/dist/bundles/remoteTutorDrawer.es.js +38347 -0
- package/dist/bundles/remoteTutorDrawer.umd.js +207 -0
- package/dist/cjs/ai.d.ts +3 -0
- package/dist/cjs/ai.js +5 -0
- package/dist/cjs/bundles/RemoteTutorDrawer/FlashcardsScreen.d.ts +9 -0
- package/dist/cjs/bundles/RemoteTutorDrawer/FlashcardsScreen.js +87 -0
- package/dist/cjs/bundles/RemoteTutorDrawer/RemoteTutorDrawer.d.ts +57 -0
- package/dist/cjs/bundles/RemoteTutorDrawer/RemoteTutorDrawer.js +276 -0
- package/dist/cjs/bundles/RemoteTutorDrawer/RemoteTutorDrawer.stories.d.ts +16 -0
- package/dist/cjs/bundles/RemoteTutorDrawer/RemoteTutorDrawer.stories.js +283 -0
- package/dist/cjs/bundles/RemoteTutorDrawer/RemoteTutorDrawer.test.d.ts +1 -0
- package/dist/cjs/bundles/RemoteTutorDrawer/RemoteTutorDrawer.test.js +241 -0
- package/dist/cjs/bundles/remoteTutorDrawer.d.ts +7 -0
- package/dist/cjs/bundles/remoteTutorDrawer.js +40 -0
- package/dist/cjs/components/AiChat/AiChat.d.ts +5 -0
- package/dist/cjs/components/AiChat/AiChat.js +247 -0
- package/dist/cjs/components/AiChat/AiChat.stories.d.ts +21 -0
- package/dist/cjs/components/AiChat/AiChat.stories.js +243 -0
- package/dist/cjs/components/AiChat/AiChat.test.d.ts +1 -0
- package/dist/cjs/components/AiChat/AiChat.test.js +211 -0
- package/dist/cjs/components/AiChat/ChatTitle.d.ts +8 -0
- package/dist/cjs/components/AiChat/ChatTitle.js +43 -0
- package/dist/cjs/components/AiChat/EntryScreen.d.ts +11 -0
- package/dist/cjs/components/AiChat/EntryScreen.js +123 -0
- package/dist/cjs/components/AiChat/TimLogo.d.ts +5 -0
- package/dist/cjs/components/AiChat/TimLogo.js +15 -0
- package/dist/cjs/components/AiChat/test-utils/api.d.ts +2 -0
- package/dist/cjs/components/AiChat/test-utils/api.js +125 -0
- package/dist/cjs/components/AiChat/types.d.ts +82 -0
- package/dist/cjs/components/AiChat/types.js +3 -0
- package/dist/cjs/components/AiChat/utils.d.ts +9 -0
- package/dist/cjs/components/AiChat/utils.js +41 -0
- package/dist/cjs/components/Alert/Alert.d.ts +15 -0
- package/dist/cjs/components/Alert/Alert.js +62 -0
- package/dist/cjs/components/Alert/Alert.stories.d.ts +8 -0
- package/dist/cjs/components/Alert/Alert.stories.js +53 -0
- package/dist/cjs/components/Button/ActionButton.d.ts +30 -0
- package/dist/cjs/components/Button/ActionButton.js +73 -0
- package/dist/cjs/components/Button/ActionButton.stories.d.ts +15 -0
- package/dist/cjs/components/Button/ActionButton.stories.js +113 -0
- package/dist/cjs/components/Button/Button.d.ts +54 -0
- package/dist/cjs/components/Button/Button.js +240 -0
- package/dist/cjs/components/Button/Button.stories.d.ts +17 -0
- package/dist/cjs/components/Button/Button.stories.js +135 -0
- package/dist/cjs/components/Button/Button.test.d.ts +1 -0
- package/dist/cjs/components/Button/Button.test.js +46 -0
- package/dist/cjs/components/ImageAdapter/ImageAdapter.d.ts +23 -0
- package/dist/cjs/components/ImageAdapter/ImageAdapter.js +30 -0
- package/dist/cjs/components/Input/Input.d.ts +116 -0
- package/dist/cjs/components/Input/Input.js +237 -0
- package/dist/cjs/components/Input/Input.stories.d.ts +19 -0
- package/dist/cjs/components/Input/Input.stories.js +135 -0
- package/dist/cjs/components/Input/Input.test.d.ts +1 -0
- package/dist/cjs/components/Input/Input.test.js +32 -0
- package/dist/cjs/components/LinkAdapter/LinkAdapter.d.ts +23 -0
- package/dist/cjs/components/LinkAdapter/LinkAdapter.js +34 -0
- package/dist/cjs/components/ScrollSnap/ScrollSnap.d.ts +19 -0
- package/dist/cjs/components/ScrollSnap/ScrollSnap.js +59 -0
- package/dist/cjs/components/ScrollSnap/ScrollSnap.stories.d.ts +6 -0
- package/dist/cjs/components/ScrollSnap/ScrollSnap.stories.js +43 -0
- package/dist/cjs/components/ScrollSnap/useScrollSnap.d.ts +6 -0
- package/dist/cjs/components/ScrollSnap/useScrollSnap.js +36 -0
- package/dist/cjs/components/SrAnnouncer/SrAnnouncer.d.ts +25 -0
- package/dist/cjs/components/SrAnnouncer/SrAnnouncer.js +43 -0
- package/dist/cjs/components/SrAnnouncer/SrAnnouncer.stories.d.ts +6 -0
- package/dist/cjs/components/SrAnnouncer/SrAnnouncer.stories.js +44 -0
- package/dist/cjs/components/SrAnnouncer/SrAnnouncer.test.d.ts +1 -0
- package/dist/cjs/components/SrAnnouncer/SrAnnouncer.test.js +62 -0
- package/dist/cjs/components/TabButtons/TabButtonList.d.ts +25 -0
- package/dist/cjs/components/TabButtons/TabButtonList.js +97 -0
- package/dist/cjs/components/TabButtons/TabButtonList.stories.d.ts +24 -0
- package/dist/cjs/components/TabButtons/TabButtonList.stories.js +139 -0
- package/dist/cjs/components/TextField/TextField.d.ts +29 -0
- package/dist/cjs/components/TextField/TextField.js +33 -0
- package/dist/cjs/components/TextField/TextField.stories.d.ts +10 -0
- package/dist/cjs/components/TextField/TextField.stories.js +136 -0
- package/dist/cjs/components/TextField/TextField.test.d.ts +1 -0
- package/dist/cjs/components/TextField/TextField.test.js +77 -0
- package/dist/cjs/components/ThemeProvider/ThemeProvider.d.ts +21 -0
- package/dist/cjs/components/ThemeProvider/ThemeProvider.js +86 -0
- package/dist/cjs/components/ThemeProvider/ThemeProvider.stories.d.ts +63 -0
- package/dist/cjs/components/ThemeProvider/ThemeProvider.stories.js +102 -0
- package/dist/cjs/components/ThemeProvider/Typography.stories.d.ts +39 -0
- package/dist/cjs/components/ThemeProvider/Typography.stories.js +65 -0
- package/dist/cjs/components/ThemeProvider/breakpoints.d.ts +4 -0
- package/dist/cjs/components/ThemeProvider/breakpoints.js +19 -0
- package/dist/cjs/components/ThemeProvider/buttons.d.ts +7 -0
- package/dist/cjs/components/ThemeProvider/buttons.js +20 -0
- package/dist/cjs/components/ThemeProvider/chips.d.ts +3 -0
- package/dist/cjs/components/ThemeProvider/chips.js +154 -0
- package/dist/cjs/components/ThemeProvider/colors.d.ts +32 -0
- package/dist/cjs/components/ThemeProvider/colors.js +35 -0
- package/dist/cjs/components/ThemeProvider/typography.d.ts +18 -0
- package/dist/cjs/components/ThemeProvider/typography.js +173 -0
- package/dist/cjs/components/VisuallyHidden/VisuallyHidden.d.ts +24 -0
- package/dist/cjs/components/VisuallyHidden/VisuallyHidden.js +33 -0
- package/dist/cjs/components/VisuallyHidden/VisuallyHidden.stories.d.ts +6 -0
- package/dist/cjs/components/VisuallyHidden/VisuallyHidden.stories.js +13 -0
- package/dist/cjs/components/internal/FormHelpers/FormHelpers.d.ts +39 -0
- package/dist/cjs/components/internal/FormHelpers/FormHelpers.js +78 -0
- package/dist/cjs/components/internal/FormHelpers/FormHelpers.test.d.ts +1 -0
- package/dist/cjs/components/internal/FormHelpers/FormHelpers.test.js +93 -0
- package/dist/cjs/index.d.ts +16 -0
- package/dist/cjs/index.js +30 -0
- package/dist/cjs/jest-setup.d.ts +1 -0
- package/dist/cjs/jest-setup.js +18 -0
- package/dist/cjs/jsdom-extended.d.ts +6 -0
- package/dist/cjs/jsdom-extended.js +14 -0
- package/dist/cjs/story-utils/index.d.ts +6 -0
- package/dist/cjs/story-utils/index.js +17 -0
- package/dist/cjs/utils/composeRefs.d.ts +7 -0
- package/dist/cjs/utils/composeRefs.js +20 -0
- package/dist/cjs/utils/composeRefs.test.d.ts +1 -0
- package/dist/cjs/utils/composeRefs.test.js +19 -0
- package/dist/cjs/utils/useDevCheckStable.d.ts +8 -0
- package/dist/cjs/utils/useDevCheckStable.js +29 -0
- package/dist/cjs/utils/useInterval.d.ts +7 -0
- package/dist/cjs/utils/useInterval.js +25 -0
- package/dist/esm/ai.d.ts +3 -0
- package/dist/esm/ai.js +1 -0
- package/dist/esm/bundles/RemoteTutorDrawer/FlashcardsScreen.d.ts +9 -0
- package/dist/esm/bundles/RemoteTutorDrawer/FlashcardsScreen.js +83 -0
- package/dist/esm/bundles/RemoteTutorDrawer/RemoteTutorDrawer.d.ts +57 -0
- package/dist/esm/bundles/RemoteTutorDrawer/RemoteTutorDrawer.js +273 -0
- package/dist/esm/bundles/RemoteTutorDrawer/RemoteTutorDrawer.stories.d.ts +16 -0
- package/dist/esm/bundles/RemoteTutorDrawer/RemoteTutorDrawer.stories.js +280 -0
- package/dist/esm/bundles/RemoteTutorDrawer/RemoteTutorDrawer.test.d.ts +1 -0
- package/dist/esm/bundles/RemoteTutorDrawer/RemoteTutorDrawer.test.js +239 -0
- package/dist/esm/bundles/remoteTutorDrawer.d.ts +7 -0
- package/dist/esm/bundles/remoteTutorDrawer.js +37 -0
- package/dist/esm/components/AiChat/AiChat.d.ts +5 -0
- package/dist/esm/components/AiChat/AiChat.js +244 -0
- package/dist/esm/components/AiChat/AiChat.stories.d.ts +21 -0
- package/dist/esm/components/AiChat/AiChat.stories.js +240 -0
- package/dist/esm/components/AiChat/AiChat.test.d.ts +1 -0
- package/dist/esm/components/AiChat/AiChat.test.js +209 -0
- package/dist/esm/components/AiChat/ChatTitle.d.ts +8 -0
- package/dist/esm/components/AiChat/ChatTitle.js +40 -0
- package/dist/esm/components/AiChat/EntryScreen.d.ts +11 -0
- package/dist/esm/components/AiChat/EntryScreen.js +120 -0
- package/dist/esm/components/AiChat/TimLogo.d.ts +5 -0
- package/dist/esm/components/AiChat/TimLogo.js +13 -0
- package/dist/esm/components/AiChat/test-utils/api.d.ts +2 -0
- package/dist/esm/components/AiChat/test-utils/api.js +122 -0
- package/dist/esm/components/AiChat/types.d.ts +82 -0
- package/dist/esm/components/AiChat/types.js +2 -0
- package/dist/esm/components/AiChat/utils.d.ts +9 -0
- package/dist/esm/components/AiChat/utils.js +38 -0
- package/dist/esm/components/Alert/Alert.d.ts +15 -0
- package/dist/esm/components/Alert/Alert.js +59 -0
- package/dist/esm/components/Alert/Alert.stories.d.ts +8 -0
- package/dist/esm/components/Alert/Alert.stories.js +50 -0
- package/dist/esm/components/Button/ActionButton.d.ts +30 -0
- package/dist/esm/components/Button/ActionButton.js +68 -0
- package/dist/esm/components/Button/ActionButton.stories.d.ts +15 -0
- package/dist/esm/components/Button/ActionButton.stories.js +110 -0
- package/dist/esm/components/Button/Button.d.ts +54 -0
- package/dist/esm/components/Button/Button.js +232 -0
- package/dist/esm/components/Button/Button.stories.d.ts +17 -0
- package/dist/esm/components/Button/Button.stories.js +132 -0
- package/dist/esm/components/Button/Button.test.d.ts +1 -0
- package/dist/esm/components/Button/Button.test.js +44 -0
- package/dist/esm/components/ImageAdapter/ImageAdapter.d.ts +23 -0
- package/dist/esm/components/ImageAdapter/ImageAdapter.js +27 -0
- package/dist/esm/components/Input/Input.d.ts +116 -0
- package/dist/esm/components/Input/Input.js +232 -0
- package/dist/esm/components/Input/Input.stories.d.ts +19 -0
- package/dist/esm/components/Input/Input.stories.js +132 -0
- package/dist/esm/components/Input/Input.test.d.ts +1 -0
- package/dist/esm/components/Input/Input.test.js +30 -0
- package/dist/esm/components/LinkAdapter/LinkAdapter.d.ts +23 -0
- package/dist/esm/components/LinkAdapter/LinkAdapter.js +31 -0
- package/dist/esm/components/ScrollSnap/ScrollSnap.d.ts +19 -0
- package/dist/esm/components/ScrollSnap/ScrollSnap.js +56 -0
- package/dist/esm/components/ScrollSnap/ScrollSnap.stories.d.ts +6 -0
- package/dist/esm/components/ScrollSnap/ScrollSnap.stories.js +40 -0
- package/dist/esm/components/ScrollSnap/useScrollSnap.d.ts +6 -0
- package/dist/esm/components/ScrollSnap/useScrollSnap.js +33 -0
- package/dist/esm/components/SrAnnouncer/SrAnnouncer.d.ts +25 -0
- package/dist/esm/components/SrAnnouncer/SrAnnouncer.js +40 -0
- package/dist/esm/components/SrAnnouncer/SrAnnouncer.stories.d.ts +6 -0
- package/dist/esm/components/SrAnnouncer/SrAnnouncer.stories.js +41 -0
- package/dist/esm/components/SrAnnouncer/SrAnnouncer.test.d.ts +1 -0
- package/dist/esm/components/SrAnnouncer/SrAnnouncer.test.js +60 -0
- package/dist/esm/components/TabButtons/TabButtonList.d.ts +25 -0
- package/dist/esm/components/TabButtons/TabButtonList.js +92 -0
- package/dist/esm/components/TabButtons/TabButtonList.stories.d.ts +24 -0
- package/dist/esm/components/TabButtons/TabButtonList.stories.js +136 -0
- package/dist/esm/components/TextField/TextField.d.ts +29 -0
- package/dist/esm/components/TextField/TextField.js +30 -0
- package/dist/esm/components/TextField/TextField.stories.d.ts +10 -0
- package/dist/esm/components/TextField/TextField.stories.js +133 -0
- package/dist/esm/components/TextField/TextField.test.d.ts +1 -0
- package/dist/esm/components/TextField/TextField.test.js +75 -0
- package/dist/esm/components/ThemeProvider/ThemeProvider.d.ts +21 -0
- package/dist/esm/components/ThemeProvider/ThemeProvider.js +82 -0
- package/dist/esm/components/ThemeProvider/ThemeProvider.stories.d.ts +63 -0
- package/dist/esm/components/ThemeProvider/ThemeProvider.stories.js +99 -0
- package/dist/esm/components/ThemeProvider/Typography.stories.d.ts +39 -0
- package/dist/esm/components/ThemeProvider/Typography.stories.js +62 -0
- package/dist/esm/components/ThemeProvider/breakpoints.d.ts +4 -0
- package/dist/esm/components/ThemeProvider/breakpoints.js +15 -0
- package/dist/esm/components/ThemeProvider/buttons.d.ts +7 -0
- package/dist/esm/components/ThemeProvider/buttons.js +17 -0
- package/dist/esm/components/ThemeProvider/chips.d.ts +3 -0
- package/dist/esm/components/ThemeProvider/chips.js +151 -0
- package/dist/esm/components/ThemeProvider/colors.d.ts +32 -0
- package/dist/esm/components/ThemeProvider/colors.js +32 -0
- package/dist/esm/components/ThemeProvider/typography.d.ts +18 -0
- package/dist/esm/components/ThemeProvider/typography.js +167 -0
- package/dist/esm/components/VisuallyHidden/VisuallyHidden.d.ts +24 -0
- package/dist/esm/components/VisuallyHidden/VisuallyHidden.js +30 -0
- package/dist/esm/components/VisuallyHidden/VisuallyHidden.stories.d.ts +6 -0
- package/dist/esm/components/VisuallyHidden/VisuallyHidden.stories.js +10 -0
- package/dist/esm/components/internal/FormHelpers/FormHelpers.d.ts +39 -0
- package/dist/esm/components/internal/FormHelpers/FormHelpers.js +73 -0
- package/dist/esm/components/internal/FormHelpers/FormHelpers.test.d.ts +1 -0
- package/dist/esm/components/internal/FormHelpers/FormHelpers.test.js +91 -0
- package/dist/esm/index.d.ts +16 -0
- package/dist/esm/index.js +11 -0
- package/dist/esm/jest-setup.d.ts +1 -0
- package/dist/esm/jest-setup.js +16 -0
- package/dist/esm/jsdom-extended.d.ts +6 -0
- package/dist/esm/jsdom-extended.js +12 -0
- package/dist/esm/story-utils/index.d.ts +6 -0
- package/dist/esm/story-utils/index.js +13 -0
- package/dist/esm/utils/composeRefs.d.ts +7 -0
- package/dist/esm/utils/composeRefs.js +17 -0
- package/dist/esm/utils/composeRefs.test.d.ts +1 -0
- package/dist/esm/utils/composeRefs.test.js +17 -0
- package/dist/esm/utils/useDevCheckStable.d.ts +8 -0
- package/dist/esm/utils/useDevCheckStable.js +26 -0
- package/dist/esm/utils/useInterval.d.ts +7 -0
- package/dist/esm/utils/useInterval.js +22 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/type-augmentation/TypescriptDocs.mdx +17 -0
- package/dist/type-augmentation/imports.d.ts +3 -0
- package/dist/type-augmentation/index.d.ts +3 -0
- package/dist/type-augmentation/theme.d.ts +105 -0
- package/dist/type-augmentation/typography.d.ts +54 -0
- package/package.json +155 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { LinkAdapterPropsOverrides } from "../LinkAdapter/LinkAdapter";
|
|
3
|
+
type ButtonVariant = "primary" | "secondary" | "tertiary" | "text" | "bordered";
|
|
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<import("../LinkAdapter/LinkAdapter").LinkAdapterProps, "ref"> & React.RefAttributes<HTMLAnchorElement> & {
|
|
35
|
+
theme?: import("@emotion/react").Theme;
|
|
36
|
+
} & ButtonStyleProps, {}, {}>;
|
|
37
|
+
type ButtonProps = ButtonStyleProps & React.ComponentProps<"button">;
|
|
38
|
+
/**
|
|
39
|
+
* Our standard button component. See [Button Docs](https://mitodl.github.io/smoot-design/?path=/docs/smoot-design-button--docs).
|
|
40
|
+
*
|
|
41
|
+
* See also:
|
|
42
|
+
* - [ButtonLink](https://mitodl.github.io/smoot-design/?path=/docs/smoot-design-button--docs#links)
|
|
43
|
+
* - [ActionButton](https://mitodl.github.io/smoot-design/?path=/docs/smoot-design-actionbutton--docs) for icon-only uses
|
|
44
|
+
*/
|
|
45
|
+
declare const Button: React.ForwardRefExoticComponent<Omit<ButtonProps, "ref"> & React.RefAttributes<HTMLButtonElement>>;
|
|
46
|
+
type ButtonLinkProps = ButtonStyleProps & React.ComponentProps<"a"> & {
|
|
47
|
+
Component?: React.ElementType;
|
|
48
|
+
} & LinkAdapterPropsOverrides;
|
|
49
|
+
/**
|
|
50
|
+
* See [ButtonLink docs](https://mitodl.github.io/smoot-design/?path=/docs/smoot-design-button--docs#links)
|
|
51
|
+
*/
|
|
52
|
+
declare const ButtonLink: React.ForwardRefExoticComponent<Omit<ButtonLinkProps, "ref"> & React.RefAttributes<HTMLAnchorElement>>;
|
|
53
|
+
export { Button, ButtonLink, ButtonRoot, DEFAULT_PROPS, ButtonLinkRoot, RESPONSIVE_SIZES, };
|
|
54
|
+
export type { ButtonProps, ButtonLinkProps, ButtonStyleProps, ButtonSize };
|
|
@@ -0,0 +1,232 @@
|
|
|
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 === "secondary" && {
|
|
98
|
+
color: colors.red,
|
|
99
|
+
backgroundColor: "transparent",
|
|
100
|
+
borderColor: "currentcolor",
|
|
101
|
+
borderStyle: "solid",
|
|
102
|
+
":hover:not(:disabled)": {
|
|
103
|
+
// brightRed at 0.06 alpha
|
|
104
|
+
backgroundColor: "rgba(255, 20, 35, 0.06)",
|
|
105
|
+
},
|
|
106
|
+
":disabled": {
|
|
107
|
+
color: colors.silverGray,
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
variant === "text" && {
|
|
111
|
+
backgroundColor: "transparent",
|
|
112
|
+
borderStyle: "none",
|
|
113
|
+
color: colors.darkGray2,
|
|
114
|
+
":hover:not(:disabled)": {
|
|
115
|
+
// darkGray1 at 6% alpha
|
|
116
|
+
backgroundColor: "rgba(64, 70, 76, 0.06)",
|
|
117
|
+
},
|
|
118
|
+
":disabled": {
|
|
119
|
+
color: colors.silverGray,
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
variant === "bordered" && {
|
|
123
|
+
backgroundColor: colors.white,
|
|
124
|
+
color: colors.silverGrayDark,
|
|
125
|
+
border: `1px solid ${colors.silverGrayLight}`,
|
|
126
|
+
":hover:not(:disabled)": {
|
|
127
|
+
backgroundColor: colors.lightGray1,
|
|
128
|
+
color: colors.darkGray2,
|
|
129
|
+
},
|
|
130
|
+
":disabled": {
|
|
131
|
+
backgroundColor: colors.lightGray2,
|
|
132
|
+
border: `1px solid ${colors.lightGray2}`,
|
|
133
|
+
color: colors.silverGrayDark,
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
variant === "tertiary" && {
|
|
137
|
+
color: colors.darkGray2,
|
|
138
|
+
border: "none",
|
|
139
|
+
backgroundColor: colors.lightGray2,
|
|
140
|
+
":hover:not(:disabled)": {
|
|
141
|
+
backgroundColor: colors.white,
|
|
142
|
+
},
|
|
143
|
+
":disabled": {
|
|
144
|
+
backgroundColor: colors.lightGray2,
|
|
145
|
+
color: colors.silverGrayLight,
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
// edge
|
|
149
|
+
edge === "rounded" && {
|
|
150
|
+
borderRadius: "4px",
|
|
151
|
+
},
|
|
152
|
+
edge === "circular" && {
|
|
153
|
+
// Pill-shaped buttons... Overlapping border radius get clipped to pill.
|
|
154
|
+
borderRadius: "100vh",
|
|
155
|
+
},
|
|
156
|
+
// color
|
|
157
|
+
color === "secondary" && {
|
|
158
|
+
color: theme.custom.colors.silverGray,
|
|
159
|
+
borderColor: theme.custom.colors.silverGray,
|
|
160
|
+
":hover:not(:disabled)": {
|
|
161
|
+
backgroundColor: theme.custom.colors.lightGray1,
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
]);
|
|
165
|
+
};
|
|
166
|
+
const ButtonRoot = styled("button", {
|
|
167
|
+
shouldForwardProp: shouldForwardButtonProp,
|
|
168
|
+
})(buttonStyles);
|
|
169
|
+
const ButtonLinkRoot = styled(LinkAdapter, {
|
|
170
|
+
shouldForwardProp: shouldForwardButtonProp,
|
|
171
|
+
})(buttonStyles);
|
|
172
|
+
const IconContainer = styled.span(({ size, side }) => [
|
|
173
|
+
{
|
|
174
|
+
height: "1em",
|
|
175
|
+
display: "flex",
|
|
176
|
+
alignItems: "center",
|
|
177
|
+
},
|
|
178
|
+
side === "start" && {
|
|
179
|
+
/**
|
|
180
|
+
* The negative margin is to counteract the padding on the button itself.
|
|
181
|
+
* Without icons, the left space is 24/16/12 px.
|
|
182
|
+
* With icons, the left space is 20/12/8 px.
|
|
183
|
+
*/
|
|
184
|
+
marginLeft: "-4px",
|
|
185
|
+
marginRight: "8px",
|
|
186
|
+
},
|
|
187
|
+
side === "end" && {
|
|
188
|
+
marginLeft: "8px",
|
|
189
|
+
marginRight: "-4px",
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
"& svg, & .MuiSvgIcon-root": {
|
|
193
|
+
width: "1em",
|
|
194
|
+
height: "1em",
|
|
195
|
+
fontSize: pxToRem({
|
|
196
|
+
small: 16,
|
|
197
|
+
medium: 20,
|
|
198
|
+
large: 24,
|
|
199
|
+
}[size]),
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
]);
|
|
203
|
+
const ButtonInner = (props) => {
|
|
204
|
+
const { children, size = DEFAULT_PROPS.size } = props;
|
|
205
|
+
return (React.createElement(React.Fragment, null,
|
|
206
|
+
props.startIcon ? (React.createElement(IconContainer, { size: size, side: "start" }, props.startIcon)) : null,
|
|
207
|
+
children,
|
|
208
|
+
props.endIcon ? (React.createElement(IconContainer, { size: size, side: "end" }, props.endIcon)) : null));
|
|
209
|
+
};
|
|
210
|
+
/**
|
|
211
|
+
* Our standard button component. See [Button Docs](https://mitodl.github.io/smoot-design/?path=/docs/smoot-design-button--docs).
|
|
212
|
+
*
|
|
213
|
+
* See also:
|
|
214
|
+
* - [ButtonLink](https://mitodl.github.io/smoot-design/?path=/docs/smoot-design-button--docs#links)
|
|
215
|
+
* - [ActionButton](https://mitodl.github.io/smoot-design/?path=/docs/smoot-design-actionbutton--docs) for icon-only uses
|
|
216
|
+
*/
|
|
217
|
+
const Button = React.forwardRef((_a, ref) => {
|
|
218
|
+
var { children } = _a, props = __rest(_a, ["children"]);
|
|
219
|
+
return (React.createElement(ButtonRoot, Object.assign({ ref: ref, type: "button" }, props),
|
|
220
|
+
React.createElement(ButtonInner, Object.assign({}, props), children)));
|
|
221
|
+
});
|
|
222
|
+
Button.displayName = "Button";
|
|
223
|
+
/**
|
|
224
|
+
* See [ButtonLink docs](https://mitodl.github.io/smoot-design/?path=/docs/smoot-design-button--docs#links)
|
|
225
|
+
*/
|
|
226
|
+
const ButtonLink = React.forwardRef((_a, ref) => {
|
|
227
|
+
var { children, Component } = _a, props = __rest(_a, ["children", "Component"]);
|
|
228
|
+
return (React.createElement(ButtonLinkRoot, Object.assign({ Component: Component, ref: ref }, props),
|
|
229
|
+
React.createElement(ButtonInner, Object.assign({}, props), children)));
|
|
230
|
+
});
|
|
231
|
+
ButtonLink.displayName = "ButtonLink";
|
|
232
|
+
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;
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { Button, ButtonLink } from "./Button";
|
|
3
|
+
import Grid from "@mui/material/Grid2";
|
|
4
|
+
import Stack from "@mui/material/Stack";
|
|
5
|
+
import { RiArrowLeftLine, RiDeleteBinLine, RiTestTubeLine, RiMailLine, } 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
|
+
});
|
|
21
|
+
const STABLE_VARIANTS = VARIANTS.filter((v) => !v.startsWith("unstable"));
|
|
22
|
+
const SIZES = enumValues({
|
|
23
|
+
small: true,
|
|
24
|
+
medium: true,
|
|
25
|
+
large: true,
|
|
26
|
+
});
|
|
27
|
+
const EDGES = enumValues({
|
|
28
|
+
circular: true,
|
|
29
|
+
rounded: true,
|
|
30
|
+
none: true,
|
|
31
|
+
});
|
|
32
|
+
const meta = {
|
|
33
|
+
title: "smoot-design/Button",
|
|
34
|
+
component: Button,
|
|
35
|
+
argTypes: {
|
|
36
|
+
startIcon: {
|
|
37
|
+
options: Object.keys(ICONS),
|
|
38
|
+
mapping: ICONS,
|
|
39
|
+
},
|
|
40
|
+
endIcon: {
|
|
41
|
+
options: Object.keys(ICONS),
|
|
42
|
+
mapping: ICONS,
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
args: {
|
|
46
|
+
onClick: fn(),
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
export default meta;
|
|
50
|
+
export const VariantsAndEdge = {
|
|
51
|
+
render: (args) => (React.createElement(React.Fragment, null,
|
|
52
|
+
React.createElement(Stack, { direction: "row", gap: 2, sx: { my: 2 } },
|
|
53
|
+
React.createElement(Button, Object.assign({ edge: "none", variant: "primary" }, args), "Primary"),
|
|
54
|
+
React.createElement(Button, Object.assign({ edge: "none", variant: "secondary" }, args), "Secondary"),
|
|
55
|
+
React.createElement(Button, Object.assign({ edge: "none", variant: "tertiary" }, args), "Tertiary"),
|
|
56
|
+
React.createElement(Button, Object.assign({ edge: "none", variant: "bordered" }, args), "Bordered"),
|
|
57
|
+
React.createElement(Button, Object.assign({ edge: "none", variant: "text" }, args), "Text")),
|
|
58
|
+
React.createElement(Stack, { direction: "row", gap: 2, sx: { my: 2 } },
|
|
59
|
+
React.createElement(Button, Object.assign({ edge: "rounded", variant: "primary" }, args), "Primary"),
|
|
60
|
+
React.createElement(Button, Object.assign({ edge: "rounded", variant: "secondary" }, args), "Secondary"),
|
|
61
|
+
React.createElement(Button, Object.assign({ edge: "rounded", variant: "tertiary" }, args), "Tertiary"),
|
|
62
|
+
React.createElement(Button, Object.assign({ edge: "rounded", variant: "bordered" }, args), "Bordered"),
|
|
63
|
+
React.createElement(Button, Object.assign({ edge: "rounded", variant: "text" }, args), "Text")),
|
|
64
|
+
React.createElement(Stack, { direction: "row", gap: 2, sx: { my: 2 } },
|
|
65
|
+
React.createElement(Button, Object.assign({ edge: "circular", variant: "primary" }, args), "Primary"),
|
|
66
|
+
React.createElement(Button, Object.assign({ edge: "circular", variant: "secondary" }, args), "Secondary"),
|
|
67
|
+
React.createElement(Button, Object.assign({ edge: "circular", variant: "tertiary" }, args), "Tertiary"),
|
|
68
|
+
React.createElement(Button, Object.assign({ edge: "circular", variant: "bordered" }, args), "Bordered"),
|
|
69
|
+
React.createElement(Button, Object.assign({ edge: "circular", variant: "text" }, args), "Text")))),
|
|
70
|
+
tags: ["main"],
|
|
71
|
+
};
|
|
72
|
+
const RESPONSIVE = [true, false];
|
|
73
|
+
export const Sizes = {
|
|
74
|
+
argTypes: {
|
|
75
|
+
size: { table: { disable: true } },
|
|
76
|
+
},
|
|
77
|
+
render: (args) => (React.createElement(Grid, { container: true, sx: { my: 2, maxWidth: "600px" }, alignItems: "center" }, RESPONSIVE.flatMap((responsive) => {
|
|
78
|
+
return (React.createElement(React.Fragment, { key: String(responsive) },
|
|
79
|
+
React.createElement(Grid, { size: { xs: 12 } },
|
|
80
|
+
React.createElement("code", null, `responsive={${responsive.toString()}}`)),
|
|
81
|
+
SIZES.map((size) => (React.createElement(Grid, { size: { xs: 4 }, gap: 2, display: "flex", alignItems: "center", key: size },
|
|
82
|
+
React.createElement(Button, Object.assign({}, args, { size: size, responsive: responsive }), size))))));
|
|
83
|
+
}))),
|
|
84
|
+
};
|
|
85
|
+
export const WithIcons = {
|
|
86
|
+
render: (args) => (React.createElement(Stack, { direction: "column", alignItems: "start", gap: 2, sx: { my: 2 } }, Object.entries(ICONS).map(([key, icon]) => (React.createElement(Button, Object.assign({}, args, { startIcon: icon, key: key }), key))))),
|
|
87
|
+
};
|
|
88
|
+
const EXTRA_PROPS = [
|
|
89
|
+
{},
|
|
90
|
+
/**
|
|
91
|
+
* Show RiTestTubeLine because it is a fairly thin icon
|
|
92
|
+
*/
|
|
93
|
+
{ startIcon: React.createElement(RiTestTubeLine, null) },
|
|
94
|
+
/**
|
|
95
|
+
* Show RiTestTubeLine because it is a fairly thick icon
|
|
96
|
+
*/
|
|
97
|
+
{ startIcon: React.createElement(RiMailLine, null) },
|
|
98
|
+
{ endIcon: React.createElement(RiTestTubeLine, null) },
|
|
99
|
+
{ endIcon: React.createElement(RiMailLine, null) },
|
|
100
|
+
];
|
|
101
|
+
/**
|
|
102
|
+
* `ButtonLink` is a styled `Button` that renders an anchor tag.
|
|
103
|
+
*
|
|
104
|
+
* To use a custom link component (E.g. `Link` from `react-router` or `next/link`),
|
|
105
|
+
* pass it as the `Component` prop. Alternatively, customize the project-wide
|
|
106
|
+
* default link adapter via [Theme's LinkAdapter](../?path=/docs/smoot-design-themeprovider--docs)
|
|
107
|
+
*/
|
|
108
|
+
export const Links = {
|
|
109
|
+
render: () => (React.createElement(Stack, { direction: "row", gap: 2, sx: { my: 2 } },
|
|
110
|
+
React.createElement(ButtonLink, { href: "#fake", variant: "primary" }, "Link"),
|
|
111
|
+
React.createElement(ButtonLink, { href: "#fake", variant: "secondary" }, "Link"),
|
|
112
|
+
React.createElement(ButtonLink, { href: "#fake", variant: "tertiary" }, "Link"),
|
|
113
|
+
React.createElement(ButtonLink, { href: "#fake", variant: "bordered" }, "Link"),
|
|
114
|
+
React.createElement(ButtonLink, { href: "#fake", variant: "text" }, "Link"))),
|
|
115
|
+
};
|
|
116
|
+
export const Showcase = {
|
|
117
|
+
render: (args) => (React.createElement(Grid, { container: true, rowGap: 2, sx: { maxWidth: "600px" } }, STABLE_VARIANTS.flatMap((variant) => EDGES.flatMap((edge) => EXTRA_PROPS.map((extraProps, i) => {
|
|
118
|
+
return (React.createElement(React.Fragment, { key: `${variant}-${edge}-${i}` },
|
|
119
|
+
React.createElement(Grid, { size: { xs: 3 } },
|
|
120
|
+
React.createElement("pre", null,
|
|
121
|
+
"variant=",
|
|
122
|
+
variant,
|
|
123
|
+
React.createElement("br", null),
|
|
124
|
+
"edge=",
|
|
125
|
+
edge)),
|
|
126
|
+
SIZES.map((size) => (React.createElement(Grid, { size: { xs: 3 }, display: "flex", alignItems: "center", key: `${size}` },
|
|
127
|
+
React.createElement(Button, Object.assign({}, args, { variant: variant, edge: edge, size: size }, extraProps), args.children))))));
|
|
128
|
+
}))))),
|
|
129
|
+
args: {
|
|
130
|
+
children: "Click me",
|
|
131
|
+
},
|
|
132
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { render, screen } from "@testing-library/react";
|
|
3
|
+
import { ThemeProvider, createTheme } from "../ThemeProvider/ThemeProvider";
|
|
4
|
+
import { ButtonLink } from "./Button";
|
|
5
|
+
import { ActionButtonLink } from "./ActionButton";
|
|
6
|
+
const withLinkOverride = createTheme({
|
|
7
|
+
custom: {
|
|
8
|
+
LinkAdapter: React.forwardRef(function LinkAdapter(props, ref) {
|
|
9
|
+
return (
|
|
10
|
+
// eslint-disable-next-line jsx-a11y/anchor-has-content
|
|
11
|
+
React.createElement("a", Object.assign({ ref: ref, "data-custom": "theme-default" }, props)));
|
|
12
|
+
}),
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
describe.each([
|
|
16
|
+
//
|
|
17
|
+
{ ButtonComponent: ButtonLink },
|
|
18
|
+
{ ButtonComponent: ActionButtonLink },
|
|
19
|
+
])("$ButtonComponent.displayName overrides", ({ ButtonComponent }) => {
|
|
20
|
+
test("Uses anchor by default", () => {
|
|
21
|
+
render(React.createElement(ButtonComponent, { href: "/test" }, "Link text here"), {
|
|
22
|
+
wrapper: ThemeProvider,
|
|
23
|
+
});
|
|
24
|
+
const link = screen.getByRole("link");
|
|
25
|
+
expect(link.dataset.custom).toBe(undefined);
|
|
26
|
+
});
|
|
27
|
+
test("Uses theme's override if supplied", () => {
|
|
28
|
+
render(React.createElement(ButtonComponent, { href: "/test" }, "Link text here"), {
|
|
29
|
+
wrapper: (props) => React.createElement(ThemeProvider, Object.assign({ theme: withLinkOverride }, props)),
|
|
30
|
+
});
|
|
31
|
+
const link = screen.getByRole("link");
|
|
32
|
+
expect(link.dataset.custom).toBe("theme-default");
|
|
33
|
+
});
|
|
34
|
+
test("Uses component's override if supplied", () => {
|
|
35
|
+
const LinkImplementation = (props) => (
|
|
36
|
+
// eslint-disable-next-line jsx-a11y/anchor-has-content
|
|
37
|
+
React.createElement("a", Object.assign({ "data-custom": "anchor-override" }, props)));
|
|
38
|
+
render(React.createElement(ButtonComponent, { Component: LinkImplementation, href: "/test" }, "Link text here"), {
|
|
39
|
+
wrapper: (props) => (React.createElement(ThemeProvider, Object.assign({ theme: withLinkOverride }, props))),
|
|
40
|
+
});
|
|
41
|
+
const link = screen.getByRole("link");
|
|
42
|
+
expect(link.dataset.custom).toBe("anchor-override");
|
|
43
|
+
});
|
|
44
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* ImageAdapterPropsOverrides 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/image` as your default
|
|
7
|
+
* image implementation, and use ImageAdapterPropsOverrides to provide
|
|
8
|
+
* `next/image`-specific props.
|
|
9
|
+
*/
|
|
10
|
+
interface ImageAdapterPropsOverrides {
|
|
11
|
+
}
|
|
12
|
+
type ImageAdapterProps = React.ComponentProps<"img"> & {
|
|
13
|
+
Component?: React.ElementType;
|
|
14
|
+
} & ImageAdapterPropsOverrides;
|
|
15
|
+
/**
|
|
16
|
+
* Overridable Image component.
|
|
17
|
+
* - If `Component` is provided, renders as `Component`
|
|
18
|
+
* - else, if `theme.custom.ImageAdapter` is provided, renders as `theme.custom.ImageAdapter`
|
|
19
|
+
* - else, renders as `img` tag
|
|
20
|
+
*/
|
|
21
|
+
declare const ImageAdapter: React.ForwardRefExoticComponent<Omit<ImageAdapterProps, "ref"> & React.RefAttributes<HTMLImageElement>>;
|
|
22
|
+
export { ImageAdapter };
|
|
23
|
+
export type { ImageAdapterPropsOverrides, ImageAdapterProps };
|
|
@@ -0,0 +1,27 @@
|
|
|
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 { useTheme } from "@emotion/react";
|
|
14
|
+
/**
|
|
15
|
+
* Overridable Image component.
|
|
16
|
+
* - If `Component` is provided, renders as `Component`
|
|
17
|
+
* - else, if `theme.custom.ImageAdapter` is provided, renders as `theme.custom.ImageAdapter`
|
|
18
|
+
* - else, renders as `img` tag
|
|
19
|
+
*/
|
|
20
|
+
const ImageAdapter = React.forwardRef(function ImageAdapter(_a, ref) {
|
|
21
|
+
var _b;
|
|
22
|
+
var { Component } = _a, props = __rest(_a, ["Component"]);
|
|
23
|
+
const theme = useTheme();
|
|
24
|
+
const ImgComponent = (_b = Component !== null && Component !== void 0 ? Component : theme.custom.ImgAdapter) !== null && _b !== void 0 ? _b : "img";
|
|
25
|
+
return React.createElement(ImgComponent, Object.assign({ ref: ref }, props));
|
|
26
|
+
});
|
|
27
|
+
export { ImageAdapter };
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import type { InputBaseProps } from "@mui/material/InputBase";
|
|
3
|
+
import type { Theme } from "@mui/material/styles";
|
|
4
|
+
type Size = "small" | "medium" | "large" | "chat" | "hero";
|
|
5
|
+
type CustomInputProps = {
|
|
6
|
+
/**
|
|
7
|
+
* If true, the input will display one size smaller at mobile breakpoint.
|
|
8
|
+
*/
|
|
9
|
+
responsive?: boolean;
|
|
10
|
+
};
|
|
11
|
+
type MuiDocOverride = {
|
|
12
|
+
size?: Size;
|
|
13
|
+
/**
|
|
14
|
+
* Slot for icon adornments.
|
|
15
|
+
*
|
|
16
|
+
* If the icon is a button, use `AdornmentButton` component.
|
|
17
|
+
*/
|
|
18
|
+
startAdornment?: React.ReactNode;
|
|
19
|
+
/**
|
|
20
|
+
* Slot for icon adornments.
|
|
21
|
+
*
|
|
22
|
+
* If the icon is a button, use `AdornmentButton` component.
|
|
23
|
+
*/
|
|
24
|
+
endAdornment?: React.ReactNode;
|
|
25
|
+
};
|
|
26
|
+
type InputProps = CustomInputProps & MuiDocOverride & Omit<InputBaseProps, "color" | keyof MuiDocOverride>;
|
|
27
|
+
/**
|
|
28
|
+
* Base styles for Input and Select components. Includes border, color, hover effects.
|
|
29
|
+
*/
|
|
30
|
+
declare const baseInputStyles: (theme: Theme) => {
|
|
31
|
+
backgroundColor: string;
|
|
32
|
+
color: string;
|
|
33
|
+
borderColor: string;
|
|
34
|
+
borderWidth: string;
|
|
35
|
+
borderStyle: string;
|
|
36
|
+
borderRadius: string;
|
|
37
|
+
overflow: string;
|
|
38
|
+
"&.Mui-disabled": {
|
|
39
|
+
backgroundColor: string;
|
|
40
|
+
};
|
|
41
|
+
"&:hover:not(.Mui-disabled):not(.Mui-focused)": {
|
|
42
|
+
borderColor: string;
|
|
43
|
+
};
|
|
44
|
+
"&.Mui-focused": {
|
|
45
|
+
/**
|
|
46
|
+
* When change border width, it affects either the elements outside of it or
|
|
47
|
+
* inside based on the border-box setting.
|
|
48
|
+
*
|
|
49
|
+
* Instead of changing the border width, we hide the border and change width
|
|
50
|
+
* using outline.
|
|
51
|
+
*/
|
|
52
|
+
borderColor: string;
|
|
53
|
+
outline: string;
|
|
54
|
+
outlineOffset: string;
|
|
55
|
+
};
|
|
56
|
+
"&.Mui-error": {
|
|
57
|
+
borderColor: string;
|
|
58
|
+
outlineColor: string;
|
|
59
|
+
};
|
|
60
|
+
"& input::placeholder, textarea::placeholder": {
|
|
61
|
+
color: string;
|
|
62
|
+
opacity: number;
|
|
63
|
+
};
|
|
64
|
+
"& input:placeholder-shown, textarea:placeholder-shown": {
|
|
65
|
+
textOverflow: string;
|
|
66
|
+
};
|
|
67
|
+
"& textarea": {
|
|
68
|
+
paddingTop: string;
|
|
69
|
+
paddingBottom: string;
|
|
70
|
+
};
|
|
71
|
+
"&.MuiInputBase-adornedStart": {
|
|
72
|
+
paddingLeft: string;
|
|
73
|
+
input: {
|
|
74
|
+
paddingLeft: string;
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
"&.MuiInputBase-adornedEnd": {
|
|
78
|
+
paddingRight: string;
|
|
79
|
+
input: {
|
|
80
|
+
paddingRight: string;
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* Use `Input` for a visually unlabelled input field. If used, it should still
|
|
86
|
+
* have an accessible label, e.g., provided via `aria-label`.
|
|
87
|
+
* For a labeled input field, use `TextField`. instead.
|
|
88
|
+
*
|
|
89
|
+
* **Note:** This component is a styled version of MUI's `InputBase`. See
|
|
90
|
+
* MUI's documentation for full info.
|
|
91
|
+
*
|
|
92
|
+
* - [Smoot Design Input Documentation](https://mitodl.github.io/smoot-design/?path=/docs/smoot-design-input--docs)
|
|
93
|
+
* - [InputBase Documentation](https://mui.com/api/input-base/)
|
|
94
|
+
*/
|
|
95
|
+
declare const Input: React.FC<InputProps>;
|
|
96
|
+
declare const AdornmentButtonStyled: import("@emotion/styled").StyledComponent<{
|
|
97
|
+
theme?: import("@emotion/react").Theme;
|
|
98
|
+
as?: React.ElementType;
|
|
99
|
+
}, React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, {}>;
|
|
100
|
+
type AdornmentButtonProps = React.ComponentProps<typeof AdornmentButtonStyled>;
|
|
101
|
+
/**
|
|
102
|
+
* Button to be used with `startAdornment` and `endAdornment` props on Input and
|
|
103
|
+
* TextField components. AdornmentButton takes care of positioning and other
|
|
104
|
+
* styling concerns.
|
|
105
|
+
*
|
|
106
|
+
* NOTES:
|
|
107
|
+
* - It is generally expected that the content of the AdornmentButton is a
|
|
108
|
+
* Remix Icon component. https://remixicon.com/
|
|
109
|
+
* - By default, the AdornmentButton calls `preventDefault` on `mouseDown`
|
|
110
|
+
* events. This prevents the button from stealing focus from the input on
|
|
111
|
+
* click. The button is still focusable via keyboard events. You can override
|
|
112
|
+
* this behavior by passing your own `onMouseDown` handler.
|
|
113
|
+
*/
|
|
114
|
+
declare const AdornmentButton: React.FC<AdornmentButtonProps>;
|
|
115
|
+
export { AdornmentButton, Input, baseInputStyles };
|
|
116
|
+
export type { InputProps, AdornmentButtonProps };
|