@graphcommerce/next-ui 3.25.2 → 4.0.1

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 (138) hide show
  1. package/AnimatedRow/index.tsx +6 -3
  2. package/ApolloError/ApolloErrorAlert.tsx +20 -21
  3. package/ApolloError/ApolloErrorFullPage.tsx +3 -4
  4. package/ApolloError/ApolloErrorSnackbar.tsx +3 -3
  5. package/Blog/BlogAuthor/index.tsx +42 -48
  6. package/Blog/BlogContent/index.tsx +6 -23
  7. package/Blog/BlogHeader/index.tsx +26 -23
  8. package/Blog/BlogList/index.tsx +7 -25
  9. package/Blog/BlogListItem/index.tsx +63 -52
  10. package/Blog/BlogTags/BlogTag.tsx +27 -0
  11. package/Blog/BlogTags/index.tsx +7 -32
  12. package/Blog/BlogTitle/index.tsx +7 -21
  13. package/Button/Button.tsx +5 -0
  14. package/Button/LinkOrButton.tsx +80 -0
  15. package/Button/index.tsx +2 -177
  16. package/CHANGELOG.md +507 -642
  17. package/ChipMenu/index.tsx +71 -77
  18. package/ContainerWithHeader/index.tsx +33 -30
  19. package/FlagAvatar/index.tsx +2 -12
  20. package/Footer/Footer.tsx +105 -88
  21. package/Footer/index.ts +0 -1
  22. package/Form/Form.tsx +35 -0
  23. package/Form/FormActions.tsx +9 -14
  24. package/Form/FormDivider.tsx +8 -13
  25. package/Form/FormHeader.tsx +5 -26
  26. package/Form/FormRow.tsx +8 -13
  27. package/Form/InputCheckmark.tsx +9 -22
  28. package/FramerScroller/SidebarGallery.tsx +340 -0
  29. package/FramerScroller/SidebarSlider.tsx +107 -0
  30. package/FramerScroller/index.ts +2 -0
  31. package/FullPageMessage/index.tsx +52 -48
  32. package/Highlight/index.tsx +1 -1
  33. package/IconHeader/index.tsx +63 -58
  34. package/JsonLd/index.tsx +3 -2
  35. package/Layout/components/LayoutHeader.tsx +75 -82
  36. package/Layout/components/LayoutHeaderBack.tsx +21 -12
  37. package/Layout/components/LayoutHeaderClose.tsx +9 -22
  38. package/Layout/components/LayoutHeaderContent.tsx +190 -154
  39. package/Layout/components/LayoutHeadertypes.ts +1 -1
  40. package/Layout/components/LayoutTitle.tsx +60 -55
  41. package/LayoutDefault/components/LayoutDefault.tsx +96 -85
  42. package/LayoutOverlay/components/LayoutOverlay.tsx +2 -8
  43. package/LayoutOverlay/components/LayoutOverlayBase.tsx +233 -239
  44. package/LayoutOverlay/test/LayoutOverlayDemo.tsx +1 -1
  45. package/LayoutParts/DesktopHeaderBadge.tsx +28 -0
  46. package/LayoutParts/DesktopNavActions.tsx +15 -0
  47. package/LayoutParts/DesktopNavBar.tsx +113 -0
  48. package/LayoutParts/DesktopNavBarItem.tsx +44 -0
  49. package/{AppShell → LayoutParts}/GlobalHead.tsx +1 -2
  50. package/LayoutParts/Logo.tsx +77 -0
  51. package/LayoutParts/MenuFab.tsx +131 -0
  52. package/LayoutParts/MenuFabItem.tsx +25 -0
  53. package/LayoutParts/MenuFabSecondaryItem.tsx +37 -0
  54. package/{AppShell/PlaceholderFab/index.tsx → LayoutParts/PlaceholderFab.tsx} +1 -1
  55. package/LayoutParts/StickyBelowHeader.tsx +25 -0
  56. package/LayoutParts/index.ts +12 -0
  57. package/{AppShell → LayoutParts}/useFabAnimation.ts +0 -0
  58. package/Page/CssAndFramerMotionProvider.tsx +21 -0
  59. package/Page/index.ts +2 -0
  60. package/Page/types.ts +2 -8
  61. package/PageLoadIndicator/index.tsx +25 -30
  62. package/PageMeta/index.tsx +1 -1
  63. package/Pagination/index.tsx +37 -54
  64. package/RenderType/index.tsx +1 -1
  65. package/Row/ButtonLinkList/ButtonLinkList.tsx +35 -37
  66. package/Row/ButtonLinkList/ButtonLinkListItem.tsx +16 -33
  67. package/Row/ColumnOne/index.tsx +5 -10
  68. package/Row/ColumnOneBoxed/index.tsx +18 -19
  69. package/Row/ColumnOneCentered/index.tsx +3 -4
  70. package/Row/ColumnThree/index.tsx +62 -57
  71. package/Row/ColumnTwo/index.tsx +37 -35
  72. package/Row/ColumnTwoSpread/index.tsx +28 -37
  73. package/Row/ColumnTwoWithTop/index.tsx +37 -43
  74. package/Row/ContentLinks/index.tsx +24 -25
  75. package/Row/HeroBanner/index.tsx +98 -82
  76. package/Row/IconBlocks/IconBlock/index.tsx +45 -37
  77. package/Row/IconBlocks/index.tsx +29 -44
  78. package/Row/ImageText/index.tsx +71 -67
  79. package/Row/ImageTextBoxed/index.tsx +66 -65
  80. package/Row/ParagraphWithSidebarSlide/index.tsx +80 -76
  81. package/Row/Quote/index.tsx +3 -3
  82. package/Row/SpecialBanner/index.tsx +97 -97
  83. package/Row/index.tsx +4 -9
  84. package/SectionContainer/index.tsx +32 -31
  85. package/SectionHeader/index.tsx +41 -43
  86. package/Separator/index.tsx +19 -18
  87. package/Snackbar/MessageSnackbar.tsx +1 -2
  88. package/Snackbar/MessageSnackbarImpl.tsx +68 -115
  89. package/StarRatingField/index.tsx +24 -25
  90. package/Stepper/Stepper.tsx +34 -32
  91. package/Styles/EmotionProvider.tsx +14 -0
  92. package/Styles/breakpointVal.tsx +16 -10
  93. package/Styles/extendableComponent.ts +70 -0
  94. package/Styles/index.tsx +9 -2
  95. package/Styles/withEmotionCache.tsx +36 -0
  96. package/Styles/withTheme.tsx +15 -24
  97. package/SvgIcon/SvgIcon.tsx +60 -0
  98. package/TextInputNumber/index.tsx +49 -50
  99. package/Theme/MuiButton.ts +128 -0
  100. package/Theme/MuiSlider.ts +28 -0
  101. package/Theme/MuiSnackbar.ts +31 -0
  102. package/Theme/{types.ts → createTheme.ts} +8 -2
  103. package/Theme/index.ts +4 -0
  104. package/Theme/themeDefaults.ts +51 -0
  105. package/TimeAgo/index.tsx +1 -1
  106. package/ToggleButton/index.tsx +43 -49
  107. package/ToggleButtonGroup/index.tsx +39 -39
  108. package/UspList/UspListItem.tsx +56 -46
  109. package/UspList/index.tsx +29 -26
  110. package/docs/building-components.mdx +3 -0
  111. package/docs/components/ComponentBasic.tsx +26 -0
  112. package/docs/components/ComponentChild.tsx +48 -0
  113. package/docs/components/ComponentChildVariant.tsx +54 -0
  114. package/docs/components/ComponentChildVariantExtendable.tsx +62 -0
  115. package/docs/components/ComponentStylable.tsx +32 -0
  116. package/docs/pages/building-components.tsx +62 -0
  117. package/index.ts +27 -81
  118. package/package.json +27 -27
  119. package/types.d.ts +1 -1
  120. package/AppShell/AppShellSticky/index.tsx +0 -38
  121. package/AppShell/DesktopNavActions.tsx +0 -32
  122. package/AppShell/DesktopNavBar.tsx +0 -158
  123. package/AppShell/Logo.tsx +0 -46
  124. package/AppShell/Menu.tsx +0 -7
  125. package/AppShell/MenuFab.tsx +0 -162
  126. package/AppShell/MenuFabSecondaryItem.tsx +0 -32
  127. package/AppShell/index.ts +0 -15
  128. package/AspectRatioContainer/index.tsx +0 -27
  129. package/Footer/SocialIcon.tsx +0 -23
  130. package/Form/index.tsx +0 -67
  131. package/FramerScroller/components/SidebarGallery.tsx +0 -317
  132. package/FramerScroller/components/SidebarSlider.tsx +0 -97
  133. package/Page/App.tsx +0 -17
  134. package/Page/Document.tsx +0 -24
  135. package/StyledBadge/index.tsx +0 -20
  136. package/Styles/classesPicker.ts +0 -41
  137. package/SvgImage/SvgImageSimple.tsx +0 -100
  138. package/SvgImage/index.tsx +0 -74
