@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.
Files changed (65) hide show
  1. package/ActionCard/ActionCard.tsx +60 -36
  2. package/ActionCard/ActionCardAccordion.tsx +2 -1
  3. package/ActionCard/ActionCardList.tsx +3 -2
  4. package/ActionCard/ActionCardListForm.tsx +1 -1
  5. package/Blog/BlogAuthor/BlogAuthor.tsx +2 -4
  6. package/Blog/BlogListItem/BlogListItem.tsx +2 -4
  7. package/Breadcrumbs/Breadcrumbs.tsx +195 -0
  8. package/Breadcrumbs/BreadcrumbsJsonLd.tsx +13 -0
  9. package/Breadcrumbs/BreadcrumbsList.tsx +101 -0
  10. package/Breadcrumbs/BreadcrumbsPopper.tsx +48 -0
  11. package/Breadcrumbs/index.ts +4 -0
  12. package/Breadcrumbs/jsonLdBreadcrumb.tsx +19 -0
  13. package/Breadcrumbs/types.ts +11 -0
  14. package/CHANGELOG.md +162 -0
  15. package/Config.graphqls +5 -0
  16. package/Document/DocumentBodyEnd.tsx +7 -0
  17. package/Document/DocumentBodyStart.tsx +7 -0
  18. package/Document/DocumentHeadEnd.tsx +7 -0
  19. package/Document/DocumentHeadStart.tsx +7 -0
  20. package/Document/index.ts +4 -0
  21. package/Footer/Footer.tsx +1 -1
  22. package/FramerScroller/SidebarGallery.tsx +54 -27
  23. package/Intl/DateTimeFormat/DateFormat.tsx +10 -0
  24. package/Intl/DateTimeFormat/DateTimeFormat.tsx +25 -0
  25. package/Intl/DateTimeFormat/TimeFormat.tsx +10 -0
  26. package/Intl/DateTimeFormat/index.ts +3 -0
  27. package/Intl/DisplayNames/DisplayNames.tsx +22 -0
  28. package/Intl/DisplayNames/index.ts +1 -0
  29. package/Intl/ListFormat.tsx +32 -0
  30. package/Intl/NumberFormat/CurrencyFormat.tsx +191 -0
  31. package/Intl/NumberFormat/NumberFormat.tsx +24 -0
  32. package/Intl/NumberFormat/PercentFormat.tsx +5 -0
  33. package/Intl/NumberFormat/UnitFormat.tsx +59 -0
  34. package/Intl/NumberFormat/index.ts +4 -0
  35. package/Intl/index.ts +11 -0
  36. package/JsonLd/JsonLd.tsx +3 -2
  37. package/Layout/components/LayoutHeader.tsx +17 -3
  38. package/Layout/components/LayoutHeaderBack.tsx +9 -1
  39. package/Layout/components/LayoutTitle.tsx +0 -5
  40. package/LazyHydrate/LazyHydrate.tsx +19 -3
  41. package/PageLoadIndicator/PageLoadIndicator.tsx +25 -14
  42. package/PageMeta/PageMeta.tsx +1 -76
  43. package/PageMeta/canonicalize.ts +78 -0
  44. package/Pagination/PaginationExtended.tsx +103 -0
  45. package/Snackbar/MessageSnackbarImpl.tsx +60 -19
  46. package/Styles/responsiveVal.tsx +4 -5
  47. package/Styles/withEmotionCache.tsx +2 -2
  48. package/Theme/DarkLightModeThemeProvider.tsx +41 -19
  49. package/hooks/index.ts +1 -1
  50. package/hooks/useDateTimeFormat.ts +4 -4
  51. package/hooks/{useSsr.ts → useIsSsr.ts} +3 -0
  52. package/hooks/useLocale.ts +2 -2
  53. package/hooks/useNumberFormat.ts +4 -3
  54. package/hooks/useStorefrontConfig.ts +1 -9
  55. package/hooks/useUrlQuery.ts +6 -4
  56. package/icons.ts +55 -0
  57. package/index.ts +10 -3
  58. package/package.json +8 -9
  59. package/server.ts +8 -0
  60. package/utils/cssFlags.tsx +53 -0
  61. package/utils/getCssFlagInitScript.tsx +20 -0
  62. package/utils/normalizeLocale.ts +26 -0
  63. package/utils/sitemap.ts +1 -1
  64. package/utils/storefrontConfig.ts +8 -0
  65. package/icons/index.ts +0 -48
