@mitodl/smoot-design 1.0.0

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 (40) hide show
  1. package/.eslintrc.js +142 -0
  2. package/.github/workflows/ci.yml +48 -0
  3. package/.github/workflows/publish-pages.yml +50 -0
  4. package/.github/workflows/release.yml +34 -0
  5. package/.github/workflows/validate-pr.yml +49 -0
  6. package/.pre-commit-config.yaml +90 -0
  7. package/.prettierignore +1 -0
  8. package/.prettierrc.json +4 -0
  9. package/.releaserc.json +40 -0
  10. package/.secrets.baseline +113 -0
  11. package/.storybook/main.ts +46 -0
  12. package/.storybook/manager-head.html +1 -0
  13. package/.storybook/preview-head.html +5 -0
  14. package/.storybook/preview.tsx +15 -0
  15. package/.storybook/public/pexels-photo-1851188.webp +0 -0
  16. package/.yarn/releases/yarn-4.5.1.cjs +934 -0
  17. package/.yarnrc.yml +23 -0
  18. package/LICENSE +28 -0
  19. package/README.md +13 -0
  20. package/jest.config.ts +22 -0
  21. package/package.json +110 -0
  22. package/src/components/Button/ActionButton.stories.tsx +186 -0
  23. package/src/components/Button/Button.stories.tsx +275 -0
  24. package/src/components/Button/Button.test.tsx +56 -0
  25. package/src/components/Button/Button.tsx +418 -0
  26. package/src/components/LinkAdapter/LinkAdapter.tsx +38 -0
  27. package/src/components/ThemeProvider/ThemeProvider.stories.tsx +94 -0
  28. package/src/components/ThemeProvider/ThemeProvider.tsx +127 -0
  29. package/src/components/ThemeProvider/Typography.stories.tsx +74 -0
  30. package/src/components/ThemeProvider/breakpoints.ts +20 -0
  31. package/src/components/ThemeProvider/buttons.ts +22 -0
  32. package/src/components/ThemeProvider/chips.tsx +167 -0
  33. package/src/components/ThemeProvider/colors.ts +33 -0
  34. package/src/components/ThemeProvider/typography.ts +174 -0
  35. package/src/index.ts +24 -0
  36. package/src/jest-setup.ts +0 -0
  37. package/src/story-utils/index.ts +28 -0
  38. package/src/types/theme.d.ts +106 -0
  39. package/src/types/typography.d.ts +54 -0
  40. package/tsconfig.json +26 -0