@@ -8,15 +8,21 @@ export function breakpointVal(
8
8
  const breakpoints = Object.values(breakpointsObject)
9
9
  const spread = breakpoints[breakpoints.length - 1] - minSize
10
10
 
11
- return Object.fromEntries(
12
- breakpoints.map((breakpoint, index) => {
13
- // Get the size between this breakpoint and the previous breakpoint
14
- const between = (breakpoint + (breakpoints[index + 1] ?? breakpoint)) / 2
15
- // Calculate the size of the value
16
- const size = Math.max(min, ((between - minSize) / spread) * (max - min) + min)
17
- const value = `${Math.round(size * 100) / 100}px`
11
+ const entries = {}
18
12
 
19
- return [`@media (min-width: ${breakpoint}px )`, { [property]: value }]
20
- }),
21
- )
13
+ breakpoints.forEach((breakpoint, index) => {
14
+ // Get the size between this breakpoint and the previous breakpoint
15
+ const between = (breakpoint + (breakpoints[index + 1] ?? breakpoint)) / 2
16
+ // Calculate the size of the value
17
+ const size = Math.max(min, ((between - minSize) / spread) * (max - min) + min)
18
+ const value = `${Math.round(size * 100) / 100}px`
19
+
20
+ if (breakpoint) {
21
+ entries[`@media (min-width: ${breakpoint}px )`] = { [property]: value }
22
+ } else {
23
+ entries[property] = value
24
+ }
25
+ })
26
+
27
+ return entries
22
28
  }
