@graphcommerce/next-ui 7.1.0-canary.9 → 8.0.0-canary.100

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 (39) hide show
  1. package/ActionCard/ActionCard.tsx +2 -0
  2. package/CHANGELOG.md +255 -8
  3. package/Config.graphqls +24 -0
  4. package/Footer/Footer.tsx +97 -94
  5. package/FramerScroller/ItemScroller.tsx +3 -3
  6. package/FramerScroller/SidebarGallery.tsx +181 -162
  7. package/JsonLd/JsonLd.tsx +0 -2
  8. package/LayoutDefault/components/LayoutDefault.tsx +6 -1
  9. package/LayoutParts/DesktopNavBar.tsx +2 -0
  10. package/LayoutParts/Logo.tsx +20 -20
  11. package/LazyHydrate/LazyHydrate.tsx +72 -0
  12. package/LazyHydrate/index.ts +1 -0
  13. package/Navigation/components/NavigationFab.tsx +9 -7
  14. package/Navigation/components/NavigationOverlay.tsx +9 -1
  15. package/Navigation/components/NavigationProvider.tsx +18 -4
  16. package/Overlay/components/OverlayBase.tsx +1 -1
  17. package/Overlay/components/index.ts +1 -0
  18. package/Page/CssAndFramerMotionProvider.tsx +20 -18
  19. package/PageMeta/PageMeta.tsx +20 -13
  20. package/RenderType/filterNonNullableKeys.ts +11 -14
  21. package/Row/ColumnOne/variant/VariantMessage.tsx +12 -0
  22. package/Row/ColumnOne/variant/index.ts +1 -0
  23. package/Row/index.ts +1 -0
  24. package/SkipLink/SkipLink.tsx +38 -0
  25. package/Snackbar/DismissibleSnackbar.tsx +28 -0
  26. package/Snackbar/MessageSnackbarImpl.tsx +19 -2
  27. package/Styles/EmotionProvider.tsx +8 -8
  28. package/Styles/createEmotionCache.ts +14 -0
  29. package/Styles/withEmotionCache.tsx +26 -16
  30. package/TextInputNumber/TextInputNumber.tsx +7 -1
  31. package/Theme/MuiButton.ts +2 -2
  32. package/Theme/MuiChip.ts +2 -2
  33. package/Theme/MuiFab.ts +1 -1
  34. package/Theme/MuiSlider.ts +2 -2
  35. package/Theme/MuiSnackbar.ts +6 -4
  36. package/hooks/useDateTimeFormat.ts +3 -5
  37. package/hooks/useNumberFormat.ts +3 -5
  38. package/index.ts +4 -2
  39. package/package.json +16 -18
@@ -1,5 +1,5 @@
1
1
  import { useMotionValueValue } from '@graphcommerce/framer-utils'
2
- import { Fab, styled, Box, SxProps, Theme, FabProps } from '@mui/material'
2
+ import { Fab, styled, Box, SxProps, Theme, FabProps, useTheme } from '@mui/material'
3
3
  import { m } from 'framer-motion'
4
4
  import { useRouter } from 'next/router'
5
5
  import React, { useEffect } from 'react'