@@ -0,0 +1,127 @@
1
+ import * as React from "react"
2
+ import {
3
+ createTheme as muiCreateTheme,
4
+ ThemeProvider as MuiThemeProvider,
5
+ } from "@mui/material/styles"
6
+ import type { ThemeOptions, Theme } from "@mui/material/styles"
7
+ import type {} from "@mui/lab/themeAugmentation"
8
+ import * as typography from "./typography"
9
+ import * as buttons from "./buttons"
10
+ import * as chips from "./chips"
11
+ import { colors } from "./colors"
12
+ import type { CustomTheme } from "../../types/theme"
13
+
14
+ const shadow = {
15
+ shadowOffsetX: 3,
16
+ shadowOffsetY: 4,
17
+ shadowColor: "rgb(0 0 0 / 36%)",
18
+ shadowBlurRadius: 12,
19
+ }
20
+
21
+ // To replace ../scss/theme.scss for #236 as we refactor it out
22
+ const custom: ThemeOptions["custom"] = {
23
+ transitionDuration: "300ms",
24
+ shadow: `${shadow.shadowOffsetX} ${shadow.shadowOffsetY} ${shadow.shadowBlurRadius} ${shadow.shadowColor}`,
25
+ colors,
26
+ dimensions: {
27
+ headerHeight: "72px",
28
+ headerHeightSm: "60px",
29
+ },
30
+ }
31
+
32
+ const BREAKPOINTS = {
33
+ values: {
34
+ xs: 0,
35
+ sm: 600,
36
+ md: 900,
37
+ lg: 1272 + 48,
38
+ xl: 1536,
39
+ },
40
+ }
41
+
42
+ const defaultThemeOptions: ThemeOptions = {
43
+ custom: custom,
44
+ palette: {
45
+ action: {
46
+ disabled: colors.lightGray2,
47
+ },
48
+ text: {
49
+ primary: "#000",
50
+ secondary: colors.silverGrayDark,
51
+ },
52
+ primary: {
53
+ main: colors.mitRed,
54
+ light: colors.lightRed,
55
+ active: colors.red,
56
+ contrastText: colors.white,
57
+ },
58
+ secondary: {
59
+ light: colors.darkGray2,
60
+ active: colors.silverGrayDark,
61
+ main: colors.black,
62
+ contrastText: colors.white,
63
+ },
64
+ },
65
+ shape: {
66
+ borderRadius: 8,
67
+ },
68
+ spacing: 8,
69
+ typography: typography.globalSettings,
70
+ breakpoints: BREAKPOINTS,
71
+ components: {
72
+ MuiButtonBase: buttons.buttonBaseComponent,
73
+ MuiTypography: typography.component,
74
+ MuiTabPanel: {
75
+ styleOverrides: {
76
+ root: {
77
+ padding: "0px",
78
+ },
79
+ },
80
+ },
81
+ MuiMenu: {
82
+ styleOverrides: { paper: { borderRadius: "4px" } },
83
+ },
84
+ MuiAutocomplete: {
85
+ styleOverrides: {
86
+ paper: { borderRadius: "4px" },
87
+ // Mui puts paddingRight: 2px, marginRight: -2px on the popupIndicator,
88
+ // which causes the browser to show a horizontal scrollbar on overflow
89
+ // containers when a scrollbar isn't really necessary.
90
+ popupIndicator: { paddingRight: 0, marginRight: 0 },
91
+ },
92
+ },
93
+ MuiChip: chips.chipComponent,
94
+ },
95
+ }
96
+
97
+ type ExtendedTheme = Theme & {
98
+ custom: CustomTheme
99
+ }
100
+
101
+ const createTheme = (options?: {
102
+ custom: Partial<ThemeOptions["custom"]>
103
+ }): ExtendedTheme =>
104
+ muiCreateTheme({
105
+ ...defaultThemeOptions,
106
+ custom: {
107
+ ...defaultThemeOptions.custom,
108
+ ...options?.custom,
109
+ },
110
+ })
111
+
112
+ const defaultTheme = createTheme()
113
+
114
+ type ThemeProviderProps = {
115
+ children?: React.ReactNode
116
+ theme?: Theme
117
+ }
118
+
119
+ const ThemeProvider: React.FC<ThemeProviderProps> = ({
120
+ children,
121
+ theme = defaultTheme,
122
+ }) => {
123
+ return <MuiThemeProvider theme={theme}>{children}</MuiThemeProvider>
124
+ }
125
+
126
+ export { ThemeProvider, createTheme }
127
+ export type { ThemeProviderProps, Theme }
@@ -0,0 +1,74 @@
1
+ import * as React from "react"
2
+ import type { Meta, StoryObj } from "@storybook/react"
3
+ import Stack from "@mui/material/Stack"
4
+ import Typography from "@mui/material/Typography"
5
+ import type { TypographyProps } from "@mui/material/Typography"
6
+
7
+ /**
8
+ * Typography styles can be controlled via the `theme.typography` object when
9
+ * using the `styled` helper or via the `<Tyopgraphy variant="..." />` component.
10
+ *
11
+ * ```tsx
12
+ * const MyHeading = styled(({ theme }) => ({
13
+ * ...theme.typography.h2,
14
+ * [theme.breakpoints.down("sm")]: {
15
+ * ...theme.typography.h3,
16
+ * },
17
+ * }))
18
+ *
19
+ * // or:
20
+ * <Typography component="h1" typography={
21
+ * {
22
+ * xs: "h3", // above xs
23
+ * sm: "h2" // above sm
24
+ * }
25
+ * }>
26
+ * Hello, world!
27
+ * </Typography>
28
+ * ```
29
+ *
30
+ */
31
+ const meta: Meta<typeof Typography> = {
32
+ title: "smoot-design/Typography",
33
+ tags: ["autodocs"],
34
+ }
35
+
36
+ export default meta
37
+
38
+ type Story = StoryObj<typeof Typography>
39
+
40
+ const text = "The quick brown fox jumps over the lazy dog. ".repeat(10)
41
+ const INSTANCES: TypographyProps[] = [
42
+ { variant: "h1", children: "Heading level 1" },
43
+ { variant: "h2", children: "Heading level 2" },
44
+ { variant: "h3", children: "Heading level 3" },
45
+ { variant: "h4", children: "Heading level 4" },
46
+ { variant: "h5", children: "Heading level 5" },
47
+ { variant: "subtitle1", children: "Subtitle level 1" },
48
+ { variant: "subtitle2", children: "Subtitle level 2" },
49
+ { variant: "subtitle3", children: "Subtitle level 3" },
50
+ { variant: "subtitle4", children: "Subtitle level 4" },
51
+ { variant: "body1", children: `body level 1... ${text}` },
52
+ { variant: "body2", children: `body level 2... ${text}` },
53
+ { variant: "body3", children: `body level 3... ${text}` },
54
+ { variant: "body4", children: `body level 4... ${text}` },
55
+ ]
56
+
57
+ /**
58
+ * Typography variants are shown below.
59
+ *
60
+ * **Note:** The typography variant is not related to the HTML element used. A
61
+ * `variant="h1"` component does not automatically render an `<h1>` element.
62
+ *
63
+ */
64
+ export const Variants: Story = {
65
+ render: () => {
66
+ return (
67
+ <Stack gap="1rem">
68
+ {INSTANCES.map((props) => (
69
+ <Typography key={props.variant} {...props} />
70
+ ))}
71
+ </Stack>
72
+ )
73
+ },
74
+ }
@@ -0,0 +1,20 @@
1
+ import type { ThemeOptions } from "@mui/material/styles"
2
+ import { createTheme } from "@mui/material/styles"
3
+
4
+ const BREAKPOINT_VALUES: ThemeOptions["breakpoints"] = {
5
+ values: {
6
+ xs: 0,
7
+ sm: 600,
8
+ md: 900,
9
+ lg: 1280,
10
+ xl: 1536,
11
+ },
12
+ }
13
+
14
+ const { breakpoints } = createTheme({
15
+ breakpoints: BREAKPOINT_VALUES,
16
+ // @ts-expect-error only using breakpoints
17
+ custom: {},
18
+ })
19
+
20
+ export { BREAKPOINT_VALUES, breakpoints }
@@ -0,0 +1,22 @@
1
+ import type { ThemeOptions } from "@mui/material/styles"
2
+
3
+ /**
4
+ * We don't use MUI's button directly, but ButtonBase does get used internally
5
+ * by some MUI components, so we override a few styles.
6
+ */
7
+ const buttonBaseComponent: NonNullable<
8
+ ThemeOptions["components"]
9
+ >["MuiButtonBase"] = {
10
+ defaultProps: {
11
+ disableRipple: true,
12
+ },
13
+ styleOverrides: {
14
+ root: {
15
+ ":focus-visible": {
16
+ outline: "revert",
17
+ },
18
+ },
19
+ },
20
+ }
21
+
22
+ export { buttonBaseComponent }
@@ -0,0 +1,167 @@
1
+ import * as React from "react"
2
+ import type { ThemeOptions } from "@mui/material/styles"
3
+ import { colors } from "./colors"
4
+ import { RiCloseLine } from "@remixicon/react"
5
+
6
+ const chipComponent: NonNullable<ThemeOptions["components"]>["MuiChip"] = {
7
+ defaultProps: {
8
+ size: "medium",
9
+ color: "default",
10
+ variant: "outlined",
11
+ deleteIcon: <RiCloseLine aria-hidden="true" />,
12
+ },
13
+ styleOverrides: {
14
+ root: {
15
+ borderRadius: "100vh",
16
+ borderWidth: "1px",
17
+ },
18
+ deleteIcon: {
19
+ "&:hover": {
20
+ color: "inherit",
21
+ },
22
+ "&.MuiChip-deleteIconLarge": {
23
+ width: "16px",
24
+ height: "16px",
25
+ },
26
+ "&.MuiChip-deleteIconMedium": {
27
+ width: "14px",
28
+ height: "14px",
29
+ },
30
+ margin: "0 -2px 0 8px",
31
+ color: "inherit",
32
+ },
33
+ icon: {
34
+ margin: "0 8px 0 -2px",
35
+ color: "inherit",
36
+ "&.MuiChip-iconLarge": {
37
+ width: "16px",
38
+ height: "16px",
39
+ },
40
+ "&.MuiChip-iconMedium": {
41
+ width: "14px",
42
+ height: "14px",
43
+ },
44
+ },
45
+ },
46
+ variants: [
47
+ {
48
+ props: { size: "medium" },
49
+ style: ({ theme }) => ({
50
+ ...theme.typography.body3,
51
+ boxSizing: "border-box",
52
+ height: "24px",
53
+ paddingRight: "12px",
54
+ paddingLeft: "12px",
55
+ ".MuiChip-label": {
56
+ paddingLeft: "0px",
57
+ paddingRight: "0px",
58
+ },
59
+ }),
60
+ },
61
+ {
62
+ props: { size: "large" },
63
+ style: ({ theme }) => ({
64
+ ...theme.typography.body2,
65
+ height: "32px",
66
+ paddingLeft: "16px",
67
+ paddingRight: "16px",
68
+ ".MuiChip-label": {
69
+ paddingLeft: "0px",
70
+ paddingRight: "0px",
71
+ },
72
+ }),
73
+ },
74
+ {
75
+ props: { variant: "outlined" },
76
+ style: {
77
+ borderColor: colors.silverGrayLight,
78
+ color: colors.darkGray1,
79
+ "&.Mui-focusVisible": {
80
+ backgroundColor: "transparent",
81
+ },
82
+ "&.MuiChip-clickable:hover, &.MuiChip-deletable:hover": {
83
+ color: colors.darkGray1,
84
+ borderColor: colors.silverGrayDark,
85
+ backgroundColor: "transparent", // mui has a default background color for hover
86
+ },
87
+ },
88
+ },
89
+ {
90
+ props: { variant: "outlinedWhite" },
91
+ style: {
92
+ backgroundColor: "white",
93
+ border: "1px solid",
94
+ borderColor: colors.silverGrayLight,
95
+ color: colors.darkGray1,
96
+ "&.Mui-focusVisible": {
97
+ backgroundColor: "white",
98
+ },
99
+ "&.MuiChip-clickable:hover, &.MuiChip-deletable:hover": {
100
+ color: colors.darkGray1,
101
+ borderColor: colors.silverGrayDark,
102
+ backgroundColor: "white", // mui has a default background color hover
103
+ },
104
+ },
105
+ },
106
+ {
107
+ props: { variant: "gray" },
108
+ style: {
109
+ backgroundColor: colors.lightGray2,
110
+ border: "none",
111
+ color: colors.darkGray2,
112
+ "&.Mui-focusVisible": {
113
+ backgroundColor: colors.lightGray2,
114
+ },
115
+ "&.MuiChip-clickable:hover, &.MuiChip-deletable:hover": {
116
+ color: colors.darkGray1,
117
+ backgroundColor: colors.silverGrayLight,
118
+ },
119
+ },
120
+ },
121
+ {
122
+ props: { variant: "dark" },
123
+ style: {
124
+ backgroundColor: colors.silverGrayDark,
125
+ border: "none",
126
+ color: colors.white,
127
+ "&.Mui-focusVisible": {
128
+ backgroundColor: colors.silverGrayDark,
129
+ },
130
+ "&.MuiChip-clickable:hover, &.MuiChip-deletable:hover": {
131
+ backgroundColor: colors.darkGray1,
132
+ },
133
+ },
134
+ },
135
+ {
136
+ props: { variant: "darker" },
137
+ style: {
138
+ backgroundColor: colors.darkGray2,
139
+ border: `1px solid ${colors.darkGray1}`,
140
+ color: colors.white,
141
+ "&.Mui-focusVisible": {
142
+ backgroundColor: colors.darkGray2,
143
+ },
144
+ "&.MuiChip-clickable:hover, &.MuiChip-deletable:hover": {
145
+ backgroundColor: colors.black,
146
+ border: `1px solid ${colors.silverGray}`,
147
+ },
148
+ },
149
+ },
150
+ {
151
+ props: { variant: "filled" },
152
+ style: {
153
+ backgroundColor: colors.mitRed,
154
+ border: "none",
155
+ color: colors.white,
156
+ "&.Mui-focusVisible": {
157
+ backgroundColor: colors.mitRed,
158
+ },
159
+ "&.MuiChip-clickable:hover, &.MuiChip-deletable:hover": {
160
+ backgroundColor: colors.red,
161
+ },
162
+ },
163
+ },
164
+ ],
165
+ }
166
+
167
+ export { chipComponent }
@@ -0,0 +1,33 @@
1
+ const colors = {
2
+ mitRed: "#750014",
3
+ brightRed: "#FF1423",
4
+ black: "#000000",
5
+ white: "#FFFFFF",
6
+ darkGray2: "#212326",
7
+ darkGray1: "#40464C",
8
+ silverGrayDark: "#626A73",
9
+ silverGray: "#8B959E",
10
+ silverGrayLight: "#B8C2CC",
11
+ lightGray2: "#DDE1E6",
12
+ lightGray1: "#F3F4F8",
13
+ navGray: "#303337",
14
+ darkPink: "#750062",
15
+ pink: "#FF14F0",
16
+ lightPink: "#FFB3FF",
17
+ darkPurple: "#3E006B",
18
+ purple: "#93F",
19
+ lightPurple: "#BFB3FF",
20
+ darkBlue: "#002896",
21
+ blue: "#1966FF",
22
+ lightBlue: "#99EBFF",
23
+ darkGreen: "#004D1A",
24
+ green: "#00AD00",
25
+ lightGreen: "#AF3",
26
+ darkRed: "#83192A",
27
+ red: "#A31F34",
28
+ lightRed: "#D02E44",
29
+ orange: "#FAB005",
30
+ yellow: "#FFEB00",
31
+ }
32
+
33
+ export { colors }
@@ -0,0 +1,174 @@
1
+ import type { ThemeOptions } from "@mui/material/styles"
2
+ import { createTheme } from "@mui/material/styles"
3
+
4
+ const fontWeights = {
5
+ text: {
6
+ roman: 400,
7
+ medium: 500,
8
+ bold: 700,
9
+ },
10
+ }
11
+
12
+ /**
13
+ * This function converts from pixels to rems, assuming a base font size of 16px
14
+ * (which is the default for most modern browsers).
15
+ *
16
+ * Using this function, we can:
17
+ * - match desgins that are in pixels for default font size
18
+ * - allow users to scale the font size up or down by chaning base font size.
19
+ *
20
+ * For example, a Chrome user might specify a base font size of 20px ("large")
21
+ * in their browser settings. Then, `pxToRem(32)` would actually be 40px for
22
+ * that user.
23
+ */
24
+ const pxToRem = (px: number) => `${px / 16}rem`
25
+
26
+ const globalSettings: ThemeOptions["typography"] = {
27
+ // Note: Figma calls this "Neue Haas Grotesk Text", but that is incorrect based on Adobe's font family.
28
+ fontFamily: "neue-haas-grotesk-text, sans-serif",
29
+ fontWeightLight: fontWeights.text.roman,
30
+ fontWeightRegular: fontWeights.text.roman,
31
+ fontWeightMedium: fontWeights.text.medium,
32
+ fontWeightBold: fontWeights.text.bold,
33
+ h1: {
34
+ fontFamily: "neue-haas-grotesk-text, sans-serif",
35
+ fontWeight: fontWeights.text.bold,
36
+ fontStyle: "normal",
37
+ fontSize: pxToRem(52),
38
+ lineHeight: pxToRem(60),
39
+ },
40
+ h2: {
41
+ fontFamily: "neue-haas-grotesk-text, sans-serif",
42
+ fontWeight: fontWeights.text.bold,
43
+ fontStyle: "normal",
44
+ fontSize: pxToRem(34),
45
+ lineHeight: pxToRem(40),
46
+ },
47
+ h3: {
48
+ fontFamily: "neue-haas-grotesk-text, sans-serif",
49
+ fontWeight: fontWeights.text.bold,
50
+ fontStyle: "normal",
51
+ fontSize: pxToRem(28),
52
+ lineHeight: pxToRem(36),
53
+ },
54
+ h4: {
55
+ fontFamily: "neue-haas-grotesk-text, sans-serif",
56
+ fontWeight: fontWeights.text.bold,
57
+ fontStyle: "normal",
58
+ fontSize: pxToRem(24),
59
+ lineHeight: pxToRem(30),
60
+ },
61
+ h5: {
62
+ fontFamily: "neue-haas-grotesk-text, sans-serif",
63
+ fontWeight: fontWeights.text.medium,
64
+ fontStyle: "normal",
65
+ fontSize: pxToRem(18),
66
+ lineHeight: pxToRem(22),
67
+ },
68
+ subtitle1: {
69
+ fontFamily: "neue-haas-grotesk-text, sans-serif",
70
+ fontWeight: fontWeights.text.medium,
71
+ fontStyle: "normal",
72
+ fontSize: pxToRem(16),
73
+ lineHeight: pxToRem(20),
74
+ },
75
+ subtitle2: {
76
+ fontFamily: "neue-haas-grotesk-text, sans-serif",
77
+ fontWeight: fontWeights.text.medium,
78
+ fontStyle: "normal",
79
+ fontSize: pxToRem(14),
80
+ lineHeight: pxToRem(18),
81
+ },
82
+ subtitle3: {
83
+ fontFamily: "neue-haas-grotesk-text, sans-serif",
84
+ fontWeight: fontWeights.text.medium,
85
+ fontStyle: "normal",
86
+ fontSize: pxToRem(12),
87
+ lineHeight: pxToRem(16),
88
+ },
89
+ subtitle4: {
90
+ fontFamily: "neue-haas-grotesk-text, sans-serif",
91
+ fontWeight: fontWeights.text.medium,
92
+ fontStyle: "normal",
93
+ fontSize: pxToRem(10),
94
+ lineHeight: pxToRem(14),
95
+ },
96
+ body1: {
97
+ fontFamily: "neue-haas-grotesk-text, sans-serif",
98
+ fontWeight: fontWeights.text.roman,
99
+ fontStyle: "normal",
100
+ fontSize: pxToRem(16),
101
+ lineHeight: pxToRem(20),
102
+ },
103
+ body2: {
104
+ fontFamily: "neue-haas-grotesk-text, sans-serif",
105
+ fontWeight: fontWeights.text.roman,
106
+ fontStyle: "normal",
107
+ fontSize: pxToRem(14),
108
+ lineHeight: pxToRem(18),
109
+ },
110
+ body3: {
111
+ fontFamily: "neue-haas-grotesk-text, sans-serif",
112
+ fontWeight: fontWeights.text.roman,
113
+ fontStyle: "normal",
114
+ fontSize: pxToRem(12),
115
+ lineHeight: pxToRem(16),
116
+ },
117
+ body4: {
118
+ fontFamily: "neue-haas-grotesk-text, sans-serif",
119
+ fontWeight: fontWeights.text.roman,
120
+ fontStyle: "normal",
121
+ fontSize: pxToRem(10),
122
+ lineHeight: pxToRem(14),
123
+ },
124
+ buttonLarge: {
125
+ fontFamily: "neue-haas-grotesk-text, sans-serif",
126
+ fontWeight: fontWeights.text.medium,
127
+ fontStyle: "normal",
128
+ fontSize: pxToRem(16),
129
+ lineHeight: pxToRem(20),
130
+ },
131
+ button: {
132
+ fontFamily: "neue-haas-grotesk-text, sans-serif",
133
+ fontWeight: fontWeights.text.medium,
134
+ fontStyle: "normal",
135
+ fontSize: pxToRem(14),
136
+ lineHeight: pxToRem(18),
137
+ textTransform: "none",
138
+ },
139
+ buttonSmall: {
140
+ fontFamily: "neue-haas-grotesk-text, sans-serif",
141
+ fontWeight: fontWeights.text.medium,
142
+ fontStyle: "normal",
143
+ fontSize: pxToRem(12),
144
+ lineHeight: pxToRem(16),
145
+ },
146
+ }
147
+ const component: NonNullable<ThemeOptions["components"]>["MuiTypography"] = {
148
+ defaultProps: {
149
+ variantMapping: {
150
+ h1: "span",
151
+ h2: "span",
152
+ h3: "span",
153
+ h4: "span",
154
+ h5: "span",
155
+ body1: "p",
156
+ body2: "p",
157
+ body3: "p",
158
+ body4: "p",
159
+ subtitle1: "p",
160
+ subtitle2: "p",
161
+ subtitle3: "p",
162
+ subtitle4: "p",
163
+ button: "span",
164
+ },
165
+ },
166
+ }
167
+
168
+ const { typography } = createTheme({
169
+ typography: globalSettings,
170
+ // @ts-expect-error: we only care about typography from this theme
171
+ custom: {},
172
+ })
173
+
174
+ export { globalSettings, component, pxToRem, typography }
package/src/index.ts ADDED
@@ -0,0 +1,24 @@
1
+ "use client"
2
+ /// <reference types="./types/theme.d.ts" />
3
+ /// <reference types="./types/typography.d.ts" />
4
+
5
+ export { default as styled } from "@emotion/styled"
6
+ export { css, Global } from "@emotion/react"
7
+
8
+ export { AppRouterCacheProvider as NextJsAppRouterCacheProvider } from "@mui/material-nextjs/v15-appRouter"
9
+
10
+ export {
11
+ ThemeProvider,
12
+ createTheme,
13
+ } from "./components/ThemeProvider/ThemeProvider"
14
+
15
+ export {
16
+ Button,
17
+ ButtonLink,
18
+ ActionButton,
19
+ ActionButtonLink,
20
+ } from "./components/Button/Button"
21
+
22
+ export type { LinkAdapterPropsOverrides } from "./components/LinkAdapter/LinkAdapter"
23
+
24
+ export type { ButtonProps, ButtonLinkProps } from "./components/Button/Button"
File without changes
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Generate a string that represents an enum of the keys of the given object.
3
+ *
4
+ * Example:
5
+ * ```ts
6
+ * const SIZES = {
7
+ * small: "irrelevant-value",
8
+ * large: "irrelevant-value",
9
+ * }
10
+ * console.log(docsEnum(SIZES))
11
+ * // '"small" | "large"'
12
+ *
13
+ * ```
14
+ *
15
+ * Use case: Storybook docs are created with react-docgen, which fails to infer
16
+ * typescript enum types.
17
+ *
18
+ *
19
+ */
20
+ const docsEnum = <T extends string>(values: T[]) => {
21
+ return values.map((key) => `"${key}"`).join(" | ")
22
+ }
23
+
24
+ const enumValues = <T extends string>(obj: Record<T, unknown>): T[] => {
25
+ return Object.keys(obj) as T[]
26
+ }
27
+
28
+ export { docsEnum, enumValues }