@@ -0,0 +1,70 @@
1
+ import { capitalize, Interpolation, Theme } from '@mui/material'
2
+ import React from 'react'
3
+
4
+ export type ExtendableComponent<StyleProps extends Record<string, unknown>> = {
5
+ defaultProps?: Partial<StyleProps>
6
+ variants?: { props: Partial<StyleProps>; style: Interpolation<{ theme: Theme }> }[]
7
+ }
8
+
9
+ export function slotClasses<Name extends string, ClassNames extends ReadonlyArray<string>>(
10
+ name: Name,
11
+ slotNames: ClassNames,
12
+ ) {
13
+ return Object.fromEntries(slotNames.map((slot) => [slot, `${name}-${slot}`])) as {
14
+ [P in ClassNames[number]]: `${Name}-${P}`
15
+ }
16
+ }
17
+
18
+ /** Maps incoming classes to a selectors that can be used to extend the component */
19
+ export const partselectorsMap = <O extends Record<string, string>>(
20
+ obj: O,
21
+ ): {
22
+ [P in keyof O]: `& .${O[P]}`
23
+ } => {
24
+ const mapped = Object.entries(obj).map(([target, className]) => [target, `& .${className}`])
25
+ return Object.fromEntries(mapped)
26
+ }
27
+
28
+ /**
29
+ * Utility function to:
30
+ *
31
+ * - Define parts
32
+ * - Generate state css classes.
33
+ */
34
+ export function extendableComponent<
35
+ ComponentStyleProps extends Record<string, boolean | string | number | undefined>,
36
+ Name extends string = string,
37
+ ClassNames extends ReadonlyArray<string> = ReadonlyArray<string>,
38
+ >(componentName: Name, slotNames: ClassNames) {
39
+ const classes = slotClasses(componentName, slotNames)
40
+ const partselectors = partselectorsMap(classes)
41
+
42
+ const withState = (state: ComponentStyleProps) => {
43
+ const stateClas = Object.fromEntries(
44
+ Object.entries<string>(classes).map(([slot, className]) => {
45
+ const mapped = Object.entries(state).map(([key, value]) => {
46
+ if (typeof value === 'boolean' && value === true) return key
47
+ if (typeof value === 'string' && value.length > 0) return `${key}${capitalize(value)}`
48
+ if (typeof value === 'number' && value > 0) return `${key}${value}`
49
+ return ''
50
+ })
51
+
52
+ if (className) mapped.unshift(className)
53
+ return [slot, mapped.filter(Boolean).join(' ')]
54
+ }),
55
+ ) as {
56
+ [P in ClassNames[number]]: `${Name}-${P} ${string}`
57
+ }
58
+
59
+ return stateClas
60
+ }
61
+
62
+ return {
63
+ classes,
64
+ selectors: {
65
+ // ...stateSelectors,
66
+ ...partselectors,
67
+ },
68
+ withState,
69
+ }
70
+ }
package/Styles/index.tsx CHANGED
@@ -1,8 +1,15 @@
1
+ /**
2
+ * Consider moving to the `sx` prop with `selectors`
3
+ *
4
+ * @deprecated
5
+ */
1
6
  export type UseStyles<T extends (...args: never[]) => unknown> = {
2
- classes?: Partial<ReturnType<T>>
7
+ classes?: Partial<ReturnType<T>['classes']>
3
8
  }
4
9
 
5
10
  export * from './breakpointVal'
11
+ export * from './EmotionProvider'
12
+ export * from './extendableComponent'
6
13
  export * from './responsiveVal'
