@graphcommerce/next-ui 8.1.0-canary.9 → 9.0.0-canary.55
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/ActionCard/ActionCard.tsx +60 -36
- package/ActionCard/ActionCardAccordion.tsx +2 -1
- package/ActionCard/ActionCardList.tsx +3 -2
- package/ActionCard/ActionCardListForm.tsx +1 -1
- package/Blog/BlogAuthor/BlogAuthor.tsx +2 -4
- package/Blog/BlogListItem/BlogListItem.tsx +2 -4
- package/Breadcrumbs/Breadcrumbs.tsx +195 -0
- package/Breadcrumbs/BreadcrumbsJsonLd.tsx +13 -0
- package/Breadcrumbs/BreadcrumbsList.tsx +101 -0
- package/Breadcrumbs/BreadcrumbsPopper.tsx +48 -0
- package/Breadcrumbs/index.ts +4 -0
- package/Breadcrumbs/jsonLdBreadcrumb.tsx +19 -0
- package/Breadcrumbs/types.ts +11 -0
- package/CHANGELOG.md +162 -0
- package/Config.graphqls +5 -0
- package/Document/DocumentBodyEnd.tsx +7 -0
- package/Document/DocumentBodyStart.tsx +7 -0
- package/Document/DocumentHeadEnd.tsx +7 -0
- package/Document/DocumentHeadStart.tsx +7 -0
- package/Document/index.ts +4 -0
- package/Footer/Footer.tsx +1 -1
- package/FramerScroller/SidebarGallery.tsx +54 -27
- package/Intl/DateTimeFormat/DateFormat.tsx +10 -0
- package/Intl/DateTimeFormat/DateTimeFormat.tsx +25 -0
- package/Intl/DateTimeFormat/TimeFormat.tsx +10 -0
- package/Intl/DateTimeFormat/index.ts +3 -0
- package/Intl/DisplayNames/DisplayNames.tsx +22 -0
- package/Intl/DisplayNames/index.ts +1 -0
- package/Intl/ListFormat.tsx +32 -0
- package/Intl/NumberFormat/CurrencyFormat.tsx +191 -0
- package/Intl/NumberFormat/NumberFormat.tsx +24 -0
- package/Intl/NumberFormat/PercentFormat.tsx +5 -0
- package/Intl/NumberFormat/UnitFormat.tsx +59 -0
- package/Intl/NumberFormat/index.ts +4 -0
- package/Intl/index.ts +11 -0
- package/JsonLd/JsonLd.tsx +3 -2
- package/Layout/components/LayoutHeader.tsx +17 -3
- package/Layout/components/LayoutHeaderBack.tsx +9 -1
- package/Layout/components/LayoutTitle.tsx +0 -5
- package/LazyHydrate/LazyHydrate.tsx +19 -3
- package/PageLoadIndicator/PageLoadIndicator.tsx +25 -14
- package/PageMeta/PageMeta.tsx +1 -76
- package/PageMeta/canonicalize.ts +78 -0
- package/Pagination/PaginationExtended.tsx +103 -0
- package/Snackbar/MessageSnackbarImpl.tsx +60 -19
- package/Styles/responsiveVal.tsx +4 -5
- package/Styles/withEmotionCache.tsx +2 -2
- package/Theme/DarkLightModeThemeProvider.tsx +41 -19
- package/hooks/index.ts +1 -1
- package/hooks/useDateTimeFormat.ts +4 -4
- package/hooks/{useSsr.ts → useIsSsr.ts} +3 -0
- package/hooks/useLocale.ts +2 -2
- package/hooks/useNumberFormat.ts +4 -3
- package/hooks/useStorefrontConfig.ts +1 -9
- package/hooks/useUrlQuery.ts +6 -4
- package/icons.ts +55 -0
- package/index.ts +10 -3
- package/package.json +8 -9
- package/server.ts +8 -0
- package/utils/cssFlags.tsx +53 -0
- package/utils/getCssFlagInitScript.tsx +20 -0
- package/utils/normalizeLocale.ts +26 -0
- package/utils/sitemap.ts +1 -1
- package/utils/storefrontConfig.ts +8 -0
- package/icons/index.ts +0 -48
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { NumberFormat, NumberFormatPropsType } from './NumberFormat'
|
|
2
|
+
|
|
3
|
+
// https://en.wikipedia.org/wiki/ISO_4217#List_of_ISO_4217_currency_codes
|
|
4
|
+
type Currency =
|
|
5
|
+
| 'AED'
|
|
6
|
+
| 'AFN'
|
|
7
|
+
| 'ALL'
|
|
8
|
+
| 'AMD'
|
|
9
|
+
| 'ANG'
|
|
10
|
+
| 'AOA'
|
|
11
|
+
| 'ARS'
|
|
12
|
+
| 'AUD'
|
|
13
|
+
| 'AWG'
|
|
14
|
+
| 'AZN'
|
|
15
|
+
| 'BAM'
|
|
16
|
+
| 'BBD'
|
|
17
|
+
| 'BDT'
|
|
18
|
+
| 'BGN'
|
|
19
|
+
| 'BHD'
|
|
20
|
+
| 'BIF'
|
|
21
|
+
| 'BMD'
|
|
22
|
+
| 'BND'
|
|
23
|
+
| 'BOB'
|
|
24
|
+
| 'BOV'
|
|
25
|
+
| 'BRL'
|
|
26
|
+
| 'BSD'
|
|
27
|
+
| 'BTN'
|
|
28
|
+
| 'BWP'
|
|
29
|
+
| 'BYN'
|
|
30
|
+
| 'BZD'
|
|
31
|
+
| 'CAD'
|
|
32
|
+
| 'CDF'
|
|
33
|
+
| 'CHE'
|
|
34
|
+
| 'CHF'
|
|
35
|
+
| 'CHW'
|
|
36
|
+
| 'CLF'
|
|
37
|
+
| 'CLP'
|
|
38
|
+
| 'CNY'
|
|
39
|
+
| 'COP'
|
|
40
|
+
| 'COU'
|
|
41
|
+
| 'CRC'
|
|
42
|
+
| 'CUP'
|
|
43
|
+
| 'CVE'
|
|
44
|
+
| 'CZK'
|
|
45
|
+
| 'DJF'
|
|
46
|
+
| 'DKK'
|
|
47
|
+
| 'DOP'
|
|
48
|
+
| 'DZD'
|
|
49
|
+
| 'EGP'
|
|
50
|
+
| 'ERN'
|
|
51
|
+
| 'ETB'
|
|
52
|
+
| 'EUR'
|
|
53
|
+
| 'FJD'
|
|
54
|
+
| 'FKP'
|
|
55
|
+
| 'GBP'
|
|
56
|
+
| 'GEL'
|
|
57
|
+
| 'GHS'
|
|
58
|
+
| 'GIP'
|
|
59
|
+
| 'GMD'
|
|
60
|
+
| 'GNF'
|
|
61
|
+
| 'GTQ'
|
|
62
|
+
| 'GYD'
|
|
63
|
+
| 'HKD'
|
|
64
|
+
| 'HNL'
|
|
65
|
+
| 'HTG'
|
|
66
|
+
| 'HUF'
|
|
67
|
+
| 'IDR'
|
|
68
|
+
| 'ILS'
|
|
69
|
+
| 'INR'
|
|
70
|
+
| 'IQD'
|
|
71
|
+
| 'IRR'
|
|
72
|
+
| 'ISK'
|
|
73
|
+
| 'JMD'
|
|
74
|
+
| 'JOD'
|
|
75
|
+
| 'JPY'
|
|
76
|
+
| 'KES'
|
|
77
|
+
| 'KGS'
|
|
78
|
+
| 'KHR'
|
|
79
|
+
| 'KMF'
|
|
80
|
+
| 'KPW'
|
|
81
|
+
| 'KRW'
|
|
82
|
+
| 'KWD'
|
|
83
|
+
| 'KYD'
|
|
84
|
+
| 'KZT'
|
|
85
|
+
| 'LAK'
|
|
86
|
+
| 'LBP'
|
|
87
|
+
| 'LKR'
|
|
88
|
+
| 'LRD'
|
|
89
|
+
| 'LSL'
|
|
90
|
+
| 'LYD'
|
|
91
|
+
| 'MAD'
|
|
92
|
+
| 'MDL'
|
|
93
|
+
| 'MGA'
|
|
94
|
+
| 'MKD'
|
|
95
|
+
| 'MMK'
|
|
96
|
+
| 'MNT'
|
|
97
|
+
| 'MOP'
|
|
98
|
+
| 'MRU'
|
|
99
|
+
| 'MUR'
|
|
100
|
+
| 'MVR'
|
|
101
|
+
| 'MWK'
|
|
102
|
+
| 'MXN'
|
|
103
|
+
| 'MXV'
|
|
104
|
+
| 'MYR'
|
|
105
|
+
| 'MZN'
|
|
106
|
+
| 'NAD'
|
|
107
|
+
| 'NGN'
|
|
108
|
+
| 'NIO'
|
|
109
|
+
| 'NOK'
|
|
110
|
+
| 'NPR'
|
|
111
|
+
| 'NZD'
|
|
112
|
+
| 'OMR'
|
|
113
|
+
| 'PAB'
|
|
114
|
+
| 'PEN'
|
|
115
|
+
| 'PGK'
|
|
116
|
+
| 'PHP'
|
|
117
|
+
| 'PKR'
|
|
118
|
+
| 'PLN'
|
|
119
|
+
| 'PYG'
|
|
120
|
+
| 'QAR'
|
|
121
|
+
| 'RON'
|
|
122
|
+
| 'RSD'
|
|
123
|
+
| 'RUB'
|
|
124
|
+
| 'RWF'
|
|
125
|
+
| 'SAR'
|
|
126
|
+
| 'SBD'
|
|
127
|
+
| 'SCR'
|
|
128
|
+
| 'SDG'
|
|
129
|
+
| 'SEK'
|
|
130
|
+
| 'SGD'
|
|
131
|
+
| 'SHP'
|
|
132
|
+
| 'SLE'
|
|
133
|
+
| 'SLL'
|
|
134
|
+
| 'SOS'
|
|
135
|
+
| 'SRD'
|
|
136
|
+
| 'SSP'
|
|
137
|
+
| 'STN'
|
|
138
|
+
| 'SVC'
|
|
139
|
+
| 'SYP'
|
|
140
|
+
| 'SZL'
|
|
141
|
+
| 'THB'
|
|
142
|
+
| 'TJS'
|
|
143
|
+
| 'TMT'
|
|
144
|
+
| 'TND'
|
|
145
|
+
| 'TOP'
|
|
146
|
+
| 'TRY'
|
|
147
|
+
| 'TTD'
|
|
148
|
+
| 'TWD'
|
|
149
|
+
| 'TZS'
|
|
150
|
+
| 'UAH'
|
|
151
|
+
| 'UGX'
|
|
152
|
+
| 'USD'
|
|
153
|
+
| 'USN'
|
|
154
|
+
| 'UYI'
|
|
155
|
+
| 'UYU'
|
|
156
|
+
| 'UYW'
|
|
157
|
+
| 'UZS'
|
|
158
|
+
| 'VED'
|
|
159
|
+
| 'VES'
|
|
160
|
+
| 'VND'
|
|
161
|
+
| 'VUV'
|
|
162
|
+
| 'WST'
|
|
163
|
+
| 'XAF'
|
|
164
|
+
| 'XAG'
|
|
165
|
+
| 'XAU'
|
|
166
|
+
| 'XBA'
|
|
167
|
+
| 'XBB'
|
|
168
|
+
| 'XBC'
|
|
169
|
+
| 'XBD'
|
|
170
|
+
| 'XCD'
|
|
171
|
+
| 'XDR'
|
|
172
|
+
| 'XOF'
|
|
173
|
+
| 'XPD'
|
|
174
|
+
| 'XPF'
|
|
175
|
+
| 'XPT'
|
|
176
|
+
| 'XSU'
|
|
177
|
+
| 'XTS'
|
|
178
|
+
| 'XUA'
|
|
179
|
+
| 'XXX'
|
|
180
|
+
| 'YER'
|
|
181
|
+
| 'ZAR'
|
|
182
|
+
| 'ZMW'
|
|
183
|
+
| 'ZWL'
|
|
184
|
+
|
|
185
|
+
export type CurrencyFormatProps = Omit<NumberFormatPropsType, 'numberStyle'> & {
|
|
186
|
+
currency: Currency | (string & Record<never, never>)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export function CurrencyFormat(props: CurrencyFormatProps) {
|
|
190
|
+
return <NumberFormat {...props} numberStyle='currency' />
|
|
191
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Box, SxProps, Theme } from '@mui/material'
|
|
2
|
+
import { useMemo } from 'react'
|
|
3
|
+
import { useLocale } from '../../hooks/useLocale'
|
|
4
|
+
import { useMemoObject } from '../../hooks/useMemoObject'
|
|
5
|
+
|
|
6
|
+
export type NumberFormatPropsType = {
|
|
7
|
+
children?: number | bigint | null | undefined
|
|
8
|
+
numberStyle: Intl.NumberFormatOptions['style']
|
|
9
|
+
sx?: SxProps<Theme>
|
|
10
|
+
} & Omit<Intl.NumberFormatOptions, 'style'>
|
|
11
|
+
|
|
12
|
+
export function NumberFormat(props: NumberFormatPropsType) {
|
|
13
|
+
const { children, numberStyle, ...options } = props
|
|
14
|
+
|
|
15
|
+
const memoOptions = useMemoObject({ ...options, style: numberStyle })
|
|
16
|
+
const locale = useLocale()
|
|
17
|
+
const formatter = useMemo(() => new Intl.NumberFormat(locale, memoOptions), [locale, memoOptions])
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<Box component='span' suppressHydrationWarning>
|
|
21
|
+
{children ? formatter.format(children) : null}
|
|
22
|
+
</Box>
|
|
23
|
+
)
|
|
24
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { NumberFormatPropsType, NumberFormat } from './NumberFormat'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* https://tc39.es/ecma402/#table-sanctioned-single-unit-identifiers
|
|
5
|
+
*/
|
|
6
|
+
type Unit =
|
|
7
|
+
| 'acre'
|
|
8
|
+
| 'bit'
|
|
9
|
+
| 'byte'
|
|
10
|
+
| 'celsius'
|
|
11
|
+
| 'centimeter'
|
|
12
|
+
| 'day'
|
|
13
|
+
| 'degree'
|
|
14
|
+
| 'fahrenheit'
|
|
15
|
+
| 'fluid-ounce'
|
|
16
|
+
| 'foot'
|
|
17
|
+
| 'gallon'
|
|
18
|
+
| 'gigabit'
|
|
19
|
+
| 'gigabyte'
|
|
20
|
+
| 'gram'
|
|
21
|
+
| 'hectare'
|
|
22
|
+
| 'hour'
|
|
23
|
+
| 'inch'
|
|
24
|
+
| 'kilobit'
|
|
25
|
+
| 'kilobyte'
|
|
26
|
+
| 'kilogram'
|
|
27
|
+
| 'kilometer'
|
|
28
|
+
| 'liter'
|
|
29
|
+
| 'megabit'
|
|
30
|
+
| 'megabyte'
|
|
31
|
+
| 'meter'
|
|
32
|
+
| 'microsecond'
|
|
33
|
+
| 'mile'
|
|
34
|
+
| 'mile-scandinavian'
|
|
35
|
+
| 'milliliter'
|
|
36
|
+
| 'millimeter'
|
|
37
|
+
| 'millisecond'
|
|
38
|
+
| 'minute'
|
|
39
|
+
| 'month'
|
|
40
|
+
| 'nanosecond'
|
|
41
|
+
| 'ounce'
|
|
42
|
+
| 'percent'
|
|
43
|
+
| 'petabyte'
|
|
44
|
+
| 'pound'
|
|
45
|
+
| 'second'
|
|
46
|
+
| 'stone'
|
|
47
|
+
| 'terabit'
|
|
48
|
+
| 'terabyte'
|
|
49
|
+
| 'week'
|
|
50
|
+
| 'yard'
|
|
51
|
+
| 'year'
|
|
52
|
+
|
|
53
|
+
export type UnitFormatProps = Omit<NumberFormatPropsType, 'numberStyle'> & {
|
|
54
|
+
unit: Unit | (string & Record<never, never>)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function UnitFormat(props: UnitFormatProps) {
|
|
58
|
+
return <NumberFormat {...props} numberStyle='unit' />
|
|
59
|
+
}
|
package/Intl/index.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Collator
|
|
2
|
+
// export * from './Collator' // Intl.Collator
|
|
3
|
+
|
|
4
|
+
export * from './DisplayNames' // Intl.DisplayNames
|
|
5
|
+
export * from './DateTimeFormat' // Intl.DateTimeFormat
|
|
6
|
+
export * from './ListFormat' // Intl.ListFormat
|
|
7
|
+
// export * from './Locale' // Intl.Locale
|
|
8
|
+
export * from './NumberFormat' // Intl.NumberFormat
|
|
9
|
+
// export * from './PluralRules' // Intl.PluralRules
|
|
10
|
+
// export * from './RelativeTimeFormat' // Intl.RelativeTimeFormat
|
|
11
|
+
// export * from './Segmenter' // Intl.Segmenter
|
package/JsonLd/JsonLd.tsx
CHANGED
|
@@ -2,14 +2,15 @@ import Head from 'next/head'
|
|
|
2
2
|
import { safeJsonLdReplacer } from './safeJsonLdReplacer'
|
|
3
3
|
|
|
4
4
|
export function JsonLd<T extends { '@type': string }>(props: {
|
|
5
|
+
keyVal?: string
|
|
5
6
|
item: T & { '@context': 'https://schema.org' }
|
|
6
7
|
}) {
|
|
7
|
-
const { item } = props
|
|
8
|
+
const { item, keyVal } = props
|
|
8
9
|
|
|
9
10
|
return (
|
|
10
11
|
<Head>
|
|
11
12
|
<script
|
|
12
|
-
key='jsonld'
|
|
13
|
+
key={keyVal ?? 'jsonld'}
|
|
13
14
|
type='application/ld+json'
|
|
14
15
|
// eslint-disable-next-line react/no-danger
|
|
15
16
|
dangerouslySetInnerHTML={{ __html: JSON.stringify(item, safeJsonLdReplacer) }}
|
|
@@ -28,6 +28,9 @@ export type LayoutHeaderProps = FloatingProps &
|
|
|
28
28
|
sx?: SxProps<Theme>
|
|
29
29
|
|
|
30
30
|
hideBackButton?: boolean
|
|
31
|
+
|
|
32
|
+
hideSm?: boolean
|
|
33
|
+
hideMd?: boolean
|
|
31
34
|
}
|
|
32
35
|
|
|
33
36
|
type ComponentStyleProps = {
|
|
@@ -36,6 +39,8 @@ type ComponentStyleProps = {
|
|
|
36
39
|
children: boolean
|
|
37
40
|
floatingSm: boolean
|
|
38
41
|
floatingMd: boolean
|
|
42
|
+
hideSm: boolean
|
|
43
|
+
hideMd: boolean
|
|
39
44
|
size: 'small' | 'responsive'
|
|
40
45
|
}
|
|
41
46
|
|
|
@@ -44,7 +49,7 @@ const { selectors, withState } = extendableComponent<ComponentStyleProps, 'Layou
|
|
|
44
49
|
['root'] as const,
|
|
45
50
|
)
|
|
46
51
|
|
|
47
|
-
export
|
|
52
|
+
export const LayoutHeader = React.memo<LayoutHeaderProps>((props) => {
|
|
48
53
|
const {
|
|
49
54
|
children,
|
|
50
55
|
divider,
|
|
@@ -56,6 +61,8 @@ export function LayoutHeader(props: LayoutHeaderProps) {
|
|
|
56
61
|
size = 'responsive',
|
|
57
62
|
sx = [],
|
|
58
63
|
bgColor,
|
|
64
|
+
hideSm = false,
|
|
65
|
+
hideMd = false,
|
|
59
66
|
} = props
|
|
60
67
|
const showBack = useShowBack() && !hideBackButton
|
|
61
68
|
const showClose = useShowClose()
|
|
@@ -88,6 +95,8 @@ export function LayoutHeader(props: LayoutHeaderProps) {
|
|
|
88
95
|
children: !!children,
|
|
89
96
|
divider: !!divider,
|
|
90
97
|
size,
|
|
98
|
+
hideSm,
|
|
99
|
+
hideMd,
|
|
91
100
|
})
|
|
92
101
|
|
|
93
102
|
return (
|
|
@@ -115,6 +124,9 @@ export function LayoutHeader(props: LayoutHeaderProps) {
|
|
|
115
124
|
'&.divider': {
|
|
116
125
|
marginBottom: 0,
|
|
117
126
|
},
|
|
127
|
+
'&.hideSm .LayoutHeaderContent-left': {
|
|
128
|
+
display: 'none',
|
|
129
|
+
},
|
|
118
130
|
},
|
|
119
131
|
|
|
120
132
|
[theme.breakpoints.up('md')]: {
|
|
@@ -140,6 +152,9 @@ export function LayoutHeader(props: LayoutHeaderProps) {
|
|
|
140
152
|
'&.divider': {
|
|
141
153
|
marginBottom: 0,
|
|
142
154
|
},
|
|
155
|
+
'&.hideMd .LayoutHeaderContent-left': {
|
|
156
|
+
display: 'none',
|
|
157
|
+
},
|
|
143
158
|
},
|
|
144
159
|
}),
|
|
145
160
|
...(Array.isArray(sx) ? sx : [sx]),
|
|
@@ -159,5 +174,4 @@ export function LayoutHeader(props: LayoutHeaderProps) {
|
|
|
159
174
|
</LayoutHeaderContent>
|
|
160
175
|
</Box>
|
|
161
176
|
)
|
|
162
|
-
}
|
|
163
|
-
LayoutHeader.selectors = selectors
|
|
177
|
+
})
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
useUp,
|
|
3
|
+
usePrevUp,
|
|
4
|
+
usePageContext,
|
|
5
|
+
usePrevPageRouter,
|
|
6
|
+
} from '@graphcommerce/framer-next-pages'
|
|
2
7
|
import { i18n } from '@lingui/core'
|
|
3
8
|
import { Box, SxProps, Theme } from '@mui/material'
|
|
4
9
|
import { useRouter } from 'next/router'
|
|
@@ -41,6 +46,7 @@ export function LayoutHeaderBack(props: BackProps) {
|
|
|
41
46
|
const up = useUp()
|
|
42
47
|
const prevUp = usePrevUp()
|
|
43
48
|
const { backSteps } = usePageContext()
|
|
49
|
+
const prevPageRouter = usePrevPageRouter()
|
|
44
50
|
|
|
45
51
|
const backIcon = <IconSvg src={iconChevronLeft} size='medium' />
|
|
46
52
|
const canClickBack = backSteps > 0 && path !== prevUp?.href
|
|
@@ -49,6 +55,8 @@ export function LayoutHeaderBack(props: BackProps) {
|
|
|
49
55
|
if (up?.href === path && up?.title) label = up.title
|
|
50
56
|
if (prevUp?.href === path && prevUp?.title) label = prevUp.title
|
|
51
57
|
|
|
58
|
+
if (up && prevPageRouter?.asPath === up?.href) label = up.title
|
|
59
|
+
|
|
52
60
|
if (canClickBack) {
|
|
53
61
|
return (
|
|
54
62
|
<LinkOrButton
|
|
@@ -40,12 +40,7 @@ export const LayoutTitle = React.forwardRef<HTMLDivElement, TitleProps>((props,
|
|
|
40
40
|
alignItems: 'center',
|
|
41
41
|
justifyContent: 'center',
|
|
42
42
|
gap: `6px`,
|
|
43
|
-
flexFlow: 'unset',
|
|
44
|
-
[theme.breakpoints.up('md')]: {
|
|
45
|
-
flexFlow: 'column',
|
|
46
|
-
},
|
|
47
43
|
'&.sizeSmall': {
|
|
48
|
-
flexFlow: 'unset',
|
|
49
44
|
overflow: 'hidden',
|
|
50
45
|
'& svg': {
|
|
51
46
|
width: responsiveVal(24, 28),
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { Box, BoxProps } from '@mui/material'
|
|
2
|
-
import React, {
|
|
2
|
+
import React, {
|
|
3
|
+
useState,
|
|
4
|
+
useRef,
|
|
5
|
+
startTransition,
|
|
6
|
+
useLayoutEffect,
|
|
7
|
+
useEffect,
|
|
8
|
+
CSSProperties,
|
|
9
|
+
} from 'react'
|
|
3
10
|
|
|
4
11
|
// Make sure the server doesn't choke on the useLayoutEffect
|
|
5
12
|
export const useLayoutEffect2 = typeof window !== 'undefined' ? useLayoutEffect : useEffect
|
|
@@ -18,6 +25,14 @@ export type LazyHydrateProps = BoxProps<'div'> & {
|
|
|
18
25
|
* - Hydrate the component on some state `<LazyHydrate hydrated={someState}>` where someState initially is false and later becomes true.
|
|
19
26
|
*/
|
|
20
27
|
hydrated?: boolean
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* By default LazyHydrate does not defer the rendering of components when they are rendered client
|
|
31
|
+
* side, because using an IntersectionObserver on an element with no height, will cause all siblings to render at once.
|
|
32
|
+
*
|
|
33
|
+
* By proving a height, we can use the IntersectionObserver on the client as well.
|
|
34
|
+
*/
|
|
35
|
+
height?: CSSProperties['height']
|
|
21
36
|
}
|
|
22
37
|
|
|
23
38
|
/**
|
|
@@ -26,7 +41,7 @@ export type LazyHydrateProps = BoxProps<'div'> & {
|
|
|
26
41
|
* This can be a way to improve the TBT of a page.
|
|
27
42
|
*/
|
|
28
43
|
export function LazyHydrate(props: LazyHydrateProps) {
|
|
29
|
-
const { hydrated, children, ...elementProps } = props
|
|
44
|
+
const { hydrated, children, height, ...elementProps } = props
|
|
30
45
|
const rootRef = useRef<HTMLDivElement>(null)
|
|
31
46
|
|
|
32
47
|
const [isHydrated, setIsHydrated] = useState(hydrated || false)
|
|
@@ -37,7 +52,7 @@ export function LazyHydrate(props: LazyHydrateProps) {
|
|
|
37
52
|
if (isHydrated || !rootRef.current) return undefined
|
|
38
53
|
|
|
39
54
|
// If the element wasn't rendered on the server, we hydrate it immediately
|
|
40
|
-
if (!rootRef.current?.hasAttribute('data-lazy-hydrate')) {
|
|
55
|
+
if (!height && !rootRef.current?.hasAttribute('data-lazy-hydrate')) {
|
|
41
56
|
setIsHydrated(true)
|
|
42
57
|
return undefined
|
|
43
58
|
}
|
|
@@ -77,6 +92,7 @@ export function LazyHydrate(props: LazyHydrateProps) {
|
|
|
77
92
|
dangerouslySetInnerHTML={{ __html: '' }}
|
|
78
93
|
suppressHydrationWarning
|
|
79
94
|
{...elementProps}
|
|
95
|
+
style={{ ...elementProps.style, height }}
|
|
80
96
|
/>
|
|
81
97
|
)
|
|
82
98
|
}
|
|
@@ -1,6 +1,15 @@
|
|
|
1
|
-
import { LinearProgress,
|
|
1
|
+
import { LinearProgress, LinearProgressProps } from '@mui/material'
|
|
2
|
+
import { m, motionValue, useTransform } from 'framer-motion'
|
|
2
3
|
import { useRouter } from 'next/router'
|
|
3
|
-
import { useEffect, useState } from 'react'
|
|
4
|
+
import { forwardRef, useEffect, useState } from 'react'
|
|
5
|
+
|
|
6
|
+
export const showPageLoadIndicator = motionValue(false)
|
|
7
|
+
|
|
8
|
+
const MLinearProgress = m(
|
|
9
|
+
forwardRef((props: Omit<LinearProgressProps, 'style'>, ref: LinearProgressProps['ref']) => (
|
|
10
|
+
<LinearProgress ref={ref} {...props} />
|
|
11
|
+
)),
|
|
12
|
+
)
|
|
4
13
|
|
|
5
14
|
/**
|
|
6
15
|
* Creates a [LinearProgress](https://mui.com/components/progress/#linear) animation when the route
|
|
@@ -24,18 +33,20 @@ export function PageLoadIndicator() {
|
|
|
24
33
|
}
|
|
25
34
|
}, [events])
|
|
26
35
|
|
|
36
|
+
const opacity = useTransform(() => (showPageLoadIndicator.get() || loading ? 1 : 0))
|
|
37
|
+
|
|
27
38
|
return (
|
|
28
|
-
<
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
<MLinearProgress
|
|
40
|
+
style={{ opacity }}
|
|
41
|
+
sx={{
|
|
42
|
+
position: 'fixed',
|
|
43
|
+
width: '100%',
|
|
44
|
+
top: 0,
|
|
45
|
+
height: 3,
|
|
46
|
+
marginBottom: '-3px',
|
|
47
|
+
zIndex: 'tooltip',
|
|
48
|
+
transition: 'opacity 0.3s',
|
|
49
|
+
}}
|
|
50
|
+
/>
|
|
40
51
|
)
|
|
41
52
|
}
|
package/PageMeta/PageMeta.tsx
CHANGED
|
@@ -1,13 +1,7 @@
|
|
|
1
1
|
import { usePageContext } from '@graphcommerce/framer-next-pages'
|
|
2
|
-
import { addBasePath } from 'next/dist/client/add-base-path'
|
|
3
|
-
import { addLocale } from 'next/dist/client/add-locale'
|
|
4
|
-
import { getDomainLocale } from 'next/dist/client/get-domain-locale'
|
|
5
|
-
import { resolveHref } from 'next/dist/client/resolve-href'
|
|
6
|
-
import { NextRouter } from 'next/dist/shared/lib/router/router'
|
|
7
2
|
import Head from 'next/head'
|
|
8
|
-
import { useRouter } from 'next/router'
|
|
9
3
|
import type {} from '@graphcommerce/next-config'
|
|
10
|
-
import {
|
|
4
|
+
import { Canonical, useCanonical } from './canonicalize'
|
|
11
5
|
|
|
12
6
|
// https://developers.google.com/search/docs/advanced/robots/robots_meta_tag#directives
|
|
13
7
|
export type MetaRobots =
|
|
@@ -23,8 +17,6 @@ export type MetaRobots =
|
|
|
23
17
|
| `max-video-preview:${number}`
|
|
24
18
|
type MetaRobotsAll = ['all' | 'none']
|
|
25
19
|
|
|
26
|
-
type Canonical = `http://${string}` | `https://${string}` | `/${string}` | string
|
|
27
|
-
|
|
28
20
|
export type PageMetaProps = {
|
|
29
21
|
title: string
|
|
30
22
|
canonical?: Canonical
|
|
@@ -36,73 +28,6 @@ export type PageMetaProps = {
|
|
|
36
28
|
ogType?: string | null
|
|
37
29
|
}
|
|
38
30
|
|
|
39
|
-
type PartialNextRouter = Pick<
|
|
40
|
-
NextRouter,
|
|
41
|
-
'pathname' | 'locale' | 'locales' | 'isLocaleDomain' | 'domainLocales' | 'defaultLocale'
|
|
42
|
-
>
|
|
43
|
-
export function canonicalize(router: PartialNextRouter, incoming?: Canonical) {
|
|
44
|
-
let canonical = incoming
|
|
45
|
-
|
|
46
|
-
if (!canonical) return canonical
|
|
47
|
-
|
|
48
|
-
if (!canonical.startsWith('http') && !canonical.startsWith('/')) {
|
|
49
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
50
|
-
console.warn(
|
|
51
|
-
`canonical is relative (${canonical}), a canonical must start with '/', 'http://' or 'https://'`,
|
|
52
|
-
)
|
|
53
|
-
}
|
|
54
|
-
canonical = `/${canonical}`
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (canonical.startsWith('/')) {
|
|
58
|
-
let [href, as = href] = resolveHref(router as NextRouter, canonical, true)
|
|
59
|
-
|
|
60
|
-
const curLocale = router.locale
|
|
61
|
-
|
|
62
|
-
// Copied from here https://github.com/vercel/next.js/blob/213c42f446874d29d07fa2cca6e6b11fc9c3b711/packages/next/client/link.tsx#L512
|
|
63
|
-
const localeDomain = getDomainLocale(
|
|
64
|
-
as,
|
|
65
|
-
curLocale,
|
|
66
|
-
router && router.locales,
|
|
67
|
-
router.domainLocales,
|
|
68
|
-
)
|
|
69
|
-
|
|
70
|
-
if (localeDomain) {
|
|
71
|
-
canonical = localeDomain
|
|
72
|
-
} else {
|
|
73
|
-
const conf = storefrontConfig(router.locale)
|
|
74
|
-
|
|
75
|
-
href = addBasePath(
|
|
76
|
-
addLocale(as, curLocale, conf?.domain ? conf.locale : router.defaultLocale),
|
|
77
|
-
)
|
|
78
|
-
|
|
79
|
-
let siteUrl = conf?.canonicalBaseUrl || import.meta.graphCommerce.canonicalBaseUrl
|
|
80
|
-
|
|
81
|
-
if (conf?.domain && !conf?.canonicalBaseUrl) siteUrl = `https://${conf.domain}`
|
|
82
|
-
|
|
83
|
-
if (siteUrl.endsWith('/')) siteUrl = siteUrl.slice(0, -1)
|
|
84
|
-
|
|
85
|
-
canonical = `${siteUrl}${href}`
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (!canonical.startsWith('http')) {
|
|
90
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
91
|
-
throw new Error(
|
|
92
|
-
`canonical must start with '/', 'http://' or 'https://', '${canonical}' given`,
|
|
93
|
-
)
|
|
94
|
-
}
|
|
95
|
-
canonical = undefined
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return canonical
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
export function useCanonical(incoming?: Canonical) {
|
|
102
|
-
const router = useRouter()
|
|
103
|
-
return canonicalize(router, incoming)
|
|
104
|
-
}
|
|
105
|
-
|
|
106
31
|
export function PageMeta(props: PageMetaProps) {
|
|
107
32
|
const { active } = usePageContext()
|
|
108
33
|
const {
|