@skyscanner/backpack-web 42.27.1 → 42.27.2

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.
@@ -1,4 +1,4 @@
1
- export { BpkProvider } from './src/BpkProvider';
1
+ export { BpkProvider, BpkEmotionCacheContext } from './src/BpkProvider';
2
2
  export { BpkBox } from './src/BpkBox';
3
3
  export { BpkVessel } from './src/BpkVessel';
4
4
  export { BpkFlex } from './src/BpkFlex';
@@ -16,7 +16,7 @@
16
16
  * limitations under the License.
17
17
  */
18
18
 
19
- export { BpkProvider } from "./src/BpkProvider";
19
+ export { BpkProvider, BpkEmotionCacheContext } from "./src/BpkProvider";
20
20
  export { BpkBox } from "./src/BpkBox";
21
21
  export { BpkVessel } from "./src/BpkVessel";
22
22
  export { BpkFlex } from "./src/BpkFlex";
@@ -1,11 +1,14 @@
1
- import type { ReactElement, ReactNode } from 'react';
1
+ import type { ReactNode, ReactElement } from 'react';
2
+ import type { EmotionCache } from '@emotion/cache';
2
3
  export interface BpkProviderProps {
3
4
  children: ReactNode;
4
5
  }
6
+ export declare const BpkEmotionCacheContext: import("react").Context<EmotionCache | null>;
5
7
  /**
6
8
  * BpkProvider - Provides context for Backpack layout and Ark-based components.
7
9
  *
8
10
  * Wraps children with:
11
+ * - Emotion CacheProvider (own cache, or external cache injected via BpkEmotionCacheContext)
9
12
  * - Chakra UI system context (for layout components: BpkFlex, BpkGrid, etc.)
10
13
  * - Ark UI LocaleProvider (for Ark-based components: BpkCheckboxV2, BpkSegmentedControlV2, etc.)
11
14
  *
@@ -13,6 +16,11 @@ export interface BpkProviderProps {
13
16
  * the appropriate locale to Ark's LocaleProvider. All Ark-based components in the
14
17
  * tree render correctly in RTL without requiring additional wrapping or prop changes.
15
18
  *
19
+ * External cache injection: host apps can supply an Emotion cache via
20
+ * BpkEmotionCacheContext. When a non-null value is provided, BpkProvider uses it
21
+ * directly and skips creating its own cache. This allows the host to swap in a
22
+ * fresh cache after a hydration error so all Backpack styles are re-injected.
23
+ *
16
24
  * @param {BpkProviderProps} props - The provider props.
17
25
  * @returns {ReactElement} The provider wrapping its children with Chakra and Ark context.
18
26
  */
@@ -23,6 +23,12 @@ import createCache from '@emotion/cache';
23
23
  import { CacheProvider } from '@emotion/react';
24
24
  import { createBpkConfig } from "./theme";
25
25
  import { jsx as _jsx } from "react/jsx-runtime";
26
+ // Exported so host apps can inject an externally-managed Emotion cache into
27
+ // BpkProvider (e.g. to force re-injection after a hydration error recovery).
28
+ // When a non-null value is provided via this context, BpkProvider operates in
29
+ // "external cache" mode: it skips creating its own cache and delegates to the external one.
30
+ export const BpkEmotionCacheContext = /*#__PURE__*/createContext(null);
31
+
26
32
  /**
27
33
  * Creates a Chakra UI system with Backpack token mappings.
28
34
  *
@@ -37,6 +43,14 @@ const bpkSystem = createSystem(defaultBaseConfig, createBpkConfig());
37
43
  // Force speedy:false + recreate after mount in Cypress. Remove once Emotion /
38
44
  // React Router 7 provide a cleaner hydration story. Ported from hotels-website#12025.
39
45
 
46
+ // `'css'` is shared with Chakra v3's internal key on purpose — keeps this
47
+ // boundary in front of Chakra's auto-created cache.
48
+ const createBpkEmotionCache = speedy => createCache(speedy === undefined ? {
49
+ key: 'css'
50
+ } : {
51
+ key: 'css',
52
+ speedy
53
+ });
40
54
  const isCypressEnv = () => {
41
55
  if (typeof window === 'undefined') return false;
42
56
  const win = window;
@@ -49,16 +63,6 @@ const isCypressEnv = () => {
49
63
  return false; // cross-origin parent frame
50
64
  }
51
65
  };
52
-
53
- // `'css'` is shared with Chakra v3's internal key on purpose — keeps this
54
- // boundary in front of Chakra's auto-created cache.
55
- const createBpkEmotionCache = speedy => createCache(speedy === undefined ? {
56
- key: 'css'
57
- } : {
58
- key: 'css',
59
- speedy
60
- });
61
- const BpkEmotionCacheContext = /*#__PURE__*/createContext(null);
62
66
  // Fallback locale mapping used when no explicit locale is available on the document.