@@ -35,6 +35,8 @@ export function NavigationFab(props: NavigationFabProps) {
35
35
  const scrollY = useScrollY()
36
36
  const scrolled = useMotionValueValue(scrollY, (y) => y > 10)
37
37
 
38
+ const theme = useTheme()
39
+
38
40
  useEffect(() => {
39
41
  const clear = () => setOpenEl(null)
40
42
  router.events.on('routeChangeStart', clear)
@@ -54,19 +56,19 @@ export function NavigationFab(props: NavigationFabProps) {
54
56
  >
55
57
  <MotionDiv
56
58
  className={classes.wrapper}
57
- sx={(theme) => ({
59
+ sx={{
58
60
  [theme.breakpoints.down('md')]: {
59
61
  opacity: '1 !important',
60
62
  transform: 'none !important',
61
63
  },
62
- })}
64
+ }}
63
65
  style={{ opacity }}
64
66
  >
65
67
  <Fab
66
68
  color='inherit'
67
69
  aria-label='Open Menu'
68
70
  size='responsive'
69
- sx={(theme) => ({
71
+ sx={{
70
72
  boxShadow: 'none',
71
73
  '&:hover, &:focus': {
72
74
  boxShadow: 'none',
@@ -75,7 +77,7 @@ export function NavigationFab(props: NavigationFabProps) {
75
77
  background: theme.palette.text.primary,
76
78
  pointerEvents: 'all',
77
79
  color: theme.palette.background.paper,
78
- })}
80
+ }}
79
81
  className={classes.fab}
80
82
  {...fabProps}
81
83
  >
@@ -87,7 +89,7 @@ export function NavigationFab(props: NavigationFabProps) {
87
89
  )}
88
90
  </Fab>
89
91
  <MotionDiv
90
- sx={(theme) => ({
92
+ sx={{
91
93
  pointerEvents: 'none',
92
94
  borderRadius: '99em',
93
95
  position: 'absolute',
@@ -96,7 +98,7 @@ export function NavigationFab(props: NavigationFabProps) {
96
98
  boxShadow: theme.shadows[6],
97
99
  top: 0,
98
100
  [theme.breakpoints.down('md')]: { opacity: '1 !important' },
99
- })}
101
+ }}
100
102
  className={classes.shadow}
101
103
  style={{ opacity: shadowOpacity }}
102
104
  />
@@ -2,7 +2,7 @@ import { useMotionValueValue, useMotionSelector, dvw } from '@graphcommerce/fram
2
2
  import { i18n } from '@lingui/core'
3
3
  import { useTheme, Box, Fab, SxProps, Theme, useEventCallback, styled } from '@mui/material'
4
4
  import { m } from 'framer-motion'
5
- import React, { useEffect } from 'react'
5
+ import React, { useEffect, useRef } from 'react'
6
6
  import type { LiteralUnion } from 'type-fest'
7
7
  import { IconSvg, useIconSvgSize } from '../../IconSvg'
8
8
  import { LayoutHeaderContent } from '../../Layout/components/LayoutHeaderContent'
@@ -71,6 +71,8 @@ export const NavigationOverlay = React.memo((props: NavigationOverlayProps) => {
71
71
  } else selection.set([])
72
72
  })
73
73
 
74
+ const a11yFocusRef = useRef<HTMLButtonElement | null>(null)
75
+
74
76
  const selectedLevel = useMotionValueValue(selection, (s) => (s === false ? -1 : s.length))
75
77
  const selectionValue = useMotionValueValue(selection, (s) => (s ? s.join('') : s))
76
78
  const activeAndNotClosing = useMotionSelector([selection, closing], ([s, c]) =>
@@ -79,6 +81,10 @@ export const NavigationOverlay = React.memo((props: NavigationOverlayProps) => {
79
81
 
80
82
  useEffect(() => {
81
83
  animating.set(true)
84
+
85
+ if (activeAndNotClosing) {
86
+ a11yFocusRef.current?.focus()
87
+ }
82
88
  }, [activeAndNotClosing, animating])
83
89
 
84
90
  const afterClose = useEventCallback(() => {
@@ -161,6 +167,7 @@ export const NavigationOverlay = React.memo((props: NavigationOverlayProps) => {
161
167
  sx={{ boxShadow: 'none', my: fabMarginY }}
162
168
  size='responsive'
163
169
  aria-label={i18n._(/* i18n */ 'Close')}
170
+ ref={a11yFocusRef}
164
171
  >
165
172
  <IconSvg src={iconClose} size='large' aria-hidden />
166
173
  </Fab>
@@ -178,6 +185,7 @@ export const NavigationOverlay = React.memo((props: NavigationOverlayProps) => {
178
185
  (theme) => ({
179
186
  display: 'grid',
180
187
  alignItems: !stretchColumns ? 'start' : undefined,
188
+ justifyContent: 'end',
181
189
  [theme.breakpoints.down('md')]: {
182
190
  width:
183
191
  sizeSm !== 'floating'
@@ -1,6 +1,8 @@
1
- import { MotionConfig, useMotionValue } from 'framer-motion'
1
+ import { MotionConfig, useMotionValue, useTransform } from 'framer-motion'
2
2
  import React, { useMemo } from 'react'
3
3
  import { isElement } from 'react-is'
4
+ import { LazyHydrate } from '../../LazyHydrate'
5
+ import { nonNullable } from '../../RenderType/nonNullable'
4
6
  import {
5
7
  NavigationNode,
6
8
  NavigationContextType,
@@ -9,8 +11,9 @@ import {
9
11
  NavigationNodeType,
10
12
  NavigationNodeComponent,
11
13
  } from '../hooks/useNavigation'
14
+ import { useMotionValueValue } from '@graphcommerce/framer-utils'
12
15
 
13
- export type NavigationProviderProps = {
16
+ export type NavigationProviderBaseProps = {
14
17
  items: (NavigationNode | React.ReactElement)[]
15
18
  hideRootOnNavigate?: boolean
16
19
  closeAfterNavigate?: boolean
@@ -20,9 +23,9 @@ export type NavigationProviderProps = {
20
23
  serverRenderDepth?: number
21
24
  }
22
25
 
23
- const nonNullable = <T,>(value: T): value is NonNullable<T> => value !== null && value !== undefined
26
+ export type NavigationProviderProps = NavigationProviderBaseProps & { hold?: boolean }
24
27
 
25
- export const NavigationProvider = React.memo<NavigationProviderProps>((props) => {
28
+ const NavigationProviderBase = React.memo<NavigationProviderBaseProps>((props) => {
26
29
  const {
27
30
  items,
28
31
  hideRootOnNavigate = true,
@@ -73,3 +76,14 @@ export const NavigationProvider = React.memo<NavigationProviderProps>((props) =>
73
76
  </MotionConfig>
74
77
  )
75
78
  })
79
+
80
+ export function NavigationProvider(props: NavigationProviderProps) {
81
+ const { selection } = props
82
+ const hydrateManually = useMotionValueValue(selection, (s) => s !== false)
83
+
84
+ return (
85
+ <LazyHydrate hydrated={hydrateManually}>
86
+ <NavigationProviderBase {...props} />
87
+ </LazyHydrate>
88
+ )
89
+ }
@@ -311,7 +311,7 @@ export function OverlayBase(incomingProps: LayoutOverlayBaseProps) {
311
311
  const handleEscape = (e: KeyboardEvent | Event) => {
312
312
  if (active && (e as KeyboardEvent)?.key === 'Escape') closeOverlay()
313
313
  }
314
- useDomEvent(windowRef, 'keyup', handleEscape, { passive: true })
314
+ useDomEvent(windowRef, 'keydown', handleEscape, { passive: true })
315
315
 
316
316
  const dragging = useMotionValue(false)
317
317
  const scrollerElementRef = scrollerRef as React.RefObject<HTMLElement>
@@ -1,2 +1,3 @@
1
1
  export * from './OverlayBase'
2
2
  export * from './Overlay'
3
+ export * from './OverlayStickyBottom'
@@ -1,9 +1,8 @@
1
1
  import { GlobalStyles } from '@mui/material'
2
2
  import { LazyMotion } from 'framer-motion'
3
+ import { EmotionProvider, EmotionProviderProps } from '../Styles/EmotionProvider'
3
4
 
4
- export type GraphCommerceProviderProps = {
5
- children: React.ReactNode
6
- }
5
+ export type CssAndFramerMotionProviderProps = EmotionProviderProps
7
6
 
8
7
  /**
9
8
  * For [@emotion/core](https://emotion.sh/docs/introduction) and
@@ -12,22 +11,25 @@ export type GraphCommerceProviderProps = {
12
11
  * - Wrapps the app to lazily load framer-motion.
13
12
  * - Wrapps the app to have Emotion CSS styles
14
13
  */
15
- export function CssAndFramerMotionProvider({ children }: GraphCommerceProviderProps) {
14
+ export function CssAndFramerMotionProvider(props: CssAndFramerMotionProviderProps) {
15
+ const { children, emotionCache } = props
16
16
  return (
17
- <LazyMotion features={async () => (await import('./framerFeatures')).default} strict>
18
- {children}
19
- <GlobalStyles
20
- styles={{
21
- ':root': {
22
- '--client-size-y': '100vh',
23
- '--client-size-x': '100vw',
24
- '@supports(height: 100dvh)': {
25
- '--client-size-y': '100dvh',
26
- '--client-size-x': '100dvw',
17
+ <EmotionProvider emotionCache={emotionCache}>
18
+ <LazyMotion features={async () => (await import('./framerFeatures')).default} strict>
19
+ {children}
20
+ <GlobalStyles
21
+ styles={{
22
+ ':root': {
23
+ '--client-size-y': '100vh',
24
+ '--client-size-x': '100vw',
25
+ '@supports(height: 100dvh)': {
26
+ '--client-size-y': '100dvh',
27
+ '--client-size-x': '100dvw',
28
+ },
27
29
  },
28
- },
29
- }}
30
- />
31
- </LazyMotion>
30
+ }}
31
+ />
32
+ </LazyMotion>
33
+ </EmotionProvider>
32
34
  )
33
35
  }
@@ -2,8 +2,8 @@ import { usePageContext } from '@graphcommerce/framer-next-pages'
2
2
  import { addBasePath } from 'next/dist/client/add-base-path'
3
3
  import { addLocale } from 'next/dist/client/add-locale'
4
4
  import { getDomainLocale } from 'next/dist/client/get-domain-locale'
5
+ import { resolveHref } from 'next/dist/client/resolve-href'
5
6
  import { NextRouter } from 'next/dist/shared/lib/router/router'
6
- import { resolveHref } from 'next/dist/shared/lib/router/utils/resolve-href'
7
7
  import Head from 'next/head'
8
8
  import { useRouter } from 'next/router'
9
9
  import type {} from '@graphcommerce/next-config'
@@ -60,18 +60,25 @@ export function canonicalize(router: PartialNextRouter, incoming?: Canonical) {
60
60
  const curLocale = router.locale
61
61
 
62
62
  // Copied from here https://github.com/vercel/next.js/blob/213c42f446874d29d07fa2cca6e6b11fc9c3b711/packages/next/client/link.tsx#L512
63
- const localeDomain =
64
- router.isLocaleDomain &&
65
- getDomainLocale(as, curLocale, router && router.locales, router.domainLocales)
66
-
67
- href = localeDomain || addBasePath(addLocale(as, curLocale, router.defaultLocale))
68
-
69
- let siteUrl =
70
- storefrontConfig(router.locale)?.canonicalBaseUrl ||
71
- import.meta.graphCommerce.canonicalBaseUrl
72
- if (siteUrl.endsWith('/')) siteUrl = siteUrl.slice(0, -1)
73
-
74
- canonical = `${siteUrl}${href}`
63
+ const localeDomain = getDomainLocale(
64
+ as,
65
+ curLocale,
66
+ router && router.locales,
67
+ router.domainLocales,
68
+ )
69
+
70
+ if (localeDomain) {
71
+ canonical = localeDomain
72
+ } else {
73
+ href = addBasePath(addLocale(as, curLocale, router.defaultLocale))
74
+
75
+ let siteUrl =
76
+ storefrontConfig(router.locale)?.canonicalBaseUrl ||
77
+ import.meta.graphCommerce.canonicalBaseUrl
78
+ if (siteUrl.endsWith('/')) siteUrl = siteUrl.slice(0, -1)
79
+
80
+ canonical = `${siteUrl}${href}`
81
+ }
75
82
  }
76
83
 
77
84
  if (!canonical.startsWith('http')) {
@@ -1,26 +1,23 @@
1
- import type { OptionalKeysOf, Simplify } from 'type-fest'
1
+ import type { OptionalKeysOf } from 'type-fest'
2
2
 
3
- export type RequiredKeys<
4
- T extends Record<string, unknown>,
5
- Keys extends OptionalKeysOf<T>,
6
- > = Simplify<
7
- Omit<T, Keys> & {
8
- [K in Keys]: NonNullable<T[K]>
9
- }
10
- >
3
+ export type RequiredKeys<T extends Record<string, unknown>, Keys extends OptionalKeysOf<T>> = Omit<
4
+ T,
5
+ Keys
6
+ > & { [K in Keys]: NonNullable<T[K]> }
11
7
 
12
8
  export function filterNonNullableKeys<
13
9
  T extends Record<string, unknown>,
14
10
  Keys extends OptionalKeysOf<T>,
15
- >(items: (T | null | undefined)[] | null | undefined, values: Keys[] = []) {
11
+ >(
12
+ items: (T | null | undefined)[] | null | undefined,
13
+ values: Keys[] = [],
14
+ ): RequiredKeys<T, Keys>[] {
16
15
  if (!items) return []
17
16
 
18
- const result = items.filter(
17
+ return items.filter(
19
18
  (item) =>
20
19
  item !== null &&
21
20
  typeof item !== 'undefined' &&
22
21
  values.every((v) => item?.[v] !== null && typeof item?.[v] !== 'undefined'),
23
- )
24
-
25
- return result as RequiredKeys<T, Keys>[]
22
+ ) as RequiredKeys<T, Keys>[]
26
23
  }
@@ -0,0 +1,12 @@
1
+ import {
2
+ DismissibleSnackbar,
3
+ DismissibleSnackbarProps,
4
+ } from '../../../Snackbar/DismissibleSnackbar'
5
+
6
+ export type VariantMessageProps = DismissibleSnackbarProps
7
+
8
+ export function VariantMessage(props: VariantMessageProps) {
9
+ const { ...rest } = props
10
+
11
+ return <DismissibleSnackbar variant='pill' severity='info' disableBackdropClick {...rest} />
12
+ }
@@ -0,0 +1 @@
1
+ export * from './VariantMessage'
package/Row/index.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from './Row'
2
2
  export * from './ButtonLinkList'
3
3
  export * from './ColumnOne/ColumnOne'
4
+ export * from './ColumnOne/variant'
4
5
  export * from './ColumnOneBoxed/ColumnOneBoxed'
5
6
  export * from './ColumnOneCentered/ColumnOneCentered'
6
7
  export * from './ColumnThree/ColumnThree'
@@ -0,0 +1,38 @@
1
+ import { Trans } from '@lingui/react'
2
+ import { Link } from '@mui/material'
3
+
4
+ export function SkipLink() {
5
+ const setFocus = (e) => {
6
+ e.preventDefault()
7
+ globalThis.document.querySelector<HTMLDivElement>('#skip-nav')?.focus()
8
+ globalThis.document.querySelector<HTMLDivElement>('#skip-nav')?.scrollIntoView()
9
+ }
10
+
11
+ return (
12
+ <Link
13
+ href='#skip-nav'
14
+ tabIndex={0}
15
+ onClick={setFocus}
16
+ onKeyDown={(e) => {
17
+ if (e.key === 'Enter') {
18
+ setFocus(e)
19
+ }
20
+ }}
21
+ sx={(theme) => ({
22
+ position: 'absolute',
23
+ top: theme.page.vertical,
24
+ zIndex: '-1',
25
+ marginLeft: theme.page.horizontal,
26
+ padding: theme.spacings.xxs,
27
+ backgroundColor: theme.palette.background.paper,
28
+ border: theme.palette.text.primary,
29
+ borderRadius: theme.shape.borderRadius,
30
+ '&:focus': {
31
+ zIndex: 9999,
32
+ },
33
+ })}
34
+ >
35
+ <Trans id='Skip to main content' />
36
+ </Link>
37
+ )
38
+ }
@@ -0,0 +1,28 @@
1
+ import { useEffect, useState } from 'react'
2
+ import { MessageSnackbar } from './MessageSnackbar'
3
+ import { MessageSnackbarProps } from './MessageSnackbarImpl'
4
+
5
+ export type DismissibleSnackbarProps = MessageSnackbarProps & {
6
+ id: string
7
+ storageType?: 'localStorage' | 'sessionStorage'
8
+ }
9
+ export function DismissibleSnackbar(props: DismissibleSnackbarProps) {
10
+ const { storageType = 'localStorage', id, onClose, ...rest } = props
11
+ const messageId = `DismissibleSnackbar_${id}`
12
+ const [open, setOpen] = useState(false)
13
+
14
+ useEffect(() => {
15
+ setOpen(!globalThis[storageType]?.getItem(messageId))
16
+ }, [messageId, storageType])
17
+
18
+ return (
19
+ <MessageSnackbar
20
+ {...rest}
21
+ open={open}
22
+ onClose={() => {
23
+ globalThis[storageType]?.setItem(messageId, `${Date.now()}`)
24
+ onClose?.()
25
+ }}
26
+ />
27
+ )
28
+ }
@@ -14,6 +14,7 @@ import React, { useEffect, useState } from 'react'
14
14
  import { IconSvg } from '../IconSvg'
15
15
  import { extendableComponent, breakpointVal } from '../Styles'
16
16
  import { iconClose, iconCheckmark, iconSadFace } from '../icons'
17
+ import iconInfo from '../icons/info.svg'
17
18
 
18
19
  type Size = 'normal' | 'wide'
19
20
  type Variant = 'contained' | 'pill'
@@ -34,6 +35,10 @@ type OwnerState = {
34
35
  size?: Size
35
36
  severity?: 'success' | 'info' | 'warning' | 'error'
36
37
  variant?: Variant
38
+ /**
39
+ * Setting this to true allows interaction with the rest of the page without closing the Snackbar
40
+ */
41
+ disableBackdropClick?: boolean
37
42
  }
38
43
 
39
44
  const name = 'MessageSnackbarImpl' as const
@@ -56,6 +61,7 @@ export default function MessageSnackbarImpl(props: MessageSnackbarProps) {
56
61
  onClose,
57
62
  severity = 'info',
58
63
  sx,
64
+ disableBackdropClick,
59
65
  ...snackbarProps
60
66
  } = props
61
67
 
@@ -65,7 +71,11 @@ export default function MessageSnackbarImpl(props: MessageSnackbarProps) {
65
71
  setShowSnackbar(!!open)
66
72
  }, [open])
67
73
 
68
- const hideSnackbar = () => {
74
+ const hideSnackbar = (event: React.SyntheticEvent | Event, reason?: string) => {
75
+ if (disableBackdropClick && reason === 'clickaway') {
76
+ return
77
+ }
78
+
69
79
  setShowSnackbar(false)
70
80
  onClose?.()
71
81
  }
@@ -80,6 +90,7 @@ export default function MessageSnackbarImpl(props: MessageSnackbarProps) {
80
90
  }
81
91
 
82
92
  let icon = iconCheckmark
93
+ if (severity === 'info') icon = iconInfo
83
94
  if (severity === 'error') icon = iconSadFace
84
95
 
85
96
  return (
@@ -91,7 +102,13 @@ export default function MessageSnackbarImpl(props: MessageSnackbarProps) {
91
102
  open={showSnackbar}
92
103
  autoHideDuration={autoHide ? 5000 : null}
93
104
  className={classes.root}
94
- sx={sx}
105
+ sx={[
106
+ {
107
+ pointerEvents: 'none',
108
+ '& > *': { pointerEvents: 'auto' },
109
+ },
110
+ ...(Array.isArray(sx) ? sx : [sx]),
111
+ ]}
95
112
  onClose={hideSnackbar}
96
113
  >
97
114
  <SnackbarContent
@@ -1,14 +1,14 @@
1
- import createCache from '@emotion/cache'
2
1
  import type { EmotionCache } from '@emotion/cache'
3
2
  import { CacheProvider } from '@emotion/react'
3
+ import { createEmotionCache } from './createEmotionCache'
4
4
 
5
- let muiCache: EmotionCache | undefined
6
- export const createMuiCache = () => {
7
- muiCache = createCache({ key: 'mui' })
8
- return muiCache
9
- }
5
+ export type EmotionProviderProps = { children?: React.ReactNode; emotionCache?: EmotionCache }
6
+
7
+ const clientSideEmotionCache = createEmotionCache()
10
8
 
11
9
  /** Provider that is supposed to be used in your `pages/_app.tsx` */
12
- export function EmotionProvider({ children }: { children: React.ReactNode }) {
13
- return <CacheProvider value={muiCache ?? createMuiCache()}>{children}</CacheProvider>
10
+ export function EmotionProvider(props: EmotionProviderProps) {
11
+ const { children, emotionCache = clientSideEmotionCache } = props
12
+
13
+ return <CacheProvider value={emotionCache}>{children}</CacheProvider>
14
14
  }
@@ -0,0 +1,14 @@
1
+ import createCache from '@emotion/cache'
2
+
3
+ export const createEmotionCache = () => {
4
+ let insertionPoint: HTMLElement | undefined
5
+
6
+ if (typeof window !== 'undefined') {
7
+ const emotionInsertionPoint = document.querySelector<HTMLMetaElement>(
8
+ 'meta[name="emotion-insertion-point"]',
9
+ )
10
+ insertionPoint = emotionInsertionPoint ?? undefined
11
+ }
12
+
13
+ return createCache({ key: 'mui-style', insertionPoint })
14
+ }
@@ -1,36 +1,46 @@
1
1
  import type { EmotionJSX } from '@emotion/react/types/jsx-namespace'
2
2
  import createEmotionServer from '@emotion/server/create-instance'
3
3
  // eslint-disable-next-line @next/next/no-document-import-in-page
4
+ import { AppType } from 'next/app'
4
5
  import type NextDocument from 'next/document'
5
6
  // eslint-disable-next-line @next/next/no-document-import-in-page
6
7
  import type { DocumentContext, DocumentInitialProps } from 'next/document'
7
- import { createMuiCache } from './EmotionProvider'
8
+ import { EmotionProviderProps } from './EmotionProvider'
9
+ import { createEmotionCache } from './createEmotionCache'
8
10
 
9
11
  export type EmotionCacheProps = { emotionStyleTags: EmotionJSX.Element[] }
10
12
 
11
13
  export function withEmotionCache(Document: typeof NextDocument): typeof NextDocument {
12
14
  return class DocumentWithEmotionCache extends Document {
13
15
  static async getInitialProps(ctx: DocumentContext) {
14
- const emotionServer = createEmotionServer(createMuiCache())
15
- const initialProps = await Document.getInitialProps(ctx)
16
+ const cache = createEmotionCache()
17
+ const emotionServer = createEmotionServer(cache)
18
+
19
+ const originalRenderPage = ctx.renderPage
20
+ ctx.renderPage = () =>
21
+ originalRenderPage({
22
+ enhanceApp:
23
+ (App: React.ComponentType<React.ComponentProps<AppType> & EmotionProviderProps>) =>
24
+ (props) => <App emotionCache={cache} {...props} />,
25
+ })
16
26
 
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
- ))
27
+ const initialProps = await Document.getInitialProps(ctx)
28
+ // This is important. It prevents Emotion to render invalid HTML.
29
+ // See https://github.com/mui/material-ui/issues/26561#issuecomment-855286153
30
+ const emotionStyles = emotionServer.extractCriticalToChunks(initialProps.html)
31
+ const emotionStyleTags = emotionStyles.styles.map((style) => (
32
+ <style
33
+ data-emotion={`${style.key} ${style.ids.join(' ')}`}
34
+ key={style.key}
35
+ // eslint-disable-next-line react/no-danger
36
+ dangerouslySetInnerHTML={{ __html: style.css }}
37
+ />
38
+ ))
28
39
 
29
- const props: DocumentInitialProps & EmotionCacheProps = {
40
+ return {
30
41
  ...initialProps,
31
42
  emotionStyleTags,
32
43
  }
33
- return props
34
44
  }
35
45
  }
36
46
  }
@@ -32,6 +32,9 @@ const name = 'TextInputNumber' as const
32
32
  const parts = ['quantity', 'quantityInput', 'button'] as const
33
33
  const { withState } = extendableComponent<OwnerState, typeof name, typeof parts>(name, parts)
34
34
 
35
+ /**
36
+ * @deprecated Please us NumberFieldElement
37
+ */
35
38
  export function TextInputNumber(props: TextInputNumberProps) {
36
39
  const {
37
40
  DownProps = {},
@@ -102,6 +105,9 @@ export function TextInputNumber(props: TextInputNumberProps) {
102
105
  width: responsiveVal(90, 120),
103
106
  },
104
107
  {
108
+ '& input[type=number]': {
109
+ MozAppearance: 'textfield',
110
+ },
105
111
  '& .MuiOutlinedInput-root': {
106
112
  px: '3px',
107
113
  display: 'grid',
@@ -159,8 +165,8 @@ export function TextInputNumber(props: TextInputNumberProps) {
159
165
  updateDisabled(e.target)
160
166
  }}
161
167
  inputProps={{
162
- ...inputProps,
163
168
  'aria-label': i18n._(/* i18n */ 'Number'),
169
+ ...inputProps,
164
170
  sx: [
165
171
  {
166
172
  typography: 'body1',
@@ -1,4 +1,4 @@
1
- import { ComponentsVariants } from '@mui/material'
1
+ import { ComponentsVariants, Theme } from '@mui/material'
2
2
  import { responsiveVal } from '../Styles/responsiveVal'
3
3
 
4
4
  declare module '@mui/material/Button/Button' {
@@ -8,7 +8,7 @@ declare module '@mui/material/Button/Button' {
8
8
  }
9
9
  }
10
10
 
11
- type ButtonVariants = NonNullable<ComponentsVariants['MuiButton']>
11
+ type ButtonVariants = NonNullable<ComponentsVariants<Theme>['MuiButton']>
12
12
 
13
13
  export const MuiButtonResponsive: ButtonVariants = [
14
14
  {
package/Theme/MuiChip.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { ComponentsVariants, darken } from '@mui/material'
1
+ import { ComponentsVariants, Theme, darken } from '@mui/material'
2
2
  import { responsiveVal } from '../Styles'
3
3
 
4
4
  declare module '@mui/material/Chip/Chip' {
@@ -10,7 +10,7 @@ declare module '@mui/material/Chip/Chip' {
10
10
  }
11
11
  }
12
12
 
13
- type ChipVariants = NonNullable<ComponentsVariants['MuiChip']>
13
+ type ChipVariants = NonNullable<ComponentsVariants<Theme>['MuiChip']>
14
14
 
15
15
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
16
16
  export const MuiChip: ChipVariants = [
package/Theme/MuiFab.ts CHANGED
@@ -64,7 +64,7 @@ function fabWidthHeight(size: FabSize, theme: Theme) {
64
64
  }
65
65
  }
66
66
 
67
- type FabVariants = NonNullable<ComponentsVariants['MuiFab']>
67
+ type FabVariants = NonNullable<ComponentsVariants<Theme>['MuiFab']>
68
68
 
69
69
  const sizes: FabSize[] = [
70
70
  'smaller',
@@ -1,11 +1,11 @@
1
- import { ComponentsVariants } from '@mui/material'
1
+ import { ComponentsVariants, Theme } from '@mui/material'
2
2
 
3
3
  declare module '@mui/material/Slider/Slider' {
4
4
  interface SliderPropsSizeOverrides {
5
5
  large: true
6
6
  }
7
7
  }
8
- type SliderVariants = NonNullable<ComponentsVariants['MuiSlider']>
8
+ type SliderVariants = NonNullable<ComponentsVariants<Theme>['MuiSlider']>
9
9
 
10
10
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
11
11
  export const MuiSlider: SliderVariants = [