7
- export * from './classesPicker'
14
+ export * from './withEmotionCache'
8
15
  export * from './withTheme'
@@ -0,0 +1,36 @@
1
+ import { EmotionJSX } from '@emotion/react/types/jsx-namespace'
2
+ import createEmotionServer from '@emotion/server/create-instance'
3
+ // eslint-disable-next-line @next/next/no-document-import-in-page
4
+ import type NextDocument from 'next/document'
5
+ // eslint-disable-next-line @next/next/no-document-import-in-page
6
+ import type { DocumentContext, DocumentInitialProps } from 'next/document'
7
+ import { createMuiCache } from './EmotionProvider'
8
+
9
+ export type EmotionCacheProps = { emotionStyleTags: EmotionJSX.Element[] }
10
+
11
+ export function withEmotionCache(Document: typeof NextDocument): typeof NextDocument {
12
+ return class DocumentWithEmotionCache extends Document {
13
+ static async getInitialProps(ctx: DocumentContext) {
14
+ const emotionServer = createEmotionServer(createMuiCache())
15
+ const initialProps = await Document.getInitialProps(ctx)
16
+
17
+ const emotionStyleTags = emotionServer
18
+ .extractCriticalToChunks(initialProps.html)
19
+ .styles.filter(({ css }) => css !== '')
20
+ .map((style) => (
21
+ <style
22
+ data-emotion={`${style.key} ${style.ids.join(' ')}`}
23
+ key={style.key}
24
+ // eslint-disable-next-line react/no-danger
25
+ dangerouslySetInnerHTML={{ __html: style.css }}
26
+ />
27
+ ))
28
+
29
+ const props: DocumentInitialProps & EmotionCacheProps = {
30
+ ...initialProps,
31
+ emotionStyleTags,
32
+ }
33
+ return props
34
+ }
35
+ }
36
+ }
@@ -1,17 +1,4 @@
1
- import { makeStyles, Theme, ThemeProvider } from '@material-ui/core'
2
-
3
- const useStyles = makeStyles(
4
- {
5
- // These theme specific styles are copied from
6
- // https://github.com/mui-org/material-ui/blob/master/packages/mui-material/src/CssBaseline/CssBaseline.js#L18-L24
7
- root: (theme: Theme) => ({
8
- color: theme.palette.text.primary,
9
- ...theme.typography.body1,
10
- backgroundColor: theme.palette.background.default,
11
- }),
12
- },
13
- { name: 'Theme' },
14
- )
1
+ import { css, Theme, ThemeProvider } from '@mui/material'
15
2
 
16
3
  /**
17
4
  * It will provide a theme for the underlying tree and will set the color/font and backgroundColor
@@ -38,14 +25,18 @@ const useStyles = makeStyles(
38
25
  * export default withTheme(MyPage, darkTheme)
39
26
  * ```
40
27
  */
