@graphcommerce/next-ui 3.25.3 → 4.1.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 (140) 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 +524 -645
  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 +26 -18
  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 +132 -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 -32
  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/DarkLightModeThemeProvider.tsx +119 -0
  100. package/Theme/MuiButton.ts +128 -0
  101. package/Theme/MuiSlider.ts +28 -0
  102. package/Theme/MuiSnackbar.ts +31 -0
  103. package/Theme/{types.ts → createTheme.ts} +8 -2
  104. package/Theme/index.ts +5 -0
  105. package/Theme/themeDefaults.ts +51 -0
  106. package/TimeAgo/index.tsx +1 -1
  107. package/ToggleButton/index.tsx +43 -49
  108. package/ToggleButtonGroup/index.tsx +39 -39
  109. package/UspList/UspListItem.tsx +56 -46
  110. package/UspList/index.tsx +29 -26
  111. package/docs/building-components.mdx +3 -0
  112. package/docs/components/ComponentBasic.tsx +26 -0
  113. package/docs/components/ComponentChild.tsx +48 -0
  114. package/docs/components/ComponentChildVariant.tsx +54 -0
  115. package/docs/components/ComponentChildVariantExtendable.tsx +62 -0
  116. package/docs/components/ComponentStylable.tsx +32 -0
  117. package/docs/pages/building-components.tsx +62 -0
  118. package/icons/index.tsx +2 -0
  119. package/index.ts +27 -81
  120. package/package.json +27 -27
  121. package/types.d.ts +1 -1
  122. package/AppShell/AppShellSticky/index.tsx +0 -38
  123. package/AppShell/DesktopNavActions.tsx +0 -32
  124. package/AppShell/DesktopNavBar.tsx +0 -158
  125. package/AppShell/Logo.tsx +0 -46
  126. package/AppShell/Menu.tsx +0 -7
  127. package/AppShell/MenuFab.tsx +0 -162
  128. package/AppShell/MenuFabSecondaryItem.tsx +0 -32
  129. package/AppShell/index.ts +0 -15
  130. package/AspectRatioContainer/index.tsx +0 -27
  131. package/Footer/SocialIcon.tsx +0 -23
  132. package/Form/index.tsx +0 -67
  133. package/FramerScroller/components/SidebarGallery.tsx +0 -317
  134. package/FramerScroller/components/SidebarSlider.tsx +0 -97
  135. package/Page/App.tsx +0 -17
  136. package/Page/Document.tsx +0 -24
  137. package/StyledBadge/index.tsx +0 -20
  138. package/Styles/classesPicker.ts +0 -41
  139. package/SvgImage/SvgImageSimple.tsx +0 -100
  140. package/SvgImage/index.tsx +0 -74