63
67
  // Maps DOM direction to minimal BCP 47 locales understood by Ark's isRTL() utility.
64
68
  // 'ar-SA' is the minimal RTL locale — Ark only uses it to derive dir='rtl'.
@@ -153,6 +157,7 @@ const useArkLocale = () => {
153
157
  * BpkProvider - Provides context for Backpack layout and Ark-based components.
154
158
  *
155
159
  * Wraps children with:
160
+ * - Emotion CacheProvider (own cache, or external cache injected via BpkEmotionCacheContext)
156
161
  * - Chakra UI system context (for layout components: BpkFlex, BpkGrid, etc.)
157
162
  * - Ark UI LocaleProvider (for Ark-based components: BpkCheckboxV2, BpkSegmentedControlV2, etc.)
158
163
  *
@@ -160,16 +165,21 @@ const useArkLocale = () => {
160
165
  * the appropriate locale to Ark's LocaleProvider. All Ark-based components in the
161
166
  * tree render correctly in RTL without requiring additional wrapping or prop changes.
162
167
  *
168
+ * External cache injection: host apps can supply an Emotion cache via
169
+ * BpkEmotionCacheContext. When a non-null value is provided, BpkProvider uses it
170
+ * directly and skips creating its own cache. This allows the host to swap in a
171
+ * fresh cache after a hydration error so all Backpack styles are re-injected.
172
+ *
163
173
  * @param {BpkProviderProps} props - The provider props.
164
174
  * @returns {ReactElement} The provider wrapping its children with Chakra and Ark context.
165
175
  */
166
176
  export const BpkProvider = ({
167
177
  children
168
178
  }) => {
169
- const parentCache = useContext(BpkEmotionCacheContext);
170
- const isNested = parentCache !== null;
179
+ const externalCache = useContext(BpkEmotionCacheContext);
180
+ const hasExternalCache = externalCache !== null;
171
181
  const [isCypress] = useState(isCypressEnv);
172
- const [ownCache, setOwnCache] = useState(() => isNested ? parentCache : createBpkEmotionCache(isCypress ? false : undefined));
182
+ const [ownCache, setOwnCache] = useState(() => hasExternalCache ? externalCache : createBpkEmotionCache(isCypress ? false : undefined));
173
183
  const hasRecreated = useRef(false);
174
184
  const locale = useArkLocale();
175
185
 
@@ -177,12 +187,19 @@ export const BpkProvider = ({
177
187
  // nodes the hydrator stripped. `hasRecreated` guards StrictMode double-invoke.
178
188
  // Deps stable for provider lifetime → empty array is intentional.
179
189
  useEffect(() => {
180
- if (isNested || !isCypress) return;
190
+ if (hasExternalCache || !isCypress) return;
181
191
  if (hasRecreated.current) return;
182
192
  hasRecreated.current = true;
183
193
  setOwnCache(createBpkEmotionCache(false));
184
194
  // eslint-disable-next-line react-hooks/exhaustive-deps
185
195
  }, []);
196
+
197
+ // NOTE: if externalCache changes from non-null to null at runtime, ownCache
198
+ // will still hold the value it was initialised with (the old external cache).
199
+ // This is intentional: BpkEmotionCacheContext.Provider is expected to be
200
+ // mounted for the lifetime of the app once set — toggling it off is not a
201
+ // supported use case. The state initialiser runs only once per mount.
202
+ const activeCache = hasExternalCache ? externalCache : ownCache;
186
203
  const inner = /*#__PURE__*/_jsx(ChakraProvider, {
187
204
  value: bpkSystem,
188
205
  children: /*#__PURE__*/_jsx(LocaleProvider, {
@@ -190,13 +207,10 @@ export const BpkProvider = ({
190
207
  children: children
191
208
  })
192
209
  });
193
- if (isNested) {
194
- return inner;
195
- }
196
210
  return /*#__PURE__*/_jsx(BpkEmotionCacheContext.Provider, {
197
- value: ownCache,
211
+ value: activeCache,
198
212
  children: /*#__PURE__*/_jsx(CacheProvider, {
199
- value: ownCache,
213
+ value: activeCache,
200
214
  children: inner
201
215
  })
202
216
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skyscanner/backpack-web",
3
- "version": "42.27.1",
3
+ "version": "42.27.2",
4
4
  "description": "Backpack Design System web library",
5
5
  "repository": {
6
6
  "type": "git",