41
- export function withTheme<P extends { className?: string }>(Component: React.FC<P>, theme: Theme) {
42
- return (props: P) => {
43
- const classes = useStyles(theme)
44
-
45
- return (
46
- <ThemeProvider theme={theme}>
47
- <Component {...props} className={classes.root} />
48
- </ThemeProvider>
49
- )
50
- }
28
+ export function withTheme(Component: React.FC<{ className?: string }>, theme: Theme) {
29
+ return (props: Record<string, unknown>) => (
30
+ <ThemeProvider theme={theme}>
31
+ <Component
32
+ {...props}
33
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
34
+ css={css({
35
+ color: theme.palette.text.primary,
36
+ backgroundColor: theme.palette.background.default,
37
+ ...(theme.typography.body1 as any),
38
+ })}
39
+ />
40
+ </ThemeProvider>
41
+ )
51
42
  }
@@ -0,0 +1,60 @@
1
+ import { ImageProps, srcToString } from '@graphcommerce/image'
2
+ import { Box, SxProps, Theme } from '@mui/material'
3
+ import { ComponentProps, forwardRef } from 'react'
4
+ import { ExtendableComponent } from '../Styles/extendableComponent'
5
+ import { responsiveVal as rv } from '../Styles/responsiveVal'
6
+
7
+ const name = 'SvgIcon'
8
+ type StyleProps = {
9
+ size?: 'default' | 'inherit' | 'xxl' | 'xl' | 'large' | 'medium' | 'small' | 'xs'
10
+ fillIcon?: boolean
11
+ }
12
+
13
+ // Expose the component to be exendable in your theme.components
14
+ declare module '@mui/material/styles/components' {
15
+ interface Components {
16
+ SvgIcon?: ExtendableComponent<StyleProps>
17
+ }
18
+ }
19
+
20
+ export type SvgIconProps = StyleProps &
21
+ Pick<ImageProps, 'src'> &
22
+ Pick<ComponentProps<'svg'>, 'className'> & { sx?: SxProps<Theme> }
23
+
24
+ /** SvgIcon component is supposed to be used in combination with `icons` */
25
+ export const SvgIcon = forwardRef<SVGSVGElement, SvgIconProps>((props, ref) => {
26
+ const { className, src, size, fillIcon, sx = [], ...svgProps } = props
27
+
28
+ return (
29
+ <Box
30
+ component='svg'
31
+ ref={ref}
32
+ aria-hidden='true'
33
+ className={`${name} ${className ?? ''}`}
34
+ {...svgProps}
35
+ sx={[
36
+ {
37
+ userSelect: 'none',
38
+ width: '1.3em',
39
+ height: '1.3em',
40
+ strokeWidth: 1.8,
41
+ strokeLinecap: 'square',
42
+ strokeLinejoin: 'miter',
43
+ fill: 'none',
44
+ stroke: 'currentColor',
45
+ },
46
+ size === 'xs' && { width: rv(11, 13), height: rv(11, 13), strokeWidth: 2.1 },
47
+ size === 'small' && { width: rv(12, 16), height: rv(12, 16), strokeWidth: 2.1 },
48
+ size === 'medium' && { width: rv(22, 24), height: rv(22, 24), strokeWidth: 1.8 },
49
+ size === 'large' && { width: rv(24, 28), height: rv(24, 28), strokeWidth: 1.4 },
50
+ size === 'xl' && { width: rv(38, 62), height: rv(38, 62), strokeWidth: 1.1 },
51
+ size === 'xxl' && { width: rv(96, 148), height: rv(96, 148), strokeWidth: 0.8 },
52
+ fillIcon === true && { fill: 'currentColor', stroke: `none` },
53
+ ...(Array.isArray(sx) ? sx : [sx]),
54
+ ]}
55
+ >
56
+ <use href={`${srcToString(src)}#icon`} />
57
+ </Box>
58
+ )
59
+ })
60
+ SvgIcon.displayName = 'SvgIcon'
@@ -1,42 +1,19 @@
1
1
  import {
2
2
  IconButton,
3
3
  IconButtonProps,
4
- makeStyles,
5
4
  OutlinedTextFieldProps,
5
+ SxProps,
6
6
  TextField,
7
7
  TextFieldProps,
8
8
  useForkRef,
9
- } from '@material-ui/core'
10
- import clsx from 'clsx'
11
- import React, { ChangeEvent, Ref, useCallback, useEffect, useRef, useState } from 'react'
12
- import { UseStyles } from '../Styles'
9
+ Theme,
10
+ } from '@mui/material'
11
+ import { ChangeEvent, Ref, useCallback, useEffect, useRef, useState } from 'react'
12
+ import { extendableComponent } from '../Styles'
13
13
  import { responsiveVal } from '../Styles/responsiveVal'
14
- import SvgImageSimple from '../SvgImage/SvgImageSimple'
14
+ import { SvgIcon } from '../SvgIcon/SvgIcon'
15
15
  import { iconMin, iconPlus } from '../icons'
16
16
 
17
- const useStyles = makeStyles(
18
- {
19
- quantity: {
20
- width: responsiveVal(80, 120),
21
- backgroundColor: 'inherit',
22
- },
23
- quantityInput: {
24
- textAlign: 'center',
25
- '&::-webkit-inner-spin-button,&::-webkit-outer-spin-button': {
26
- appearance: 'none',
27
- },
28
- },
29
- button: {},
30
- adornedEnd: {
31
- paddingRight: responsiveVal(7, 14),
32
- },
33
- adornedStart: {
34
- paddingLeft: responsiveVal(7, 14),
35
- },
36
- },
37
- { name: 'TextInputNumber' },
38
- )
39
-
40
17
  export type IconButtonPropsOmit = Omit<
41
18
  IconButtonProps,
42
19
  'aria-label' | 'size' | 'onMouseDown' | 'onMouseUp' | 'disabled'
@@ -45,15 +22,30 @@ export type IconButtonPropsOmit = Omit<
45
22
  export type TextInputNumberProps = Omit<TextFieldProps, 'type'> & {
46
23
  DownProps?: IconButtonPropsOmit
47
24
  UpProps?: IconButtonPropsOmit
48
- } & UseStyles<typeof useStyles>
25
+ sx?: SxProps<Theme>
26
+ }
49
27
 
50
28
  function isOutlined(props: TextFieldProps): props is OutlinedTextFieldProps {
51
29
  return props.variant === 'outlined'
52
30
  }
53
31
 
