@graphcommerce/ecommerce-ui 9.0.4-canary.9 → 9.0.4
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 +7 -21
- package/components/ComposedSubmitButton/ComposedSubmitButton.tsx +1 -1
- package/components/ComposedSubmitButton/ComposedSubmitLinkOrButton.tsx +1 -1
- package/components/FormComponents/CheckboxButtonGroup.tsx +47 -35
- package/components/FormComponents/CheckboxElement.tsx +8 -18
- package/components/FormComponents/InputBaseElement.tsx +18 -27
- package/components/FormComponents/NumberFieldElement.tsx +8 -15
- package/components/FormComponents/RadioButtonGroup.tsx +43 -32
- package/components/FormComponents/SelectElement.tsx +75 -21
- package/components/FormComponents/SliderElement.tsx +16 -32
- package/components/FormComponents/SwitchElement.tsx +14 -20
- package/components/FormComponents/TextFieldElement.tsx +21 -30
- package/components/FormComponents/index.ts +1 -0
- package/components/PreviewMode/LightTooltip.tsx +1 -1
- package/components/PreviewMode/PreviewMode.tsx +138 -2
- package/components/PreviewMode/previewModeDefaults.ts +1 -1
- package/package.json +7 -7
- package/components/FormComponents/types.ts +0 -26
- package/components/PreviewMode/PreviewModeDisabled.tsx +0 -56
- package/components/PreviewMode/PreviewModeEnabled.tsx +0 -98
package/CHANGELOG.md
CHANGED
|
@@ -1,32 +1,18 @@
|
|
|
1
1
|
# @graphcommerce/ecommerce-ui
|
|
2
2
|
|
|
3
|
-
## 9.0.4
|
|
3
|
+
## 9.0.4
|
|
4
4
|
|
|
5
|
-
## 9.0.
|
|
5
|
+
## 9.0.3
|
|
6
6
|
|
|
7
|
-
## 9.0.
|
|
7
|
+
## 9.0.3-canary.0
|
|
8
8
|
|
|
9
|
-
## 9.0.
|
|
9
|
+
## 9.0.2
|
|
10
10
|
|
|
11
|
-
## 9.0.
|
|
11
|
+
## 9.0.2-canary.0
|
|
12
12
|
|
|
13
|
-
## 9.0.
|
|
13
|
+
## 9.0.1
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
- [`026114e`](https://github.com/graphcommerce-org/graphcommerce/commit/026114ece325d8f675ba8820c6b63345e48532fa) - Sovle issue where showValid would be forwarded to the textField element ([@paales](https://github.com/paales))
|
|
18
|
-
|
|
19
|
-
## 9.0.4-canary.3
|
|
20
|
-
|
|
21
|
-
## 9.0.4-canary.2
|
|
22
|
-
|
|
23
|
-
## 9.0.4-canary.1
|
|
24
|
-
|
|
25
|
-
### Patch Changes
|
|
26
|
-
|
|
27
|
-
- [#2470](https://github.com/graphcommerce-org/graphcommerce/pull/2470) [`910e6aa`](https://github.com/graphcommerce-org/graphcommerce/commit/910e6aab024a925bb042cf17968b2ab826f97d88) - Refactor the FormComponents for better TypeScript checking performance. ([@paales](https://github.com/paales))
|
|
28
|
-
|
|
29
|
-
## 9.0.4-canary.0
|
|
15
|
+
## 9.0.1-canary.1
|
|
30
16
|
|
|
31
17
|
## 9.0.0
|
|
32
18
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ButtonProps } from '@graphcommerce/next-ui'
|
|
2
|
-
import { Button,
|
|
2
|
+
import { Button, IconSvg, iconChevronRight } from '@graphcommerce/next-ui'
|
|
3
3
|
import type { ComposedSubmitRenderComponentProps } from '@graphcommerce/react-hook-form'
|
|
4
4
|
import { forwardRef } from 'react'
|
|
5
5
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { LinkOrButtonProps } from '@graphcommerce/next-ui'
|
|
2
|
-
import {
|
|
2
|
+
import { IconSvg, LinkOrButton, iconChevronRight } from '@graphcommerce/next-ui'
|
|
3
3
|
import type { ComposedSubmitRenderComponentProps } from '@graphcommerce/react-hook-form'
|
|
4
4
|
import { forwardRef } from 'react'
|
|
5
5
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FieldValues } from '@graphcommerce/react-hook-form'
|
|
1
|
+
import type { FieldValues, UseControllerProps } from '@graphcommerce/react-hook-form'
|
|
2
2
|
import { useController } from '@graphcommerce/react-hook-form'
|
|
3
3
|
import { i18n } from '@lingui/core'
|
|
4
4
|
import type { CheckboxProps } from '@mui/material'
|
|
@@ -11,33 +11,27 @@ import {
|
|
|
11
11
|
FormLabel,
|
|
12
12
|
useTheme,
|
|
13
13
|
} from '@mui/material'
|
|
14
|
-
import type { BaseControllerProps } from './types'
|
|
15
14
|
|
|
16
|
-
type
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
options: TOption[]
|
|
15
|
+
export type CheckboxButtonGroupProps<T extends FieldValues> = {
|
|
16
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17
|
+
options: { id: string | number; label: string }[] | any[]
|
|
20
18
|
helperText?: string
|
|
21
19
|
required?: boolean
|
|
22
20
|
label?: string
|
|
23
|
-
labelKey?:
|
|
24
|
-
valueKey?:
|
|
25
|
-
|
|
21
|
+
labelKey?: string
|
|
22
|
+
valueKey?: string
|
|
23
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
24
|
+
onChange?: Function
|
|
25
|
+
returnObject?: boolean
|
|
26
26
|
disabled?: boolean
|
|
27
27
|
row?: boolean
|
|
28
28
|
checkboxColor?: CheckboxProps['color']
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export type CheckboxButtonGroupProps<
|
|
32
|
-
TFieldValues extends FieldValues = FieldValues,
|
|
33
|
-
TOption extends OptionBase = OptionBase,
|
|
34
|
-
> = BaseControllerProps<TFieldValues> & AdditionalProps<TOption>
|
|
29
|
+
} & UseControllerProps<T>
|
|
35
30
|
|
|
36
|
-
|
|
31
|
+
/** @public */
|
|
32
|
+
export function CheckboxButtonGroup<TFieldValues extends FieldValues>(
|
|
37
33
|
props: CheckboxButtonGroupProps<TFieldValues>,
|
|
38
|
-
)
|
|
39
|
-
|
|
40
|
-
function CheckboxButtonGroupBase(props: CheckboxButtonGroupProps) {
|
|
34
|
+
): JSX.Element {
|
|
41
35
|
const {
|
|
42
36
|
helperText,
|
|
43
37
|
options,
|
|
@@ -46,6 +40,7 @@ function CheckboxButtonGroupBase(props: CheckboxButtonGroupProps) {
|
|
|
46
40
|
required,
|
|
47
41
|
labelKey = 'label',
|
|
48
42
|
valueKey = 'id',
|
|
43
|
+
returnObject,
|
|
49
44
|
disabled,
|
|
50
45
|
row,
|
|
51
46
|
control,
|
|
@@ -70,37 +65,57 @@ function CheckboxButtonGroupBase(props: CheckboxButtonGroupProps) {
|
|
|
70
65
|
|
|
71
66
|
const parsedHelperText = error ? error.message : helperText
|
|
72
67
|
|
|
73
|
-
const handleChange = (
|
|
74
|
-
|
|
75
|
-
const newArray = [...
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
68
|
+
const handleChange = (index: number | string) => {
|
|
69
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
70
|
+
const newArray: (string | number)[] | any[] = [...value]
|
|
71
|
+
const exists =
|
|
72
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
73
|
+
value.findIndex((i: any) => (returnObject ? i[valueKey] === index : i === index)) === -1
|
|
74
|
+
if (exists) {
|
|
75
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
76
|
+
newArray.push(returnObject ? options.find((i) => i[valueKey] === index) : index)
|
|
80
77
|
} else {
|
|
81
|
-
newArray.splice(
|
|
78
|
+
newArray.splice(
|
|
79
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
80
|
+
value.findIndex((i: any) => (returnObject ? i[valueKey] === index : i === index)),
|
|
81
|
+
1,
|
|
82
|
+
)
|
|
82
83
|
}
|
|
83
|
-
|
|
84
|
+
// setValue(name, newArray, { shouldValidate: true })
|
|
84
85
|
onChange(newArray)
|
|
85
|
-
rest.onChange
|
|
86
|
+
if (typeof rest.onChange === 'function') {
|
|
87
|
+
rest.onChange(newArray)
|
|
88
|
+
}
|
|
86
89
|
}
|
|
87
90
|
|
|
88
91
|
return (
|
|
89
92
|
<FormControl error={invalid} required={required}>
|
|
90
93
|
{label && <FormLabel error={invalid}>{label}</FormLabel>}
|
|
91
94
|
<FormGroup row={row}>
|
|
92
|
-
{options.map((option) => {
|
|
95
|
+
{options.map((option: any) => {
|
|
93
96
|
const optionKey = option[valueKey]
|
|
94
|
-
|
|
97
|
+
if (!optionKey) {
|
|
98
|
+
console.error(
|
|
99
|
+
`CheckboxButtonGroup: valueKey ${valueKey} does not exist on option`,
|
|
100
|
+
option,
|
|
101
|
+
)
|
|
102
|
+
}
|
|
103
|
+
const isChecked =
|
|
104
|
+
value.findIndex((item) =>
|
|
105
|
+
returnObject ? item[valueKey] === optionKey : item === optionKey,
|
|
106
|
+
) !== -1
|
|
95
107
|
return (
|
|
96
108
|
<FormControlLabel
|
|
97
109
|
control={
|
|
98
110
|
<Checkbox
|
|
99
|
-
sx={{
|
|
111
|
+
sx={{
|
|
112
|
+
color: invalid ? theme.palette.error.main : undefined,
|
|
113
|
+
}}
|
|
100
114
|
color={checkboxColor || 'primary'}
|
|
101
115
|
value={optionKey}
|
|
102
116
|
checked={isChecked}
|
|
103
117
|
disabled={disabled}
|
|
118
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
104
119
|
onChange={() => handleChange(optionKey)}
|
|
105
120
|
/>
|
|
106
121
|
}
|
|
@@ -114,6 +129,3 @@ function CheckboxButtonGroupBase(props: CheckboxButtonGroupProps) {
|
|
|
114
129
|
</FormControl>
|
|
115
130
|
)
|
|
116
131
|
}
|
|
117
|
-
|
|
118
|
-
/** @public */
|
|
119
|
-
export const CheckboxButtonGroup = CheckboxButtonGroupBase as CheckboxButtonGroupComponent
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FieldValues } from '@graphcommerce/react-hook-form'
|
|
1
|
+
import type { ControllerProps, FieldValues } from '@graphcommerce/react-hook-form'
|
|
2
2
|
import { useController } from '@graphcommerce/react-hook-form'
|
|
3
3
|
import { i18n } from '@lingui/core'
|
|
4
4
|
import type {
|
|
@@ -16,23 +16,18 @@ import {
|
|
|
16
16
|
FormHelperText,
|
|
17
17
|
useForkRef,
|
|
18
18
|
} from '@mui/material'
|
|
19
|
-
import type { FieldElementProps } from './types'
|
|
20
19
|
|
|
21
|
-
type
|
|
20
|
+
export type CheckboxElementProps<T extends FieldValues> = Omit<CheckboxProps, 'name'> & {
|
|
22
21
|
label?: FormControlLabelProps['label']
|
|
23
22
|
helperText?: string
|
|
24
23
|
sx?: SxProps<Theme>
|
|
25
24
|
formControl?: Omit<FormControlProps<'div'>, 'required' | 'error'>
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export type CheckboxElementProps<TFieldValues extends FieldValues = FieldValues> =
|
|
29
|
-
FieldElementProps<TFieldValues, CheckboxProps> & AdditionalProps
|
|
25
|
+
} & Omit<ControllerProps<T>, 'render'>
|
|
30
26
|
|
|
31
|
-
|
|
27
|
+
/** @public */
|
|
28
|
+
export function CheckboxElement<TFieldValues extends FieldValues>(
|
|
32
29
|
props: CheckboxElementProps<TFieldValues>,
|
|
33
|
-
)
|
|
34
|
-
|
|
35
|
-
function CheckboxElementBase(props: CheckboxElementProps): JSX.Element {
|
|
30
|
+
): JSX.Element {
|
|
36
31
|
const {
|
|
37
32
|
name,
|
|
38
33
|
rules = {},
|
|
@@ -53,7 +48,7 @@ function CheckboxElementBase(props: CheckboxElementProps): JSX.Element {
|
|
|
53
48
|
}
|
|
54
49
|
|
|
55
50
|
const {
|
|
56
|
-
field: { value, onChange, ref,
|
|
51
|
+
field: { value, onChange, ref, ...field },
|
|
57
52
|
fieldState: { invalid, error },
|
|
58
53
|
} = useController({
|
|
59
54
|
name,
|
|
@@ -74,9 +69,7 @@ function CheckboxElementBase(props: CheckboxElementProps): JSX.Element {
|
|
|
74
69
|
control={
|
|
75
70
|
<Checkbox
|
|
76
71
|
{...rest}
|
|
77
|
-
|
|
78
|
-
disabled={disabled}
|
|
79
|
-
name={name}
|
|
72
|
+
{...field}
|
|
80
73
|
inputRef={useForkRef(ref, rest.inputRef)}
|
|
81
74
|
color={rest.color || 'primary'}
|
|
82
75
|
sx={{
|
|
@@ -94,6 +87,3 @@ function CheckboxElementBase(props: CheckboxElementProps): JSX.Element {
|
|
|
94
87
|
</FormControl>
|
|
95
88
|
)
|
|
96
89
|
}
|
|
97
|
-
|
|
98
|
-
/** @public */
|
|
99
|
-
export const CheckboxElement = CheckboxElementBase as CheckboxElementComponent
|
|
@@ -1,21 +1,24 @@
|
|
|
1
|
-
|
|
2
|
-
import { useController } from '@graphcommerce/react-hook-form'
|
|
1
|
+
/* eslint-disable no-nested-ternary */
|
|
2
|
+
import { FieldValues, UseControllerProps, useController } from '@graphcommerce/react-hook-form'
|
|
3
3
|
import { i18n } from '@lingui/core'
|
|
4
|
-
import
|
|
5
|
-
import { InputBase } from '@mui/material'
|
|
4
|
+
import { InputBase, InputBaseProps } from '@mui/material'
|
|
6
5
|
import React from 'react'
|
|
7
|
-
import type { FieldElementProps } from './types'
|
|
8
6
|
|
|
9
|
-
export type InputBaseElementProps<
|
|
10
|
-
|
|
7
|
+
export type InputBaseElementProps<T extends FieldValues = FieldValues> = Omit<
|
|
8
|
+
InputBaseProps,
|
|
9
|
+
'name' | 'defaultValue'
|
|
10
|
+
> & {
|
|
11
|
+
showValid?: boolean
|
|
12
|
+
} & UseControllerProps<T>
|
|
11
13
|
|
|
12
14
|
type InputBaseElementComponent = <TFieldValues extends FieldValues>(
|
|
13
15
|
props: InputBaseElementProps<TFieldValues> & { ref?: React.Ref<HTMLInputElement> },
|
|
14
|
-
) =>
|
|
16
|
+
) => JSX.Element
|
|
15
17
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
export const InputBaseElement = React.forwardRef<
|
|
19
|
+
HTMLInputElement,
|
|
20
|
+
InputBaseElementProps<FieldValues>
|
|
21
|
+
>((props: InputBaseElementProps<FieldValues>, ref: React.Ref<HTMLInputElement>): JSX.Element => {
|
|
19
22
|
const {
|
|
20
23
|
type,
|
|
21
24
|
required,
|
|
@@ -24,26 +27,19 @@ function InputBaseElementBase(
|
|
|
24
27
|
defaultValue,
|
|
25
28
|
rules = {},
|
|
26
29
|
shouldUnregister,
|
|
30
|
+
showValid,
|
|
27
31
|
disabled,
|
|
28
|
-
ref,
|
|
29
32
|
...rest
|
|
30
33
|
} = props
|
|
31
34
|
|
|
32
|
-
if (required && !rules
|
|
35
|
+
if (required && !rules?.required) {
|
|
33
36
|
rules.required = i18n._(/* i18n */ 'This field is required')
|
|
34
37
|
}
|
|
35
38
|
|
|
36
39
|
const {
|
|
37
40
|
field,
|
|
38
41
|
fieldState: { error },
|
|
39
|
-
} = useController({
|
|
40
|
-
name,
|
|
41
|
-
control,
|
|
42
|
-
rules,
|
|
43
|
-
defaultValue,
|
|
44
|
-
shouldUnregister,
|
|
45
|
-
disabled,
|
|
46
|
-
})
|
|
42
|
+
} = useController({ name, control, rules, defaultValue, shouldUnregister, disabled })
|
|
47
43
|
|
|
48
44
|
return (
|
|
49
45
|
<InputBase
|
|
@@ -55,9 +51,4 @@ function InputBaseElementBase(
|
|
|
55
51
|
error={Boolean(error) || rest.error}
|
|
56
52
|
/>
|
|
57
53
|
)
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/** @public */
|
|
61
|
-
export const InputBaseElement = React.forwardRef<HTMLInputElement, InputBaseElementProps>(
|
|
62
|
-
(props, ref) => InputBaseElementBase({ ...props, ref }),
|
|
63
|
-
) as InputBaseElementComponent
|
|
54
|
+
}) as InputBaseElementComponent
|
|
@@ -5,25 +5,20 @@ import {
|
|
|
5
5
|
IconSvg,
|
|
6
6
|
responsiveVal,
|
|
7
7
|
} from '@graphcommerce/next-ui'
|
|
8
|
-
import type { FieldValues } from '@graphcommerce/react-hook-form'
|
|
9
|
-
import { useController } from '@graphcommerce/react-hook-form'
|
|
8
|
+
import type { ControllerProps, FieldValues } from '@graphcommerce/react-hook-form'
|
|
9
|
+
import { Controller, useController } from '@graphcommerce/react-hook-form'
|
|
10
10
|
import { i18n } from '@lingui/core'
|
|
11
11
|
import type { IconButtonProps, SxProps, TextFieldProps, Theme } from '@mui/material'
|
|
12
12
|
import { Fab, TextField, useForkRef } from '@mui/material'
|
|
13
|
-
import type { FieldElementProps } from './types'
|
|
14
13
|
|
|
15
|
-
type
|
|
14
|
+
export type NumberFieldElementProps<T extends FieldValues = FieldValues> = Omit<
|
|
15
|
+
TextFieldProps,
|
|
16
|
+
'type' | 'defaultValue'
|
|
17
|
+
> & {
|
|
16
18
|
DownProps?: IconButtonProps
|
|
17
19
|
UpProps?: IconButtonProps
|
|
18
20
|
sx?: SxProps<Theme>
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export type NumberFieldElementProps<TFieldValues extends FieldValues = FieldValues> =
|
|
22
|
-
FieldElementProps<TFieldValues, Omit<TextFieldProps, 'type'>> & AdditionalProps
|
|
23
|
-
|
|
24
|
-
type NumberFieldElementComponent = <TFieldValues extends FieldValues>(
|
|
25
|
-
props: NumberFieldElementProps<TFieldValues>,
|
|
26
|
-
) => React.ReactNode
|
|
21
|
+
} & Omit<ControllerProps<T>, 'render'>
|
|
27
22
|
|
|
28
23
|
type OwnerState = { size?: 'small' | 'medium' }
|
|
29
24
|
const componentName = 'TextInputNumber'
|
|
@@ -34,7 +29,7 @@ const { withState } = extendableComponent<OwnerState, typeof componentName, type
|
|
|
34
29
|
)
|
|
35
30
|
|
|
36
31
|
/** @public */
|
|
37
|
-
function
|
|
32
|
+
export function NumberFieldElement<T extends FieldValues>(props: NumberFieldElementProps<T>) {
|
|
38
33
|
const {
|
|
39
34
|
DownProps = {},
|
|
40
35
|
UpProps = {},
|
|
@@ -187,5 +182,3 @@ function NumberFieldElementBase(props: NumberFieldElementProps) {
|
|
|
187
182
|
/>
|
|
188
183
|
)
|
|
189
184
|
}
|
|
190
|
-
|
|
191
|
-
export const NumberFieldElement = NumberFieldElementBase as NumberFieldElementComponent
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FieldValues } from '@graphcommerce/react-hook-form'
|
|
1
|
+
import type { FieldValues, UseControllerProps } from '@graphcommerce/react-hook-form'
|
|
2
2
|
import { useController } from '@graphcommerce/react-hook-form'
|
|
3
3
|
import { i18n } from '@lingui/core'
|
|
4
4
|
import {
|
|
@@ -11,33 +11,27 @@ import {
|
|
|
11
11
|
useTheme,
|
|
12
12
|
} from '@mui/material'
|
|
13
13
|
import type { ChangeEvent } from 'react'
|
|
14
|
-
import type { BaseControllerProps } from './types'
|
|
15
14
|
|
|
16
|
-
type
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
options: TOption[]
|
|
15
|
+
export type RadioButtonGroupProps<T extends FieldValues> = {
|
|
16
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17
|
+
options: { label: string; id: string | number }[] | any[]
|
|
20
18
|
helperText?: string
|
|
21
19
|
required?: boolean
|
|
22
20
|
label?: string
|
|
23
|
-
labelKey?:
|
|
24
|
-
valueKey?:
|
|
25
|
-
|
|
26
|
-
|
|
21
|
+
labelKey?: string
|
|
22
|
+
valueKey?: string
|
|
23
|
+
type?: 'number' | 'string'
|
|
24
|
+
emptyOptionLabel?: 'string'
|
|
25
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
26
|
+
onChange?: (value: any) => void
|
|
27
|
+
returnObject?: boolean
|
|
27
28
|
row?: boolean
|
|
28
|
-
|
|
29
|
-
}
|
|
29
|
+
} & UseControllerProps<T>
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
TOption extends OptionBase = OptionBase,
|
|
34
|
-
> = BaseControllerProps<TFieldValues> & AdditionalProps<TOption>
|
|
35
|
-
|
|
36
|
-
type RadioButtonGroupComponent = <TFieldValues extends FieldValues>(
|
|
31
|
+
/** @public */
|
|
32
|
+
export function RadioButtonGroup<TFieldValues extends FieldValues>(
|
|
37
33
|
props: RadioButtonGroupProps<TFieldValues>,
|
|
38
|
-
)
|
|
39
|
-
|
|
40
|
-
function RadioButtonGroupBase(props: RadioButtonGroupProps): JSX.Element {
|
|
34
|
+
): JSX.Element {
|
|
41
35
|
const {
|
|
42
36
|
helperText,
|
|
43
37
|
options,
|
|
@@ -47,6 +41,7 @@ function RadioButtonGroupBase(props: RadioButtonGroupProps): JSX.Element {
|
|
|
47
41
|
valueKey = 'id',
|
|
48
42
|
required,
|
|
49
43
|
emptyOptionLabel,
|
|
44
|
+
returnObject,
|
|
50
45
|
row,
|
|
51
46
|
control,
|
|
52
47
|
defaultValue,
|
|
@@ -70,16 +65,26 @@ function RadioButtonGroupBase(props: RadioButtonGroupProps): JSX.Element {
|
|
|
70
65
|
|
|
71
66
|
const parsedHelperText = error ? error.message : helperText
|
|
72
67
|
|
|
73
|
-
const
|
|
74
|
-
const radioValue = event.target.value
|
|
75
|
-
|
|
76
|
-
|
|
68
|
+
const onRadioChange = (event: ChangeEvent<HTMLInputElement>) => {
|
|
69
|
+
const radioValue = (event.target as HTMLInputElement).value
|
|
70
|
+
const returnValue = returnObject
|
|
71
|
+
? options.find((items) => items[valueKey] === radioValue)
|
|
72
|
+
: radioValue
|
|
73
|
+
// setValue(name, returnValue, { shouldValidate: true })
|
|
74
|
+
onChange(returnValue)
|
|
75
|
+
if (typeof rest.onChange === 'function') {
|
|
76
|
+
rest.onChange(returnValue)
|
|
77
|
+
}
|
|
77
78
|
}
|
|
78
79
|
|
|
79
80
|
return (
|
|
80
|
-
<FormControl error={invalid}
|
|
81
|
-
{label &&
|
|
82
|
-
|
|
81
|
+
<FormControl error={invalid}>
|
|
82
|
+
{label && (
|
|
83
|
+
<FormLabel required={required} error={invalid}>
|
|
84
|
+
{label}
|
|
85
|
+
</FormLabel>
|
|
86
|
+
)}
|
|
87
|
+
<RadioGroup onChange={onRadioChange} name={name} row={row} value={value || ''}>
|
|
83
88
|
{emptyOptionLabel && (
|
|
84
89
|
<FormControlLabel
|
|
85
90
|
control={
|
|
@@ -96,6 +101,15 @@ function RadioButtonGroupBase(props: RadioButtonGroupProps): JSX.Element {
|
|
|
96
101
|
)}
|
|
97
102
|
{options.map((option) => {
|
|
98
103
|
const optionKey = option[valueKey]
|
|
104
|
+
if (!optionKey) {
|
|
105
|
+
console.error(
|
|
106
|
+
`CheckboxButtonGroup: valueKey ${valueKey} does not exist on option`,
|
|
107
|
+
option,
|
|
108
|
+
)
|
|
109
|
+
}
|
|
110
|
+
const isChecked = !!(
|
|
111
|
+
value && (returnObject ? value[valueKey] === optionKey : value === optionKey)
|
|
112
|
+
)
|
|
99
113
|
return (
|
|
100
114
|
<FormControlLabel
|
|
101
115
|
control={
|
|
@@ -103,7 +117,7 @@ function RadioButtonGroupBase(props: RadioButtonGroupProps): JSX.Element {
|
|
|
103
117
|
sx={{
|
|
104
118
|
color: invalid ? theme.palette.error.main : undefined,
|
|
105
119
|
}}
|
|
106
|
-
checked={
|
|
120
|
+
checked={isChecked}
|
|
107
121
|
/>
|
|
108
122
|
}
|
|
109
123
|
value={optionKey}
|
|
@@ -117,6 +131,3 @@ function RadioButtonGroupBase(props: RadioButtonGroupProps): JSX.Element {
|
|
|
117
131
|
</FormControl>
|
|
118
132
|
)
|
|
119
133
|
}
|
|
120
|
-
|
|
121
|
-
/** @public */
|
|
122
|
-
export const RadioButtonGroup = RadioButtonGroupBase as RadioButtonGroupComponent
|
|
@@ -1,31 +1,87 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { InputCheckmark } from '@graphcommerce/next-ui'
|
|
2
|
+
import type { ControllerProps, FieldValues } from '@graphcommerce/react-hook-form'
|
|
3
|
+
import { useController } from '@graphcommerce/react-hook-form'
|
|
4
|
+
import { i18n } from '@lingui/core'
|
|
2
5
|
import type { TextFieldProps } from '@mui/material'
|
|
3
|
-
import { MenuItem } from '@mui/material'
|
|
4
|
-
import { TextFieldElement, type TextFieldElementProps } from './TextFieldElement'
|
|
6
|
+
import { MenuItem, TextField, useForkRef } from '@mui/material'
|
|
5
7
|
|
|
6
8
|
type OptionBase = { id: string | number; label: string | number }
|
|
7
9
|
|
|
8
|
-
type
|
|
10
|
+
export type SelectElementProps<T extends FieldValues, O extends OptionBase> = Omit<
|
|
11
|
+
TextFieldProps,
|
|
12
|
+
'name' | 'type' | 'onChange' | 'defaultValue'
|
|
13
|
+
> & {
|
|
14
|
+
options?: O[]
|
|
15
|
+
type?: 'string' | 'number'
|
|
16
|
+
onChange?: (value: string | number) => void
|
|
17
|
+
showValid?: boolean
|
|
18
|
+
} & Omit<ControllerProps<T>, 'render'>
|
|
9
19
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
20
|
+
/** @public */
|
|
21
|
+
export function SelectElement<TFieldValues extends FieldValues, O extends OptionBase>({
|
|
22
|
+
name,
|
|
23
|
+
required,
|
|
24
|
+
options = [],
|
|
25
|
+
type,
|
|
26
|
+
control,
|
|
27
|
+
defaultValue,
|
|
28
|
+
rules = {},
|
|
29
|
+
showValid,
|
|
30
|
+
disabled,
|
|
31
|
+
shouldUnregister,
|
|
32
|
+
...rest
|
|
33
|
+
}: SelectElementProps<TFieldValues, O>): JSX.Element {
|
|
34
|
+
const isNativeSelect = !!rest.SelectProps?.native
|
|
35
|
+
const ChildComponent = isNativeSelect ? 'option' : MenuItem
|
|
14
36
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
37
|
+
if (required && !rules.required) {
|
|
38
|
+
rules.required = i18n._(/* i18n */ 'This field is required')
|
|
39
|
+
}
|
|
18
40
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
41
|
+
const {
|
|
42
|
+
field: { onChange, value, ref, ...field },
|
|
43
|
+
fieldState: { invalid, error },
|
|
44
|
+
} = useController({
|
|
45
|
+
name,
|
|
46
|
+
rules,
|
|
47
|
+
control,
|
|
48
|
+
defaultValue,
|
|
49
|
+
disabled,
|
|
50
|
+
shouldUnregister,
|
|
51
|
+
})
|
|
23
52
|
|
|
24
|
-
|
|
25
|
-
|
|
53
|
+
// handle shrink on number input fields
|
|
54
|
+
if (type === 'number' && typeof value !== 'undefined') {
|
|
55
|
+
rest.InputLabelProps = rest.InputLabelProps || {}
|
|
56
|
+
rest.InputLabelProps.shrink = true
|
|
57
|
+
}
|
|
26
58
|
|
|
27
59
|
return (
|
|
28
|
-
<
|
|
60
|
+
<TextField
|
|
61
|
+
{...rest}
|
|
62
|
+
value={value ?? ''}
|
|
63
|
+
{...field}
|
|
64
|
+
inputRef={useForkRef(ref, rest.inputRef)}
|
|
65
|
+
onChange={(event) => {
|
|
66
|
+
let item: number | string | O | undefined = event.target.value
|
|
67
|
+
if (type === 'number') item = Number(item)
|
|
68
|
+
rest.onChange?.(item)
|
|
69
|
+
onChange(item)
|
|
70
|
+
}}
|
|
71
|
+
select
|
|
72
|
+
required={required}
|
|
73
|
+
error={invalid}
|
|
74
|
+
helperText={error ? error.message : rest.helperText}
|
|
75
|
+
InputProps={{
|
|
76
|
+
...rest.InputProps,
|
|
77
|
+
endAdornment:
|
|
78
|
+
showValid && value && !error ? (
|
|
79
|
+
<InputCheckmark show={!error} />
|
|
80
|
+
) : (
|
|
81
|
+
rest.InputProps?.endAdornment
|
|
82
|
+
),
|
|
83
|
+
}}
|
|
84
|
+
>
|
|
29
85
|
{/* eslint-disable-next-line jsx-a11y/control-has-associated-label */}
|
|
30
86
|
{isNativeSelect && <option />}
|
|
31
87
|
{options.map((item) => (
|
|
@@ -33,8 +89,6 @@ function SelectElementBase(props: SelectElementProps): JSX.Element {
|
|
|
33
89
|
{item.label}
|
|
34
90
|
</ChildComponent>
|
|
35
91
|
))}
|
|
36
|
-
</
|
|
92
|
+
</TextField>
|
|
37
93
|
)
|
|
38
94
|
}
|
|
39
|
-
|
|
40
|
-
export const SelectElement = SelectElementBase as SelectElementComponent
|
|
@@ -1,41 +1,28 @@
|
|
|
1
|
-
import type { FieldValues } from '@graphcommerce/react-hook-form'
|
|
1
|
+
import type { ControllerProps, FieldValues } from '@graphcommerce/react-hook-form'
|
|
2
2
|
import { useController } from '@graphcommerce/react-hook-form'
|
|
3
3
|
import { i18n } from '@lingui/core'
|
|
4
4
|
import type { FormControlProps, SliderProps } from '@mui/material'
|
|
5
5
|
import { FormControl, FormHelperText, FormLabel, Slider } from '@mui/material'
|
|
6
|
-
import React from 'react'
|
|
7
|
-
import type { FieldElementProps } from './types'
|
|
8
6
|
|
|
9
|
-
type
|
|
7
|
+
export type SliderElementProps<T extends FieldValues> = Omit<SliderProps, 'control'> & {
|
|
10
8
|
label?: string
|
|
11
9
|
required?: boolean
|
|
12
10
|
formControlProps?: FormControlProps
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export type SliderElementProps<TFieldValues extends FieldValues = FieldValues> = FieldElementProps<
|
|
16
|
-
TFieldValues,
|
|
17
|
-
Omit<SliderProps, 'name'>
|
|
18
|
-
> &
|
|
19
|
-
AdditionalProps
|
|
20
|
-
|
|
21
|
-
type SliderElementComponent = <TFieldValues extends FieldValues>(
|
|
22
|
-
props: SliderElementProps<TFieldValues>,
|
|
23
|
-
) => React.ReactNode
|
|
24
|
-
|
|
25
|
-
function SliderElementBase(props: SliderElementProps): JSX.Element {
|
|
26
|
-
const {
|
|
27
|
-
name,
|
|
28
|
-
control,
|
|
29
|
-
label,
|
|
30
|
-
rules = {},
|
|
31
|
-
required,
|
|
32
|
-
formControlProps,
|
|
33
|
-
defaultValue,
|
|
34
|
-
disabled,
|
|
35
|
-
shouldUnregister,
|
|
36
|
-
...other
|
|
37
|
-
} = props
|
|
11
|
+
} & Omit<ControllerProps<T>, 'render'>
|
|
38
12
|
|
|
13
|
+
/** @public */
|
|
14
|
+
export function SliderElement<TFieldValues extends FieldValues>({
|
|
15
|
+
name,
|
|
16
|
+
control,
|
|
17
|
+
label,
|
|
18
|
+
rules = {},
|
|
19
|
+
required,
|
|
20
|
+
formControlProps,
|
|
21
|
+
defaultValue,
|
|
22
|
+
disabled,
|
|
23
|
+
shouldUnregister,
|
|
24
|
+
...other
|
|
25
|
+
}: SliderElementProps<TFieldValues>) {
|
|
39
26
|
if (required && !rules.required) {
|
|
40
27
|
rules.required = i18n._(/* i18n */ 'This field is required')
|
|
41
28
|
}
|
|
@@ -66,6 +53,3 @@ function SliderElementBase(props: SliderElementProps): JSX.Element {
|
|
|
66
53
|
</FormControl>
|
|
67
54
|
)
|
|
68
55
|
}
|
|
69
|
-
|
|
70
|
-
/** @public */
|
|
71
|
-
export const SliderElement = SliderElementBase as SliderElementComponent
|
|
@@ -1,25 +1,22 @@
|
|
|
1
|
-
import type { FieldValues } from '@graphcommerce/react-hook-form'
|
|
1
|
+
import type { ControllerProps, FieldValues } from '@graphcommerce/react-hook-form'
|
|
2
2
|
import { useController } from '@graphcommerce/react-hook-form'
|
|
3
|
-
import type { FormControlLabelProps
|
|
3
|
+
import type { FormControlLabelProps } from '@mui/material'
|
|
4
4
|
import { FormControlLabel, Switch } from '@mui/material'
|
|
5
|
-
import React from 'react'
|
|
6
|
-
import type { FieldElementProps } from './types'
|
|
7
5
|
|
|
8
|
-
type
|
|
6
|
+
type IProps = Omit<FormControlLabelProps, 'control'>
|
|
9
7
|
|
|
10
|
-
export type SwitchElementProps<
|
|
11
|
-
TFieldValues,
|
|
12
|
-
SwitchProps
|
|
13
|
-
> &
|
|
14
|
-
AdditionalProps
|
|
15
|
-
|
|
16
|
-
type SwitchElementComponent = <TFieldValues extends FieldValues>(
|
|
17
|
-
props: SwitchElementProps<TFieldValues>,
|
|
18
|
-
) => React.ReactNode
|
|
19
|
-
|
|
20
|
-
function SwitchElementBase(props: SwitchElementProps): JSX.Element {
|
|
21
|
-
const { name, control, defaultValue, disabled, shouldUnregister, rules, ...other } = props
|
|
8
|
+
export type SwitchElementProps<T extends FieldValues> = IProps & Omit<ControllerProps<T>, 'render'>
|
|
22
9
|
|
|
10
|
+
/** @public */
|
|
11
|
+
export function SwitchElement<TFieldValues extends FieldValues>({
|
|
12
|
+
name,
|
|
13
|
+
control,
|
|
14
|
+
defaultValue,
|
|
15
|
+
disabled,
|
|
16
|
+
shouldUnregister,
|
|
17
|
+
rules,
|
|
18
|
+
...other
|
|
19
|
+
}: SwitchElementProps<TFieldValues>) {
|
|
23
20
|
const { field } = useController({
|
|
24
21
|
name,
|
|
25
22
|
control,
|
|
@@ -31,6 +28,3 @@ function SwitchElementBase(props: SwitchElementProps): JSX.Element {
|
|
|
31
28
|
|
|
32
29
|
return <FormControlLabel control={<Switch {...field} checked={!!field.value} />} {...other} />
|
|
33
30
|
}
|
|
34
|
-
|
|
35
|
-
/** @public */
|
|
36
|
-
export const SwitchElement = SwitchElementBase as SwitchElementComponent
|
|
@@ -1,37 +1,32 @@
|
|
|
1
1
|
/* eslint-disable no-nested-ternary */
|
|
2
2
|
import { InputCheckmark } from '@graphcommerce/next-ui'
|
|
3
|
-
import type { FieldValues } from '@graphcommerce/react-hook-form'
|
|
3
|
+
import type { FieldValues, UseControllerProps } from '@graphcommerce/react-hook-form'
|
|
4
4
|
import { emailPattern, useController } from '@graphcommerce/react-hook-form'
|
|
5
5
|
import { i18n } from '@lingui/core'
|
|
6
6
|
import type { TextFieldProps } from '@mui/material'
|
|
7
7
|
import { TextField, useForkRef } from '@mui/material'
|
|
8
8
|
import React, { useState } from 'react'
|
|
9
|
-
import type { BaseControllerProps, FieldElementProps } from './types'
|
|
10
9
|
|
|
11
|
-
type
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
props: TextFieldElementProps<TFieldValues>,
|
|
18
|
-
) => React.ReactNode
|
|
10
|
+
export type TextFieldElementProps<T extends FieldValues = FieldValues> = Omit<
|
|
11
|
+
TextFieldProps,
|
|
12
|
+
'name' | 'defaultValue'
|
|
13
|
+
> & {
|
|
14
|
+
showValid?: boolean
|
|
15
|
+
} & UseControllerProps<T>
|
|
19
16
|
|
|
20
17
|
/** @public */
|
|
21
|
-
function
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
} = props as TextFieldProps & ShowValidProps & BaseControllerProps
|
|
34
|
-
|
|
18
|
+
export function TextFieldElement<TFieldValues extends FieldValues>({
|
|
19
|
+
type,
|
|
20
|
+
required,
|
|
21
|
+
name,
|
|
22
|
+
control,
|
|
23
|
+
defaultValue,
|
|
24
|
+
rules = {},
|
|
25
|
+
shouldUnregister,
|
|
26
|
+
showValid,
|
|
27
|
+
disabled,
|
|
28
|
+
...rest
|
|
29
|
+
}: TextFieldElementProps<TFieldValues>): JSX.Element {
|
|
35
30
|
if (required && !rules.required) {
|
|
36
31
|
rules.required = i18n._(/* i18n */ 'This field is required')
|
|
37
32
|
}
|
|
@@ -44,7 +39,7 @@ function TextFieldElementBase(props: TextFieldElementProps): JSX.Element {
|
|
|
44
39
|
}
|
|
45
40
|
|
|
46
41
|
const {
|
|
47
|
-
field: { onChange, ref, value = '',
|
|
42
|
+
field: { onChange, ref, value = '', ...field },
|
|
48
43
|
fieldState: { error },
|
|
49
44
|
} = useController({ name, control, rules, defaultValue, shouldUnregister, disabled })
|
|
50
45
|
|
|
@@ -63,9 +58,7 @@ function TextFieldElementBase(props: TextFieldElementProps): JSX.Element {
|
|
|
63
58
|
return (
|
|
64
59
|
<TextField
|
|
65
60
|
{...rest}
|
|
66
|
-
|
|
67
|
-
name={name}
|
|
68
|
-
disabled={disabled}
|
|
61
|
+
{...field}
|
|
69
62
|
value={value}
|
|
70
63
|
inputProps={{ ...rest.inputProps, onAnimationStart }}
|
|
71
64
|
onChange={(ev) => {
|
|
@@ -90,5 +83,3 @@ function TextFieldElementBase(props: TextFieldElementProps): JSX.Element {
|
|
|
90
83
|
/>
|
|
91
84
|
)
|
|
92
85
|
}
|
|
93
|
-
|
|
94
|
-
export const TextFieldElement = TextFieldElementBase as TextFieldElementComponent
|
|
@@ -2,6 +2,7 @@ export * from './ActionCardListForm'
|
|
|
2
2
|
export * from './CheckboxButtonGroup'
|
|
3
3
|
export * from './CheckboxElement'
|
|
4
4
|
export * from './EmailElement'
|
|
5
|
+
export * from './MultiSelectElement'
|
|
5
6
|
export * from './NumberFieldElement'
|
|
6
7
|
export * from './PasswordElement'
|
|
7
8
|
export * from './PasswordRepeatElement'
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Tooltip, styled, tooltipClasses } from '@mui/material'
|
|
2
2
|
|
|
3
3
|
export const LightTooltip = styled<typeof Tooltip>(({ className, ...props }) => (
|
|
4
4
|
<Tooltip {...props} classes={{ popper: className }} />
|
|
@@ -1,6 +1,20 @@
|
|
|
1
|
+
import type { PreviewData } from '@graphcommerce/graphql'
|
|
2
|
+
import {
|
|
3
|
+
iconChevronRight,
|
|
4
|
+
iconClose,
|
|
5
|
+
iconContrast,
|
|
6
|
+
iconInfo,
|
|
7
|
+
iconRefresh,
|
|
8
|
+
IconSvg,
|
|
9
|
+
MessageSnackbar,
|
|
10
|
+
} from '@graphcommerce/next-ui'
|
|
11
|
+
import { FormAutoSubmit, FormPersist, FormProvider, useForm } from '@graphcommerce/react-hook-form'
|
|
12
|
+
import { Box, IconButton } from '@mui/material'
|
|
1
13
|
import { useRouter } from 'next/router'
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
14
|
+
import { TextFieldElement } from '../FormComponents'
|
|
15
|
+
import { LightTooltip } from './LightTooltip'
|
|
16
|
+
import { PreviewModeActions } from './PreviewModeActions'
|
|
17
|
+
import { PreviewModeToolbar } from './PreviewModeToolbar'
|
|
4
18
|
|
|
5
19
|
function getPreviewUrl() {
|
|
6
20
|
const url = new URL(window.location.href)
|
|
@@ -9,6 +23,128 @@ function getPreviewUrl() {
|
|
|
9
23
|
return url
|
|
10
24
|
}
|
|
11
25
|
|
|
26
|
+
function PreviewModeEnabled() {
|
|
27
|
+
const form = useForm<{ secret: string; previewData: PreviewData }>({})
|
|
28
|
+
|
|
29
|
+
const submit = form.handleSubmit((formValues) => {
|
|
30
|
+
const url = getPreviewUrl()
|
|
31
|
+
url.searchParams.append('action', 'update')
|
|
32
|
+
|
|
33
|
+
Object.entries(formValues).forEach(([key, value]) => {
|
|
34
|
+
url.searchParams.append(key, JSON.stringify(value))
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
window.location.href = url.toString()
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
const exitHandler = form.handleSubmit(() => {
|
|
41
|
+
const url = getPreviewUrl()
|
|
42
|
+
url.searchParams.append('action', 'exit')
|
|
43
|
+
|
|
44
|
+
window.location.href = url.toString()
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
const revalidateHandler = form.handleSubmit((formValues) => {
|
|
48
|
+
const url = getPreviewUrl()
|
|
49
|
+
Object.entries(formValues).forEach(([key, value]) => {
|
|
50
|
+
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
|
51
|
+
url.searchParams.append(key, `${value}`)
|
|
52
|
+
})
|
|
53
|
+
url.searchParams.append('action', 'revalidate')
|
|
54
|
+
window.location.href = url.toString()
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<FormProvider {...form}>
|
|
59
|
+
<MessageSnackbar
|
|
60
|
+
variant='pill'
|
|
61
|
+
severity='warning'
|
|
62
|
+
disableBackdropClick
|
|
63
|
+
disableClose
|
|
64
|
+
open
|
|
65
|
+
icon={iconContrast}
|
|
66
|
+
onClose={() => {}}
|
|
67
|
+
action={
|
|
68
|
+
<>
|
|
69
|
+
<PreviewModeActions />
|
|
70
|
+
<LightTooltip title='Revalidate / Regenerate Page' placement='top'>
|
|
71
|
+
<IconButton color='secondary' type='submit' onClick={revalidateHandler}>
|
|
72
|
+
<IconSvg src={iconRefresh} />
|
|
73
|
+
</IconButton>
|
|
74
|
+
</LightTooltip>
|
|
75
|
+
<LightTooltip title='Stop preview mode' placement='top'>
|
|
76
|
+
<IconButton color='secondary' type='submit' onClick={exitHandler}>
|
|
77
|
+
<IconSvg src={iconClose} />
|
|
78
|
+
</IconButton>
|
|
79
|
+
</LightTooltip>
|
|
80
|
+
</>
|
|
81
|
+
}
|
|
82
|
+
>
|
|
83
|
+
<Box sx={{ display: 'grid', gridAutoFlow: 'column', placeItems: 'center', gap: 4 }}>
|
|
84
|
+
<Box sx={{ display: 'flex', placeItems: 'center' }}>
|
|
85
|
+
Preview Mode{' '}
|
|
86
|
+
<LightTooltip title='You are currently viewing the website in Preview Mode (caches are disabled).'>
|
|
87
|
+
<IconButton size='small'>
|
|
88
|
+
<IconSvg src={iconInfo} />
|
|
89
|
+
</IconButton>
|
|
90
|
+
</LightTooltip>
|
|
91
|
+
</Box>
|
|
92
|
+
<PreviewModeToolbar />
|
|
93
|
+
</Box>
|
|
94
|
+
</MessageSnackbar>
|
|
95
|
+
<FormPersist form={form} name='PreviewModePreviewData' />
|
|
96
|
+
<FormAutoSubmit control={form.control} submit={submit} />
|
|
97
|
+
</FormProvider>
|
|
98
|
+
)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function PreviewModeDisabled() {
|
|
102
|
+
const form = useForm<{ secret: string }>({
|
|
103
|
+
defaultValues: {
|
|
104
|
+
secret:
|
|
105
|
+
process.env.NODE_ENV === 'development'
|
|
106
|
+
? (import.meta.graphCommerce.previewSecret ?? '')
|
|
107
|
+
: '',
|
|
108
|
+
},
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
const submit = form.handleSubmit((formValues) => {
|
|
112
|
+
const url = getPreviewUrl()
|
|
113
|
+
url.searchParams.append('action', 'enable')
|
|
114
|
+
|
|
115
|
+
Object.entries(formValues).forEach(([key, value]) => {
|
|
116
|
+
url.searchParams.append(key, typeof value === 'string' ? value : JSON.stringify(value))
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
window.location.href = url.toString()
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
return (
|
|
123
|
+
<FormProvider {...form}>
|
|
124
|
+
<MessageSnackbar
|
|
125
|
+
variant='pill'
|
|
126
|
+
severity='warning'
|
|
127
|
+
disableBackdropClick
|
|
128
|
+
disableClose
|
|
129
|
+
open
|
|
130
|
+
icon={iconContrast}
|
|
131
|
+
onClose={() => {}}
|
|
132
|
+
action={
|
|
133
|
+
<IconButton color='secondary' type='submit' onClick={submit}>
|
|
134
|
+
<IconSvg src={iconChevronRight} />
|
|
135
|
+
</IconButton>
|
|
136
|
+
}
|
|
137
|
+
>
|
|
138
|
+
<Box sx={{ display: 'grid', gridAutoFlow: 'column', placeItems: 'center', gap: 4 }}>
|
|
139
|
+
<Box sx={{ display: 'flex', placeItems: 'center' }}>Preview Mode</Box>
|
|
140
|
+
<TextFieldElement control={form.control} name='secret' label='Secret' />
|
|
141
|
+
</Box>
|
|
142
|
+
</MessageSnackbar>
|
|
143
|
+
<FormPersist form={form} name='PreviewModePreviewData' />
|
|
144
|
+
</FormProvider>
|
|
145
|
+
)
|
|
146
|
+
}
|
|
147
|
+
|
|
12
148
|
export function PreviewMode() {
|
|
13
149
|
const router = useRouter()
|
|
14
150
|
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@graphcommerce/ecommerce-ui",
|
|
3
3
|
"homepage": "https://www.graphcommerce.org/",
|
|
4
4
|
"repository": "github:graphcommerce-org/graphcommerce",
|
|
5
|
-
"version": "9.0.4
|
|
5
|
+
"version": "9.0.4",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"prettier": "@graphcommerce/prettier-config-pwa",
|
|
8
8
|
"eslintConfig": {
|
|
@@ -12,12 +12,12 @@
|
|
|
12
12
|
}
|
|
13
13
|
},
|
|
14
14
|
"peerDependencies": {
|
|
15
|
-
"@graphcommerce/eslint-config-pwa": "^9.0.4
|
|
16
|
-
"@graphcommerce/graphql": "^9.0.4
|
|
17
|
-
"@graphcommerce/next-ui": "^9.0.4
|
|
18
|
-
"@graphcommerce/prettier-config-pwa": "^9.0.4
|
|
19
|
-
"@graphcommerce/react-hook-form": "^9.0.4
|
|
20
|
-
"@graphcommerce/typescript-config-pwa": "^9.0.4
|
|
15
|
+
"@graphcommerce/eslint-config-pwa": "^9.0.4",
|
|
16
|
+
"@graphcommerce/graphql": "^9.0.4",
|
|
17
|
+
"@graphcommerce/next-ui": "^9.0.4",
|
|
18
|
+
"@graphcommerce/prettier-config-pwa": "^9.0.4",
|
|
19
|
+
"@graphcommerce/react-hook-form": "^9.0.4",
|
|
20
|
+
"@graphcommerce/typescript-config-pwa": "^9.0.4",
|
|
21
21
|
"@lingui/core": "^4.2.1",
|
|
22
22
|
"@lingui/macro": "^4.2.1",
|
|
23
23
|
"@lingui/react": "^4.2.1",
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
Control,
|
|
3
|
-
FieldPath,
|
|
4
|
-
FieldPathValue,
|
|
5
|
-
FieldValues,
|
|
6
|
-
RegisterOptions,
|
|
7
|
-
} from '@graphcommerce/react-hook-form'
|
|
8
|
-
|
|
9
|
-
export type BaseControllerProps<TFieldValues extends FieldValues = FieldValues> = {
|
|
10
|
-
name: FieldPath<TFieldValues>
|
|
11
|
-
control?: Control<TFieldValues>
|
|
12
|
-
rules?: Omit<
|
|
13
|
-
RegisterOptions<NoInfer<TFieldValues>, FieldPath<TFieldValues>>,
|
|
14
|
-
'valueAsNumber' | 'valueAsDate' | 'setValueAs' | 'disabled'
|
|
15
|
-
>
|
|
16
|
-
shouldUnregister?: boolean
|
|
17
|
-
defaultValue?: FieldPathValue<NoInfer<TFieldValues>, FieldPath<TFieldValues>>
|
|
18
|
-
disabled?: boolean
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
type BaseControllerPropsKeys = keyof BaseControllerProps
|
|
22
|
-
|
|
23
|
-
export type FieldElementProps<
|
|
24
|
-
TFieldValues extends FieldValues,
|
|
25
|
-
BaseTypes = Record<string, unknown>,
|
|
26
|
-
> = BaseControllerProps<TFieldValues> & Omit<BaseTypes, BaseControllerPropsKeys>
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { iconChevronRight, iconContrast, IconSvg, MessageSnackbar } from '@graphcommerce/next-ui'
|
|
2
|
-
import { FormPersist, FormProvider, useForm } from '@graphcommerce/react-hook-form'
|
|
3
|
-
import { Box, IconButton } from '@mui/material'
|
|
4
|
-
import { TextFieldElement } from '../FormComponents'
|
|
5
|
-
|
|
6
|
-
function getPreviewUrl() {
|
|
7
|
-
const url = new URL(window.location.href)
|
|
8
|
-
url.pathname = '/api/preview'
|
|
9
|
-
;[...url.searchParams.entries()].forEach(([key]) => url.searchParams.delete(key))
|
|
10
|
-
return url
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const secret =
|
|
14
|
-
process.env.NODE_ENV === 'development' ? (import.meta.graphCommerce.previewSecret ?? '') : ''
|
|
15
|
-
|
|
16
|
-
type FormValues = { secret: string }
|
|
17
|
-
|
|
18
|
-
export function PreviewModeDisabled() {
|
|
19
|
-
const form = useForm<FormValues>({ defaultValues: { secret } })
|
|
20
|
-
|
|
21
|
-
const submit = form.handleSubmit((formValues) => {
|
|
22
|
-
const url = getPreviewUrl()
|
|
23
|
-
url.searchParams.append('action', 'enable')
|
|
24
|
-
|
|
25
|
-
Object.entries(formValues).forEach(([key, value]) => {
|
|
26
|
-
url.searchParams.append(key, typeof value === 'string' ? value : JSON.stringify(value))
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
window.location.href = url.toString()
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
return (
|
|
33
|
-
<FormProvider<FormValues> {...form}>
|
|
34
|
-
<MessageSnackbar
|
|
35
|
-
variant='pill'
|
|
36
|
-
severity='warning'
|
|
37
|
-
disableBackdropClick
|
|
38
|
-
disableClose
|
|
39
|
-
open
|
|
40
|
-
icon={iconContrast}
|
|
41
|
-
onClose={() => {}}
|
|
42
|
-
action={
|
|
43
|
-
<IconButton color='secondary' type='submit' onClick={submit}>
|
|
44
|
-
<IconSvg src={iconChevronRight} />
|
|
45
|
-
</IconButton>
|
|
46
|
-
}
|
|
47
|
-
>
|
|
48
|
-
<Box sx={{ display: 'grid', gridAutoFlow: 'column', placeItems: 'center', gap: 4 }}>
|
|
49
|
-
<Box sx={{ display: 'flex', placeItems: 'center' }}>Preview Mode</Box>
|
|
50
|
-
<TextFieldElement control={form.control} name='secret' label='Secret' />
|
|
51
|
-
</Box>
|
|
52
|
-
</MessageSnackbar>
|
|
53
|
-
<FormPersist form={form} name='PreviewModePreviewData' />
|
|
54
|
-
</FormProvider>
|
|
55
|
-
)
|
|
56
|
-
}
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import type { PreviewData } from '@graphcommerce/graphql'
|
|
2
|
-
import {
|
|
3
|
-
iconClose,
|
|
4
|
-
iconContrast,
|
|
5
|
-
iconInfo,
|
|
6
|
-
iconRefresh,
|
|
7
|
-
IconSvg,
|
|
8
|
-
MessageSnackbar,
|
|
9
|
-
} from '@graphcommerce/next-ui'
|
|
10
|
-
import { FormAutoSubmit, FormPersist, FormProvider, useForm } from '@graphcommerce/react-hook-form'
|
|
11
|
-
import { Box, IconButton } from '@mui/material'
|
|
12
|
-
import { LightTooltip } from './LightTooltip'
|
|
13
|
-
import { PreviewModeActions } from './PreviewModeActions'
|
|
14
|
-
import { PreviewModeToolbar } from './PreviewModeToolbar'
|
|
15
|
-
|
|
16
|
-
function getPreviewUrl() {
|
|
17
|
-
const url = new URL(window.location.href)
|
|
18
|
-
url.pathname = '/api/preview'
|
|
19
|
-
;[...url.searchParams.entries()].forEach(([key]) => url.searchParams.delete(key))
|
|
20
|
-
return url
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
type FormValues = { secret: string; previewData: PreviewData }
|
|
24
|
-
|
|
25
|
-
export function PreviewModeEnabled() {
|
|
26
|
-
const form = useForm<FormValues>({})
|
|
27
|
-
|
|
28
|
-
const submit = form.handleSubmit((formValues) => {
|
|
29
|
-
const url = getPreviewUrl()
|
|
30
|
-
url.searchParams.append('action', 'update')
|
|
31
|
-
|
|
32
|
-
Object.entries(formValues).forEach(([key, value]) => {
|
|
33
|
-
url.searchParams.append(key, JSON.stringify(value))
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
window.location.href = url.toString()
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
const exitHandler = form.handleSubmit(() => {
|
|
40
|
-
const url = getPreviewUrl()
|
|
41
|
-
url.searchParams.append('action', 'exit')
|
|
42
|
-
|
|
43
|
-
window.location.href = url.toString()
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
const revalidateHandler = form.handleSubmit((formValues) => {
|
|
47
|
-
const url = getPreviewUrl()
|
|
48
|
-
Object.entries(formValues).forEach(([key, value]) => {
|
|
49
|
-
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
|
50
|
-
url.searchParams.append(key, `${value}`)
|
|
51
|
-
})
|
|
52
|
-
url.searchParams.append('action', 'revalidate')
|
|
53
|
-
window.location.href = url.toString()
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
return (
|
|
57
|
-
<FormProvider<FormValues> {...form}>
|
|
58
|
-
<MessageSnackbar
|
|
59
|
-
variant='pill'
|
|
60
|
-
severity='warning'
|
|
61
|
-
disableBackdropClick
|
|
62
|
-
disableClose
|
|
63
|
-
open
|
|
64
|
-
icon={iconContrast}
|
|
65
|
-
onClose={() => {}}
|
|
66
|
-
action={
|
|
67
|
-
<>
|
|
68
|
-
<PreviewModeActions />
|
|
69
|
-
<LightTooltip title='Revalidate / Regenerate Page' placement='top'>
|
|
70
|
-
<IconButton color='secondary' type='submit' onClick={revalidateHandler}>
|
|
71
|
-
<IconSvg src={iconRefresh} />
|
|
72
|
-
</IconButton>
|
|
73
|
-
</LightTooltip>
|
|
74
|
-
<LightTooltip title='Stop preview mode' placement='top'>
|
|
75
|
-
<IconButton color='secondary' type='submit' onClick={exitHandler}>
|
|
76
|
-
<IconSvg src={iconClose} />
|
|
77
|
-
</IconButton>
|
|
78
|
-
</LightTooltip>
|
|
79
|
-
</>
|
|
80
|
-
}
|
|
81
|
-
>
|
|
82
|
-
<Box sx={{ display: 'grid', gridAutoFlow: 'column', placeItems: 'center', gap: 4 }}>
|
|
83
|
-
<Box sx={{ display: 'flex', placeItems: 'center' }}>
|
|
84
|
-
Preview Mode{' '}
|
|
85
|
-
<LightTooltip title='You are currently viewing the website in Preview Mode (caches are disabled).'>
|
|
86
|
-
<IconButton size='small'>
|
|
87
|
-
<IconSvg src={iconInfo} />
|
|
88
|
-
</IconButton>
|
|
89
|
-
</LightTooltip>
|
|
90
|
-
</Box>
|
|
91
|
-
<PreviewModeToolbar />
|
|
92
|
-
</Box>
|
|
93
|
-
</MessageSnackbar>
|
|
94
|
-
<FormPersist form={form} name='PreviewModePreviewData' />
|
|
95
|
-
<FormAutoSubmit control={form.control} submit={submit} />
|
|
96
|
-
</FormProvider>
|
|
97
|
-
)
|
|
98
|
-
}
|