Skip to content

Commit

Permalink
chore(storybook): support static color settings in testing grid
Browse files Browse the repository at this point in the history
  • Loading branch information
castastrophe committed Sep 27, 2024
1 parent 5f52369 commit 3c68620
Show file tree
Hide file tree
Showing 22 changed files with 205 additions and 147 deletions.
1 change: 0 additions & 1 deletion .storybook/assets/base.css
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ svg:has(symbol):not(:has(use)) {

/* --- DOCS STYLES --- */
.docs-story > *:first-child {
background-color: var(--spectrum-background-layer-1-color);
overflow: hidden;
}

Expand Down
82 changes: 68 additions & 14 deletions .storybook/decorators/context.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ export const withContextWrapper = makeDecorator({
color = "light",
context = "legacy",
scale = "medium",
} = {},
testingPreview = false,
},
id,
viewMode,
} = data;
Expand All @@ -36,6 +37,37 @@ export const withContextWrapper = makeDecorator({
},
};

const updateScale = (scale) => {
const isRaw = Boolean(context === "raw");

for (const container of fetchContainers(id, viewMode === "docs", testingPreview)) {
container.classList.toggle("spectrum--medium", scale === "medium" && !isRaw);
container.classList.toggle("spectrum--large", scale === "large" && !isRaw);
}
};

const resizeObserver = new ResizeObserver((entries) => {
for (const entry of entries) {
const { contentRect } = entry;
const { width } = contentRect;

if (width >= 480 && scale !== "medium") {
scale = "medium";
updateScale("medium");
}
else if (width < 480 && scale !== "large") {
scale = "large";
updateScale("large");
}
}
});

const original = {
color,
context,
scale,
};