54
- export default function TextInputNumber(props: TextInputNumberProps) {
55
- const { DownProps = {}, UpProps = {}, inputProps = {}, inputRef, ...textFieldProps } = props
56
- const classes = useStyles(props)
32
+ type OwnerState = { size?: 'small' | 'medium' }
33
+ const name = 'TextInputNumber' as const
34
+ const parts = ['quantity', 'quantityInput', 'button'] as const
35
+ const { withState } = extendableComponent<OwnerState, typeof name, typeof parts>(name, parts)
36
+
37
+ export function TextInputNumber(props: TextInputNumberProps) {
38
+ const {
39
+ DownProps = {},
40
+ UpProps = {},
41
+ inputProps = {},
42
+ inputRef,
43
+ sx = [],
44
+ ...textFieldProps
45
+ } = props
46
+
47
+ const classes = withState({})
48
+
57
49
  const ref = useRef<HTMLInputElement>(null)
58
50
  const forkRef = useForkRef<HTMLInputElement>(ref, inputRef as Ref<HTMLInputElement>)
59
51
 
@@ -98,21 +90,20 @@ export default function TextInputNumber(props: TextInputNumberProps) {
98
90
  setTimeout(() => ref.current && updateDisabled(ref.current))
99
91
  }, [ref, inputProps.min, inputProps.max])
100
92
 
101
- if (!textFieldProps.InputProps) textFieldProps.InputProps = {}
102
- if (isOutlined(textFieldProps)) {
103
- textFieldProps.InputProps.classes = {
104
- ...textFieldProps.InputProps?.classes,
105
- adornedEnd: classes.adornedEnd,
106
- adornedStart: classes.adornedStart,
107
- }
108
- }
109
-
110
93
  return (
111
94
  <TextField
112
95
  {...textFieldProps}
113
96
  type='number'
114
97
  inputRef={forkRef}
115
- className={clsx(textFieldProps.className, classes.quantity)}
98
+ className={`${textFieldProps.className ?? ''} ${classes.quantity}`}
99
+ sx={[
100
+ {
101
+ width: responsiveVal(80, 120),
102
+ backgroundColor: 'inherit',
103
+ },
104
+
105
+ ...(Array.isArray(sx) ? sx : [sx]),
106
+ ]}
116
107
  autoComplete='off'
117
108
  label={' '}
118
109
  id='quantity-input'
@@ -127,12 +118,12 @@ export default function TextInputNumber(props: TextInputNumberProps) {
127
118
  onPointerDown={() => setDirection('down')}
128
119
  onPointerUp={stop}
129
120
  // disabled={textFieldProps.disabled || disabled === 'min'}
130
- tabIndex='-1'
121
+ tabIndex={-1}
131
122
  color='inherit'
132
- className={clsx(classes.button, DownProps.className)}
133
123
  {...DownProps}
124
+ className={`${classes.button} ${DownProps.className ?? ''}`}
134
125
  >
135
- {DownProps.children ?? <SvgImageSimple src={iconMin} size='small' />}
126
+ {DownProps.children ?? <SvgIcon src={iconMin} size='small' />}
136
127
  </IconButton>
137
128
  ),
138
129
  endAdornment: (
@@ -143,12 +134,12 @@ export default function TextInputNumber(props: TextInputNumberProps) {
143
134
  onPointerDown={() => setDirection('up')}
144
135
  onPointerUp={() => setDirection(null)}
145
136
  // disabled={textFieldProps.disabled || disabled === 'max'}
146
- tabIndex='-1'
137
+ tabIndex={-1}
147
138
  color='inherit'
148
- className={clsx(classes.button, UpProps.className)}
149
139
  {...UpProps}
140
+ className={`${classes.button} ${UpProps.className ?? ''}`}
150
141
  >
151
- {UpProps.children ?? <SvgImageSimple src={iconPlus} size='small' />}
142
+ {UpProps.children ?? <SvgIcon src={iconPlus} size='small' />}
152
143
  </IconButton>
153
144
  ),
154
145
  }}
@@ -158,7 +149,15 @@ export default function TextInputNumber(props: TextInputNumberProps) {
158
149
  }}
159
150
  inputProps={{
160
151
  ...inputProps,
161
- className: clsx(inputProps?.className, classes.quantityInput),
152
+ sx: [
153
+ {
154
+ textAlign: 'center',
155
+ '&::-webkit-inner-spin-button,&::-webkit-outer-spin-button': {
156
+ appearance: 'none',
157
+ },
158
+ },
159
+ ],
160
+ className: `${inputProps?.className ?? ''} ${classes.quantityInput}`,
162
161
  }}
163
162
  />
164
163
  )