@@ -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,5 @@
1
+ export * from './MuiSlider'
2
+ export * from './MuiButton'
3
+ export * from './MuiSnackbar'
4
+ export * from './themeDefaults'
5
+ export * from './DarkLightModeThemeProvider'
@@ -0,0 +1,51 @@
1
+ import { BreakpointsOptions, experimental_sx, SxProps, Theme, ThemeOptions } from '@mui/material'
2
+ import { Shadows } from '@mui/material/styles/shadows'
3
+
4
+ import { SetRequired } from 'type-fest'
5
+
6
+ // https://material.io/design/environment/elevation.html#default-elevations
7
+
8
+ const breakpoints: SetRequired<BreakpointsOptions, 'values'> = {
9
+ values: {
10
+ xs: 0,
11
+ sm: 600,
12
+ md: 960,
13
+ lg: 1536,
14
+ xl: 1920,
15
+ },
16
+ }
17
+
18
+ const shadows: Shadows = [
19
+ /* 0 */ 'none',
20
+ /* 1 */ `0px 0px 1.5px hsl(0deg 0% 0% / 0.15),0px 0.5px 0.6px hsl(0deg 0% 0% / 0.06),0px 1.4px 1.8px -1.5px hsl(0deg 0% 0% / 0.09)`,
21
+ /* 2 */ `0px 0px 1.5px hsl(0deg 0% 0% / 0.15),0px 0.5px 0.6px hsl(0deg 0% 0% / 0.06),0px 2.6px 3.3px -1.5px hsl(0deg 0% 0% / 0.09)`,
22
+ /* 3 */ `0px 0px 1.5px hsl(0deg 0% 0% / 0.15),0px 0.5px 0.6px hsl(0deg 0% 0% / 0.06),0px 3.8px 4.8px -1.5px hsl(0deg 0% 0% / 0.09)`,
23
+ /* 4 */ `0px 0px 1.5px hsl(0deg 0% 0% / 0.15),0px 0.5px 0.6px hsl(0deg 0% 0% / 0.04),0px 1.7px 2.2px -0.7px hsl(0deg 0% 0% / 0.06),0px 5px 6.4px -1.5px hsl(0deg 0% 0% / 0.08)`,
24
+ /* 5 */ 'none',
25
+ /* 6 */ `0px 0px 1.5px hsl(0deg 0% 0% / 0.15),0px 0.5px 0.6px hsl(0deg 0% 0% / 0.04),0px 2.3px 2.9px -0.7px hsl(0deg 0% 0% / 0.06),0px 7.6px 9.7px -1.5px hsl(0deg 0% 0% / 0.08)`,
26
+ /* 7 */ 'none',
27
+ /* 8 */ `0px 0px 1.5px hsl(0deg 0% 0% / 0.15),0px 0.5px 0.6px hsl(0deg 0% 0% / 0.05),0px 2.9px 3.7px -0.7px hsl(0deg 0% 0% / 0.07),0px 10px 12.8px -1.5px hsl(0deg 0% 0% / 0.1)`,
28
+ /* 9 */ 'none',
29
+ /* 10 */ 'none',
30
+ /* 11 */ 'none',
31
+ /* 12 */ `0px 0px 1.5px hsl(0deg 0% 0% / 0.15),0px 0.5px 0.6px hsl(0deg 0% 0% / 0.06),0px 4.2px 5.4px -0.7px hsl(0deg 0% 0% / 0.09),0px 15px 19.1px -1.5px hsl(0deg 0% 0% / 0.11)`,
32
+ /* 13 */ 'none',
33
+ /* 14 */ 'none',
34
+ /* 15 */ 'none',
35
+ /* 16 */ `0px 0px 1.5px hsl(0deg 0% 0% / 0.15),0px 0.5px 0.6px hsl(0deg 0% 0% / 0.05),0px 3.5px 4.5px -0.5px hsl(0deg 0% 0% / 0.07),0px 8.6px 11px -1px hsl(0deg 0% 0% / 0.08),0px 20px 25.5px -1.5px hsl(0deg 0% 0% / 0.1)`,
36
+ /* 17 */ 'none',
37
+ /* 18 */ 'none',
38
+ /* 19 */ 'none',
39
+ /* 20 */ 'none',
40
+ /* 21 */ 'none',
41
+ /* 22 */ 'none',
42
+ /* 23 */ 'none',
43
+ /* 24 */ `0px 0px 1.5px hsl(0deg 0% 0% / 0.15),0px 0.5px 0.6px hsl(0deg 0% 0% / 0.05),0px 3.9px 5px -0.4px hsl(0deg 0% 0% / 0.07),0px 8.1px 10.3px -0.7px hsl(0deg 0% 0% / 0.08),0px 15.8px 20.1px -1.1px hsl(0deg 0% 0% / 0.1),0px 30px 38.3px -1.5px hsl(0deg 0% 0% / 0.11)`,
44
+ ]
45
+
46
+ export const themeBaseDefaults = {
47
+ breakpoints,
48
+ shadows,
49
+ }
50
+
51
+ export const sx = (props: SxProps<Theme>) => experimental_sx<Theme>(props)
package/TimeAgo/index.tsx CHANGED
@@ -3,7 +3,7 @@ export type TimeAgoProps = {
3
3
  locale?: string
4
4
  }
5
5
 