useEffect(() => {
const isRaw = Boolean(context === "raw");
const isModern = Boolean(context === "spectrum");
Expand All @@ -47,25 +79,35 @@ export const withContextWrapper = makeDecorator({
document.body.classList.add("spectrum", "spectrum--light", "spectrum--medium");
}

for (const container of fetchContainers(id, viewMode === "docs")) {
// Start by attaching the appropriate tokens to the container
toggleStyles(container, "tokens", tokens, !isRaw);
// Start by attaching the appropriate tokens to the container
toggleStyles(document.body, "tokens", tokens, !isRaw);

for (const container of fetchContainers(id, viewMode === "docs", testingPreview)) {
// Reset the context to the original values
color = original.color;
context = original.context;
scale = original.scale;

// Check if the container has a static color element
const hasStaticElement = container.matches(`:has(.${rootClass}--staticWhite, .${rootClass}--staticBlack, .${rootClass}--overBackground)`);
let hasStaticElement = container.matches(`:has([data-html-preview])`) ? container.matches(`:has([data-html-preview] .${rootClass}--staticWhite, [data-html-preview] .${rootClass}--staticBlack, [data-html-preview] .${rootClass}--overBackground)`) : container.matches(`:has(.${rootClass}--staticWhite, .${rootClass}--staticBlack, .${rootClass}--overBackground)`);

let staticKey = staticColor;
if (!staticKey && hasStaticElement) {
staticKey = (
container.querySelector(`.${rootClass}--staticWhite`) && "white" ||
container.querySelector(`.${rootClass}--staticBlack, .${rootClass}--overBackground`) && "black"
container.querySelector(`.${rootClass}--staticWhite, .${rootClass}--overBackground`) && "white" ||
container.querySelector(`.${rootClass}--staticBlack`) && "black"
);
}

// If we can't determine the static key, we can't use the static color
if (!staticKey) hasStaticElement = false;

// Every container gets the spectrum class
container.classList.toggle("spectrum", !isRaw);

// S1 and S1 Express get the legacy class
container.classList.toggle("spectrum--legacy", !isModern && !isRaw);

// Express only gets the express class
container.classList.toggle("spectrum--express", isExpress && !isRaw);

Expand All @@ -76,16 +118,23 @@ export const withContextWrapper = makeDecorator({
color = "dark";
}

for (let c of ["light", "dark", "darkest"]) {
// Force light or dark mode if the static color is set
const isColor = staticKey && c === staticColorSettings[staticKey]?.color || !staticKey && c === color;
// Let the static color override the color if it's set
if (hasStaticElement && staticColorSettings[staticKey]?.color) {
color = staticColorSettings[staticKey].color;
}

container.classList.toggle(`spectrum--${c}`, isColor && !isRaw);
// Force a light theme for the body wrapper in testing preview mode
// because the individual containers will bring in the correct theme
if (testingPreview && container.matches("body:has([data-testing-preview]")) {
color = "light";
}

for (let c of ["light", "dark", "darkest"]) {
container.classList.toggle(`spectrum--${c}`, c === color && !isRaw);
}

for (const s of ["medium", "large"]) {
const isScale = s === scale;
container.classList.toggle(`spectrum--${s}`, isScale && !isRaw);
container.classList.toggle(`spectrum--${s}`, s === scale && !isRaw);
}

// Start by removing the background color from the container and then add it back if needed
Expand All @@ -94,7 +143,12 @@ export const withContextWrapper = makeDecorator({
container.style.background = staticColorSettings[staticKey].background;
}
}
}, [color, context, staticColor, scale, viewMode, rootClass, tokens, staticColorSettings]);

}, [context, viewMode, original, staticColor, color, scale, rootClass, tokens, staticColorSettings]);


// We only need to observe the body element for a viewport change
resizeObserver.observe(document.body);

return StoryFn(data);
},
Expand Down
34 changes: 20 additions & 14 deletions .storybook/decorators/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,22 +50,28 @@ export function fetchStyleContainer(id, container) {
* @type (id: string, isDocs: boolean = false) => HTMLElement[]
* @description Fetches the style container for the given ID or creates a new one
**/
export function fetchContainers(id, isDocs = false) {
if (!id) return [];
const { document } = global;
export function fetchContainers(id, isDocs = false, isTesting = false) {
if (!id) return [];
const { document } = global;

let containers = [];

let containers = [document.body];
// Storybook IDs used to target the container element for the docs pages
const roots = [
...document.querySelectorAll(`#story--${id}`),
...document.querySelectorAll(`#story--${id}--primary`)
];

// Storybook IDs used to target the container element for the docs pages
const roots = [
...document.querySelectorAll(`#story--${id}`),
...document.querySelectorAll(`#story--${id}--primary`)
];
// viewMode is either "docs" or "story"
if (isDocs && roots.length > 0) {
containers = roots.map(root => root.closest(".docs-story") ?? root);
}
else if (isTesting) {
// Only capture the top-level container for testing previews
containers.push(...document.querySelectorAll("[data-inner-container]"), document.body);
}

// viewMode is either "docs" or "story"
if (isDocs && roots.length > 0) {
containers = roots.map(root => root.closest(".docs-story") ?? root);
}
if (containers.length === 0) containers = [document.body];

return containers;
return containers;
}
28 changes: 26 additions & 2 deletions .storybook/decorators/utilities.js
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,8 @@ export const ArgGrid = ({
withWrapperBorder = true,
...args
} = {}, context = {}) => {
const isDocs = context.viewMode === "docs";

if (typeof argKey === "undefined") {
console.warn("ArgGrid: argKey is required to render the grid.");
return nothing;
Expand All @@ -230,6 +232,11 @@ export const ArgGrid = ({
return nothing;
}

// If no heading and this is a docs view, skip the border
if (!heading && isDocs) {
withWrapperBorder = false;
}

return Container({
heading,
direction,
Expand Down Expand Up @@ -323,17 +330,26 @@ export const Variants = ({
TestTemplate = Template;
}

const staticColor = {
black: "var(--spectrum-docs-static-black-background-color)",
white: "var(--spectrum-docs-static-white-background-color)",
};

return (args, context) => {
// Fetch any docs configurations from the context to use for VRT
const { parameters = {} } = context;
const { argTypes = {}, parameters = {} } = context;

const height = parameters?.docs?.story?.height;
const width = parameters?.docs?.story?.width;

// Check if the staticColor property exists in this story
const hasStaticColor = Object.keys(argTypes).includes("staticColor");

return html`
<!-- Simple, clean template preview for non-testing grid views -->
<div
style=${styleMap({
backgroundColor: hasStaticColor && staticColor[args.staticColor],
"padding": "12px",
"min-block-size": typeof height === "number" ? `${height}px` : height,
"min-inline-size": typeof width === "number" ? `${width}px` : width,
Expand All @@ -347,6 +363,7 @@ export const Variants = ({
<!-- Start testing grid markup -->
<div
data-testing-preview
style=${styleMap({
"padding": "24px",
"display": window.isChromatic() ? "flex" : "none",
Expand Down Expand Up @@ -391,7 +408,14 @@ export const Variants = ({
testHeading = "Default";
}
// Check if the staticColor property is being used in this story
let backgroundColor;
if (hasStaticColor && data.staticColor) {
backgroundColor = staticColor[data.staticColor];
}
const combinedStyles = {
backgroundColor,
...wrapperStyles,
...testWrapperStyles,
};
Expand All @@ -405,7 +429,7 @@ export const Variants = ({
...containerStyles,
},
// if the test has multiple states, pass the wrapper styles to that container, otherwise use it here
wrapperStyles: withStates ? {} : combinedStyles,
wrapperStyles: withStates ? { backgroundColor } : combinedStyles,
content: html`
${when(withStates, () =>
States({
Expand Down
24 changes: 0 additions & 24 deletions components/actionbutton/stories/actionbutton.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,30 +111,6 @@ Quiet.parameters = {
};

// ********* VRT ONLY ********* //
export const StaticBlack = ActionButtonGroup.bind({});
StaticBlack.tags = ["!autodocs", "!dev"];
StaticBlack.args = {
...Default.args,
staticColor: "black",
};
StaticBlack.parameters = {
chromatic: {
modes: disableDefaultModes
},
};

export const StaticWhite = ActionButtonGroup.bind({});
StaticWhite.tags = ["!autodocs", "!dev"];
StaticWhite.args = {
...Default.args,
staticColor: "white",
};
StaticWhite.parameters = {
chromatic: {
modes: disableDefaultModes
},
};

export const WithForcedColors = ActionButtonGroup.bind({});
WithForcedColors.args = Default.args;
WithForcedColors.tags = ["!autodocs", "!dev"];
Expand Down
8 changes: 8 additions & 0 deletions components/actionbutton/stories/actionbutton.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,14 @@ export const ActionButtonGroup = Variants({
},
withStates: false,
},
{
testHeading: "Static black",
staticColor: "black",
},
{
testHeading: "Static white",
staticColor: "white",
},
],
stateData: [{
testHeading: "Disabled",
Expand Down
8 changes: 8 additions & 0 deletions components/actiongroup/stories/actiongroup.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,13 @@ export const ActionGroups = Variants({
testHeading: "Vertical",
vertical: true,
},
{
testHeading: "Static black",
staticColor: "black",
},
{
testHeading: "Static white",
staticColor: "white",
},
],
});
26 changes: 2 additions & 24 deletions components/button/stories/button.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,28 +93,6 @@ export const Default = ButtonGroups.bind({});
Default.args = {};

// ********* VRT ONLY ********* //
export const StaticWhite = ButtonGroups.bind({});
StaticWhite.tags = ["!autodocs", "!dev"];
StaticWhite.args = {
staticColor: "white",
};
StaticWhite.parameters = {
chromatic: {
modes: disableDefaultModes
},
};

export const StaticBlack = ButtonGroups.bind({});
StaticBlack.tags = ["!autodocs", "!dev"];
StaticBlack.args = {
staticColor: "black",
};
StaticBlack.parameters = {
chromatic: {
modes: disableDefaultModes
},
};

export const WithForcedColors = ButtonGroups.bind({});
WithForcedColors.args = Default.args;
WithForcedColors.tags = ["!autodocs", "!dev"];
Expand Down Expand Up @@ -266,7 +244,7 @@ Pending.parameters = {
};

/**
* A button in a disabled state shows that an action exists, but is not available in that circumstance.
* A button in a disabled state shows that an action exists, but is not available in that circumstance.
* This state can be used to maintain layout continuity and to communicate that an action may become
* available later.
*/
Expand All @@ -281,7 +259,7 @@ Disabled.parameters = {
};

/**
* When the button text is too long for the horizontal space available, it wraps to form another line.
* When the button text is too long for the horizontal space available, it wraps to form another line.
* When there is no icon present, the text is aligned center. When there is an icon present, the text is
* aligned `start` (left with a writing direction of left-to-right) and the icon remains vertically aligned
* at the top.
Expand Down
8 changes: 8 additions & 0 deletions components/button/stories/button.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ export const ButtonGroups = Variants({
variant,
treatment: "outline",
})),
{
testHeading: "Static black",
staticColor: "black",
},
{
testHeading: "Static white",
staticColor: "white",
},
{
testHeading: "Text wrapping with workflow icon",
customStyles: {
Expand Down
4 changes: 1 addition & 3 deletions components/clearbutton/stories/clearbutton.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,7 @@ OverBackground.args = {
staticColor: "white",
};
OverBackground.parameters = {
chromatic: {
modes: disableDefaultModes
},
chromatic: { disableSnapshot: true },
};

// ********* VRT ONLY ********* //
Expand Down
Loading

0 comments on commit 3c68620

Please sign in to comment.