package/CHANGELOG.md CHANGED
@@ -1,5 +1,167 @@
1
1
  # Change Log
2
2
 
3
+ ## 9.0.0-canary.55
4
+
5
+ ## 9.0.0-canary.54
6
+
7
+ ## 8.1.0-canary.53
8
+
9
+ ## 8.1.0-canary.52
10
+
11
+ ## 8.1.0-canary.51
12
+
13
+ ## 8.1.0-canary.50
14
+
15
+ ### Patch Changes
16
+
17
+ - [#2321](https://github.com/graphcommerce-org/graphcommerce/pull/2321) [`fa261d4`](https://github.com/graphcommerce-org/graphcommerce/commit/fa261d4ae600b46ae08c5ca7514163f2da54eead) - Add the possibility to place content before or after the scroller.
18
+ ([@carlocarels90](https://github.com/carlocarels90))
19
+
20
+ ## 8.1.0-canary.49
21
+
22
+ ### Patch Changes
23
+
24
+ - [#2317](https://github.com/graphcommerce-org/graphcommerce/pull/2317) [`6c173c7`](https://github.com/graphcommerce-org/graphcommerce/commit/6c173c7bba601413cc5e1c9cf0595b8ec262fb92) - Added new plugin insertion points: `<DocumentHeadStart/>`, `<DocumentHeadEnd/>`, `<DocumentBodyEnd/>`, `<DocumentBodyStart/>` for the \_document.app to allow creating plugins for those locations to insert scripts etc.
25
+ ([@paales](https://github.com/paales))
26
+
27
+ ## 8.1.0-canary.48
28
+
29
+ ## 8.1.0-canary.47
30
+
31
+ ### Minor Changes
32
+
33
+ - [#2315](https://github.com/graphcommerce-org/graphcommerce/pull/2315) [`fb9118e`](https://github.com/graphcommerce-org/graphcommerce/commit/fb9118ec819d1b507d4fbde04f2ca34ec01ecf49) - Add guestOrder functionality, remove `size: 'max'` from getStaticProps
34
+ ([@Giovanni-Schroevers](https://github.com/Giovanni-Schroevers))
35
+
36
+ ## 8.1.0-canary.46
37
+
38
+ ### Patch Changes
39
+
40
+ - [#2314](https://github.com/graphcommerce-org/graphcommerce/pull/2314) [`59874b5`](https://github.com/graphcommerce-org/graphcommerce/commit/59874b572bda17905dc836554f9a3e31f393eb3e) - Solve issue where the page would reload during development when the first call to /graphql was made.
41
+ ([@paales](https://github.com/paales))
42
+
43
+ ## 8.1.0-canary.45
44
+
45
+ ### Patch Changes
46
+
47
+ - [#2216](https://github.com/graphcommerce-org/graphcommerce/pull/2216) [`1895176`](https://github.com/graphcommerce-org/graphcommerce/commit/1895176b5776adcf588999ceab7edd6f53cff294) - USPS would be loaded after other pages, causing uneceesasry slowdown
48
+ ([@paales](https://github.com/paales))
49
+
50
+ - [#2216](https://github.com/graphcommerce-org/graphcommerce/pull/2216) [`74eb239`](https://github.com/graphcommerce-org/graphcommerce/commit/74eb2393a64988649178d59f53b33d41fecdd769) - Added Intl components and replaced usage sites
51
+ ([@paales](https://github.com/paales))
52
+
53
+ - [#2216](https://github.com/graphcommerce-org/graphcommerce/pull/2216) [`012b865`](https://github.com/graphcommerce-org/graphcommerce/commit/012b86560d93e35dd7ca4a9469ed65e6fb83ead0) - Move arguments of responsiveVal around so the minBreakpoint can be given as third argument
54
+ ([@paales](https://github.com/paales))
55
+
56
+ - [#2216](https://github.com/graphcommerce-org/graphcommerce/pull/2216) [`223f16a`](https://github.com/graphcommerce-org/graphcommerce/commit/223f16a0e9a7718e52e81a4e2902471a8b78d35c) - LazyHydrate component now accepts a height prop that allows deferring of rendering of the child component when initially rendered on the client. This improves performance.
57
+ ([@paales](https://github.com/paales))
58
+
59
+ ## 8.1.0-canary.44
60
+
61
+ ## 8.1.0-canary.43
62
+
63
+ ## 8.1.0-canary.42
64
+
65
+ ## 8.1.0-canary.41
66
+
67
+ ### Patch Changes
68
+
69
+ - [#2242](https://github.com/graphcommerce-org/graphcommerce/pull/2242) [`a4cce76`](https://github.com/graphcommerce-org/graphcommerce/commit/a4cce76ca37af2bec604e953ada4bb11bd91f55d) - Add option to show an extended version of the pagination component. Configurable via the "productListPaginationVariant" key in your graphcommerce.config.js
70
+ COMPACT means: "< Page X of Y >"
71
+ EXTENDED means: "< 1 2 ... [5] ... 10 11 >" ([@FrankHarland](https://github.com/FrankHarland))
72
+
73
+ ## 8.1.0-canary.40
74
+
75
+ ### Minor Changes
76
+
77
+ - [#2306](https://github.com/graphcommerce-org/graphcommerce/pull/2306) [`5e188e8`](https://github.com/graphcommerce-org/graphcommerce/commit/5e188e830dca4730c73830858f59a94e9d41ed12) - Add delete account functionality to the account section. Disabled by default and can be enabled through the config.
78
+ ([@Giovanni-Schroevers](https://github.com/Giovanni-Schroevers))
79
+
80
+ ## 8.1.0-canary.39
81
+
82
+ ## 8.1.0-canary.38
83
+
84
+ ## 8.1.0-canary.37
85
+
86
+ ## 8.1.0-canary.36
87
+
88
+ ## 8.1.0-canary.35
89
+
90
+ ## 8.1.0-canary.34
91
+
92
+ ## 8.1.0-canary.33
93
+
94
+ ## 8.1.0-canary.32
95
+
96
+ ## 8.1.0-canary.31
97
+
98
+ ### Patch Changes
99
+
100
+ - [#2297](https://github.com/graphcommerce-org/graphcommerce/pull/2297) [`e41cb6f`](https://github.com/graphcommerce-org/graphcommerce/commit/e41cb6fcdde95629d29c03b1a700c6097f00c901) - Prevent gallery thunbnails from scrolling when opening or closing a layout overlay
101
+ ([@Giovanni-Schroevers](https://github.com/Giovanni-Schroevers))
102
+
103
+ ## 8.1.0-canary.30
104
+
105
+ ## 8.1.0-canary.29
106
+
107
+ ## 8.1.0-canary.28
108
+
109
+ ## 8.1.0-canary.27
110
+
111
+ ### Minor Changes
112
+
113
+ - [#2273](https://github.com/graphcommerce-org/graphcommerce/pull/2273) [`77955c5`](https://github.com/graphcommerce-org/graphcommerce/commit/77955c56ac8633ab1c5e0f3ddb25e3a87236e2bb) - Improve Breadcrumbs on Category and Product pages
114
+ ([@Jessevdpoel](https://github.com/Jessevdpoel))
115
+
116
+ ## 8.1.0-canary.26
117
+
118
+ ### Minor Changes
119
+
120
+ - [#2274](https://github.com/graphcommerce-org/graphcommerce/pull/2274) [`4a24813`](https://github.com/graphcommerce-org/graphcommerce/commit/4a248130041484833768fe6018f91d05a59522de) - Add props to DarkLightModeThemeProvider to disable dark/light mode or to change the default ssr mode. Save user chosen mode in localStorage
121
+ ([@Giovanni-Schroevers](https://github.com/Giovanni-Schroevers))
122
+
123
+ ### Patch Changes
124
+
125
+ - [#2274](https://github.com/graphcommerce-org/graphcommerce/pull/2274) [`57131cf`](https://github.com/graphcommerce-org/graphcommerce/commit/57131cfcc43695cc3e22f28912feb2a8439620a7) - Created a cssFlags functionality to allow for conditional rendering based on stored flags in the localStorage
126
+ ([@Giovanni-Schroevers](https://github.com/Giovanni-Schroevers))
127
+
128
+ ## 8.1.0-canary.25
129
+
130
+ ## 8.1.0-canary.24
131
+
132
+ ## 8.1.0-canary.23
133
+
134
+ ## 8.1.0-canary.22
135
+
136
+ ## 8.1.0-canary.21
137
+
138
+ ## 8.1.0-canary.20
139
+
140
+ ## 8.1.0-canary.19
141
+
142
+ ## 8.1.0-canary.18
143
+
144
+ ## 8.1.0-canary.17
145
+
146
+ ### Minor Changes
147
+
148
+ - [#2209](https://github.com/graphcommerce-org/graphcommerce/pull/2209) [`2872cab`](https://github.com/graphcommerce-org/graphcommerce/commit/2872cabdca9ee4f0378fd411c6a633f71bb92f1f) - Removed useMediaQuery from the wishlist and cart ItemActionCard and replaced it with a new responsive size prop.
149
+ ([@Jessevdpoel](https://github.com/Jessevdpoel))
150
+
151
+ ## 8.1.0-canary.16
152
+
153
+ ## 8.1.0-canary.15
154
+
155
+ ## 8.1.0-canary.14
156
+
157
+ ## 8.1.0-canary.13
158
+
159
+ ## 8.1.0-canary.12
160
+
161
+ ## 8.1.0-canary.11
162
+
163
+ ## 8.1.0-canary.10
164
+
3
165
  ## 8.1.0-canary.9
4
166
 
5
167
  ### Patch Changes
package/Config.graphqls CHANGED
@@ -3,6 +3,11 @@ extend input GraphCommerceConfig {
3
3
  Configuration for the SidebarGallery component
4
4
  """
5
5
  sidebarGallery: SidebarGalleryConfig
6
+
7
+ """
8
+ Configuration for the SidebarGallery component
9
+ """
10
+ breadcrumbs: Boolean = false
6
11
  }
7
12
 
8
13
  """
@@ -0,0 +1,7 @@
1
+ // eslint-disable-next-line @next/next/no-document-import-in-page
2
+ import { DocumentProps } from 'next/document'
3
+
4
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
5
+ export function DocumentBodyEnd(props: DocumentProps) {
6
+ return null
7
+ }
@@ -0,0 +1,7 @@
1
+ // eslint-disable-next-line @next/next/no-document-import-in-page
2
+ import { DocumentProps } from 'next/document'
3
+
4
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
5
+ export function DocumentBodyStart(props: DocumentProps) {
6
+ return null
7
+ }
@@ -0,0 +1,7 @@
1
+ // eslint-disable-next-line @next/next/no-document-import-in-page
2
+ import { DocumentProps } from 'next/document'
3
+
4
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
5
+ export function DocumentHeadEnd(props: DocumentProps) {
6
+ return null
7
+ }
@@ -0,0 +1,7 @@
1
+ // eslint-disable-next-line @next/next/no-document-import-in-page
2
+ import { DocumentProps } from 'next/document'
3
+
4
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
5
+ export function DocumentHeadStart(props: DocumentProps) {
6
+ return null
7
+ }
@@ -0,0 +1,4 @@
1
+ export * from './DocumentBodyEnd'
2
+ export * from './DocumentBodyStart'
3
+ export * from './DocumentHeadEnd'
4
+ export * from './DocumentHeadStart'
package/Footer/Footer.tsx CHANGED
@@ -31,7 +31,7 @@ export function Footer(props: FooterProps) {
31
31
  } = props
32
32
 
33
33
  return (
34
- <LazyHydrate>
34
+ <LazyHydrate height={300}>
35
35
  <Container
36
36
  sx={[
37
37
  (theme) => ({
@@ -31,7 +31,14 @@ import { iconChevronLeft, iconChevronRight, iconFullscreen, iconFullscreenExit }
31
31
 
32
32
  const MotionBox = styled(m.div)({})
33
33
 
34
- type OwnerState = { zoomed: boolean; disableZoom: boolean }
34
+ type SidebarGalleryVariant = 'default' | 'oneColumn'
35
+
36
+ type OwnerState = {
37
+ zoomed: boolean
38
+ disableZoom: boolean
39
+ sticky: boolean
40
+ variantMd: SidebarGalleryVariant
41
+ }
35
42
  const name = 'SidebarGallery' as const
36
43
  const parts = [
37
44
  'row',
@@ -60,6 +67,10 @@ export type SidebarGalleryProps = {
60
67
  routeHash?: string
61
68
  sx?: SxProps<Theme>
62
69
  disableZoom?: boolean
70
+ disableSticky?: boolean
71
+ variantMd?: SidebarGalleryVariant
72
+ beforeScroller?: React.ReactNode
73
+ afterScroller?: React.ReactNode
63
74
  } & Pick<ScrollerButtonProps, 'showButtons'>
64
75
 
65
76
  export function SidebarGallery(props: SidebarGalleryProps) {
@@ -71,6 +82,10 @@ export function SidebarGallery(props: SidebarGalleryProps) {
71
82
  routeHash = 'gallery',
72
83
  showButtons,
73
84
  disableZoom = false,
85
+ disableSticky = false,
86
+ variantMd = 'default',
87
+ beforeScroller,
88
+ afterScroller,
74
89
  } = props
75
90
 
76
91
  const router = useRouter()
@@ -103,7 +118,7 @@ export function SidebarGallery(props: SidebarGalleryProps) {
103
118
  }
104
119
  }
105
120
 
106
- const classes = withState({ zoomed, disableZoom })
121
+ const classes = withState({ zoomed, disableZoom, sticky: !disableSticky, variantMd })
107
122
  const theme = useTheme()
108
123
  const windowRef = useRef(typeof window !== 'undefined' ? window : null)
109
124
 
@@ -144,25 +159,31 @@ export function SidebarGallery(props: SidebarGalleryProps) {
144
159
  display: 'grid',
145
160
  gridTemplate: '"left" "right"',
146
161
  [theme.breakpoints.up('md')]: {
147
- gridTemplate: `"left right" / 1fr calc(${responsiveVal(300, 500, theme.breakpoints.values.lg)} + ${
148
- theme.page.horizontal
149
- } * 2)`,
162
+ '&:not(.variantMdOneColumn)': {
163
+ gridTemplate: `"left right" / 1fr calc(${responsiveVal(300, 500, undefined, theme.breakpoints.values.lg)} + ${
164
+ theme.page.horizontal
165
+ } * 2)`,
166
+ },
150
167
  },
151
168
  background:
152
169
  theme.palette.mode === 'light'
153
170
  ? theme.palette.background.image
154
171
  : theme.palette.background.paper,
155
- paddingRight: `calc((100% - ${theme.breakpoints.values.lg}px) / 2)`,
156
- },
157
- zoomed && {
158
- position: 'relative',
159
- zIndex: theme.zIndex.modal,
160
- marginTop: `calc(${theme.appShell.headerHeightSm} * -1)`,
161
- [theme.breakpoints.up('md')]: {
162
- marginTop: `calc(${theme.appShell.headerHeightMd} * -1 - ${theme.spacings.lg})`,
163
- gridTemplateColumns: '1fr auto',
172
+
173
+ '&:not(.variantMdOneColumn)': {
174
+ paddingRight: `calc((100% - ${theme.breakpoints.values.lg}px) / 2)`,
175
+ },
176
+
177
+ '&.zoomed': {
178
+ position: 'relative',
179
+ zIndex: theme.zIndex.modal,
180
+ marginTop: `calc(${theme.appShell.headerHeightSm} * -1)`,
181
+ [theme.breakpoints.up('md')]: {
182
+ marginTop: `calc(${theme.appShell.headerHeightMd} * -1 - ${theme.spacings.lg})`,
183
+ gridTemplateColumns: '1fr auto',
184
+ },
185
+ paddingRight: 0,
164
186
  },
165
- paddingRight: 0,
166
187
  },
167
188
  ]}
168
189
  >
@@ -183,11 +204,13 @@ export function SidebarGallery(props: SidebarGalleryProps) {
183
204
  width: '100%',
184
205
  },
185
206
  [theme.breakpoints.up('md')]: {
186
- height: `calc(${dvh(100)} - ${theme.appShell.headerHeightMd} - ${
187
- theme.spacings.lg
188
- })`,
189
- position: 'sticky',
190
- top: theme.appShell.headerHeightMd,
207
+ '&:not(.variantMdOneColumn)': {
208
+ height: `max(${dvh(90)}, 40vw)`,
209
+ '&.sticky': {
210
+ position: 'sticky',
211
+ top: theme.appShell.headerHeightMd,
212
+ },
213
+ },
191
214
  },
192
215
  },
193
216
  zoomed && {
@@ -201,6 +224,7 @@ export function SidebarGallery(props: SidebarGalleryProps) {
201
224
  if (!zoomed) document.body.style.overflow = ''
202
225
  }}
203
226
  >
227
+ {beforeScroller}
204
228
  <Scroller
205
229
  className={classes.scroller}
206
230
  hideScrollbar
@@ -242,6 +266,7 @@ export function SidebarGallery(props: SidebarGalleryProps) {
242
266
  />
243
267
  ))}
244
268
  </Scroller>
269
+ {afterScroller}
245
270
  <MotionBox
246
271
  layout='position'
247
272
  layoutDependency={zoomed}
@@ -333,9 +358,9 @@ export function SidebarGallery(props: SidebarGalleryProps) {
333
358
  >
334
359
  {import.meta.graphCommerce.sidebarGallery?.paginationVariant ===
335
360
  'THUMBNAILS_BOTTOM' ? (
336
- <ScrollerThumbnails images={images} />
361
+ <ScrollerThumbnails layoutDependency={zoomed} images={images} />
337
362
  ) : (
338
- <ScrollerDots />
363
+ <ScrollerDots layout />
339
364
  )}
340
365
  </Box>
341
366
  </MotionBox>
@@ -353,10 +378,10 @@ export function SidebarGallery(props: SidebarGalleryProps) {
353
378
  },
354
379
  zoomed && {
355
380
  [theme.breakpoints.up('md')]: {
356
- marginLeft: `calc((${responsiveVal(300, 500, theme.breakpoints.values.lg)} + ${
381
+ marginLeft: `calc((${responsiveVal(300, 500, undefined, theme.breakpoints.values.lg)} + ${
357
382
  theme.page.horizontal
358
383
  } * 2) * -1)`,
359
- left: `calc(${responsiveVal(300, 500, theme.breakpoints.values.lg)} + ${
384
+ left: `calc(${responsiveVal(300, 500, undefined, theme.breakpoints.values.lg)} + ${
360
385
  theme.page.horizontal
361
386
  } * 2)`,
362
387
  },
@@ -370,9 +395,11 @@ export function SidebarGallery(props: SidebarGalleryProps) {
370
395
  sx={{
371
396
  boxSizing: 'border-box',
372
397
  width: '100%',
373
- padding: `${theme.spacings.lg} ${theme.page.horizontal}`,
374
- [theme.breakpoints.up('md')]: {
375
- paddingLeft: theme.spacings.lg,
398
+ '&:not(.variantMdOneColumn)': {
399
+ padding: `${theme.spacings.lg} ${theme.page.horizontal}`,
400
+ [theme.breakpoints.up('md')]: {
401
+ paddingLeft: theme.spacings.lg,
402
+ },
376
403
  },
377
404
  }}
378
405
  >
@@ -0,0 +1,10 @@
1
+ import { DateTimeFormat, DateTimeFormatPropsType } from './DateTimeFormat'
2
+
3
+ type DateFormatOptions = Omit<
4
+ DateTimeFormatPropsType,
5
+ 'timeStyle' | 'hour' | 'minute' | 'second' | 'timeZoneName'
6
+ >
7
+
8
+ export function DateFormat(props: DateFormatOptions) {
9
+ return <DateTimeFormat timeStyle={undefined} {...props} />
10
+ }
@@ -0,0 +1,25 @@
1
+ import { useMemo } from 'react'
2
+ import { useLocale } from '../../hooks/useLocale'
3
+ import { useMemoObject } from '../../hooks/useMemoObject'
4
+
5
+ export function useDateTimeFormatter(props: Intl.DateTimeFormatOptions) {
6
+ const locale = useLocale()
7
+ const memoOptions = useMemoObject(props)
8
+ return useMemo(() => new Intl.DateTimeFormat(locale, memoOptions), [locale, memoOptions])
9
+ }
10
+
11
+ type DateValue = Date | string | number | null | undefined
12
+ export type DateTimeFormatPropsType = { children: DateValue } & Intl.DateTimeFormatOptions
13
+
14
+ export function DateTimeFormat(props: DateTimeFormatPropsType) {
15
+ const { children } = props
16
+ const formatter = useDateTimeFormatter({ dateStyle: 'medium', timeStyle: 'short', ...props })
17
+
18
+ return (
19
+ <span suppressHydrationWarning>
20
+ {children
21
+ ? formatter.format(typeof children === 'string' ? new Date(children) : children)
22
+ : null}
23
+ </span>
24
+ )
25
+ }
@@ -0,0 +1,10 @@
1
+ import { DateTimeFormat, DateTimeFormatPropsType } from './DateTimeFormat'
2
+
3
+ type TimeFormatProps = Omit<
4
+ DateTimeFormatPropsType,
5
+ 'dateStyle' | 'month' | 'day' | 'era' | 'month' | 'weekday' | 'year'
6
+ >
7
+
8
+ export function TimeFormat(props: TimeFormatProps) {
9
+ return <DateTimeFormat dateStyle={undefined} {...props} />
10
+ }
@@ -0,0 +1,3 @@
1
+ export * from './DateTimeFormat'
2
+ export * from './DateFormat'
3
+ export * from './TimeFormat'
@@ -0,0 +1,22 @@
1
+ import { useMemo } from 'react'
2
+ import { useLocale } from '../../hooks/useLocale'
3
+ import { useMemoObject } from '../../hooks/useMemoObject'
4
+
5
+ export type UseDisplayNamesProps = Intl.DisplayNamesOptions
6
+
7
+ export function useDisplayNames(props: UseDisplayNamesProps) {
8
+ const locale = useLocale()
9
+ const memoOptions = useMemoObject(props)
10
+ return useMemo(() => new Intl.DisplayNames(locale, memoOptions), [locale, memoOptions])
11
+ }
12
+
13
+ type DisplayNamesProps = UseDisplayNamesProps & {
14
+ code: string
15
+ }
16
+
17
+ export function DisplayNames(props: DisplayNamesProps) {
18
+ const { code, ...options } = props
19
+ const formatter = useDisplayNames(options)
20
+
21
+ return <span suppressHydrationWarning>{formatter.of(code)}</span>
22
+ }
@@ -0,0 +1 @@
1
+ export * from './DisplayNames'
@@ -0,0 +1,32 @@
1
+ import React, { useMemo } from 'react'
2
+ import { useLocale } from '../hooks'
3
+
4
+ type ListFormatProps = {
5
+ children: React.ReactNode[]
6
+ listStyle?: Intl.ListFormatOptions['style']
7
+ } & Omit<Intl.ListFormatOptions, 'style'>
8
+
9
+ export function ListFormat(props: ListFormatProps) {
10
+ const { children, localeMatcher, listStyle: style, type } = props
11
+
12
+ const locale = useLocale()
13
+
14
+ const formatter = useMemo(
15
+ () => new Intl.ListFormat(locale, { localeMatcher, style, type }),
16
+ [locale, localeMatcher, style, type],
17
+ )
18
+
19
+ const childArray = React.Children.toArray(children)
20
+ const fauxChildren = childArray.map((child, index) => `${index}`) ?? []
21
+ const parts = formatter.formatToParts(fauxChildren)
22
+
23
+ return (
24
+ <>
25
+ {parts.map((part) => (
26
+ <React.Fragment key={part.value}>
27
+ {part.type === 'literal' ? part.value : childArray[part.value]}
28
+ </React.Fragment>
29
+ ))}
30
+ </>
31
+ )
32
+ }