@graphcommerce/storyblok-ui 10.1.0-canary.21 → 10.1.0-canary.23
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 +8 -0
- package/Config.graphqls +13 -0
- package/lib/fetch.ts +22 -1
- package/lib/useStoryblokState.ts +46 -14
- package/package.json +8 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# @graphcommerce/storyblok-ui
|
|
2
2
|
|
|
3
|
+
## 10.1.0-canary.23
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#2634](https://github.com/graphcommerce-org/graphcommerce/pull/2634) [`e1a7e85`](https://github.com/graphcommerce-org/graphcommerce/commit/e1a7e856669b792b5c7464a7585868b4c8107622) - Sync Storyblok content with the Visual Editor's selected language ([@bramvanderholst](https://github.com/bramvanderholst))
|
|
8
|
+
|
|
9
|
+
## 10.1.0-canary.22
|
|
10
|
+
|
|
3
11
|
## 10.1.0-canary.21
|
|
4
12
|
|
|
5
13
|
## 10.1.0-canary.20
|
package/Config.graphqls
CHANGED
|
@@ -30,3 +30,16 @@ extend input GraphCommerceConfig {
|
|
|
30
30
|
"""
|
|
31
31
|
storyblok: StoryblokConfig!
|
|
32
32
|
}
|
|
33
|
+
|
|
34
|
+
extend input GraphCommerceStorefrontConfig {
|
|
35
|
+
"""
|
|
36
|
+
Storyblok language code to request for this storefront. Maps the storefront's
|
|
37
|
+
GraphCommerce locale to a Storyblok language version. When unset, the storefront's
|
|
38
|
+
GraphCommerce locale prefix is used as the language code, unless it matches the
|
|
39
|
+
default locale (in which case no `language` param is sent and Storyblok serves
|
|
40
|
+
its space-default language). Set this when the GraphCommerce default locale
|
|
41
|
+
differs from the Storyblok default language (e.g. GraphCommerce default `nl_NL`
|
|
42
|
+
while the Storyblok space default stays English).
|
|
43
|
+
"""
|
|
44
|
+
storyblokLocale: String
|
|
45
|
+
}
|
package/lib/fetch.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ApolloClient } from '@graphcommerce/graphql'
|
|
2
|
+
import { storefrontConfig } from '@graphcommerce/next-ui'
|
|
2
3
|
import {
|
|
3
4
|
getStoryblokApi,
|
|
4
5
|
type ISbStoriesParams,
|
|
@@ -18,6 +19,14 @@ export type FetchStoryOpts = {
|
|
|
18
19
|
* into full story objects in the response (e.g. `row_button_link_list.links`).
|
|
19
20
|
*/
|
|
20
21
|
resolveRelations?: string | string[]
|
|
22
|
+
/**
|
|
23
|
+
* Direct Storyblok language override. When set, takes precedence over the
|
|
24
|
+
* storefront-config based `storyblokLocale` and the locale-prefix fallback.
|
|
25
|
+
* Empty string means "no `language` param" — Storyblok serves its space
|
|
26
|
+
* default. Used by `useStoryblokState` to refetch in the editor's selected
|
|
27
|
+
* language.
|
|
28
|
+
*/
|
|
29
|
+
language?: string
|
|
21
30
|
}
|
|
22
31
|
export type FetchStoriesParams = ISbStoriesParams & FetchStoryOpts
|
|
23
32
|
|
|
@@ -36,6 +45,18 @@ export const sbParams = (opts: FetchStoryOpts = {}) => {
|
|
|
36
45
|
const lang = langPrefix(opts.locale)
|
|
37
46
|
const defaultLang = langPrefix(opts.defaultLocale)
|
|
38
47
|
const isDefault = !lang || lang === defaultLang
|
|
48
|
+
// Per-storefront override — lets projects map a GraphCommerce locale to a
|
|
49
|
+
// Storyblok language explicitly. Needed when the GC default locale differs
|
|
50
|
+
// from the Storyblok space's default language (e.g. GC default `nl_NL` while
|
|
51
|
+
// Storyblok stays English-default). When unset, fall back to the legacy
|
|
52
|
+
// locale-prefix heuristic.
|
|
53
|
+
const explicitLanguage = storefrontConfig(opts.locale)?.storyblokLocale
|
|
54
|
+
// Direct override has highest priority. Empty string = no `language` param
|
|
55
|
+
// (Storyblok serves its default language).
|
|
56
|
+
const language =
|
|
57
|
+
opts.language !== undefined
|
|
58
|
+
? opts.language || undefined
|
|
59
|
+
: (explicitLanguage ?? (!isDefault ? lang : undefined))
|
|
39
60
|
|
|
40
61
|
const resolveRelations = Array.isArray(opts.resolveRelations)
|
|
41
62
|
? opts.resolveRelations.join(',')
|
|
@@ -49,7 +70,7 @@ export const sbParams = (opts: FetchStoryOpts = {}) => {
|
|
|
49
70
|
resolve_links: 'story' as const,
|
|
50
71
|
...(resolveRelations && { resolve_relations: resolveRelations }),
|
|
51
72
|
...(isDev && { cv: Date.now() }),
|
|
52
|
-
...(
|
|
73
|
+
...(language && { language }),
|
|
53
74
|
}
|
|
54
75
|
}
|
|
55
76
|
|
package/lib/useStoryblokState.ts
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
type SbBlokData,
|
|
6
6
|
} from '@storyblok/react'
|
|
7
7
|
import { useEffect, useRef, useState } from 'react'
|
|
8
|
+
import { fetchStory } from './fetch'
|
|
8
9
|
import { resolveStoryblokProducts } from './resolveProducts'
|
|
9
10
|
|
|
10
11
|
export type UseStoryblokStateOptions = {
|
|
@@ -14,6 +15,14 @@ export type UseStoryblokStateOptions = {
|
|
|
14
15
|
* fully resolved by `fetchStory` in `getStaticProps`.
|
|
15
16
|
*/
|
|
16
17
|
skip?: boolean
|
|
18
|
+
/**
|
|
19
|
+
* Storyblok language code the Visual Editor is currently showing. When
|
|
20
|
+
* different from `initialStory`'s language, the hook refetches the story
|
|
21
|
+
* in this language on mount so the editor preview matches the editor's
|
|
22
|
+
* sidebar selection regardless of which GraphCommerce storefront the page
|
|
23
|
+
* renders in. Empty string means "Storyblok-default language".
|
|
24
|
+
*/
|
|
25
|
+
editorLanguage?: string
|
|
17
26
|
}
|
|
18
27
|
|
|
19
28
|
/**
|
|
@@ -22,18 +31,52 @@ export type UseStoryblokStateOptions = {
|
|
|
22
31
|
* `magento_category_id` fields are changed.
|
|
23
32
|
*
|
|
24
33
|
* The generic `T` lets the caller narrow the returned `content` to an auto-generated Storyblok
|
|
25
|
-
* content type.
|
|
34
|
+
* content type.
|
|
26
35
|
*/
|
|
27
36
|
export function useStoryblokState<T = SbBlokData>(
|
|
28
37
|
initialStory: ISbStoryData | null,
|
|
29
38
|
options: UseStoryblokStateOptions = {},
|
|
30
39
|
): ISbStoryData<T> | null {
|
|
31
|
-
const { skip = false } = options
|
|
40
|
+
const { skip = false, editorLanguage } = options
|
|
32
41
|
const story = useStoryblokStateBase(initialStory, { resolveLinks: 'story' })
|
|
33
42
|
const client = useApolloClient()
|
|
34
43
|
const [resolvedStory, setResolvedStory] = useState(story)
|
|
35
44
|
const prevStoryRef = useRef(story)
|
|
36
45
|
|
|
46
|
+
// Editor language refetch: Storyblok's bridge doesn't proactively push
|
|
47
|
+
// content on language switches (only on field edits), and preview cookies
|
|
48
|
+
// can't reach getStaticProps from third-party iframes. So when the editor's
|
|
49
|
+
// language differs from the initial SSR fetch we refetch client-side once.
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
if (skip || editorLanguage === undefined || !initialStory?.full_slug) return
|
|
52
|
+
const target = editorLanguage || 'default'
|
|
53
|
+
const current = initialStory.lang ?? 'default'
|
|
54
|
+
if (target === current) return
|
|
55
|
+
|
|
56
|
+
// Storyblok's `full_slug` is prefixed with the language folder (e.g.
|
|
57
|
+
// `nl/home`). Strip it so the refetch targets the canonical story
|
|
58
|
+
// regardless of which language we're switching to.
|
|
59
|
+
const lang = initialStory.lang
|
|
60
|
+
const baseSlug =
|
|
61
|
+
lang && lang !== 'default' && initialStory.full_slug.startsWith(`${lang}/`)
|
|
62
|
+
? initialStory.full_slug.slice(lang.length + 1)
|
|
63
|
+
: initialStory.full_slug
|
|
64
|
+
|
|
65
|
+
let cancelled = false
|
|
66
|
+
fetchStory(baseSlug, { preview: true, language: editorLanguage }, client).then(
|
|
67
|
+
(result) => {
|
|
68
|
+
if (cancelled) return
|
|
69
|
+
const fetched = result.data?.story
|
|
70
|
+
if (!fetched) return
|
|
71
|
+
prevStoryRef.current = fetched
|
|
72
|
+
setResolvedStory(fetched as typeof story)
|
|
73
|
+
},
|
|
74
|
+
)
|
|
75
|
+
return () => {
|
|
76
|
+
cancelled = true
|
|
77
|
+
}
|
|
78
|
+
}, [skip, editorLanguage, initialStory, client])
|
|
79
|
+
|
|
37
80
|
useEffect(() => {
|
|
38
81
|
if (skip) return
|
|
39
82
|
if (prevStoryRef.current === story) return
|
|
@@ -53,16 +96,5 @@ export function useStoryblokState<T = SbBlokData>(
|
|
|
53
96
|
}, [skip, story, client])
|
|
54
97
|
|
|
55
98
|
const finalStory = skip ? initialStory : resolvedStory
|
|
56
|
-
|
|
57
|
-
if (!finalStory) return null
|
|
58
|
-
if (finalStory.content?.component === 'page') {
|
|
59
|
-
return finalStory as ISbStoryData<T>
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (process.env.NODE_ENV === 'development') {
|
|
63
|
-
throw new Error(
|
|
64
|
-
`useStoryblokState: expected story content of type 'page' but got '${finalStory.content?.component}' for slug '${finalStory.full_slug}'. Use the upstream @storyblok/react useStoryblokState for non-page content.`,
|
|
65
|
-
)
|
|
66
|
-
}
|
|
67
|
-
return null
|
|
99
|
+
return (finalStory as ISbStoryData<T> | null) ?? null
|
|
68
100
|
}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@graphcommerce/storyblok-ui",
|
|
3
3
|
"homepage": "https://www.graphcommerce.org/",
|
|
4
4
|
"repository": "github:graphcommerce-org/graphcommerce",
|
|
5
|
-
"version": "10.1.0-canary.
|
|
5
|
+
"version": "10.1.0-canary.23",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"prettier": "@graphcommerce/prettier-config-pwa",
|
|
8
8
|
"eslintConfig": {
|
|
@@ -12,13 +12,13 @@
|
|
|
12
12
|
}
|
|
13
13
|
},
|
|
14
14
|
"peerDependencies": {
|
|
15
|
-
"@graphcommerce/eslint-config-pwa": "^10.1.0-canary.
|
|
16
|
-
"@graphcommerce/graphql": "^10.1.0-canary.
|
|
17
|
-
"@graphcommerce/image": "^10.1.0-canary.
|
|
18
|
-
"@graphcommerce/magento-product": "^10.1.0-canary.
|
|
19
|
-
"@graphcommerce/next-ui": "^10.1.0-canary.
|
|
20
|
-
"@graphcommerce/prettier-config-pwa": "^10.1.0-canary.
|
|
21
|
-
"@graphcommerce/typescript-config-pwa": "^10.1.0-canary.
|
|
15
|
+
"@graphcommerce/eslint-config-pwa": "^10.1.0-canary.23",
|
|
16
|
+
"@graphcommerce/graphql": "^10.1.0-canary.23",
|
|
17
|
+
"@graphcommerce/image": "^10.1.0-canary.23",
|
|
18
|
+
"@graphcommerce/magento-product": "^10.1.0-canary.23",
|
|
19
|
+
"@graphcommerce/next-ui": "^10.1.0-canary.23",
|
|
20
|
+
"@graphcommerce/prettier-config-pwa": "^10.1.0-canary.23",
|
|
21
|
+
"@graphcommerce/typescript-config-pwa": "^10.1.0-canary.23",
|
|
22
22
|
"@mui/material": "^7.0.0",
|
|
23
23
|
"@storyblok/react": "^6.0.0",
|
|
24
24
|
"react": "^19.2.0",
|