@graphcommerce/next-ui 3.25.1 → 4.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/AnimatedRow/index.tsx +6 -3
- package/ApolloError/ApolloErrorAlert.tsx +20 -21
- package/ApolloError/ApolloErrorFullPage.tsx +3 -4
- package/ApolloError/ApolloErrorSnackbar.tsx +3 -3
- package/Blog/BlogAuthor/index.tsx +42 -48
- package/Blog/BlogContent/index.tsx +6 -23
- package/Blog/BlogHeader/index.tsx +26 -23
- package/Blog/BlogList/index.tsx +7 -25
- package/Blog/BlogListItem/index.tsx +63 -52
- package/Blog/BlogTags/BlogTag.tsx +27 -0
- package/Blog/BlogTags/index.tsx +7 -32
- package/Blog/BlogTitle/index.tsx +7 -21
- package/Button/Button.tsx +5 -0
- package/Button/LinkOrButton.tsx +80 -0
- package/Button/index.tsx +2 -177
- package/CHANGELOG.md +497 -636
- package/ChipMenu/index.tsx +71 -77
- package/ContainerWithHeader/index.tsx +33 -30
- package/FlagAvatar/index.tsx +2 -12
- package/Footer/Footer.tsx +105 -88
- package/Footer/index.ts +0 -1
- package/Form/Form.tsx +35 -0
- package/Form/FormActions.tsx +9 -14
- package/Form/FormDivider.tsx +8 -13
- package/Form/FormHeader.tsx +5 -26
- package/Form/FormRow.tsx +8 -13
- package/Form/InputCheckmark.tsx +9 -22
- package/FramerScroller/SidebarGallery.tsx +340 -0
- package/FramerScroller/SidebarSlider.tsx +107 -0
- package/FramerScroller/index.ts +2 -0
- package/FullPageMessage/index.tsx +52 -48
- package/Highlight/index.tsx +1 -1
- package/IconHeader/index.tsx +63 -58
- package/JsonLd/index.tsx +3 -2
- package/Layout/components/LayoutHeader.tsx +75 -82
- package/Layout/components/LayoutHeaderBack.tsx +21 -12
- package/Layout/components/LayoutHeaderClose.tsx +9 -22
- package/Layout/components/LayoutHeaderContent.tsx +190 -154
- package/Layout/components/LayoutHeadertypes.ts +1 -1
- package/Layout/components/LayoutTitle.tsx +60 -55
- package/LayoutDefault/components/LayoutDefault.tsx +96 -85
- package/LayoutOverlay/components/LayoutOverlay.tsx +2 -8
- package/LayoutOverlay/components/LayoutOverlayBase.tsx +233 -239
- package/LayoutOverlay/test/LayoutOverlayDemo.tsx +1 -1
- package/LayoutParts/DesktopHeaderBadge.tsx +28 -0
- package/LayoutParts/DesktopNavActions.tsx +15 -0
- package/LayoutParts/DesktopNavBar.tsx +113 -0
- package/LayoutParts/DesktopNavBarItem.tsx +44 -0
- package/{AppShell → LayoutParts}/GlobalHead.tsx +1 -2
- package/LayoutParts/Logo.tsx +77 -0
- package/LayoutParts/MenuFab.tsx +131 -0
- package/LayoutParts/MenuFabItem.tsx +25 -0
- package/LayoutParts/MenuFabSecondaryItem.tsx +37 -0
- package/{AppShell/PlaceholderFab/index.tsx → LayoutParts/PlaceholderFab.tsx} +1 -1
- package/LayoutParts/StickyBelowHeader.tsx +25 -0
- package/LayoutParts/index.ts +12 -0
- package/{AppShell → LayoutParts}/useFabAnimation.ts +0 -0
- package/Page/CssAndFramerMotionProvider.tsx +21 -0
- package/Page/index.ts +2 -0
- package/Page/types.ts +2 -8
- package/PageLoadIndicator/index.tsx +25 -30
- package/PageMeta/index.tsx +1 -1
- package/Pagination/index.tsx +37 -54
- package/RenderType/index.tsx +1 -1
- package/Row/ButtonLinkList/ButtonLinkList.tsx +35 -37
- package/Row/ButtonLinkList/ButtonLinkListItem.tsx +16 -33
- package/Row/ColumnOne/index.tsx +5 -10
- package/Row/ColumnOneBoxed/index.tsx +18 -19
- package/Row/ColumnOneCentered/index.tsx +3 -4
- package/Row/ColumnThree/index.tsx +62 -57
- package/Row/ColumnTwo/index.tsx +37 -35
- package/Row/ColumnTwoSpread/index.tsx +28 -37
- package/Row/ColumnTwoWithTop/index.tsx +37 -43
- package/Row/ContentLinks/index.tsx +24 -25
- package/Row/HeroBanner/index.tsx +98 -82
- package/Row/IconBlocks/IconBlock/index.tsx +45 -37
- package/Row/IconBlocks/index.tsx +29 -44
- package/Row/ImageText/index.tsx +71 -67
- package/Row/ImageTextBoxed/index.tsx +66 -65
- package/Row/ParagraphWithSidebarSlide/index.tsx +80 -76
- package/Row/Quote/index.tsx +3 -3
- package/Row/SpecialBanner/index.tsx +97 -97
- package/Row/index.tsx +4 -9
- package/SectionContainer/index.tsx +32 -31
- package/SectionHeader/index.tsx +41 -43
- package/Separator/index.tsx +19 -18
- package/Snackbar/MessageSnackbar.tsx +1 -2
- package/Snackbar/MessageSnackbarImpl.tsx +68 -115
- package/StarRatingField/index.tsx +24 -25
- package/Stepper/Stepper.tsx +34 -32
- package/Styles/EmotionProvider.tsx +14 -0
- package/Styles/breakpointVal.tsx +16 -10
- package/Styles/extendableComponent.ts +70 -0
- package/Styles/index.tsx +9 -2
- package/Styles/withEmotionCache.tsx +36 -0
- package/Styles/withTheme.tsx +15 -24
- package/SvgIcon/SvgIcon.tsx +60 -0
- package/TextInputNumber/index.tsx +49 -50
- package/Theme/MuiButton.ts +128 -0
- package/Theme/MuiSlider.ts +28 -0
- package/Theme/MuiSnackbar.ts +31 -0
- package/Theme/{types.ts → createTheme.ts} +8 -2
- package/Theme/index.ts +4 -0
- package/Theme/themeDefaults.ts +51 -0
- package/TimeAgo/index.tsx +1 -1
- package/ToggleButton/index.tsx +43 -49
- package/ToggleButtonGroup/index.tsx +39 -39
- package/UspList/UspListItem.tsx +56 -46
- package/UspList/index.tsx +29 -26
- package/docs/building-components.mdx +3 -0
- package/docs/components/ComponentBasic.tsx +26 -0
- package/docs/components/ComponentChild.tsx +48 -0
- package/docs/components/ComponentChildVariant.tsx +54 -0
- package/docs/components/ComponentChildVariantExtendable.tsx +62 -0
- package/docs/components/ComponentStylable.tsx +32 -0
- package/docs/pages/building-components.tsx +62 -0
- package/index.ts +27 -81
- package/package.json +25 -27
- package/types.d.ts +1 -1
- package/AppShell/AppShellSticky/index.tsx +0 -38
- package/AppShell/DesktopNavActions.tsx +0 -32
- package/AppShell/DesktopNavBar.tsx +0 -158
- package/AppShell/Logo.tsx +0 -46
- package/AppShell/Menu.tsx +0 -7
- package/AppShell/MenuFab.tsx +0 -162
- package/AppShell/MenuFabSecondaryItem.tsx +0 -32
- package/AppShell/index.ts +0 -15
- package/AspectRatioContainer/index.tsx +0 -27
- package/Footer/SocialIcon.tsx +0 -23
- package/Form/index.tsx +0 -67
- package/FramerScroller/components/SidebarGallery.tsx +0 -317
- package/FramerScroller/components/SidebarSlider.tsx +0 -97
- package/Page/App.tsx +0 -17
- package/Page/Document.tsx +0 -24
- package/StyledBadge/index.tsx +0 -20
- package/Styles/classesPicker.ts +0 -41
- package/SvgImage/SvgImageSimple.tsx +0 -100
- package/SvgImage/index.tsx +0 -74
package/Styles/breakpointVal.tsx
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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 './
|
|
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
|
+
}
|
package/Styles/withTheme.tsx
CHANGED
|
@@ -1,17 +1,4 @@
|
|
|
1
|
-
import {
|
|
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<
|
|
42
|
-
return (props:
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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
|
-
|
|
10
|
-
|
|
11
|
-
import
|
|
12
|
-
import {
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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={
|
|
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=
|
|
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 ?? <
|
|
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=
|
|
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 ?? <
|
|
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
|
-
|
|
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
|
|
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
|
|
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