@graphcommerce/next-ui 7.0.0-canary.21 → 7.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.
package/Footer/Footer.tsx CHANGED
@@ -65,63 +65,71 @@ export function Footer(props: FooterProps) {
65
65
  className={classes.root}
66
66
  {...containerProps}
67
67
  >
68
- <Box
69
- sx={(theme) => ({
70
- display: 'grid',
71
- justifyContent: 'start',
72
- gridAutoFlow: 'column',
73
- gridArea: 'social',
74
- gap: { xs: `0 ${theme.spacings.xs}`, md: `0 ${theme.spacings.xs}` },
75
- '& > *': {
76
- minWidth: 'min-content',
77
- },
78
- })}
79
- className={classes.social}
80
- >
81
- {socialLinks}
82
- </Box>
83
- <Box
84
- sx={(theme) => ({
85
- gridArea: 'switcher',
86
- justifySelf: 'end',
87
- [theme.breakpoints.down('md')]: {
88
- justifySelf: 'center',
89
- },
90
- })}
91
- className={classes.storeSwitcher}
92
- >
93
- {storeSwitcher}
94
- </Box>
95
- <Box
96
- sx={(theme) => ({
97
- gridArea: 'support',
98
- justifySelf: 'flex-end',
99
- [theme.breakpoints.down('md')]: {
100
- justifySelf: 'center',
101
- },
102
- })}
103
- className={classes.support}
104
- >
105
- {customerService}
106
- </Box>
107
- <Box
108
- sx={(theme) => ({
109
- typography: 'body2',
110
- display: 'grid',
111
- gridAutoFlow: 'column',
112
- alignContent: 'center',
113
- gridArea: 'links',
114
- gap: theme.spacings.sm,
115
- [theme.breakpoints.down('md')]: {
116
- gridAutoFlow: 'row',
117
- textAlign: 'center',
118
- gap: `8px`,
119
- },
120
- })}
121
- className={classes.copyright}
122
- >
123
- {copyright}
124
- </Box>
68
+ {socialLinks && (
69
+ <Box
70
+ sx={(theme) => ({
71
+ display: 'grid',
72
+ justifyContent: 'start',
73
+ gridAutoFlow: 'column',
74
+ gridArea: 'social',
75
+ gap: { xs: `0 ${theme.spacings.xs}`, md: `0 ${theme.spacings.xs}` },
76
+ '& > *': {
77
+ minWidth: 'min-content',
78
+ },
79
+ })}
80
+ className={classes.social}
81
+ >
82
+ {socialLinks}
83
+ </Box>
84
+ )}
85
+ {storeSwitcher && (
86
+ <Box
87
+ sx={(theme) => ({
88
+ gridArea: 'switcher',
89
+ justifySelf: 'end',
90
+ [theme.breakpoints.down('md')]: {
91
+ justifySelf: 'center',
92
+ },
93
+ })}
94
+ className={classes.storeSwitcher}
95
+ >
96
+ {storeSwitcher}
97
+ </Box>
98
+ )}
99
+ {customerService && (
100
+ <Box
101
+ sx={(theme) => ({
102
+ gridArea: 'support',
103
+ justifySelf: 'flex-end',
104
+ [theme.breakpoints.down('md')]: {
105
+ justifySelf: 'center',
106
+ },
107
+ })}
108
+ className={classes.support}
109
+ >
110
+ {customerService}
111
+ </Box>
112
+ )}
113
+ {copyright && (
114
+ <Box
115
+ sx={(theme) => ({
116
+ typography: 'body2',
117
+ display: 'grid',
118
+ gridAutoFlow: 'column',
119
+ alignContent: 'center',
120
+ gridArea: 'links',
121
+ gap: theme.spacings.sm,
122
+ [theme.breakpoints.down('md')]: {
123
+ gridAutoFlow: 'row',
124
+ textAlign: 'center',
125
+ gap: `8px`,
126
+ },
127
+ })}
128
+ className={classes.copyright}
129
+ >
130
+ {copyright}
131
+ </Box>
132
+ )}
125
133
  </Container>
126
134
  )
127
135
  }
@@ -48,6 +48,7 @@ export type SidebarGalleryProps = {
48
48
  aspectRatio?: [number, number]
49
49
  routeHash?: string
50
50
  sx?: SxProps<Theme>
51
+ disableZoom?: boolean
51
52
  }
52
53
 
