diff --git a/.storybook/main.js b/.storybook/main.ts
similarity index 67%
rename from .storybook/main.js
rename to .storybook/main.ts
index 7d063fd6ffe1..33f4befb0f40 100644
--- a/.storybook/main.js
+++ b/.storybook/main.ts
@@ -1,12 +1,20 @@
-module.exports = {
+import type {StorybookConfig} from '@storybook/core-common';
+
+type Main = {
+ managerHead: (head: string) => string;
+} & StorybookConfig;
+
+const main: Main = {
stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],
addons: ['@storybook/addon-essentials', '@storybook/addon-a11y', '@storybook/addon-react-native-web'],
staticDirs: ['./public', {from: '../assets/css', to: 'css'}, {from: '../assets/fonts/web', to: 'fonts'}],
core: {
builder: 'webpack5',
},
- managerHead: (head) => `
+ managerHead: (head: string) => `
${head}
${process.env.ENV === 'staging' ? '' : ''}
`,
};
+
+export default main;
diff --git a/.storybook/manager.js b/.storybook/manager.ts
similarity index 100%
rename from .storybook/manager.js
rename to .storybook/manager.ts
diff --git a/.storybook/preview.js b/.storybook/preview.tsx
similarity index 53%
rename from .storybook/preview.js
rename to .storybook/preview.tsx
index a89c720976c9..4767c7d81343 100644
--- a/.storybook/preview.js
+++ b/.storybook/preview.tsx
@@ -1,15 +1,16 @@
import {PortalProvider} from '@gorhom/portal';
+import type {Parameters} from '@storybook/addons';
import React from 'react';
import Onyx from 'react-native-onyx';
import {SafeAreaProvider} from 'react-native-safe-area-context';
-import ComposeProviders from '../src/components/ComposeProviders';
-import HTMLEngineProvider from '../src/components/HTMLEngineProvider';
-import {LocaleContextProvider} from '../src/components/LocaleContextProvider';
-import OnyxProvider from '../src/components/OnyxProvider';
-import {EnvironmentProvider} from '../src/components/withEnvironment';
-import {KeyboardStateProvider} from '../src/components/withKeyboardState';
-import {WindowDimensionsProvider} from '../src/components/withWindowDimensions';
-import ONYXKEYS from '../src/ONYXKEYS';
+import ComposeProviders from '@src/components/ComposeProviders';
+import HTMLEngineProvider from '@src/components/HTMLEngineProvider';
+import {LocaleContextProvider} from '@src/components/LocaleContextProvider';
+import OnyxProvider from '@src/components/OnyxProvider';
+import {EnvironmentProvider} from '@src/components/withEnvironment';
+import {KeyboardStateProvider} from '@src/components/withKeyboardState';
+import {WindowDimensionsProvider} from '@src/components/withWindowDimensions';
+import ONYXKEYS from '@src/ONYXKEYS';
import './fonts.css';
Onyx.init({
@@ -20,7 +21,7 @@ Onyx.init({
});
const decorators = [
- (Story) => (
+ (Story: React.ElementType) => (
@@ -29,7 +30,7 @@ const decorators = [
),
];
-const parameters = {
+const parameters: Parameters = {
controls: {
matchers: {
color: /(background|color)$/i,
diff --git a/.storybook/theme.js b/.storybook/theme.ts
similarity index 80%
rename from .storybook/theme.js
rename to .storybook/theme.ts
index 08d8b584d580..a28a0f031b0c 100644
--- a/.storybook/theme.js
+++ b/.storybook/theme.ts
@@ -1,7 +1,9 @@
+import type {ThemeVars} from '@storybook/theming';
import {create} from '@storybook/theming';
+// eslint-disable-next-line @dword-design/import-alias/prefer-alias
import colors from '../src/styles/theme/colors';
-export default create({
+const theme: ThemeVars = create({
brandTitle: 'New Expensify UI Docs',
brandImage: 'logomark.svg',
fontBase: 'ExpensifyNeue-Regular',
@@ -21,3 +23,5 @@ export default create({
appBorderRadius: 8,
inputBorderRadius: 8,
});
+
+export default theme;
diff --git a/.storybook/webpack.config.js b/.storybook/webpack.config.js
deleted file mode 100644
index 204f70344b18..000000000000
--- a/.storybook/webpack.config.js
+++ /dev/null
@@ -1,54 +0,0 @@
-/* eslint-disable no-underscore-dangle */
-/* eslint-disable no-param-reassign */
-const path = require('path');
-const dotenv = require('dotenv');
-const _ = require('underscore');
-
-let envFile;
-switch (process.env.ENV) {
- case 'production':
- envFile = '.env.production';
- break;
- case 'staging':
- envFile = '.env.staging';
- break;
- default:
- envFile = '.env';
-}
-
-const env = dotenv.config({path: path.resolve(__dirname, `../${envFile}`)});
-const custom = require('../config/webpack/webpack.common')({
- envFile,
-});
-
-module.exports = ({config}) => {
- config.resolve.alias = {
- 'react-native-config': 'react-web-config',
- 'react-native$': 'react-native-web',
- '@react-native-community/netinfo': path.resolve(__dirname, '../__mocks__/@react-native-community/netinfo.ts'),
- '@react-navigation/native': path.resolve(__dirname, '../__mocks__/@react-navigation/native'),
-
- // Module alias support for storybook files, coping from `webpack.common.js`
- ...custom.resolve.alias,
- };
-
- // Necessary to overwrite the values in the existing DefinePlugin hardcoded to the Config staging values
- const definePluginIndex = _.findIndex(config.plugins, (plugin) => plugin.constructor.name === 'DefinePlugin');
- config.plugins[definePluginIndex].definitions.__REACT_WEB_CONFIG__ = JSON.stringify(env);
- config.resolve.extensions = custom.resolve.extensions;
-
- const babelRulesIndex = _.findIndex(custom.module.rules, (rule) => rule.loader === 'babel-loader');
- const babelRule = custom.module.rules[babelRulesIndex];
- config.module.rules.push(babelRule);
-
- // Allows loading SVG - more context here https://github.com/storybookjs/storybook/issues/6188
- const fileLoaderRule = _.find(config.module.rules, (rule) => rule.test && rule.test.test('.svg'));
- fileLoaderRule.exclude = /\.svg$/;
- config.module.rules.push({
- test: /\.svg$/,
- enforce: 'pre',
- loader: require.resolve('@svgr/webpack'),
- });
-
- return config;
-};
diff --git a/.storybook/webpack.config.ts b/.storybook/webpack.config.ts
new file mode 100644
index 000000000000..2fdae76c1268
--- /dev/null
+++ b/.storybook/webpack.config.ts
@@ -0,0 +1,81 @@
+/* eslint-disable no-underscore-dangle */
+
+/* eslint-disable no-param-reassign */
+
+/* eslint-disable @typescript-eslint/naming-convention */
+import dotenv from 'dotenv';
+import path from 'path';
+import {DefinePlugin} from 'webpack';
+import type {Configuration, RuleSetRule} from 'webpack';
+
+type CustomWebpackConfig = {
+ resolve: {
+ alias: Record;
+ extensions: string[];
+ };
+ module: {
+ rules: RuleSetRule[];
+ };
+};
+
+let envFile: string;
+switch (process.env.ENV) {
+ case 'production':
+ envFile = '.env.production';
+ break;
+ case 'staging':
+ envFile = '.env.staging';
+ break;
+ default:
+ envFile = '.env';
+}
+
+const env = dotenv.config({path: path.resolve(__dirname, `../${envFile}`)});
+const custom: CustomWebpackConfig = require('../config/webpack/webpack.common')({
+ envFile,
+});
+
+const webpackConfig = ({config}: {config: Configuration}) => {
+ if (config.resolve && config.plugins && config.module) {
+ config.resolve.alias = {
+ 'react-native-config': 'react-web-config',
+ 'react-native$': 'react-native-web',
+ '@react-native-community/netinfo': path.resolve(__dirname, '../__mocks__/@react-native-community/netinfo.ts'),
+ '@react-navigation/native': path.resolve(__dirname, '../__mocks__/@react-navigation/native'),
+ ...custom.resolve.alias,
+ };
+
+ // Necessary to overwrite the values in the existing DefinePlugin hardcoded to the Config staging values
+ const definePluginIndex = config.plugins.findIndex((plugin) => plugin instanceof DefinePlugin);
+ if (definePluginIndex !== -1 && config.plugins[definePluginIndex] instanceof DefinePlugin) {
+ const definePlugin = config.plugins[definePluginIndex] as DefinePlugin;
+ if (definePlugin.definitions) {
+ definePlugin.definitions.__REACT_WEB_CONFIG__ = JSON.stringify(env);
+ }
+ }
+ config.resolve.extensions = custom.resolve.extensions;
+
+ const babelRulesIndex = custom.module.rules.findIndex((rule) => rule.loader === 'babel-loader');
+ const babelRule = custom.module.rules[babelRulesIndex];
+ if (babelRule) {
+ config.module.rules?.push(babelRule);
+ }
+
+ const fileLoaderRule = config.module.rules?.find(
+ (rule): rule is RuleSetRule =>
+ typeof rule !== 'boolean' && typeof rule !== 'string' && typeof rule !== 'number' && !!rule?.test && rule.test instanceof RegExp && rule.test.test('.svg'),
+ );
+ if (fileLoaderRule) {
+ fileLoaderRule.exclude = /\.svg$/;
+ }
+ config.module.rules?.push({
+ test: /\.svg$/,
+ enforce: 'pre',
+ loader: require.resolve('@svgr/webpack'),
+ });
+ }
+
+ return config;
+};
+
+export default webpackConfig;