@@ -0,0 +1,128 @@
1
+ import { ComponentsVariants } from '@mui/material'
2
+ import { responsiveVal } from '../Styles/responsiveVal'
3
+
4
+ declare module '@mui/material/Button' {
5
+ interface ButtonPropsVariantOverrides {
6
+ pill: true
7
+ }
8
+ }
9
+
10
+ type ButtonVariants = NonNullable<ComponentsVariants['MuiButton']>
11
+
12
+ export const MuiButtonResponsive: ButtonVariants = [
13
+ {
14
+ props: {},
15
+ style: ({ theme }) => ({
16
+ textTransform: 'none',
17
+ fontWeight: 500,
18
+ }),
19
+ },
20
+ {
21
+ props: { size: 'small' },
22
+ style: ({ theme }) => ({
23
+ ...theme.typography.body2,
24
+ padding: `${responsiveVal(3, 5)} ${responsiveVal(9, 15)}`,
25
+ '& .MuiLoadingButton-loadingIndicatorEnd': { right: responsiveVal(9, 15) },
26
+ '& .MuiLoadingButton-loadingIndicatorStart': { left: responsiveVal(9, 15) },
27
+ }),
28
+ },
29
+ {
30
+ props: { size: 'medium' },
31
+ style: ({ theme }) => ({
32
+ ...theme.typography.body1,
33
+ padding: `${responsiveVal(8, 11)} ${responsiveVal(16, 24)}`,
34
+ '& .MuiLoadingButton-loadingIndicatorEnd': { right: responsiveVal(16, 24) },
35
+ '& .MuiLoadingButton-loadingIndicatorStart': { left: responsiveVal(16, 24) },
36
+ }),
37
+ },
38
+ {
39
+ props: { size: 'large' },
40
+ style: ({ theme }) => ({
41
+ ...theme.typography.subtitle1,
42
+ fontWeight: theme.typography.fontWeightBold,
43
+ padding: `${responsiveVal(10, 15)} ${responsiveVal(30, 60)}`,
44
+ '& .MuiLoadingButton-loadingIndicatorEnd': { right: responsiveVal(30, 60) },
45
+ '& .MuiLoadingButton-loadingIndicatorStart': { left: responsiveVal(30, 60) },
46
+ }),
47
+ },
48
+ {
49
+ props: { variant: 'text', size: 'small' },
50
+ style: {
51
+ padding: '3px 9px',
52
+ '& .MuiLoadingButton-loadingIndicatorEnd': { right: 3 },
53
+ '& .MuiLoadingButton-loadingIndicatorStart': { left: 9 },
54
+ },
55
+ },
56
+ {
57
+ props: { variant: 'text', size: 'medium' },
58
+ style: {
59
+ padding: `${responsiveVal(3, 5)} ${responsiveVal(9, 15)}`,
60
+ '& .MuiLoadingButton-loadingIndicatorEnd': { right: responsiveVal(9, 15) },
61
+ '& .MuiLoadingButton-loadingIndicatorStart': { left: responsiveVal(9, 15) },
62
+ },
63
+ },
64
+ {
65
+ props: { variant: 'text', size: 'large' },
66
+ style: {
67
+ padding: `${responsiveVal(8, 10)} ${responsiveVal(12, 22)}`,
68
+ '& .MuiLoadingButton-loadingIndicatorEnd': { right: responsiveVal(16, 24) },
69
+ '& .MuiLoadingButton-loadingIndicatorStart': { left: responsiveVal(16, 24) },
70
+ },
71
+ },
72
+ ]
73
+
74
+ export const MuiButtonPill: ButtonVariants = [
75
+ {
76
+ props: { variant: 'pill' },
77
+ style: { borderRadius: '99em' },
78
+ },
79
+ {
80
+ props: { variant: 'pill', size: 'small' },
81
+ style: ({ theme }) => ({
82
+ '&:not(.Mui-disabled)': { boxShadow: theme.shadows[2] },
83
+ }),
84
+ },
85
+ {
86
+ props: { variant: 'pill', size: 'medium' },
87
+ style: ({ theme }) => ({
88
+ '&:not(.Mui-disabled)': { boxShadow: theme.shadows[4] },
89
+ }),
90
+ },
91
+ {
92
+ props: { variant: 'pill', size: 'large' },
93
+ style: ({ theme }) => ({
94
+ '&:not(.Mui-disabled)': { boxShadow: theme.shadows[6] },
95
+ }),
96
+ },
97
+ {
98
+ props: { variant: 'pill', disableElevation: true },
99
+ style: { boxShadow: 'none' },
100
+ },
101
+ {
102
+ props: { variant: 'pill', color: 'primary' },
103
+ style: ({ theme }) => ({
104
+ backgroundColor: theme.palette.primary.main,
105
+ color: theme.palette.primary.contrastText,
106
+ '&:hover:not(.Mui-disabled)': { backgroundColor: theme.palette.primary.dark },
107
+ }),
108
+ },
109
+ {
110
+ props: { variant: 'pill', color: 'secondary' },
111
+ style: ({ theme }) => ({
112
+ backgroundColor: theme.palette.secondary.main,
113
+ color: theme.palette.secondary.contrastText,
114
+ '&:hover:not(.Mui-disabled)': { backgroundColor: theme.palette.secondary.dark },
115
+ }),
116
+ },
117
+ {
118
+ props: { variant: 'pill', color: 'inherit' },
119
+ style: ({ theme }) => ({ backgroundColor: theme.palette.background.paper }),
120
+ },
121
+ {
122
+ props: { variant: 'pill', disabled: true },
123
+ style: ({ theme }) => ({
124
+ backgroundColor: theme.palette.action.disabledBackground,
125
+ color: theme.palette.action.disabled,
126
+ }),
127
+ },
128
+ ]
@@ -0,0 +1,28 @@
1
+ import { Components, Theme } from '@mui/material'
2
+
3
+ /**
4
+ * Not yet possible to define a size="large" for the Slider due to a limitation in Material-UI
5
+ * https://github.com/mui-org/material-ui/issues/27130#issuecomment-1006425575
6
+ *
7
+ * If that has been fixed most of the styles can be removed here:
8
+ * packages/magento-product/components/ProductListFilters/FilterRangeType.tsx
9
+ */
10
+
11
+ // declare module '@mui/material/Slider' {
12
+ // interface SliderPropsSizeOverrides {
13
+ // large: true
14
+ // }
15
+ // }
16
+
17
+ export const MuiSlider = (theme: Theme): Components['MuiSlider'] => ({
18
+ // variants: [
19
+ // {
20
+ // props: { size: 'large' },
21
+ // style: {
22
+ // '& .MuiSlider-rail': { height: 4, borderRadius: '2px' },
23
+ // '& .MuiSlider-track': { height: 4 },
24
+ // '& .MuiSlider-thumb': { width: 28, height: 28 },
25
+ // },
26
+ // },
27
+ // ],
28
+ })
@@ -0,0 +1,31 @@
1
+ import { ComponentsVariants } from '@mui/material'
2
+
3
+ type SnackbarVariants = NonNullable<ComponentsVariants['MuiSnackbar']>
4
+
5
+ /**
6
+ * The current implementation of the MuiSnackbar will only be 50% wide if no width is specificed,
7
+ * this fixes that.
8
+ */
9
+ export const MuiSnackbar: SnackbarVariants = [
10
+ {
11
+ props: {},
12
+ style: ({ theme }) => ({
13
+ '&.MuiSnackbar-anchorOriginBottomCenter, &.MuiSnackbar-anchorOriginBottomLeft, &.MuiSnackbar-anchorOriginBottomRight':
14
+ {
15
+ [theme.breakpoints.down('md')]: {
16
+ bottom: 0,
17
+ left: 0,
18
+ right: 0,
19
+ },
20
+ [theme.breakpoints.up('md')]: {
21
+ bottom: theme.page.vertical,
22
+ },
23
+ },
24
+ '&.MuiSnackbar-anchorOriginBottomCenter': {
25
+ left: 0,
26
+ right: 0,
27
+ transform: 'unset',
28
+ },
29
+ }),
30
+ },
31
+ ]
@@ -1,12 +1,12 @@
1
1
  export {}