53
54
  export function SidebarGallery(props: SidebarGalleryProps) {
@@ -57,6 +58,7 @@ export function SidebarGallery(props: SidebarGalleryProps) {
57
58
  aspectRatio: [width, height] = [1, 1],
58
59
  sx,
59
60
  routeHash = 'gallery',
61
+ disableZoom,
60
62
  } = props
61
63
 
62
64
  const router = useRouter()
@@ -76,6 +78,9 @@ export function SidebarGallery(props: SidebarGalleryProps) {
76
78
  }, [prevRoute?.pathname, route, router, zoomed])
77
79
 
78
80
  const toggle = () => {
81
+ if (disableZoom) {
82
+ return
83
+ }
79
84
  if (!zoomed) {
80
85
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
81
86
  router.push(route, undefined, { shallow: true })
@@ -192,7 +197,7 @@ export function SidebarGallery(props: SidebarGalleryProps) {
192
197
  height: '100%',
193
198
  gridAutoColumns: `100%`,
194
199
  gridTemplateRows: `100%`,
195
- cursor: 'zoom-in',
200
+ cursor: disableZoom ? 'auto' : 'zoom-in',
196
201
  },
197
202
  zoomed && {
198
203
  height: `var(--client-size-y)`,
@@ -232,16 +237,22 @@ export function SidebarGallery(props: SidebarGalleryProps) {
232
237
  right: theme.spacings.sm,
233
238
  }}
234
239
  >
235
- <Fab
236
- size='small'
237
- className={classes.toggleIcon}
238
- disabled={!hasImages}
239
- onMouseUp={toggle}
240
- aria-label='Toggle Fullscreen'
241
- sx={{ boxShadow: 6 }}
242
- >
243
- {!zoomed ? <IconSvg src={iconFullscreen} /> : <IconSvg src={iconFullscreenExit} />}
244
- </Fab>
240
+ {!disableZoom && (
241
+ <Fab
242
+ size='small'
243
+ className={classes.toggleIcon}
244
+ disabled={!hasImages}
245
+ onMouseUp={toggle}
246
+ aria-label='Toggle Fullscreen'
247
+ sx={{ boxShadow: 6 }}
248
+ >
249
+ {!zoomed ? (
250
+ <IconSvg src={iconFullscreen} />
251
+ ) : (
252
+ <IconSvg src={iconFullscreenExit} />
253
+ )}
254
+ </Fab>
255
+ )}
245
256
  </MotionBox>
246
257
  <Box
247
258
  className={classes.centerLeft}
@@ -53,37 +53,35 @@ export function useIconSvgSize(size: keyof typeof sizes) {
53
53
  return sizes[size]
54
54
  }
55
55
 
56
- const Svg = styled('svg', { name, target: name })(() => [
57
- {
58
- userSelect: 'none',
59
- width: '1em',
60
- height: '1em',
61
- display: 'inline-block',
62
-
63
- strokeLinecap: 'square',
64
- strokeLinejoin: 'miter',
65
- strokeMiterlimit: 4,
66
-
67
- fill: 'none',
68
- stroke: 'currentColor',
69
-
70
- fontSize: '1.3em',
71
-
72
- strokeWidth: svgIconStrokeWidth(28, 148, 1.4, 0.8),
73
-
74
- '&.sizeXs': { fontSize: sizes.xs },
75
- '&.sizeSmall': { fontSize: sizes.small },
76
- '&.sizeMedium': { fontSize: sizes.medium },
77
- '&.sizeLarge': { fontSize: sizes.large },
78
- '&.sizeXl': { fontSize: sizes.xl },
79
- '&.sizeXxl': { fontSize: sizes.xxl },
80
-
81
- '&.fillIcon': {
82
- fill: 'currentColor',
83
- stroke: 'none',
84
- },
56
+ const Svg = styled('svg', { name, target: name })(() => ({
57
+ userSelect: 'none',
58
+ width: '1em',
59
+ height: '1em',
60
+ display: 'inline-block',
61
+
62
+ strokeLinecap: 'square',
63
+ strokeLinejoin: 'miter',
64
+ strokeMiterlimit: 4,
65
+
66
+ fill: 'none',
67
+ stroke: 'currentColor',
68
+
69
+ fontSize: '1.3em',
70
+
71
+ strokeWidth: svgIconStrokeWidth(28, 148, 1.4, 0.8),
72
+
73
+ '&.sizeXs': { fontSize: sizes.xs },
74
+ '&.sizeSmall': { fontSize: sizes.small },
75
+ '&.sizeMedium': { fontSize: sizes.medium },
76
+ '&.sizeLarge': { fontSize: sizes.large },
77
+ '&.sizeXl': { fontSize: sizes.xl },
78
+ '&.sizeXxl': { fontSize: sizes.xxl },
79
+
80
+ '&.fillIcon': {
81
+ fill: 'currentColor',
82
+ stroke: 'none',
85
83
  },
86
- ])
84
+ }))
87
85
 
88
86
  /**
89
87
  * IconSvg component is supposed to be used in combination with `icons`
@@ -26,6 +26,8 @@ export type LayoutHeaderProps = FloatingProps &
26
26
  noAlign?: boolean
27
27
 
28
28
  sx?: SxProps<Theme>
29
+
30
+ hideBackButton?: boolean
29
31
  }
30
32
 
31
33
  type ComponentStyleProps = {
@@ -46,6 +48,7 @@ export function LayoutHeader(props: LayoutHeaderProps) {
46
48
  const {
47
49
  children,
48
50
  divider,
51
+ hideBackButton = false,
49
52
  primary,
50
53
  secondary,
51
54
  noAlign = false,
@@ -54,7 +57,7 @@ export function LayoutHeader(props: LayoutHeaderProps) {
54
57
  sx = [],
55
58
  bgColor,
56
59
  } = props
57
- const showBack = useShowBack()
60
+ const showBack = useShowBack() && !hideBackButton
58
61
  const showClose = useShowClose()
59
62
 
60
63
  const floatFallback = !children
@@ -1,11 +1,12 @@
1
1
  import { LayoutHeaderProps, LayoutHeader } from '../../Layout'
2
2
 
3
3
  export function LayoutOverlayHeader(props: LayoutHeaderProps) {
4
- const { sx } = props
4
+ const { sx, switchPoint } = props
5
5
  return (
6
6
  <LayoutHeader
7
7
  {...props}
8
8
  noAlign
9
+ switchPoint={switchPoint !== 0 ? switchPoint : -1000}
9
10
  sx={[
10
11
  (theme) => ({
11
12
  [theme.breakpoints.down('md')]: {
@@ -1,25 +1,34 @@
1
- import { Container } from '@mui/material'
1
+ import { Container, SxProps, Theme } from '@mui/material'
2
2
  import React from 'react'
3
+ import { extendableComponent } from '../Styles'
3
4
 
4
5
  export type StickyBelowHeaderProps = {
5
6
  children: React.ReactNode
7
+ sx?: SxProps<Theme>
6
8
  }
7
9
 
10
+ const { classes } = extendableComponent('StickyBelowHeader', ['root'])
11
+
8
12
  /** - Makes the children sticky to the parent container */
9
13
  export function StickyBelowHeader(props: StickyBelowHeaderProps) {
14
+ const { sx = [] } = props
10
15
  return (
11
16
  <Container
12
- sx={(theme) => ({
13
- position: 'sticky',
14
- top: { xs: theme.appShell.headerHeightSm, md: `${theme.page.vertical} !important` },
15
- zIndex: 96,
16
- pointerEvents: 'none',
17
- '& > *': {
18
- pointerEvents: 'auto',
19
- },
20
- })}
17
+ className={classes.root}
21
18
  maxWidth={false}
22
19
  {...props}
20
+ sx={[
21
+ (theme) => ({
22
+ position: 'sticky',
23
+ top: { xs: theme.appShell.headerHeightSm, md: `${theme.page.vertical} !important` },
24
+ zIndex: 96,
25
+ pointerEvents: 'none',
26
+ '& > *': {
27
+ pointerEvents: 'auto',
28
+ },
29
+ }),
30
+ ...(Array.isArray(sx) ? sx : [sx]),
31
+ ]}
23
32
  />
24
33
  )
25
34
  }
@@ -95,6 +95,7 @@ export function useNavigation() {
95
95
  * }
96
96
  * ```
97
97
  */
98
+
98
99
  export function useNavigationSelection(): UseNavigationSelection {
99
100
  return useMotionValue<NavigationPath | false>(false)
100
101
  }
@@ -13,9 +13,9 @@ import {
13
13
  motionValue,
14
14
  useDomEvent,
15
15
  useMotionValue,
16
+ useMotionValueEvent,
16
17
  useTransform,
17
18
  } from 'framer-motion'
18
- import framesync from 'framesync'
19
19
  import React, { useCallback, useEffect, useRef } from 'react'
20
20
  import { LayoutProvider } from '../../Layout/components/LayoutProvider'
21
21
  import { ExtendableComponent, extendableComponent } from '../../Styles'
@@ -196,7 +196,7 @@ export function OverlayBase(incomingProps: LayoutOverlayBaseProps) {
196
196
  scroller.scrollLeft = scroll.x.getPrevious()
197
197
  scroller.scrollTop = scroll.y.getPrevious()
198
198
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
199
- scrollTo(openClosePositions().open)
199
+ scrollTo(openClosePositions().open, { stopAnimationOnScroll: false })
200
200
  }
201
201
  }
202
202
 
@@ -281,7 +281,9 @@ export function OverlayBase(incomingProps: LayoutOverlayBaseProps) {
281
281
 
282
282
  if (position.get() !== OverlayPosition.OPENED && !scroll.animating.get()) {
283
283
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
284
- scrollTo(openClosePositions().open).then(() => position.set(OverlayPosition.OPENED))
284
+ scrollTo(openClosePositions().open, { stopAnimationOnScroll: false }).then(() =>
285
+ position.set(OverlayPosition.OPENED),
286
+ )
285
287
  }
286
288
  }, [isPresent, openClosePositions, position, scroll.animating, scrollTo, scrollerRef, variant])
287
289
 
@@ -291,7 +293,7 @@ export function OverlayBase(incomingProps: LayoutOverlayBaseProps) {
291
293
  if (isPresent || !scroller) return
292
294
 
293
295
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
294
- scrollTo(openClosePositions().closed).then(() => {
296
+ scrollTo(openClosePositions().closed, { stopAnimationOnScroll: false }).then(() => {
295
297
  safeToRemove?.()
296
298
  document.body.style.overflow = ''
297
299
  })
@@ -311,10 +313,28 @@ export function OverlayBase(incomingProps: LayoutOverlayBaseProps) {
311
313
  }
312
314
  useDomEvent(windowRef, 'keyup', handleEscape, { passive: true })
313
315
 
316
+ const dragging = useMotionValue(false)
317
+ const scrollerElementRef = scrollerRef as React.RefObject<HTMLElement>
318
+
319
+ const handleDragStart = () => {
320
+ dragging.set(true)
321
+ }
322
+ const handleDragEnd = () => {
323
+ dragging.set(false)
324
+ // When releasing pointer and visibility 0 (overlay is dragged offscreen), close the overlay
325
+ if (positions.open.visible.get() === 0) closeOverlay()
326
+ }
327
+
328
+ useDomEvent(scrollerElementRef, 'pointerdown', handleDragStart, { passive: true })
329
+ useDomEvent(scrollerElementRef, 'pointerup', handleDragEnd, { passive: true })
330
+ // We use touchend as well as pointerup, because scrolling (dragging the overlay) on mobile causes pointercancel to fire, preventing pointerup from ever firing
331
+ useDomEvent(scrollerElementRef, 'touchend', handleDragEnd, { passive: true })
332
+
314
333
  // When the overlay isn't visible anymore, we navigate back.
315
- useEffect(
316
- () => positions.open.visible.on('change', (o) => o === 0 && closeOverlay()),
317
- [closeOverlay, position, positions.open.visible],
334
+ useMotionValueEvent(
335
+ positions.open.visible,
336
+ 'change',
337
+ (o) => o === 0 && !dragging.get() && closeOverlay(),
318
338
  )
319
339
 
320
340
  // Measure the offset of the overlay in the scroller.
@@ -469,9 +489,14 @@ export function OverlayBase(incomingProps: LayoutOverlayBaseProps) {
469
489
  sx={(theme) => ({
470
490
  display: 'grid',
471
491
  gridArea: 'overlay',
472
- scrollSnapAlign: 'start',
473
492
  scrollSnapStop: 'always',
474
493
  pointerEvents: 'none',
494
+ '&.variantMdBottom, &.variantMdRight': {
495
+ scrollSnapAlign: 'end',
496
+ },
497
+ '&.variantMdLeft': {
498
+ scrollSnapAlign: 'start',
499
+ },
475
500
  [theme.breakpoints.down('md')]: {
476
501
  justifyContent: justifySm,
477
502
  alignItems: justifySm,
@@ -24,7 +24,7 @@ export const OverlayPanelActions = (props: PanelActionsProps) => {
24
24
  <>
25
25
  <LayoutOverlayHeader
26
26
  noAlign
27
- sx={{ '&.noAlign': { mb: 0 } }}
27
+ sx={[{ '&.noAlign': { mb: 0 } }, ...(Array.isArray(sx) ? sx : [sx])]}
28
28
  switchPoint={-10000}
29
29
  size='small'
30
30
  primary={
@@ -10,7 +10,7 @@ export type PopperPanelProps = PanelProps & {
10
10
 
11
11
  export function PopperPanel(props: PopperPanelProps) {
12
12
  const { activeEl, children, ...actionsProps } = props
13
- const ref = useRef(null)
13
+ const ref = useRef<HTMLDivElement>(null)
14
14
  const movement = useHandleClickNotDrag(ref)
15
15
  const handleClickAway = () => {
16
16
  if (movement.get() === 'drag') return
@@ -9,7 +9,7 @@ import { iconClose } from '../icons'
9
9
  import { PanelActionsProps } from './types'
10
10
 
11
11
  export function PopperPanelActions(props: PanelActionsProps) {
12
- const { title, children, onReset, onClose, onApply, sx } = props
12
+ const { title, children, onReset, onClose, onApply, sx = [] } = props
13
13
 
14
14
  const fabSize = useFabSize('small')
15
15
  const svgSize = useIconSvgSize('large')
@@ -18,7 +18,7 @@ export function PopperPanelActions(props: PanelActionsProps) {
18
18
  <>
19
19
  <LayoutHeader
20
20
  noAlign
21
- sx={{ '&.noAlign': { mb: 0 } }}
21
+ sx={[{ '&.noAlign': { mb: 0 } }, ...(Array.isArray(sx) ? sx : [sx])]}
22
22
  switchPoint={-10000}
23
23
  size='small'
24
24
  primary={
@@ -31,6 +31,9 @@ export type PageMetaProps = {
31
31
  metaDescription?: string
32
32
  metaRobots?: MetaRobotsAll | MetaRobots[]
33
33
  children?: React.ReactNode
34
+ ogImage?: string | null
35
+ ogImageUseFallback?: boolean
36
+ ogType?: string | null
34
37
  }
35
38
 
36
39
  type PartialNextRouter = Pick<
@@ -90,7 +93,16 @@ export function useCanonical(incoming?: Canonical) {
90
93
 
91
94
  export function PageMeta(props: PageMetaProps) {
92
95
  const { active } = usePageContext()
93
- const { children, title, canonical: canonicalBare, metaDescription, metaRobots = ['all'] } = props
96
+ const {
97
+ children,
98
+ title,
99
+ canonical: canonicalBare,
100
+ metaDescription,
101
+ ogImage,
102
+ ogType,
103
+ ogImageUseFallback = false,
104
+ metaRobots = ['all'],
105
+ } = props
94
106
 
95
107
  const canonical = useCanonical(canonicalBare)
96
108
 
@@ -99,10 +111,20 @@ export function PageMeta(props: PageMetaProps) {
99
111
  <Head>
100
112
  <title>{title.trim()}</title>
101
113
  {metaDescription && (
102
- <meta name='description' content={metaDescription.trim()} key='meta-description' />
114
+ <>
115
+ <meta name='description' content={metaDescription.trim()} key='meta-description' />
116
+ <meta property='og:description' content={metaDescription.trim()} key='og-description' />
117
+ </>
103
118
  )}
104
119
  <meta name='robots' content={metaRobots.join(',')} key='meta-robots' />
105
120
  {canonical && <link rel='canonical' href={canonical} key='canonical' />}
121
+ <meta property='og:title' content={title.trim()} key='og-title' />
122
+ <meta property='og:type' content={ogType ?? 'website'} key='og-type' />
123
+ <meta property='og:url' content={canonical} key='og-url' />
124
+ {(ogImage || ogImageUseFallback) && (
125
+ <meta property='og:image' content={ogImage ?? '/open-graph-image.jpg'} key='og-image' />
126
+ )}
127
+
106
128
  {children}
107
129
  </Head>
108
130
  )
@@ -22,7 +22,7 @@ const { classes } = extendableComponent('Pagination', parts)
22
22
  * Read more: https://ahrefs.com/blog/rel-prev-next-pagination/
23
23
  */
24
24
  export function Pagination(props: PagePaginationProps) {
25
- const { count, page, renderLink, classes: styles, ...paginationProps } = props
25
+ const { count, page, renderLink, classes: styles, sx = [], ...paginationProps } = props
26
26
 
27
27
  const { items } = usePagination({
28
28
  count,
@@ -61,18 +61,21 @@ export function Pagination(props: PagePaginationProps) {
61
61
  return (
62
62
  <Box
63
63
  className={classes.root}
64
- sx={(theme) => ({
65
- margin: '0 auto',
66
- marginTop: theme.spacings.lg,
67
- marginBottom: theme.spacings.lg,
68
- display: 'flex',
69
- alignItems: 'center',
70
- justifyContent: 'center',
71
- gap: '6px',
72
- '& .Mui-disabled': {
73
- background: 'none',
74
- },
75
- })}
64
+ sx={[
65
+ (theme) => ({
66
+ margin: '0 auto',
67
+ marginTop: theme.spacings.lg,
68
+ marginBottom: theme.spacings.lg,
69
+ display: 'flex',
70
+ alignItems: 'center',
71
+ justifyContent: 'center',
72
+ gap: '6px',
73
+ '& .Mui-disabled': {
74
+ background: 'none',
75
+ },
76
+ }),
77
+ ...(Array.isArray(sx) ? sx : [sx]),
78
+ ]}
76
79
  >
77
80
  {page === 1 ? chevronLeft : renderLink(page - 1, chevronLeft, prevBtnProps)}
78
81
 
@@ -8,7 +8,7 @@ type FilterTypeByTypename<A extends TypeObject, Typename extends string> = A ext
8
8
  : never
9
9
  : never
10
10
 
11
- type TypeRenderMethod<P> = (props: P) => React.ReactElement | null
11
+ type TypeRenderMethod<P> = (props: P) => React.ReactNode
12
12
 
13
13
  type TypeRenderMap<
14
14
  T extends TypeObject,
@@ -14,37 +14,40 @@ const name = 'IconBlock' as const
14
14
  const parts = ['block', 'link', 'title'] as const
15
15
  const { classes } = extendableComponent(name, parts)
16
16
 
17
- export const IconBlock = React.forwardRef<HTMLAnchorElement, IconBlockProps>((props, ref) => {
18
- const { title, children, icon, href = '#', sx = [], ...buttonProps } = props
17
+ export const IconBlock = React.forwardRef<HTMLAnchorElement & HTMLButtonElement, IconBlockProps>(
18
+ (props, ref) => {
19
+ const { title, children, icon, href = '#', sx = [], ...buttonProps } = props
19
20
 
20
- return (
21
- <Button
22
- href={href}
23
- variant='outlined'
24
- color='primary'
25
- className={classes.block}
26
- {...buttonProps}
27
- sx={[
28
- (theme) => ({
29
- padding: `${theme.spacings.sm}`,
30
- textAlign: 'center',
31
- '& > *': {
32
- display: 'grid',
33
- gridAutoFlow: 'row',
34
- justifyItems: 'center',
35
- gap: `${theme.spacings.xxs}`,
36
- },
37
- }),
38
- ...(Array.isArray(sx) ? sx : [sx]),
39
- ]}
40
- >
41
- <Box>
42
- {icon}
43
- <Typography variant='subtitle1' className={classes.title} component='span'>
44
- {title}
45
- </Typography>
46
- {children}
47
- </Box>
48
- </Button>
49
- )
50
- })
21
+ return (
22
+ <Button
23
+ ref={ref}
24
+ href={href}
25
+ variant='outlined'
26
+ color='primary'
27
+ className={classes.block}
28
+ {...buttonProps}
29
+ sx={[
30
+ (theme) => ({
31
+ padding: `${theme.spacings.sm}`,
32
+ textAlign: 'center',
33
+ '& > *': {
34
+ display: 'grid',
35
+ gridAutoFlow: 'row',
36
+ justifyItems: 'center',
37
+ gap: `${theme.spacings.xxs}`,
38
+ },
39
+ }),
40
+ ...(Array.isArray(sx) ? sx : [sx]),
41
+ ]}
42
+ >
43
+ <Box>
44
+ {icon}
45
+ <Typography variant='subtitle1' className={classes.title} component='span'>
46
+ {title}
47
+ </Typography>
48
+ {children}
49
+ </Box>
50
+ </Button>
51
+ )
52
+ },
53
+ )