Skip to content

Commit 6808c85

Browse files
authored
chore(storybook): fix code loading on docs pages [CSS-1070] (#3440)
Fix an issue where "show code" was blocking loading in Storybook docs pages [CSS-1070]
1 parent 5be513a commit 6808c85

File tree

33 files changed

+2736
-473
lines changed

33 files changed

+2736
-473
lines changed

.changeset/famous-comics-run.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@spectrum-css/preview": patch
3+
---
4+
5+
Fix an issue where "show code" was blocking loading in Storybook docs pages [CSS-1070]

.storybook/decorators/context.js

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ export const withContextWrapper = makeDecorator({
2020
color = "light",
2121
context = "legacy",
2222
scale = "medium",
23-
testingPreview = false,
23+
} = {},
24+
parameters: {
25+
showTestingGrid = false,
2426
} = {},
2527
id,
2628
viewMode,
@@ -45,7 +47,7 @@ export const withContextWrapper = makeDecorator({
4547

4648
useEffect(() => {
4749
const isDocs = viewMode === "docs";
48-
const isTesting = testingPreview;
50+
const isTesting = showTestingGrid;
4951
const isRaw = Boolean(context === "raw");
5052
const isModern = Boolean(context === "spectrum");
5153
const isExpress = Boolean(context === "express");
@@ -59,16 +61,18 @@ export const withContextWrapper = makeDecorator({
5961
}
6062

6163
for (const container of fetchContainers(id, isDocs, isTesting)) {
64+
// Check if the container is a testing wrapper to prevent applying colors around the testing grid
65+
const isTestingWrapper = isTesting ? container.matches("body:has([data-testing-preview]),[data-testing-preview]") : false;
66+
// Check if the container has a static color element
67+
let hasStaticElement = container.matches(`:has([data-html-preview])`) ? container.matches(`:has([data-html-preview] .${rootClass}--staticWhite, [data-html-preview] .${rootClass}--staticBlack)`) : container.matches(`:has(.${rootClass}--staticWhite, .${rootClass}--staticBlack)`);
68+
6269
// Reset the context to the original values
6370
color = original.color;
6471
context = original.context;
6572
scale = original.scale;
6673

67-
// Check if the container has a static color element
68-
let hasStaticElement = container.matches(`:has([data-html-preview])`) ? container.matches(`:has([data-html-preview] .${rootClass}--staticWhite, [data-html-preview] .${rootClass}--staticBlack)`) : container.matches(`:has(.${rootClass}--staticWhite, .${rootClass}--staticBlack)`);
69-
7074
let staticKey = staticColor;
71-
if (!staticKey && hasStaticElement) {
75+
if (!isTestingWrapper && !staticKey && hasStaticElement) {
7276
staticKey = (
7377
container.querySelector(`.${rootClass}--staticWhite`) && "white" ||
7478
container.querySelector(`.${rootClass}--staticBlack`) && "black"
@@ -95,13 +99,13 @@ export const withContextWrapper = makeDecorator({
9599
}
96100

97101
// Let the static color override the color if it's set
98-
if (hasStaticElement && staticColorSettings[staticKey]?.color) {
102+
if (!isTestingWrapper && hasStaticElement && staticColorSettings[staticKey]?.color) {
99103
color = staticColorSettings[staticKey].color;
100104
}
101105

102106
// Force a light theme for the body wrapper in testing preview mode
103107
// because the individual containers will bring in the correct theme
104-
if (isTesting && container.matches("body:has([data-testing-preview]")) {
108+
if (isTestingWrapper) {
105109
color = "light";
106110
}
107111

@@ -113,14 +117,17 @@ export const withContextWrapper = makeDecorator({
113117
container.classList.toggle(`spectrum--${s}`, s === scale && !isRaw);
114118
}
115119

116-
// Start by removing the background color from the container and then add it back if needed
117-
container.style.removeProperty("background");
118-
if (hasStaticElement && staticKey && staticColorSettings[staticKey]) {
119-
container.style.background = staticColorSettings[staticKey].background;
120+
if (!isTestingWrapper) {
121+
if (hasStaticElement && staticKey && staticColorSettings[staticKey]) {
122+
container.style.background = staticColorSettings[staticKey].background;
123+
}
124+
} else {
125+
// Testing background is stark white to highlight the gray-ish background color on light theme
126+
container.style.background = "Canvas";
120127
}
121128
}
122129

123-
}, [context, viewMode, original, staticColor, color, scale, rootClass, tokens, staticColorSettings, testingPreview]);
130+
}, [context, viewMode, original, staticColor, color, scale, rootClass, tokens, staticColorSettings, showTestingGrid]);
124131

125132
return StoryFn(data);
126133
},

.storybook/decorators/helpers.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ export function fetchContainers(id, isDocs = false, isTesting = false) {
6868
}
6969
else if (isTesting) {
7070
// Only capture the top-level container for testing previews
71-
containers.push(...document.querySelectorAll("[data-inner-container]"));
71+
containers.push(...document.querySelectorAll("body,[data-testing-preview],[data-testing-preview] [data-inner-container]"));
7272
}
7373

7474
if (containers.length === 0) containers = [document.body];

.storybook/decorators/language.js

Lines changed: 38 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { makeDecorator, useEffect } from "@storybook/preview-api";
22
import { fetchContainers } from "./helpers.js";
3-
/* global Typekit */
43

54
/**
65
* @type import('@storybook/csf').DecoratorFunction<import('@storybook/web-components').WebComponentsFramework>
@@ -17,48 +16,51 @@ export const withLanguageWrapper = makeDecorator({
1716
viewMode,
1817
} = context;
1918

19+
const currentKitId = window.currentKitId;
20+
2021
useEffect(() => {
21-
const isNotEnglish = lang && lang !== "en-US";
22+
// Set the language on all containers and track if it has changed
23+
let hasChanged = false;
24+
for (const container of fetchContainers(id, viewMode === "docs")) {
25+
if (container.lang !== lang) {
26+
container.lang = lang;
27+
hasChanged = true;
28+
}
29+
}
30+
31+
// If the fonts are actively loading, do not re-trigger the load
32+
if (window.FontsLoading === true) return;
33+
// If the language has not changed, do not re-trigger the load
34+
if (!hasChanged) return;
2235

2336
// If it is US-language or unset use the rok6rmo Adobe font web project id (smaller size),
2437
// otherwise use the mge7bvf kit with all the language settings (larger size)
25-
const kitId = isNotEnglish ? "mge7bvf" : "rok6rmo";
26-
const config = {
27-
kitId,
28-
async: true,
29-
scriptTimeout: 3000,
30-
// https://github.com/typekit/webfontloader?tab=readme-ov-file#configuration
31-
loading: function() {},
32-
fontactive: function(familyName) {
33-
console.log(`Font ${familyName} active`);
34-
},
35-
fontinactive: function(familyName) {
36-
console.log(`Font ${familyName} inactive`);
37-
},
38-
active: function() {
39-
console.log(`Font loaded [id: ${kitId}]`);
38+
const kitId = lang && lang !== "en-US" ? "mge7bvf" : "rok6rmo";
4039

41-
// Fire a custom event to indicate the Adobe Fonts have loaded
42-
document.dispatchEvent(new CustomEvent("typekit-loaded", { detail: { kitId } }));
43-
},
44-
}
40+
// If the current kit is the same as the new kit, do not re-trigger the load
41+
if (currentKitId === kitId) return;
4542

46-
if (typeof window.Typekit !== "undefined") {
47-
// If the kitId is the same as the one already loaded, do nothing
48-
if (window.Typekit.config?.kitId !== kitId) {
49-
window.Typekit.load(config);
50-
}
51-
}
52-
else {
53-
try {
54-
window.Typekit = Typekit.load(config);
55-
} catch (e) {/* empty */}
56-
}
43+
try {
44+
window.Typekit.load({
45+
kitId,
46+
async: true,
47+
scriptTimeout: 3000,
48+
// https://github.com/typekit/webfontloader?tab=readme-ov-file#configuration
49+
loading: function() {
50+
window.FontsLoading = true;
51+
},
52+
active: function() {
53+
window.FontsLoading = false;
54+
window.currentKitId = this.kitId;
55+
console.log(`Font loaded [id: ${this.kitId}]`);
5756

58-
for (const container of fetchContainers(id, viewMode === "docs")) {
59-
container.lang = lang;
60-
}
61-
}, [lang]);
57+
// Fire a custom event to indicate the Adobe Fonts have loaded
58+
document.dispatchEvent(new CustomEvent("typekit-loaded", { detail: { kitId: this.kitId } }));
59+
60+
},
61+
});
62+
} catch (e) {/* empty */}
63+
}, [lang, currentKitId, window]);
6264

6365
return StoryFn(context);
6466
},

.storybook/decorators/testing-preview.js

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import { FORCE_RE_RENDER } from '@storybook/core-events';
2-
import { addons, makeDecorator, useCallback } from "@storybook/preview-api";
1+
import { makeDecorator } from "@storybook/preview-api";
32
import isChromatic from "chromatic/isChromatic";
43

54
/**
@@ -11,27 +10,33 @@ export const withTestingPreviewWrapper = makeDecorator({
1110
parameterName: "testingPreview",
1211
wrapper: (StoryFn, context) => {
1312
const {
13+
// Testing preview reflects the state of the user-selected global value
1414
globals: {
1515
testingPreview = false,
1616
} = {},
17-
viewMode,
17+
// Show testing grid reflects whether the testing grid is currently visible in the UI
18+
parameters: {
19+
showTestingGrid,
20+
} = {},
21+
viewMode
1822
} = context;
1923

20-
const init = () => {
21-
window.isChromatic = typeof isChromatic === "function" && isChromatic() === true ? isChromatic : () => testingPreview && viewMode !== "docs";
22-
};
23-
24-
// Function that will update the global value and trigger a UI refresh.
25-
const refreshAndUpdateGlobal = () => {
26-
init();
27-
28-
// Invokes Storybook's addon API method (with the FORCE_RE_RENDER) event to trigger a UI refresh
29-
addons.getChannel().emit(FORCE_RE_RENDER);
30-
};
31-
32-
init();
24+
// Below we're setting a new parameter "showTestingGrid" to reflect whether the testing grid should be visible
25+
// This is done to ensure that the testing grid is always visible in the Chromatic testing view
26+
// and that the user-selected global value is respected in the Storybook UI
3327

34-
useCallback(() => refreshAndUpdateGlobal(), [testingPreview]);
28+
// If isChromatic() is true, we should update the global value to always show the testing grid
29+
if (typeof isChromatic === "function" && isChromatic() === true) {
30+
context.parameters.showTestingGrid = true;
31+
} else if (viewMode === "docs") {
32+
// If we're in the docs view, we should disable the testing grid
33+
context.parameters.showTestingGrid = false;
34+
} else if (typeof showTestingGrid === "undefined") {
35+
// If the global value is undefined, we should set it to the testing preview value
36+
context.parameters.showTestingGrid = testingPreview;
37+
} else if (showTestingGrid !== testingPreview) {
38+
context.parameters.showTestingGrid = testingPreview;
39+
}
3540

3641
return StoryFn(context);
3742
},

.storybook/decorators/underlay.js

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { Template as Underlay } from "@spectrum-css/underlay/stories/template.js";
22
import { makeDecorator } from "@storybook/preview-api";
3-
import isChromatic from "chromatic/isChromatic";
43
import { html } from "lit";
54
import { when } from "lit/directives/when.js";
65
import { getRandomId } from "./utilities.js";
@@ -14,22 +13,15 @@ export const withUnderlayWrapper = makeDecorator({
1413
parameterName: "withUnderlay",
1514
wrapper: (StoryFn, context) => {
1615
const {
17-
globals: {
18-
testingPreview = false,
19-
} = {},
20-
args: {
21-
isOpen = false,
22-
} = {},
23-
parameters: {
24-
withUnderlay = true,
25-
} = {},
16+
args: { isOpen = false } = {},
17+
parameters: { withUnderlay = true, showTestingGrid = false } = {},
2618
} = context;
2719

2820
const id = getRandomId("underlay");
2921

3022
// In the chromatic testing view, the underlay should be forced
3123
// to the height of the #storybook-root element to ensure it is visible
32-
if (testingPreview || isChromatic()) {
24+
if (showTestingGrid) {
3325
document.addEventListener("DOMContentLoaded", () => {
3426
setTimeout(() => {
3527
const container = document.getElementById("storybook-root");
@@ -47,6 +39,6 @@ export const withUnderlayWrapper = makeDecorator({
4739
return html`
4840
${when(withUnderlay, () => Underlay({ isOpen, id }, context))}
4941
${StoryFn(context)}
50-
`;
42+
`;
5143
},
5244
});

0 commit comments

Comments
 (0)