2
2
 
3
- declare module '@material-ui/core/styles/createPalette' {
3
+ declare module '@mui/material/styles/createPalette' {
4
4
  interface TypeBackground {
5
5
  image: string
6
6
  }
7
7
  }
8
8
 
9
- declare module '@material-ui/core/styles/createTheme' {
9
+ declare module '@mui/material/styles/createTheme' {
10
10
  interface ThemeOptions {
11
11
  spacings: {
12
12
  xxs: string
@@ -27,6 +27,9 @@ declare module '@material-ui/core/styles/createTheme' {
27
27
  appBarHeightMd: string
28
28
  appBarInnerHeightMd: string
29
29
  }
30
+
31
+ // todo: should be cleaned up to be compatible with the default mui-styles
32
+ shape: { borderRadius: number }
30
33
  }
31
34
  interface Theme {
32
35
  spacings: {
@@ -48,5 +51,8 @@ declare module '@material-ui/core/styles/createTheme' {
48
51
  appBarHeightMd: string
49
52
  appBarInnerHeightMd: string
50
53
  }
54
+
55
+ // todo: should be cleaned up to be compatible with the default mui-styles
56
+ shape: { borderRadius: number }
51
57
  }
52
58
  }
package/Theme/index.ts ADDED
@@ -0,0 +1,4 @@
1
+ export * from './MuiSlider'
2
+ export * from './MuiButton'
3
+ export * from './MuiSnackbar'
4
+ export * from './themeDefaults'