Merge pull request #27124 from backstage/storybook8
Update to Storybook 8
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 233 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 205 KiB After Width: | Height: | Size: 243 KiB |
@@ -61,7 +61,7 @@ core
|
||||
## Running locally
|
||||
|
||||
Go to `storybook`, run `yarn install` and install the dependencies, then run the
|
||||
following on your command line: `yarn start`
|
||||
following on your command line: `yarn storybook`
|
||||
|
||||

|
||||
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@
|
||||
"start:lighthouse": "yarn workspaces foreach -A --include example-backend --include example-app --parallel -v -i run start",
|
||||
"start:microsite": "cd microsite/ && yarn start",
|
||||
"start:next": "yarn workspace example-app-next start",
|
||||
"storybook": "yarn --cwd storybook && yarn --cwd storybook start",
|
||||
"storybook": "yarn ./storybook run storybook",
|
||||
"techdocs-cli": "node scripts/techdocs-cli.js",
|
||||
"techdocs-cli:dev": "cross-env TECHDOCS_CLI_DEV_MODE=true node scripts/techdocs-cli.js",
|
||||
"test": "backstage-cli repo test",
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import Dialog from '@material-ui/core/Dialog';
|
||||
import DialogActions from '@material-ui/core/DialogActions';
|
||||
@@ -23,9 +24,15 @@ import IconButton from '@material-ui/core/IconButton';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
|
||||
import CloseIcon from '@material-ui/icons/Close';
|
||||
import React, { useState } from 'react';
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) =>
|
||||
const meta = {
|
||||
title: 'Layout/Dialog',
|
||||
component: Dialog,
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
const styles = makeStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
closeButton: {
|
||||
position: 'absolute',
|
||||
@@ -36,90 +43,57 @@ const useStyles = makeStyles((theme: Theme) =>
|
||||
}),
|
||||
);
|
||||
|
||||
export default {
|
||||
title: 'Layout/Dialog',
|
||||
component: Dialog,
|
||||
};
|
||||
export const Default = {
|
||||
args: {
|
||||
open: true,
|
||||
},
|
||||
render: ({ open }: { open: boolean }) => {
|
||||
const classes = styles();
|
||||
|
||||
export const Default = () => {
|
||||
const [open, setOpen] = useState(false);
|
||||
const classes = useStyles();
|
||||
|
||||
const openDialog = () => {
|
||||
setOpen(true);
|
||||
};
|
||||
|
||||
const closeDialog = () => {
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
const dialogContent = () => {
|
||||
return (
|
||||
<>
|
||||
<Typography>
|
||||
This is an example of how to use the Dialog component.
|
||||
</Typography>
|
||||
<Typography>
|
||||
This component is used whenever confirmation of some sort is needed,
|
||||
such as:
|
||||
</Typography>
|
||||
<ul>
|
||||
<li>
|
||||
<Typography>
|
||||
Consent to sensitive matters like GDPR, access, etc;
|
||||
</Typography>
|
||||
</li>
|
||||
<li>
|
||||
<Typography>
|
||||
Save, submit, cancel after a form is completed;
|
||||
</Typography>
|
||||
</li>
|
||||
<li>
|
||||
<Typography>Alert message;</Typography>
|
||||
</li>
|
||||
<li>
|
||||
<Typography>Buttons are optional.</Typography>
|
||||
</li>
|
||||
</ul>
|
||||
<Typography>
|
||||
The color for the secondary button is the same as the primary.
|
||||
</Typography>
|
||||
<pre>color="primary"</pre>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button color="primary" variant="contained" onClick={openDialog}>
|
||||
Open Dialog
|
||||
</Button>
|
||||
<Dialog
|
||||
open={open}
|
||||
onClose={closeDialog}
|
||||
aria-labelledby="dialog-title"
|
||||
aria-describedby="dialog-description"
|
||||
open={open}
|
||||
>
|
||||
<DialogTitle id="dialog-title">
|
||||
Dialog Box Title
|
||||
<IconButton
|
||||
aria-label="close"
|
||||
className={classes.closeButton}
|
||||
onClick={closeDialog}
|
||||
>
|
||||
<IconButton aria-label="close" className={classes.closeButton}>
|
||||
<CloseIcon />
|
||||
</IconButton>
|
||||
</DialogTitle>
|
||||
<DialogContent>{dialogContent()}</DialogContent>
|
||||
<DialogContent>
|
||||
<Typography>
|
||||
This component is used whenever confirmation of some sort is needed,
|
||||
such as:
|
||||
</Typography>
|
||||
<ul>
|
||||
<li>
|
||||
<Typography>
|
||||
Consent to sensitive matters like GDPR, access, etc;
|
||||
</Typography>
|
||||
</li>
|
||||
<li>
|
||||
<Typography>
|
||||
Save, submit, cancel after a form is completed;
|
||||
</Typography>
|
||||
</li>
|
||||
<li>
|
||||
<Typography>Alert message;</Typography>
|
||||
</li>
|
||||
<li>
|
||||
<Typography>Buttons are optional.</Typography>
|
||||
</li>
|
||||
</ul>
|
||||
<Typography>
|
||||
The color for the secondary button is the same as the primary.
|
||||
</Typography>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button color="primary" onClick={closeDialog}>
|
||||
Secondary action
|
||||
</Button>
|
||||
<Button color="primary" onClick={closeDialog}>
|
||||
Primary action
|
||||
</Button>
|
||||
<Button color="primary">Secondary action</Button>
|
||||
<Button color="primary">Primary action</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
+8
-1
@@ -14,6 +14,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
// TODO: Fix this story
|
||||
// There's a bug in Storybook that causes the build to fail
|
||||
// when using the `useEntityPermission` hook
|
||||
// https://github.com/storybookjs/storybook/issues/29378
|
||||
// This has been reported and it should hopefully be fixed after 8.4
|
||||
|
||||
import { GroupEntity } from '@backstage/catalog-model';
|
||||
import {
|
||||
CatalogApi,
|
||||
@@ -59,7 +66,7 @@ const defaultEntity: GroupEntity = {
|
||||
};
|
||||
|
||||
const catalogApi: Partial<CatalogApi> = {
|
||||
async refreshEntity() {},
|
||||
async refreshEntity() { },
|
||||
};
|
||||
|
||||
const permissionApi: typeof permissionApiRef.T = {
|
||||
@@ -0,0 +1,26 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
*storybook.log
|
||||
@@ -1,121 +0,0 @@
|
||||
const path = require('path');
|
||||
const WebpackPluginFailBuildOnWarning = require('./webpack-plugin-fail-build-on-warning');
|
||||
|
||||
/**
|
||||
* This set of stories are the ones that we publish to backstage.io.
|
||||
*/
|
||||
const BACKSTAGE_CORE_STORIES = [
|
||||
'packages/core-components',
|
||||
'packages/app',
|
||||
'plugins/org',
|
||||
'plugins/search',
|
||||
'plugins/search-react',
|
||||
'plugins/home',
|
||||
'plugins/catalog-react',
|
||||
];
|
||||
|
||||
// Some configuration needs to be available directly on the exported object
|
||||
const staticConfig = {
|
||||
core: {
|
||||
builder: 'webpack5',
|
||||
},
|
||||
addons: [
|
||||
'@storybook/addon-controls',
|
||||
'@storybook/addon-a11y',
|
||||
'@storybook/addon-actions',
|
||||
'@storybook/addon-links',
|
||||
'@storybook/addon-storysource',
|
||||
'storybook-dark-mode/register',
|
||||
],
|
||||
};
|
||||
|
||||
module.exports = Object.assign(({ args }) => {
|
||||
// Calling storybook with no args causes our default list of stories to be used.
|
||||
// This set of stories are the ones that we publish to backstage.io
|
||||
//
|
||||
// If it's called with args, each arg should be the path to a package that we will
|
||||
// show the stories from, for example `yarn storybook plugins/catalog`.
|
||||
|
||||
const rootPath = '../../';
|
||||
const storiesSrcGlob = 'src/**/*.stories.tsx';
|
||||
|
||||
const getStoriesPath = package =>
|
||||
path.posix.join(rootPath, package, storiesSrcGlob);
|
||||
|
||||
const packages = args.length === 0 ? BACKSTAGE_CORE_STORIES : args;
|
||||
const stories = packages.map(getStoriesPath);
|
||||
|
||||
return {
|
||||
...staticConfig,
|
||||
stories,
|
||||
webpackFinal: async config => {
|
||||
// Mirror config in packages/cli/src/lib/bundler
|
||||
config.resolve.mainFields = ['browser', 'module', 'main'];
|
||||
|
||||
// Remove the default babel-loader for js files, we're using swc instead
|
||||
const [jsLoader] = config.module.rules.splice(0, 1);
|
||||
if (!jsLoader.use[0].loader.includes('babel-loader')) {
|
||||
throw new Error(
|
||||
`Unexpected loader removed from storybook config, ${jsLoader.use[0].loader}`,
|
||||
);
|
||||
}
|
||||
|
||||
config.resolve.extensions.push('.ts', '.tsx');
|
||||
|
||||
config.module.rules.push(
|
||||
{
|
||||
test: /\.(tsx?)$/,
|
||||
exclude: /node_modules/,
|
||||
loader: require.resolve('swc-loader'),
|
||||
options: {
|
||||
jsc: {
|
||||
target: 'ES2022',
|
||||
parser: {
|
||||
syntax: 'typescript',
|
||||
tsx: true,
|
||||
dynamicImport: true,
|
||||
},
|
||||
transform: {
|
||||
react: {
|
||||
runtime: 'automatic',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.(jsx?|mjs|cjs)$/,
|
||||
exclude: /node_modules/,
|
||||
loader: require.resolve('swc-loader'),
|
||||
options: {
|
||||
jsc: {
|
||||
target: 'ES2022',
|
||||
parser: {
|
||||
syntax: 'ecmascript',
|
||||
jsx: true,
|
||||
dynamicImport: true,
|
||||
},
|
||||
transform: {
|
||||
react: {
|
||||
runtime: 'automatic',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
// Disable ProgressPlugin which logs verbose webpack build progress. Warnings and Errors are still logged.
|
||||
config.plugins = config.plugins.filter(
|
||||
({ constructor }) => constructor.name !== 'ProgressPlugin',
|
||||
);
|
||||
|
||||
// Fail storybook build on CI if there are webpack warnings.
|
||||
if (process.env.CI) {
|
||||
config.plugins.push(new WebpackPluginFailBuildOnWarning());
|
||||
}
|
||||
|
||||
return config;
|
||||
},
|
||||
};
|
||||
}, staticConfig);
|
||||
@@ -0,0 +1,52 @@
|
||||
import type { StorybookConfig } from '@storybook/react-vite';
|
||||
|
||||
import { join, dirname, posix } from 'path';
|
||||
|
||||
/**
|
||||
* This set of stories are the ones that we publish to backstage.io.
|
||||
*/
|
||||
const backstageCoreStories = [
|
||||
'packages/core-components',
|
||||
'packages/app',
|
||||
'plugins/org',
|
||||
'plugins/search',
|
||||
'plugins/search-react',
|
||||
'plugins/home',
|
||||
'plugins/catalog-react',
|
||||
];
|
||||
|
||||
const rootPath = '../../';
|
||||
const storiesSrcMdx = 'src/**/*.mdx';
|
||||
const storiesSrcGlob = 'src/**/*.stories.@(js|jsx|mjs|ts|tsx)';
|
||||
|
||||
const getStoriesPath = (element: string, pattern: string) =>
|
||||
posix.join(rootPath, element, pattern);
|
||||
|
||||
const stories = backstageCoreStories.flatMap(element => [
|
||||
getStoriesPath(element, storiesSrcMdx),
|
||||
getStoriesPath(element, storiesSrcGlob),
|
||||
]);
|
||||
|
||||
/**
|
||||
* This function is used to resolve the absolute path of a package.
|
||||
* It is needed in projects that use Yarn PnP or are set up within a monorepo.
|
||||
*/
|
||||
function getAbsolutePath(value: string): any {
|
||||
return dirname(require.resolve(join(value, 'package.json')));
|
||||
}
|
||||
|
||||
const config: StorybookConfig = {
|
||||
stories,
|
||||
addons: [
|
||||
getAbsolutePath('@storybook/addon-links'),
|
||||
getAbsolutePath('@storybook/addon-essentials'),
|
||||
getAbsolutePath('@chromatic-com/storybook'),
|
||||
getAbsolutePath('@storybook/addon-interactions'),
|
||||
getAbsolutePath('@storybook/addon-themes'),
|
||||
],
|
||||
framework: {
|
||||
name: getAbsolutePath('@storybook/react-vite'),
|
||||
options: {},
|
||||
},
|
||||
};
|
||||
export default config;
|
||||
@@ -1,36 +0,0 @@
|
||||
import React from 'react';
|
||||
import { addDecorator, addParameters } from '@storybook/react';
|
||||
import { lightTheme, darkTheme } from '@backstage/theme';
|
||||
import { CssBaseline, ThemeProvider } from '@material-ui/core';
|
||||
import { useDarkMode } from 'storybook-dark-mode';
|
||||
import { apis } from './apis';
|
||||
|
||||
import { Content, AlertDisplay } from '@backstage/core-components';
|
||||
import { TestApiProvider } from '@backstage/test-utils';
|
||||
|
||||
addDecorator(story => (
|
||||
<TestApiProvider apis={apis}>
|
||||
<ThemeProvider theme={useDarkMode() ? darkTheme : lightTheme}>
|
||||
<CssBaseline>
|
||||
<AlertDisplay />
|
||||
<Content>{story()}</Content>
|
||||
</CssBaseline>
|
||||
</ThemeProvider>
|
||||
</TestApiProvider>
|
||||
));
|
||||
|
||||
addParameters({
|
||||
darkMode: {
|
||||
// Set the initial theme
|
||||
current: 'light',
|
||||
},
|
||||
layout: 'fullscreen',
|
||||
});
|
||||
|
||||
export const parameters = {
|
||||
options: {
|
||||
storySort: {
|
||||
order: ['Plugins', 'Layout', 'Navigation'],
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,54 @@
|
||||
import React from 'react';
|
||||
import { TestApiProvider } from '@backstage/test-utils';
|
||||
import { Content, AlertDisplay } from '@backstage/core-components';
|
||||
import { lightTheme, darkTheme } from '@backstage/theme';
|
||||
import { CssBaseline, ThemeProvider } from '@material-ui/core';
|
||||
import { apis } from './apis';
|
||||
import { withThemeFromJSXProvider } from '@storybook/addon-themes';
|
||||
|
||||
import type { Preview, ReactRenderer } from '@storybook/react';
|
||||
|
||||
const preview: Preview = {
|
||||
parameters: {
|
||||
controls: {
|
||||
matchers: {
|
||||
color: /(background|color)$/i,
|
||||
date: /Date$/i,
|
||||
},
|
||||
},
|
||||
darkMode: {
|
||||
current: 'light',
|
||||
},
|
||||
layout: 'fullscreen',
|
||||
},
|
||||
decorators: [
|
||||
withThemeFromJSXProvider<ReactRenderer>({
|
||||
themes: {
|
||||
Light: lightTheme,
|
||||
Dark: darkTheme,
|
||||
},
|
||||
defaultTheme: 'Light',
|
||||
Provider: ThemeProvider,
|
||||
GlobalStyles: CssBaseline,
|
||||
}),
|
||||
Story => (
|
||||
// @ts-ignore - TODO: Fix this
|
||||
<TestApiProvider apis={apis}>
|
||||
<AlertDisplay />
|
||||
<Content>
|
||||
<Story />
|
||||
</Content>
|
||||
</TestApiProvider>
|
||||
),
|
||||
],
|
||||
};
|
||||
|
||||
export default preview;
|
||||
|
||||
export const parameters = {
|
||||
options: {
|
||||
storySort: {
|
||||
order: ['Plugins', 'Layout', 'Navigation'],
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* When building storybook, we can have warnings which may cause issues in the future. One of the example case is
|
||||
* https://github.com/backstage/backstage/issues/718. To make sure new warnings are not introduced with new PRs, we
|
||||
* want to fail CI builds if there are warnings when building storybook.
|
||||
*
|
||||
* This webpack plugin makes sure the CI builds fail on Webpack warnings. We also have an allowlist of warnings here
|
||||
* which we think are non-critical.
|
||||
*
|
||||
* Note that this implementation will not detect other warnings emitted by storybook build that are separate from
|
||||
* Webpack. A better solution over this plugin should be preferred, possibly on Storybook level (CLI options etc.)
|
||||
*
|
||||
* The case with #718 is caused because we are using `ts-loader` for `webpack` to load all our JS/TS files, but we
|
||||
* have disabled type checking during build. This is done by setting `transpileOnly` to `true` in storybook/main.js
|
||||
* and it improves the Storybook build speed. Because of this, Webpack emits warnings when we try to re-export types.
|
||||
* Reference: https://github.com/TypeStrong/ts-loader#transpileonly
|
||||
*/
|
||||
class WebpackPluginFailBuildOnWarning {
|
||||
// Ignore the following warnings in the Webpack build.
|
||||
warningsAllowlist = new Set([
|
||||
'AssetsOverSizeLimitWarning',
|
||||
'EntrypointsOverSizeLimitWarning',
|
||||
'NoAsyncChunksWarning',
|
||||
'ModuleDependencyWarning', // @testing-library/react added support for React 19 which throws a warning https://github.com/testing-library/react-testing-library/pull/1294/files
|
||||
]);
|
||||
|
||||
/* Entry point for the Webpack plugin. */
|
||||
apply(compiler) {
|
||||
// Invoke plugin logic when Webpack build is 'done'.
|
||||
compiler.hooks.done.tap('FailBuildOnWarning', this.execute.bind(this));
|
||||
}
|
||||
|
||||
execute(stats) {
|
||||
// All the compilation warnings are stored in stats.compilation.warnings
|
||||
let warnings = stats.compilation.warnings;
|
||||
if (warnings.length > 0) {
|
||||
// Throw error if there are unexpected warnings.
|
||||
for (let warning of warnings) {
|
||||
if (!this.warningsAllowlist.has(warning.name)) {
|
||||
process.on('beforeExit', () => {
|
||||
console.log(
|
||||
`You have some unexpected warning(s) in your webpack build. Exiting process as error.`,
|
||||
);
|
||||
process.exit(1);
|
||||
});
|
||||
// No need to go over the rest of warnings from here.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = WebpackPluginFailBuildOnWarning;
|
||||
+34
-30
@@ -1,42 +1,46 @@
|
||||
{
|
||||
"name": "storybook",
|
||||
"name": "backstage-storybook",
|
||||
"version": "0.2.2",
|
||||
"description": "Storybook build for components package",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build-storybook": "build-storybook --output-dir dist",
|
||||
"start": "start-storybook -p 6006"
|
||||
"build-storybook": "storybook build --output-dir dist",
|
||||
"storybook": "storybook dev -p 6006"
|
||||
},
|
||||
"resolutions": {
|
||||
"webpack": "^5.73.0"
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"plugin:storybook/recommended"
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@swc/core": "^1.3.46",
|
||||
"react": "^18.0.2",
|
||||
"react-dom": "^18.0.2",
|
||||
"react-hot-loader": "^4.13.0",
|
||||
"react-router-dom": "^6.25.1",
|
||||
"swc-loader": "^0.2.3"
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@storybook/addon-a11y": "^6.5.9",
|
||||
"@storybook/addon-actions": "^6.5.9",
|
||||
"@storybook/addon-controls": "^6.5.9",
|
||||
"@storybook/addon-links": "^6.5.9",
|
||||
"@storybook/addon-storysource": "^6.5.9",
|
||||
"@storybook/addons": "^6.5.9",
|
||||
"@storybook/builder-webpack5": "^6.5.9",
|
||||
"@storybook/manager-webpack5": "^6.5.9",
|
||||
"@storybook/node-logger": "^6.5.9",
|
||||
"@storybook/react": "^6.5.9",
|
||||
"@storybook/testing-library": "^0.2.0",
|
||||
"storybook-dark-mode": "^1.1.0",
|
||||
"typescript": "~4.9.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@backstage/core-app-api": "*",
|
||||
"@backstage/core-plugin-api": "*",
|
||||
"@backstage/test-utils": "*",
|
||||
"@backstage/theme": "*"
|
||||
"@chromatic-com/storybook": "^1.9.0",
|
||||
"@storybook/addon-essentials": "^8.3.5",
|
||||
"@storybook/addon-interactions": "^8.3.5",
|
||||
"@storybook/addon-links": "^8.3.5",
|
||||
"@storybook/addon-themes": "^8.3.6",
|
||||
"@storybook/blocks": "^8.3.5",
|
||||
"@storybook/react": "^8.3.5",
|
||||
"@storybook/react-vite": "^8.3.5",
|
||||
"@storybook/test": "^8.3.5",
|
||||
"@storybook/types": "^8.3.5",
|
||||
"@types/react": "^18.0.0",
|
||||
"@types/react-dom": "^18.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.0.0",
|
||||
"@typescript-eslint/parser": "^5.0.0",
|
||||
"eslint": "^9.11.1",
|
||||
"eslint-plugin-storybook": "^0.9.0",
|
||||
"globals": "^15.9.0",
|
||||
"react": "^18.0.2",
|
||||
"react-dom": "^18.0.2",
|
||||
"react-router-dom": "^6.3.0",
|
||||
"storybook": "^8.3.5",
|
||||
"typescript": "^5.5.3",
|
||||
"typescript-eslint": "^8.7.0",
|
||||
"vite": "^5.4.8"
|
||||
}
|
||||
}
|
||||
|
||||
+3191
-9299
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user