@graphcommerce/magento-product-configurable 3.6.41 → 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/CHANGELOG.md +234 -167
- package/ConfigurableCartItem/OptionsList.tsx +37 -105
- package/ConfigurableOptions/index.tsx +31 -29
- package/ConfigurableProductAddToCart/ConfigurableProductAddToCart.tsx +40 -37
- package/SwatchList.tsx +3 -3
- package/Swatches/ColorSwatchData.tsx +35 -31
- package/Swatches/ImageSwatchData.tsx +37 -34
- package/Swatches/TextSwatchData.tsx +61 -49
- package/Swatches/index.tsx +1 -1
- package/package.json +22 -30
|
@@ -1,114 +1,46 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import React from 'react'
|
|
1
|
+
import { extendableComponent } from '@graphcommerce/next-ui'
|
|
2
|
+
import { Box, SxProps, Theme } from '@mui/material'
|
|
4
3
|
import { ConfigurableCartItemFragment } from './ConfigurableCartItem.gql'
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
gridArea: 'itemOptions',
|
|
10
|
-
cursor: 'default',
|
|
11
|
-
marginLeft: 0,
|
|
12
|
-
paddingBottom: 4,
|
|
13
|
-
},
|
|
14
|
-
option: {
|
|
15
|
-
color: theme.palette.text.secondary,
|
|
16
|
-
textDecoration: 'underline',
|
|
17
|
-
marginRight: theme.spacings.xs,
|
|
18
|
-
paddingBottom: 1,
|
|
19
|
-
display: 'inline',
|
|
20
|
-
},
|
|
21
|
-
menuPaper: {
|
|
22
|
-
minWidth: responsiveVal(200, 560),
|
|
23
|
-
maxWidth: 560,
|
|
24
|
-
marginTop: -8,
|
|
25
|
-
padding: `${theme.spacings.xs} ${theme.spacings.xs}`,
|
|
26
|
-
[theme.breakpoints.down('xs')]: {
|
|
27
|
-
minWidth: 0,
|
|
28
|
-
width: '100%',
|
|
29
|
-
maxWidth: `calc(100% - (${theme.page.horizontal}px * 2))`,
|
|
30
|
-
margin: '0 auto',
|
|
31
|
-
marginTop: '8px',
|
|
32
|
-
},
|
|
33
|
-
},
|
|
34
|
-
menuList: {
|
|
35
|
-
padding: 0,
|
|
36
|
-
'&:focus': {
|
|
37
|
-
outline: 'none',
|
|
38
|
-
},
|
|
39
|
-
},
|
|
40
|
-
menuTitle: {
|
|
41
|
-
...theme.typography.h5,
|
|
42
|
-
paddingBottom: theme.spacings.xxs,
|
|
43
|
-
marginBottom: theme.spacings.xxs,
|
|
44
|
-
borderBottom: `1px solid ${theme.palette.divider}`,
|
|
45
|
-
},
|
|
46
|
-
menuContent: {
|
|
47
|
-
display: 'flex',
|
|
48
|
-
},
|
|
49
|
-
saveChangesWrap: {
|
|
50
|
-
alignSelf: 'center',
|
|
51
|
-
},
|
|
52
|
-
saveChangesButton: {
|
|
53
|
-
padding: '10px 20px',
|
|
54
|
-
fontWeight: theme.typography.fontWeightBold,
|
|
55
|
-
boxShadow: theme.shadows[3],
|
|
56
|
-
},
|
|
57
|
-
}),
|
|
58
|
-
{ name: 'CartItemOptionsList' },
|
|
59
|
-
)
|
|
5
|
+
type CartItemOptionsListProps = ConfigurableCartItemFragment & {
|
|
6
|
+
sx?: SxProps<Theme>
|
|
7
|
+
}
|
|
60
8
|
|
|
61
|
-
|
|
9
|
+
const name = 'ColorSwatchData' as const
|
|
10
|
+
const parts = ['root', 'option'] as const
|
|
11
|
+
const { classes } = extendableComponent(name, parts)
|
|
62
12
|
|
|
63
13
|
export default function OptionsList(props: CartItemOptionsListProps) {
|
|
64
|
-
const { configurable_options } = props
|
|
65
|
-
const classes = useStyles()
|
|
66
|
-
// const [anchorEl, setAnchorEl] = useState<HTMLDivElement>()
|
|
67
|
-
|
|
68
|
-
// const handleClick = (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
|
|
69
|
-
// setAnchorEl(event.currentTarget)
|
|
70
|
-
// }
|
|
71
|
-
|
|
72
|
-
// const handleClose = () => {
|
|
73
|
-
// setAnchorEl(undefined)
|
|
74
|
-
// }
|
|
75
|
-
|
|
76
|
-
// const handleChange = () => {
|
|
77
|
-
// //
|
|
78
|
-
// }
|
|
14
|
+
const { configurable_options, sx = [] } = props
|
|
79
15
|
|
|
80
16
|
return (
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
</div>
|
|
110
|
-
</div>
|
|
111
|
-
</Menu> */}
|
|
112
|
-
</>
|
|
17
|
+
<Box
|
|
18
|
+
className={classes.root}
|
|
19
|
+
sx={[
|
|
20
|
+
{
|
|
21
|
+
gridArea: 'itemOptions',
|
|
22
|
+
cursor: 'default',
|
|
23
|
+
marginLeft: 0,
|
|
24
|
+
paddingBottom: '4px',
|
|
25
|
+
},
|
|
26
|
+
...(Array.isArray(sx) ? sx : [sx]),
|
|
27
|
+
]}
|
|
28
|
+
>
|
|
29
|
+
{configurable_options &&
|
|
30
|
+
configurable_options.map((option) => (
|
|
31
|
+
<Box
|
|
32
|
+
key={option?.configurable_product_option_uid}
|
|
33
|
+
className={classes.option}
|
|
34
|
+
sx={(theme) => ({
|
|
35
|
+
color: 'text.secondary',
|
|
36
|
+
textDecoration: 'underline',
|
|
37
|
+
marginRight: theme.spacings.xs,
|
|
38
|
+
display: 'inline',
|
|
39
|
+
})}
|
|
40
|
+
>
|
|
41
|
+
{option?.value_label}
|
|
42
|
+
</Box>
|
|
43
|
+
))}
|
|
44
|
+
</Box>
|
|
113
45
|
)
|
|
114
46
|
}
|
|
@@ -1,41 +1,35 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
RenderType,
|
|
3
|
+
SectionHeader,
|
|
4
|
+
ToggleButton,
|
|
5
|
+
ToggleButtonGroup,
|
|
6
|
+
extendableComponent,
|
|
7
|
+
} from '@graphcommerce/next-ui'
|
|
2
8
|
import { Controller, FieldErrors, UseControllerProps } from '@graphcommerce/react-hook-form'
|
|
3
|
-
import { BaseTextFieldProps, FormHelperText
|
|
9
|
+
import { BaseTextFieldProps, FormHelperText } from '@mui/material'
|
|
4
10
|
import React from 'react'
|
|
5
11
|
import { Selected, useConfigurableContext } from '../ConfigurableContext'
|
|
6
12
|
import { SwatchTypeRenderer, SwatchSize } from '../Swatches'
|
|
7
|
-
import ColorSwatchData from '../Swatches/ColorSwatchData'
|
|
8
|
-
import ImageSwatchData from '../Swatches/ImageSwatchData'
|
|
9
|
-
import TextSwatchData from '../Swatches/TextSwatchData'
|
|
13
|
+
import { ColorSwatchData } from '../Swatches/ColorSwatchData'
|
|
14
|
+
import { ImageSwatchData } from '../Swatches/ImageSwatchData'
|
|
15
|
+
import { TextSwatchData } from '../Swatches/TextSwatchData'
|
|
10
16
|
|
|
11
|
-
export type
|
|
17
|
+
export type ConfigurableOptionsInputProps = {
|
|
12
18
|
sku: string
|
|
13
19
|
errors?: FieldErrors
|
|
20
|
+
size?: SwatchSize
|
|
14
21
|
} & UseControllerProps<any> &
|
|
15
22
|
Pick<BaseTextFieldProps, 'FormHelperTextProps' | 'helperText'> & {
|
|
16
23
|
optionEndLabels?: Record<string, React.ReactNode>
|
|
17
24
|
}
|
|
18
25
|
|
|
19
|
-
export const useStyles = makeStyles(
|
|
20
|
-
(theme: Theme) => ({
|
|
21
|
-
toggleButtonGroup: {
|
|
22
|
-
display: 'grid',
|
|
23
|
-
gridTemplateColumns: 'repeat(2, 1fr)',
|
|
24
|
-
gap: theme.spacings.xs,
|
|
25
|
-
},
|
|
26
|
-
button: {
|
|
27
|
-
minHeight: theme.spacings.lg,
|
|
28
|
-
},
|
|
29
|
-
helperText: {
|
|
30
|
-
position: 'absolute',
|
|
31
|
-
},
|
|
32
|
-
}),
|
|
33
|
-
{ name: 'ConfigurableOptions' },
|
|
34
|
-
)
|
|
35
|
-
|
|
36
26
|
const renderer: SwatchTypeRenderer = { TextSwatchData, ImageSwatchData, ColorSwatchData }
|
|
37
27
|
|
|
38
|
-
|
|
28
|
+
const compName = 'ConfigurableOptionsInput' as const
|
|
29
|
+
const parts = ['buttonGroup', 'button', 'helperText'] as const
|
|
30
|
+
const { classes } = extendableComponent(compName, parts)
|
|
31
|
+
|
|
32
|
+
export default function ConfigurableOptionsInput(props: ConfigurableOptionsInputProps) {
|
|
39
33
|
const {
|
|
40
34
|
sku,
|
|
41
35
|
FormHelperTextProps,
|
|
@@ -44,11 +38,11 @@ export default function ConfigurableOptionsInput(props: ConfigurableOptionsProps
|
|
|
44
38
|
errors,
|
|
45
39
|
helperText,
|
|
46
40
|
optionEndLabels,
|
|
41
|
+
size = 'large',
|
|
47
42
|
...controlProps
|
|
48
43
|
} = props
|
|
49
44
|
|
|
50
45
|
const { options, selection, select, getVariants } = useConfigurableContext(sku)
|
|
51
|
-
const classes = useStyles()
|
|
52
46
|
|
|
53
47
|
return (
|
|
54
48
|
<>
|
|
@@ -77,7 +71,6 @@ export default function ConfigurableOptionsInput(props: ConfigurableOptionsProps
|
|
|
77
71
|
defaultValue={selection[attribute_code] ?? ''}
|
|
78
72
|
required
|
|
79
73
|
exclusive
|
|
80
|
-
minWidth={100}
|
|
81
74
|
onChange={(_, val: string | number) => {
|
|
82
75
|
onChange(val)
|
|
83
76
|
select((prev) => ({ ...prev, [attribute_code]: val } as Selected))
|
|
@@ -85,7 +78,8 @@ export default function ConfigurableOptionsInput(props: ConfigurableOptionsProps
|
|
|
85
78
|
ref={ref}
|
|
86
79
|
onBlur={onBlur}
|
|
87
80
|
value={value}
|
|
88
|
-
|
|
81
|
+
className={classes.buttonGroup}
|
|
82
|
+
size={size}
|
|
89
83
|
>
|
|
90
84
|
{option?.values?.map((val) => {
|
|
91
85
|
if (!val?.uid || !option.attribute_code) return null
|
|
@@ -110,20 +104,28 @@ export default function ConfigurableOptionsInput(props: ConfigurableOptionsProps
|
|
|
110
104
|
name={inputName}
|
|
111
105
|
className={classes.button}
|
|
112
106
|
disabled={!itemVariant}
|
|
107
|
+
size={size}
|
|
113
108
|
>
|
|
114
109
|
<RenderType
|
|
115
110
|
renderer={renderer}
|
|
116
111
|
{...val}
|
|
117
112
|
{...swatch_data}
|
|
118
113
|
price={itemVariant?.product?.price_range.minimum_price.final_price}
|
|
119
|
-
size={
|
|
114
|
+
size={size}
|
|
120
115
|
/>
|
|
121
116
|
</ToggleButton>
|
|
122
117
|
)
|
|
123
118
|
})}
|
|
124
119
|
</ToggleButtonGroup>
|
|
125
120
|
{error && (
|
|
126
|
-
<FormHelperText
|
|
121
|
+
<FormHelperText
|
|
122
|
+
error
|
|
123
|
+
{...FormHelperTextProps}
|
|
124
|
+
className={classes.helperText}
|
|
125
|
+
sx={{
|
|
126
|
+
position: 'absolute',
|
|
127
|
+
}}
|
|
128
|
+
>
|
|
127
129
|
{`${option.label} is ${errorHelperText?.type}`}
|
|
128
130
|
</FormHelperText>
|
|
129
131
|
)}
|
|
@@ -3,19 +3,20 @@ import { Money } from '@graphcommerce/magento-store'
|
|
|
3
3
|
import {
|
|
4
4
|
AnimatedRow,
|
|
5
5
|
Button,
|
|
6
|
+
extendableComponent,
|
|
6
7
|
iconChevronRight,
|
|
7
8
|
MessageSnackbar,
|
|
8
|
-
|
|
9
|
+
SvgIcon,
|
|
9
10
|
TextInputNumber,
|
|
10
11
|
} from '@graphcommerce/next-ui'
|
|
11
|
-
import {
|
|
12
|
-
import { Alert } from '@material
|
|
12
|
+
import { Trans } from '@lingui/macro'
|
|
13
|
+
import { Divider, Typography, Alert, Box } from '@mui/material'
|
|
13
14
|
import { AnimatePresence } from 'framer-motion'
|
|
14
15
|
import PageLink from 'next/link'
|
|
15
16
|
import React from 'react'
|
|
16
17
|
import { Selected, useConfigurableContext } from '../ConfigurableContext'
|
|
17
18
|
import cheapestVariant from '../ConfigurableContext/cheapestVariant'
|
|
18
|
-
import ConfigurableOptionsInput from '../ConfigurableOptions'
|
|
19
|
+
import ConfigurableOptionsInput, { ConfigurableOptionsInputProps } from '../ConfigurableOptions'
|
|
19
20
|
import {
|
|
20
21
|
ConfigurableProductAddToCartDocument,
|
|
21
22
|
ConfigurableProductAddToCartMutationVariables,
|
|
@@ -26,35 +27,19 @@ type ConfigurableProductAddToCartProps = {
|
|
|
26
27
|
name: string
|
|
27
28
|
optionEndLabels?: Record<string, React.ReactNode>
|
|
28
29
|
children?: React.ReactNode
|
|
30
|
+
optionsProps?: Omit<
|
|
31
|
+
ConfigurableOptionsInputProps,
|
|
32
|
+
'name' | 'sku' | 'control' | 'rules' | 'errors' | 'optionEndLabels'
|
|
33
|
+
>
|
|
29
34
|
}
|
|
30
35
|
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
width: '100%',
|
|
35
|
-
},
|
|
36
|
-
button: {
|
|
37
|
-
marginTop: theme.spacings.sm,
|
|
38
|
-
marginBottom: theme.spacings.sm,
|
|
39
|
-
width: '100%',
|
|
40
|
-
},
|
|
41
|
-
finalPrice: {
|
|
42
|
-
marginTop: theme.spacings.sm,
|
|
43
|
-
},
|
|
44
|
-
quantity: {
|
|
45
|
-
marginTop: theme.spacings.sm,
|
|
46
|
-
},
|
|
47
|
-
divider: {
|
|
48
|
-
margin: `${theme.spacings.sm} 0`,
|
|
49
|
-
},
|
|
50
|
-
}),
|
|
51
|
-
{ name: 'ConfigurableProductAddToCart' },
|
|
52
|
-
)
|
|
36
|
+
const compName = 'ConfigurableOptionsInput' as const
|
|
37
|
+
const parts = ['form', 'button', 'finalPrice', 'quantity', 'divider'] as const
|
|
38
|
+
const { classes } = extendableComponent(compName, parts)
|
|
53
39
|
|
|
54
40
|
export default function ConfigurableProductAddToCart(props: ConfigurableProductAddToCartProps) {
|
|
55
|
-
const { name, children, variables, optionEndLabels, ...buttonProps } = props
|
|
41
|
+
const { name, children, variables, optionEndLabels, optionsProps, ...buttonProps } = props
|
|
56
42
|
const { getUids, getVariants, selection } = useConfigurableContext(variables.sku)
|
|
57
|
-
const classes = useStyles()
|
|
58
43
|
|
|
59
44
|
const form = useFormGqlMutationCart(ConfigurableProductAddToCartDocument, {
|
|
60
45
|
defaultValues: { ...variables },
|
|
@@ -69,8 +54,14 @@ export default function ConfigurableProductAddToCart(props: ConfigurableProductA
|
|
|
69
54
|
const submitHandler = handleSubmit(() => {})
|
|
70
55
|
|
|
71
56
|
return (
|
|
72
|
-
<
|
|
73
|
-
|
|
57
|
+
<Box
|
|
58
|
+
component='form'
|
|
59
|
+
onSubmit={submitHandler}
|
|
60
|
+
noValidate
|
|
61
|
+
className={classes.form}
|
|
62
|
+
sx={{ width: '100%' }}
|
|
63
|
+
>
|
|
64
|
+
<Divider className={classes.divider} sx={(theme) => ({ margin: `${theme.spacings.sm} 0` })} />
|
|
74
65
|
<ConfigurableOptionsInput
|
|
75
66
|
name='selectedOptions'
|
|
76
67
|
sku={variables.sku}
|
|
@@ -78,6 +69,7 @@ export default function ConfigurableProductAddToCart(props: ConfigurableProductA
|
|
|
78
69
|
rules={{ required: required.selectedOptions }}
|
|
79
70
|
errors={formState.errors.selectedOptions}
|
|
80
71
|
optionEndLabels={optionEndLabels}
|
|
72
|
+
{...optionsProps}
|
|
81
73
|
/>
|
|
82
74
|
<TextInputNumber
|
|
83
75
|
variant='outlined'
|
|
@@ -89,9 +81,15 @@ export default function ConfigurableProductAddToCart(props: ConfigurableProductA
|
|
|
89
81
|
// disabled={loading}
|
|
90
82
|
size='small'
|
|
91
83
|
className={classes.quantity}
|
|
84
|
+
sx={(theme) => ({ marginTop: theme.spacings.sm })}
|
|
92
85
|
/>
|
|
93
|
-
<Divider className={classes.divider} />
|
|
94
|
-
<Typography
|
|
86
|
+
<Divider className={classes.divider} sx={(theme) => ({ margin: `${theme.spacings.sm} 0` })} />
|
|
87
|
+
<Typography
|
|
88
|
+
component='div'
|
|
89
|
+
variant='h3'
|
|
90
|
+
className={classes.finalPrice}
|
|
91
|
+
sx={(theme) => ({ marginTop: theme.spacings.sm })}
|
|
92
|
+
>
|
|
95
93
|
<Money
|
|
96
94
|
{...cheapestVariant(getVariants(selection))?.product?.price_range.minimum_price
|
|
97
95
|
.final_price}
|
|
@@ -104,8 +102,13 @@ export default function ConfigurableProductAddToCart(props: ConfigurableProductA
|
|
|
104
102
|
color='primary'
|
|
105
103
|
variant='pill'
|
|
106
104
|
size='large'
|
|
107
|
-
|
|
105
|
+
className={classes.button}
|
|
108
106
|
{...buttonProps}
|
|
107
|
+
sx={(theme) => ({
|
|
108
|
+
marginTop: theme.spacings.sm,
|
|
109
|
+
marginBottom: theme.spacings.sm,
|
|
110
|
+
width: '100%',
|
|
111
|
+
})}
|
|
109
112
|
>
|
|
110
113
|
Add to Cart
|
|
111
114
|
</Button>
|
|
@@ -134,17 +137,17 @@ export default function ConfigurableProductAddToCart(props: ConfigurableProductA
|
|
|
134
137
|
size='medium'
|
|
135
138
|
variant='pill'
|
|
136
139
|
color='secondary'
|
|
137
|
-
endIcon={<
|
|
140
|
+
endIcon={<SvgIcon src={iconChevronRight} />}
|
|
138
141
|
>
|
|
139
142
|
View shopping cart
|
|
140
143
|
</Button>
|
|
141
144
|
</PageLink>
|
|
142
145
|
}
|
|
143
146
|
>
|
|
144
|
-
|
|
147
|
+
<Trans>
|
|
145
148
|
<strong>{name}</strong> has been added to your shopping cart!
|
|
146
|
-
|
|
149
|
+
</Trans>
|
|
147
150
|
</MessageSnackbar>
|
|
148
|
-
</
|
|
151
|
+
</Box>
|
|
149
152
|
)
|
|
150
153
|
}
|
package/SwatchList.tsx
CHANGED
|
@@ -3,9 +3,9 @@ import { RenderType } from '@graphcommerce/next-ui'
|
|
|
3
3
|
import React from 'react'
|
|
4
4
|
import { ProductListItemConfigurableFragment } from './ProductListItemConfigurable.gql'
|
|
5
5
|
import { SwatchSize, SwatchTypeRenderer } from './Swatches'
|
|
6
|
-
import ColorSwatchData from './Swatches/ColorSwatchData'
|
|
7
|
-
import ImageSwatchData from './Swatches/ImageSwatchData'
|
|
8
|
-
import TextSwatchData from './Swatches/TextSwatchData'
|
|
6
|
+
import { ColorSwatchData } from './Swatches/ColorSwatchData'
|
|
7
|
+
import { ImageSwatchData } from './Swatches/ImageSwatchData'
|
|
8
|
+
import { TextSwatchData } from './Swatches/TextSwatchData'
|
|
9
9
|
|
|
10
10
|
type SwatchListProps = {
|
|
11
11
|
attributes: string[]
|
|
@@ -1,42 +1,46 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import clsx from 'clsx'
|
|
1
|
+
import { responsiveVal, extendableComponent } from '@graphcommerce/next-ui'
|
|
2
|
+
import { Box, SxProps, Theme } from '@mui/material'
|
|
4
3
|
import { ColorSwatchDataFragment } from './ColorSwatchData.gql'
|
|
5
4
|
import { SwatchDataProps } from '.'
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
{
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
height: responsiveVal(22, 30),
|
|
12
|
-
width: responsiveVal(22, 30),
|
|
13
|
-
borderRadius: '50%',
|
|
14
|
-
},
|
|
15
|
-
sizeSmall: {
|
|
16
|
-
height: responsiveVal(8, 12),
|
|
17
|
-
width: responsiveVal(8, 12),
|
|
18
|
-
marginTop: responsiveVal(2, 4),
|
|
19
|
-
},
|
|
20
|
-
},
|
|
21
|
-
{ name: 'ColorSwatchData' },
|
|
22
|
-
)
|
|
6
|
+
type ColorSwatchDataProps = ColorSwatchDataFragment &
|
|
7
|
+
SwatchDataProps & {
|
|
8
|
+
sx?: SxProps<Theme>
|
|
9
|
+
}
|
|
23
10
|
|
|
24
|
-
type
|
|
11
|
+
type OwnerState = Pick<SwatchDataProps, 'size'>
|
|
12
|
+
const name = 'ColorSwatchData' as const
|
|
13
|
+
const parts = ['root', 'color', 'label'] as const
|
|
14
|
+
const { withState } = extendableComponent<OwnerState, typeof name, typeof parts>(name, parts)
|
|
25
15
|
|
|
26
|
-
export
|
|
27
|
-
const
|
|
28
|
-
const
|
|
16
|
+
export function ColorSwatchData(props: ColorSwatchDataProps) {
|
|
17
|
+
const { value, store_label, size, sx } = props
|
|
18
|
+
const classes = withState({ size })
|
|
29
19
|
|
|
30
20
|
return (
|
|
31
|
-
<
|
|
32
|
-
<
|
|
33
|
-
className={
|
|
34
|
-
[classes.root]: true,
|
|
35
|
-
[classes.sizeSmall]: size === 'small',
|
|
36
|
-
})}
|
|
21
|
+
<Box className={classes.root} sx={sx}>
|
|
22
|
+
<Box
|
|
23
|
+
className={classes.color}
|
|
37
24
|
style={{ backgroundColor: value ?? undefined }}
|
|
25
|
+
sx={[
|
|
26
|
+
{
|
|
27
|
+
margin: '0 auto',
|
|
28
|
+
height: responsiveVal(22, 30),
|
|
29
|
+
width: responsiveVal(22, 30),
|
|
30
|
+
borderRadius: '50%',
|
|
31
|
+
'&.sizeSmall': {
|
|
32
|
+
height: responsiveVal(8, 12),
|
|
33
|
+
width: responsiveVal(8, 12),
|
|
34
|
+
marginTop: responsiveVal(2, 4),
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
]}
|
|
38
38
|
/>
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
{size !== 'small' && (
|
|
40
|
+
<Box component='span' className={classes.label}>
|
|
41
|
+
{store_label}
|
|
42
|
+
</Box>
|
|
43
|
+
)}
|
|
44
|
+
</Box>
|
|
41
45
|
)
|
|
42
46
|
}
|
|
@@ -1,49 +1,52 @@
|
|
|
1
1
|
import { Image } from '@graphcommerce/image'
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import clsx from 'clsx'
|
|
5
|
-
import React from 'react'
|
|
2
|
+
import { responsiveVal, extendableComponent } from '@graphcommerce/next-ui'
|
|
3
|
+
import { Box, SxProps, Theme } from '@mui/material'
|
|
6
4
|
import { ImageSwatchDataFragment } from './ImageSwatchData.gql'
|
|
7
5
|
import { SwatchDataProps } from '.'
|
|
8
6
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
width: 20,
|
|
21
|
-
height: 20,
|
|
22
|
-
},
|
|
23
|
-
}),
|
|
24
|
-
{ name: 'ImageSwatchData' },
|
|
25
|
-
)
|
|
26
|
-
type ImageSwatchDataProps = ImageSwatchDataFragment & SwatchDataProps & UseStyles<typeof useStyles>
|
|
7
|
+
type ImageSwatchDataProps = ImageSwatchDataFragment & SwatchDataProps & { sx?: SxProps<Theme> }
|
|
8
|
+
|
|
9
|
+
type OwnerState = Pick<SwatchDataProps, 'size'>
|
|
10
|
+
const name = 'ColorSwatchData' as const
|
|
11
|
+
const parts = ['root', 'image', 'label'] as const
|
|
12
|
+
const { withState } = extendableComponent<OwnerState, typeof name, typeof parts>(name, parts)
|
|
13
|
+
|
|
14
|
+
export function ImageSwatchData(props: ImageSwatchDataProps) {
|
|
15
|
+
const { value, thumbnail, store_label, size, sx = [] } = props
|
|
16
|
+
|
|
17
|
+
const classes = withState({ size })
|
|
27
18
|
|
|
28
|
-
export default function ImageSwatchData(props: ImageSwatchDataProps) {
|
|
29
|
-
const classes = useStyles(props)
|
|
30
|
-
const { value, thumbnail, store_label, size } = props
|
|
31
19
|
return (
|
|
32
|
-
|
|
20
|
+
<Box
|
|
21
|
+
sx={[
|
|
22
|
+
(theme) => ({
|
|
23
|
+
'& .image': {
|
|
24
|
+
height: responsiveVal(40, 80),
|
|
25
|
+
width: responsiveVal(40, 80),
|
|
26
|
+
border: `3px solid ${theme.palette.divider}`,
|
|
27
|
+
boxSizing: 'border-box',
|
|
28
|
+
borderRadius: '50%',
|
|
29
|
+
objectFit: 'cover',
|
|
30
|
+
},
|
|
31
|
+
'&.small .image': {
|
|
32
|
+
width: 20,
|
|
33
|
+
height: 20,
|
|
34
|
+
},
|
|
35
|
+
}),
|
|
36
|
+
...(Array.isArray(sx) ? sx : [sx]),
|
|
37
|
+
]}
|
|
38
|
+
>
|
|
33
39
|
{thumbnail ? (
|
|
34
40
|
<Image
|
|
35
41
|
src={thumbnail}
|
|
36
|
-
width={
|
|
37
|
-
height={
|
|
42
|
+
width={size === 'small' ? 20 : 40}
|
|
43
|
+
height={size === 'small' ? 20 : 40}
|
|
38
44
|
alt={value ?? ''}
|
|
39
|
-
className={
|
|
40
|
-
[classes.root]: true,
|
|
41
|
-
[classes.sizeSmall]: size === 'small',
|
|
42
|
-
})}
|
|
45
|
+
className={classes.image}
|
|
43
46
|
/>
|
|
44
47
|
) : (
|
|
45
|
-
<div>{store_label}</div>
|
|
48
|
+
<div className={classes.image}>{store_label}</div>
|
|
46
49
|
)}
|
|
47
|
-
|
|
50
|
+
</Box>
|
|
48
51
|
)
|
|
49
52
|
}
|