Skip to content

chore(storybook): add migrated components list #3745

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: spectrum-two
Choose a base branch
from
59 changes: 58 additions & 1 deletion .storybook/blocks/ComponentDetails.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@ import React, { useEffect, useState } from "react";

import { Body, Code, Heading } from "./Typography.jsx";
import { DDefinition, DList, DTerm } from "./Layouts.jsx";
import { fetchToken } from "./utilities.js";
import { fetchToken, getComponentsByStatusWrapper } from "./utilities.js";

import AdobeSVG from "../assets/images/adobe_logo.svg?raw";
import GitHubSVG from "../assets/images/github_logo.svg?raw";
import NpmSVG from "../assets/images/npm_logo.svg?raw";
import WCSVG from "../assets/images/wc_logo.svg?raw";

// Import the pre-generated migrated components data
import migratedComponentsData from '../data/migrated-components.json';

export const DSet = ({ term, children }) => {
return (
<>
Expand Down Expand Up @@ -443,4 +446,58 @@ export const TaggedReleases = () => {
);
};

/**
* Displays a list of all components that have been migrated to Spectrum 2.
*
* Usage of this doc block within MDX template(s):
* <MigratedComponentsList />
*/
export const MigratedComponentsList = () => {
const [components, setComponents] = useState([]);
const [isLoading, setIsLoading] = useState(true);

useEffect(() => {
// Try to load components server-side first (Node.js environment)
try {
// Use the pre-generated data from our JSON file
if (migratedComponentsData && migratedComponentsData.components) {
setComponents(migratedComponentsData.components);
setIsLoading(false);
return;
}

// Dynamic loading as fallback
const migrated = getComponentsByStatusWrapper({ statusType: 'migrated' });

if (migrated && migrated.length > 0) {
setComponents(migrated);
}
} catch (error) {
console.warn('Failed to get migrated components:', error);
}

setIsLoading(false);
}, []);

return (
<ResetWrapper>
{!isLoading ? (
<>
<ul className="sb-unstyled" style={{ columnCount: 3, columnGap: '1rem', listStyle: 'none', padding: 0, marginTop: '1rem' }}>
{components.map((component, idx) => (
<li key={`${component.name || component}-${idx}`} style={{ marginBottom: '0.5rem' }}>
<a href={`./?path=/docs/components-${component.url}--docs`}>
{component.title || (typeof component === 'string' ? component.charAt(0).toUpperCase() + component.slice(1) : '')}
</a>
</li>
))}
</ul>
</>
) : (
<Body>Loading migrated components...</Body>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the fallback to load dynamically doesn't work and we're always pulling from the json file, it might be worth another look to determine if we need a loading state.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call. I think that depends on whether we want to commit that JSON file, right? I had some other questions about that file, but this is another good one.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because, yes, if we always pull from that file, I don't think we need the fallback. 👍

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep. It's not hurting anything to keep the loading state logic but as it is right now, I don't think there's a situation where we'd see the loading state in the UI.

Now, it is also fair to say we don't have a way to handle if the json file somehow fails after the build (if it's somehow missing when ComponentDetails reaches for it, right now this causes an error; or if the components array is empty, or the components property is missing altogether, which makes the list empty, which is okay)...

And yeah, I'd agree, I think we do want to commit the json file unless it's set up to automatically regenerate when you start storybook?

)}
</ResetWrapper>
);
};

export default ComponentDetails;
46 changes: 45 additions & 1 deletion .storybook/blocks/utilities.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,51 @@
import spectrum from "@spectrum-css/tokens/dist/json/tokens.json";

import { useTheme } from "@storybook/theming";

// Import fs and path conditionally to avoid browser issues
let isNode = false;
let componentUtils = null;

// Check if we're running in Node.js environment
try {
isNode = typeof process !== 'undefined' &&
typeof process.versions !== 'undefined' &&
typeof process.versions.node !== 'undefined';

if (isNode) {
// Import the component utility functions from migrated-component-scanner.js
try {
componentUtils = require('../../tasks/migrated-component-scanner');
} catch (err) {
console.warn('Failed to import component utilities:', err);
}
}
} catch (e) {
// We're in a browser environment
console.log('Running in browser environment, file system functions will be limited');
}

/**
* Gets all component directories that have a specific status.
* This is a Storybook-facing "wrapper" that defers the actual work to the
* Node.js script in tasks/migrated-component-scanner.js. In this browser this
* wrapper returns an empty array and prevents bundlers from pulling in fs/path
* and avoiding runtime errors.
* @param {Object} options Options for filtering components
* @param {string} options.statusType Status type to filter by (e.g., 'migrated')
* @returns {string[]} Array of matching component directory names
*/
export function getComponentsByStatusWrapper(options = {}) {
// Check if we're in a Node.js environment
if (!isNode || !componentUtils) {
console.warn('getComponentsByStatus can only be used in a Node.js environment');
return [];
}

const { statusType } = options;

return componentUtils.getComponentsByStatus(statusType);
}

/**
* A nestable function to search for a token value in the spectrum token data
* - If the key doesn't exist, it will log a warning
Expand Down
Loading
Loading