6
- export default function TimeAgo(props: TimeAgoProps) {
6
+ export function TimeAgo(props: TimeAgoProps) {
7
7
  const { date, locale = 'en' } = props
8
8
  const msPerMinute = 60 * 1000
9
9
  const msPerHour = msPerMinute * 60
@@ -1,47 +1,24 @@
1
- import { makeStyles, Theme } from '@material-ui/core'
2
- import clsx from 'clsx'
1
+ import { Button, ButtonProps } from '@mui/material'
3
2
  import React, { FormEvent } from 'react'
4
- import Button, { ButtonProps } from '../Button'
5
- import { UseStyles } from '../Styles'
3
+ import { extendableComponent } from '../Styles'
6
4
  import { responsiveVal } from '../Styles/responsiveVal'
7
5
 
8
- type StyleProps = { selected?: boolean; color?: ButtonProps['color'] }
9
-
10
- export const useStyles = makeStyles(
11
- (theme: Theme) => ({
12
- /* Styles applied to the root element. */
13
- root: {
14
- borderRadius: responsiveVal(theme.shape.borderRadius * 2, theme.shape.borderRadius * 3),
15
- border: `1px solid ${theme.palette.divider}`,
16
- '&$disabled': {
17
- borderWidth: 2,
18
- },
19
- '&:hover': {},
20
- '&$selected': {},
21
- },
22
- disabled: {},
23
- selected: ({ color = 'default' }: StyleProps) => ({
24
- border: `1px solid ${theme.palette[color]?.main ?? theme.palette.primary.main}`,
25
- boxShadow: `inset 0 0 0 1px ${theme.palette[color]?.main ?? theme.palette.primary.main}`,
26
- }),
27
- /* Styles applied to the `label` wrapper element. */
28
- label: {},
29
- sizeSmall: {},
30
- sizeLarge: {
31
- padding: `${theme.spacings.xxs} ${theme.spacings.xs}`,
32
- },
33
- }),
34
- { name: 'ToggleButton' },
35
- )
36
-
37
6
  export type ToggleButtonProps = Omit<ButtonProps, 'onClick' | 'onChange'> & {
38
7
  selected?: boolean
39
8
  onClick?: (e: FormEvent<HTMLButtonElement>, v: any) => void
40
9
  onChange?: (e: FormEvent<HTMLButtonElement>, v: any) => void
41
- } & UseStyles<typeof useStyles>
10
+ }
42
11
 
43
- const ToggleButton = React.forwardRef<any, ToggleButtonProps>((props, ref) => {
44
- const { root, selected: selectedClass, sizeLarge, sizeSmall, ...classes } = useStyles(props)
12
+ type OwnerState = Pick<ButtonProps, 'size' | 'disabled'> & { selected?: boolean }
13
+
14
+ const compName = 'ToggleButton' as const
15
+ const parts = ['root', 'button', 'helperText'] as const
16
+ const { withState } = extendableComponent<OwnerState, typeof compName, typeof parts>(
17
+ compName,
18
+ parts,
19
+ )
20
+
21
+ export const ToggleButton = React.forwardRef<any, ToggleButtonProps>((props, ref) => {
45
22
  const {
46
23
  children,
47
24
  className,
@@ -51,9 +28,11 @@ const ToggleButton = React.forwardRef<any, ToggleButtonProps>((props, ref) => {
51
28
  selected,
52
29
  size = 'medium',
53
30
  value,
54
- color,
31
+ color = 'default',
32
+ sx = [],
55
33
  ...other
56
34
  } = props
35
+ const classes = withState({ size, selected, disabled })
57
36
 
58
37
  const handleChange = (event: FormEvent<HTMLButtonElement>) => onChange?.(event, value)
59
38
 
@@ -67,16 +46,7 @@ const ToggleButton = React.forwardRef<any, ToggleButtonProps>((props, ref) => {
67
46
 
68
47
  return (
69
48
  <Button
70
- className={clsx(
71
- root,
72
- {
73
- [classes.disabled]: disabled,
74
- [selectedClass]: selected,
75
- [sizeLarge]: size === 'large',
76
- [sizeSmall]: size === 'small',
77
- },
78
- className,
79
- )}
49
+ className={`${classes.root} ${className ?? ''}`}
80
50
  variant='outlined'
81
51
  disabled={disabled}
82
52
  ref={ref}
@@ -87,10 +57,34 @@ const ToggleButton = React.forwardRef<any, ToggleButtonProps>((props, ref) => {
87
57
  size={size}
88
58
  {...other}
89
59
  classes={classes}
60
+ sx={[
61
+ (theme) => ({
62
+ borderRadius: responsiveVal(theme.shape.borderRadius * 2, theme.shape.borderRadius * 3),
63
+ border: 1,
64
+ borderColor: 'divider',
65
+ bgcolor: 'background.paper',
66
+
67
+ '&.disabled': {
68
+ borderWidth: 2,
69
+ },
70
+
71
+ '&.selected': {
72
+ border: `1px solid ${theme.palette[color]?.main ?? theme.palette.primary.main}`,
73
+ boxShadow: `inset 0 0 0 1px ${
74
+ theme.palette[color]?.main ?? theme.palette.primary.main
75
+ }`,
76
+ },
77
+ ':not(&.sizeSmall)': {
78
+ padding: `${theme.spacings.xxs} ${theme.spacings.xs}`,
79
+ },
80
+ '&.sizeSmall': {
81
+ aspectRatio: `4/3`,
82
+ },
83
+ }),
84
+ ...(Array.isArray(sx) ? sx : [sx]),
85
+ ]}
90
86
  >
91
87
  {children}
92
88
  </Button>
93
89
  )
94
90
  })
95
-
96
- export default ToggleButton
@@ -1,10 +1,7 @@
1
- import { makeStyles, Theme } from '@material-ui/core'
2
- import { capitalize } from '@material-ui/core/utils'
3
- import { ToggleButtonGroupProps } from '@material-ui/lab'
4
- import clsx from 'clsx'
5
- import React, { PropsWithoutRef } from 'react'
1
+ import { Box, ToggleButtonGroupProps as ToggleButtonGroupPropsBase } from '@mui/material'
2
+ import React from 'react'
6
3
  import { isFragment } from 'react-is'
7
- import { UseStyles } from '../Styles'
4
+ import { extendableComponent } from '../Styles'
8
5
 
9
6
  function isValueSelected(value: string, candidate: string | string[]) {
10
7
  if (candidate === undefined || value === undefined) return false
@@ -12,32 +9,15 @@ function isValueSelected(value: string, candidate: string | string[]) {
12
9
  return value === candidate
13
10
  }
14
11
 
15
- export type ToggleButtonPropsBase = Omit<PropsWithoutRef<ToggleButtonGroupProps>, 'size'> & {
16
- required?: boolean
17
- minWidth?: number
18
- }
12
+ type OwnerState = Pick<ToggleButtonGroupPropsBase, 'orientation' | 'size'>
19
13
 
20
- export const useStyles = makeStyles(
21
- (theme: Theme) => ({
22
- root: ({ minWidth = 200 }: ToggleButtonPropsBase) => ({
23
- display: 'grid',
24
- gridTemplateColumns: `repeat(auto-fit, minmax(${minWidth}px, 1fr))`,
25
- gap: `calc(${theme.spacings.xxs} * 2)`,
26
- }),
27
- vertical: {
28
- gridAutoFlow: 'column',
29
- },
30
- grouped: {},
31
- groupedHorizontal: {},
32
- groupedVertical: {},
33
- }),
34
- { name: 'ToggleButtonGroup' },
35
- )
14
+ const name = 'ToggleButtonGroup' as const
15
+ const parts = ['root', 'button'] as const
16
+ const { withState } = extendableComponent<OwnerState, typeof name, typeof parts>(name, parts)
36
17
 
37
- export type ToggleButtonProps = ToggleButtonPropsBase & UseStyles<typeof useStyles>
18
+ export type ToggleButtonGroupProps = ToggleButtonGroupPropsBase & { required?: boolean }
38
19
 
39
- const ToggleButtonGroup = React.forwardRef<HTMLDivElement, ToggleButtonProps>((props, ref) => {
40
- const classes = useStyles(props)
20
+ const ToggleButtonGroup = React.forwardRef<HTMLDivElement, ToggleButtonGroupProps>((props, ref) => {
41
21
  const {
42
22
  children,
43
23
  className,
@@ -45,11 +25,15 @@ const ToggleButtonGroup = React.forwardRef<HTMLDivElement, ToggleButtonProps>((p
45
25
  required = false,
46
26
  onChange,
47
27
  orientation = 'horizontal',
48
- minWidth,
49
28
  value,
29
+ size = 'large',
30
+ sx = [],
50
31
  ...other
51
32
  } = props
52
33
 
34
+ const classes = withState({ orientation, size })
35
+
36
+ /* eslint-disable @typescript-eslint/no-unsafe-argument */
53
37
  const handleChange = (event, buttonValue) => {
54
38
  if (!onChange) return
55
39
 
@@ -72,9 +56,29 @@ const ToggleButtonGroup = React.forwardRef<HTMLDivElement, ToggleButtonProps>((p
72
56
  }
73
57
 
74
58
  return (
75
- <div
59
+ <Box
76
60
  role='group'
77
- className={clsx(classes.root, { [classes.vertical]: orientation === 'vertical' }, className)}
61
+ className={`${classes.root} ${className ?? ''}`}
62
+ sx={[
63
+ (theme) => ({
64
+ display: 'grid',
65
+ rowGap: theme.spacings.xxs,
66
+ columnGap: theme.spacings.xs,
67
+ '&.orientationVertical': {
68
+ gridAutoFlow: 'column',
69
+ },
70
+ '&.sizeSmall.orientationHorizontal': {
71
+ gridTemplateColumns: `repeat(auto-fill, minmax(60px, 1fr))`,
72
+ },
73
+ '&.sizeMedium.orientationHorizontal': {
74
+ gridTemplateColumns: 'repeat(2, 1fr)',
75
+ },
76
+ '&.sizeLarge.orientationHorizontal': {
77
+ gridTemplateColumns: 'repeat(2, 1fr)',
78
+ },
79
+ }),
80
+ ...(Array.isArray(sx) ? sx : [sx]),
81
+ ]}
78
82
  ref={ref}
79
83
  {...other}
80
84
  >
@@ -93,11 +97,7 @@ const ToggleButtonGroup = React.forwardRef<HTMLDivElement, ToggleButtonProps>((p
93
97
  }
94
98
 
95
99
  return React.cloneElement(child, {
96
- className: clsx(
97
- classes.grouped,
98
- classes[`grouped${capitalize(orientation)}`],
99
- child.props.className,
100
- ),
100
+ className: `${classes.button} ${child.props.className ?? ''}`,
101
101
  onChange: exclusive ? handleExclusiveChange : handleChange,
102
102
  selected:
103
103
  child.props.selected === undefined
@@ -105,8 +105,8 @@ const ToggleButtonGroup = React.forwardRef<HTMLDivElement, ToggleButtonProps>((p
105
105
  : child.props.selected,
106
106
  })
107
107
  })}
108
- </div>
108
+ </Box>
109
109
  )
110
110
  })
111
111
 
112
- export default ToggleButtonGroup
112
+ export { ToggleButtonGroup }
@@ -1,55 +1,65 @@
1
- import { makeStyles, Theme } from '@material-ui/core'
2
- import clsx from 'clsx'
3
- import React from 'react'
4
- import { UseStyles } from '../Styles'
1
+ import { Box, SxProps, Theme } from '@mui/material'
2
+ import { extendableComponent } from '../Styles'
5
3
  import { responsiveVal } from '../Styles/responsiveVal'
6
4
 
7
- const useStyles = makeStyles(
8
- (theme: Theme) => ({
9
- root: {
10
- display: 'grid',
11
- gridAutoFlow: 'column',
12
- alignItems: 'center',
13
- gridTemplateColumns: `${responsiveVal(32, 38)} auto`,
14
- gap: theme.spacings.xs,
15
- '& > p': {
16
- ...theme.typography.body2,
17
- },
18
- },
19
- icon: {
20
- display: 'flex',
21
-
22
- '& > * > img': {
23
- display: 'block',
24
- },
25
- },
26
- smallCopy: {
27
- '& > p': {
28
- ...theme.typography.body2,
29
- },
30
- },
31
- smallIcons: {
32
- gridTemplateColumns: `${responsiveVal(10, 14)} auto`,
33
- gap: theme.spacings.xxs,
34
- },
35
- }),
36
- { name: 'UspListItem' },
37
- )
38
-
39
- export type UspListItemProps = UseStyles<typeof useStyles> & {
5
+ export type UspListItemProps = {
40
6
  text: React.ReactNode
41
7
  icon?: React.ReactNode
42
- size?: string
43
- }
8
+ sx?: SxProps<Theme>
9
+ } & OwnerState
10
+
11
+ type OwnerState = { size?: 'small' | 'medium' }
12
+ const name = 'UspListItem' as const
13
+ const parts = ['root', 'icon', 'text'] as const
14
+ const { withState } = extendableComponent<OwnerState, typeof name, typeof parts>(name, parts)
44
15
 
45
- export default function UspListItem(props: UspListItemProps) {
46
- const { text, icon, size = 'normal' } = props
47
- const classes = useStyles()
16
+ export function UspListItem(props: UspListItemProps) {
17
+ const { text, icon, size = 'medium', sx = [] } = props
18
+ const classes = withState({ size })
48
19
 
49
20
  return (
50
- <li className={clsx(classes.root, size === 'small' && classes.smallIcons)}>
51
- <div className={classes.icon}>{icon}</div>
52
- <div className={clsx(size === 'small' && classes.smallCopy)}>{text}</div>
53
- </li>
21
+ <Box
22
+ component='li'
23
+ className={classes.root}
24
+ sx={[
25
+ (theme) => ({
26
+ display: 'grid',
27
+ gridAutoFlow: 'column',
28
+ alignItems: 'center',
29
+ gridTemplateColumns: `${responsiveVal(32, 38)} auto`,
30
+ gap: theme.spacings.xs,
31
+ '& > p': {
32
+ typography: 'body2',
33
+ },
34
+ '&.sizeSmall': {
35
+ gridTemplateColumns: `${responsiveVal(10, 14)} auto`,
36
+ gap: theme.spacings.xxs,
37
+ },
38
+ }),
39
+ ...(Array.isArray(sx) ? sx : [sx]),
40
+ ]}
41
+ >
42
+ <Box
43
+ className={classes.icon}
44
+ sx={{
45
+ display: 'flex',
46
+ '& > * > img': {
47
+ display: 'block',
48
+ },
49
+ }}
50
+ >
51
+ {icon}
52
+ </Box>
53
+ <Box
54
+ className={classes.text}
55
+ sx={{
56
+ '&.sizeSmall > p': {
57
+ typography: 'body2',
58
+ },
59
+ }}
60
+ >
61
+ {text}
62
+ </Box>
63
+ </Box>
54
64
  )
55
65
  }
package/UspList/index.tsx CHANGED
@@ -1,33 +1,36 @@
1
- import { makeStyles, Theme } from '@material-ui/core'
2
- import clsx from 'clsx'
3
- import React from 'react'
4
- import { UseStyles } from '../Styles'
1
+ import { Box } from '@mui/material'
2
+ import { extendableComponent } from '../Styles'
5
3
 
6
- const useStyles = makeStyles(
7
- (theme: Theme) => ({
8
- root: {
9
- listStyleType: 'none',
10
- padding: 0,
11
- margin: 0,
12
- display: 'grid',
13
- alignContent: 'start',
14
- rowGap: theme.spacings.xs,
15
- },
16
- small: {
17
- rowGap: 3,
18
- },
19
- }),
20
- { name: 'UspList' },
21
- )
22
-
23
- export type UspListProps = UseStyles<typeof useStyles> & {
4
+ export type UspListProps = OwnerState & {
24
5
  children: React.ReactNode
25
- size?: 'normal' | 'small'
26
6
  }
27
7
 
28
- export default function UspList(props: UspListProps) {
8
+ type OwnerState = { size?: 'small' | 'medium' }
9
+ const name = 'UspList' as const
10
+ const parts = ['root'] as const
11
+ const { withState } = extendableComponent<OwnerState, typeof name, typeof parts>(name, parts)
12
+
13
+ export function UspList(props: UspListProps) {
29
14
  const { children, size } = props
30
- const classes = useStyles()
15
+ const classes = withState({ size })
31
16
 
32
- return <ul className={clsx(classes.root, size === 'small' && classes.small)}>{children}</ul>
17
+ return (
18
+ <Box
19
+ component='ul'
20
+ className={classes.root}
21
+ sx={(theme) => ({
22
+ listStyleType: 'none',
23
+ padding: 0,
24
+ margin: 0,
25
+ display: 'grid',
26
+ alignContent: 'start',
27
+ rowGap: theme.spacings.xs,
28
+ '&.sizeSmall': {
29
+ rowGap: '3px',
30
+ },
31
+ })}
32
+ >
33
+ {children}
34
+ </Box>
35
+ )
33
36
  }
@@ -0,0 +1,3 @@
1
+ # Building components
2
+
3
+ If you are looking to style components, please take a look at.
@@ -0,0 +1,26 @@
1
+ import { styled } from '@mui/material'
2
+ import React from 'react'
3
+
4
+ // ---- Root component ----
5
+
6
+ // We're creating a new styled('div') component and apply our styles to it.
7
+ const Root = styled('div')(({ theme }) => ({
8
+ padding: '3px',
9
+ display: 'flex',
10
+ color: theme.palette.text.primary,
11
+ }))
12
+
13
+ // ---- MyComponent component ----
14
+
15
+ // Props of the component we are writing
16
+ export type MyComponentProps = { children: React.ReactNode }
17
+
18
+ export function MyComponent(props: MyComponentProps) {
19
+ const { children } = props
20
+ return (
21
+ <Root as='span'>
22
+ My Component
23
+ {children}
24
+ </Root>
25
+ )
26
+ }
@@ -0,0 +1,48 @@
1
+ import { extendableComponent } from '@graphcommerce/next-ui'
2
+ import { styled } from '@mui/material'
3
+ import { ComponentProps } from 'react'
4
+
5
+ // ---- Setup ----
6
+
7
+ // To be able to select children from the consuming side, we define the classes.
8
+ // Minimal utility to convert the classes to selectors. Hover over `selectors` to see what it means.
9
+ const componentName = 'MyComponent' as const
10
+ const { classes, selectors } = extendableComponent(componentName, ['root', 'child'] as const)
11
+
12
+ // ---- Root component ----
13
+
14
+ // We're creating a new styled('div') component and apply our styles to it.
15
+ const Root = styled('div', {
16
+ name: componentName,
17
+ target: classes.root,
18
+ })(({ theme }) => ({
19
+ display: 'flex',
20
+ color: theme.palette.text.primary,
21
+ }))
22
+
23
+ // ---- Child component ----
24
+
25
+ const Child = styled('div', {
26
+ name: componentName,
27
+ target: classes.child,
28
+ })(({ theme }) => ({
29
+ backgroundColor: theme.palette.primary.main,
30
+ width: 100,
31
+ height: 100,
32
+ }))
33
+
34
+ // ---- MyComponent component ----
35
+
36
+ // Props of the component we are writing
37
+ export type MyComponentProps = Pick<ComponentProps<typeof Root>, 'sx' | 'children'>
38
+
39
+ export function MyComponent(props: MyComponentProps) {
40
+ const { sx, children } = props
41
+ return (
42
+ <Root as='span' sx={sx}>
43
+ My Component
44
+ <Child>{children}</Child>
45
+ </Root>
46
+ )
47
+ }
48
+ MyComponent.selectors = selectors