Merge pull request #53 from aleleba/PR-227028

PR-227028: Update dependencies, migrate to TypeScript 6 and ESLint flat config
This commit is contained in:
2026-06-09 11:49:52 -06:00
committed by GitHub
25 changed files with 4120 additions and 3104 deletions

View File

@@ -1,7 +1,7 @@
{ {
"presets": [ "presets": [
["@babel/preset-env", {"targets": {"node": "current"}}], ["@babel/preset-env", {"targets": {"node": "current"}}],
"@babel/preset-react", ["@babel/preset-react", {"runtime": "automatic"}],
"@babel/preset-typescript" "@babel/preset-typescript"
] ]
} }

View File

@@ -1,30 +0,0 @@
module.exports = {
'env': {
'browser': true,
'node': true,
'es2021': true
},
'extends': ['eslint:recommended', 'plugin:react/recommended', 'plugin:@typescript-eslint/recommended', 'plugin:storybook/recommended', 'plugin:storybook/recommended'],
'parser': '@typescript-eslint/parser',
'parserOptions': {
'ecmaFeatures': {
'jsx': true
},
'ecmaVersion': 'latest',
'sourceType': 'module'
},
'plugins': ['react', '@typescript-eslint'],
'rules': {
'indent': ['error', 'tab'],
'linebreak-style': ['error', 'unix'],
'quotes': ['error', 'single'],
'semi': ['error', 'always'],
'eol-last': ['error', 'always'],
'@typescript-eslint/no-var-requires': 0
},
'settings': {
'react': {
'version': 'detect'
}
}
};

View File

@@ -16,14 +16,14 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
node-version: [20.x] node-version: [22.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/ # See supported Node.js release schedule at https://nodejs.org/en/about/releases/
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Use Node.js 20 - name: Use Node.js 22
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: 20 node-version: 22
cache: 'npm' cache: 'npm'
registry-url: https://registry.npmjs.org/ registry-url: https://registry.npmjs.org/
- run: npm ci - run: npm ci
@@ -34,10 +34,10 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Use Node.js 20 - name: Use Node.js 22
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: 20 node-version: 22
cache: 'npm' cache: 'npm'
registry-url: https://registry.npmjs.org/ registry-url: https://registry.npmjs.org/
- name: Cypress install - name: Cypress install
@@ -57,7 +57,7 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version: 20 node-version: 22
registry-url: https://registry.npmjs.org/ registry-url: https://registry.npmjs.org/
- run: npm ci - run: npm ci
- run: npm run build - run: npm run build
@@ -71,7 +71,7 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version: 20 node-version: 22
registry-url: https://registry.npmjs.org/ registry-url: https://registry.npmjs.org/
- run: npm ci - run: npm ci
- run: npm publish --access=public - run: npm publish --access=public

View File

@@ -1,81 +1,81 @@
const path = require('path'); const path = require('path');
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin'); const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
const deFaultValues = { const deFaultValues = {
PREFIX_URL: '' PREFIX_URL: ''
} };
const prefixUrl = process.env.PREFIX_URL ? process.env.PREFIX_URL : deFaultValues.PREFIX_URL; const prefixUrl = process.env.PREFIX_URL ? process.env.PREFIX_URL : deFaultValues.PREFIX_URL;
module.exports = { module.exports = {
stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"], stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],
addons: ["@storybook/addon-webpack5-compiler-babel", "@storybook/addon-links", { addons: ['@storybook/addon-webpack5-compiler-babel', '@storybook/addon-links', {
name: '@storybook/addon-styling-webpack', name: '@storybook/addon-styling-webpack',
options: { options: {
rules: [ rules: [
{ {
test: /\.(css|sass|scss)$/, test: /\.(css|sass|scss)$/,
use: [ use: [
'style-loader', 'style-loader',
{ {
loader: 'css-loader', loader: 'css-loader',
options: { options: {
modules: { modules: {
namedExport: false, namedExport: false,
exportLocalsConvention: 'as-is', exportLocalsConvention: 'as-is',
auto: /\.module\.\w+$/i, auto: /\.module\.\w+$/i,
} }
}, },
}, },
'sass-loader', 'sass-loader',
], ],
} }
] ]
}, },
}, "@storybook/addon-docs"], }, '@storybook/addon-docs'],
webpackFinal: async config => { webpackFinal: async config => {
config.entry = config.entry.map(function(entry) { config.entry = config.entry.map(function(entry) {
if (entry.includes("webpack-hot-middleware")) { if (entry.includes('webpack-hot-middleware')) {
return `${require.resolve('webpack-hot-middleware/client')}?path=${prefixUrl}__webpack_hmr&reload=true`; return `${require.resolve('webpack-hot-middleware/client')}?path=${prefixUrl}__webpack_hmr&reload=true`;
} }
return entry; return entry;
}), });
config.resolve.alias = { config.resolve.alias = {
...config.resolve.alias, ...config.resolve.alias,
'@components': path.resolve(__dirname, "../src/components/") '@components': path.resolve(__dirname, '../src/components/')
}; };
config.resolve.plugins = [new TsconfigPathsPlugin()]; config.resolve.plugins = [new TsconfigPathsPlugin()];
return config; return config;
}, },
framework: { framework: {
name: "@storybook/react-webpack5", name: '@storybook/react-webpack5',
options: {} options: {}
}, },
typescript: { typescript: {
reactDocgenTypescriptOptions: { reactDocgenTypescriptOptions: {
compilerOptions: { compilerOptions: {
"paths": { 'paths': {
"@Components/*": ["Components/*"] '@Components/*': ['Components/*']
} }
}, },
propFilter: (prop) => { propFilter: (prop) => {
// Filter out props that might contain Symbol values // Filter out props that might contain Symbol values
if (prop.name && typeof prop.name === 'symbol') { if (prop.name && typeof prop.name === 'symbol') {
return false; return false;
} }
// Filter out React internal props that might cause issues // Filter out React internal props that might cause issues
if (prop.name && prop.name.startsWith('$$')) { if (prop.name && prop.name.startsWith('$$')) {
return false; return false;
} }
return true; return true;
} }
} }
}, },
docs: { docs: {
autodocs: 'tag', autodocs: 'tag',
defaultName: 'Docs', defaultName: 'Docs',
} }
}; };

View File

@@ -1,29 +1,29 @@
export const parameters = { export const parameters = {
actions: { argTypesRegex: "^on[A-Z].*" }, actions: { argTypesRegex: '^on[A-Z].*' },
controls: { controls: {
matchers: { matchers: {
color: /(background|color)$/i, color: /(background|color)$/i,
date: /Date$/, date: /Date$/,
}, },
}, },
docs: { docs: {
extractArgTypes: (component) => { extractArgTypes: (component) => {
// Filter out Symbol values to prevent serialization errors // Filter out Symbol values to prevent serialization errors
const argTypes = {}; const argTypes = {};
if (component && component.propTypes) { if (component && component.propTypes) {
Object.keys(component.propTypes).forEach(key => { Object.keys(component.propTypes).forEach(key => {
const propType = component.propTypes[key]; const propType = component.propTypes[key];
// Only include non-Symbol values // Only include non-Symbol values
if (typeof propType !== 'symbol') { if (typeof propType !== 'symbol') {
argTypes[key] = propType; argTypes[key] = propType;
} }
}); });
} }
return argTypes; return argTypes;
}, },
source: { source: {
excludeDecorators: true, excludeDecorators: true,
}, },
}, },
} };
export const tags = ["autodocs"]; export const tags = ['autodocs'];

View File

@@ -2,62 +2,62 @@
const { execSync } = require('child_process'); const { execSync } = require('child_process');
var fs = require('fs'); var fs = require('fs');
const isWin = process.platform === "win32"; const isWin = process.platform === 'win32';
const runCommand = command => { const runCommand = command => {
try{ try{
execSync(`${command}`, {stdio: 'inherit'}); execSync(`${command}`, {stdio: 'inherit'});
} catch (e) { } catch (e) {
console.error(`Failed to execute ${command}`, e); console.error(`Failed to execute ${command}`, e);
return false; return false;
} }
return true; return true;
} };
const runCommandWithOutput = command => { const runCommandWithOutput = command => {
try{ try{
return execSync(`${command}`); return execSync(`${command}`);
} catch (e) { } catch (e) {
console.error(`Failed to execute ${command}`, e); console.error(`Failed to execute ${command}`, e);
return false; return false;
} }
} };
const replaceTextOnFile = ({ const replaceTextOnFile = ({
file, file,
textToBeReplaced, textToBeReplaced,
textReplace, textReplace,
arrOfObjectsBeReplaced arrOfObjectsBeReplaced
}) => { }) => {
let data let data;
try{ try{
data = fs.readFileSync(file, 'utf8'); data = fs.readFileSync(file, 'utf8');
} catch (e) { } catch (e) {
console.error(`Failed to read file ${file}`, e); console.error(`Failed to read file ${file}`, e);
return false; return false;
} }
let result let result;
if(arrOfObjectsBeReplaced){ if(arrOfObjectsBeReplaced){
arrOfObjectsBeReplaced.forEach( obj => { arrOfObjectsBeReplaced.forEach( obj => {
if(result){ if(result){
result = result.replace(obj.textToBeReplaced, obj.textReplace).replace(/^\s*[\r\n]/gm, ' '); result = result.replace(obj.textToBeReplaced, obj.textReplace).replace(/^\s*[\r\n]/gm, ' ');
}else{ }else{
result = data.replace(obj.textToBeReplaced, obj.textReplace).replace(/^\s*[\r\n]/gm, ' '); result = data.replace(obj.textToBeReplaced, obj.textReplace).replace(/^\s*[\r\n]/gm, ' ');
} }
}) });
}else{ }else{
result = data.replace(textToBeReplaced, textReplace).replace(/^\s*[\r\n]/gm, ' '); result = data.replace(textToBeReplaced, textReplace).replace(/^\s*[\r\n]/gm, ' ');
} }
try{ try{
console.log('text changed') console.log('text changed');
fs.writeFileSync(file, result, 'utf8'); fs.writeFileSync(file, result, 'utf8');
} catch (e) { } catch (e) {
console.error(`Failed to read file ${file}`, e); console.error(`Failed to read file ${file}`, e);
return false; return false;
} }
} };
const repoName = process.argv[2]; const repoName = process.argv[2];
const gitCheckoutCommand = `git clone --depth 1 https://github.com/aleleba/create-react-component-library ${repoName}`; const gitCheckoutCommand = `git clone --depth 1 https://github.com/aleleba/create-react-component-library ${repoName}`;
@@ -65,13 +65,13 @@ console.log(`Cloning the repository with name ${repoName}`);
const checkedOut = runCommand(gitCheckoutCommand); const checkedOut = runCommand(gitCheckoutCommand);
if(!checkedOut) process.exit(-1); if(!checkedOut) process.exit(-1);
const actualVersion = runCommandWithOutput(`cd ${repoName} && node -p "require('./package.json').version"`).toString().trim() const actualVersion = runCommandWithOutput(`cd ${repoName} && node -p "require('./package.json').version"`).toString().trim();
const installDepsCommand = `cd ${repoName} && npm i`; const installDepsCommand = `cd ${repoName} && npm i`;
const cleanGitHistoryCommand = `cd ${repoName} && rm -rf .git && git init && git add --all -- ":!.github" ":!bin" && git commit -m "Initial commit"` const cleanGitHistoryCommand = `cd ${repoName} && rm -rf .git && git init && git add --all -- ":!.github" ":!bin" && git commit -m "Initial commit"`;
const cleanGitHistoryCommandWindows = `cd ${repoName} && rmdir .git /s /q && git init && git add --all -- ":!.github" ":!bin" && git commit -m "Initial commit"` const cleanGitHistoryCommandWindows = `cd ${repoName} && rmdir .git /s /q && git init && git add --all -- ":!.github" ":!bin" && git commit -m "Initial commit"`;
const deleteFoldersCommand = `cd ${repoName} && rm -rf .github && rm -rf bin` const deleteFoldersCommand = `cd ${repoName} && rm -rf .github && rm -rf bin`;
const deleteFoldersCommandWindows = `cd ${repoName} && rmdir .github /s /q && rmdir bin /s /q` const deleteFoldersCommandWindows = `cd ${repoName} && rmdir .github /s /q && rmdir bin /s /q`;
console.log(`Installing dependencies for ${repoName}`); console.log(`Installing dependencies for ${repoName}`);
const installedDeps = runCommand(installDepsCommand); const installedDeps = runCommand(installDepsCommand);
@@ -79,31 +79,31 @@ if(!installedDeps) process.exit(-1);
console.log(`Replacing Json data for ${repoName}`); console.log(`Replacing Json data for ${repoName}`);
replaceTextOnFile({ replaceTextOnFile({
file: `./${repoName}/package.json`, file: `./${repoName}/package.json`,
arrOfObjectsBeReplaced: [ arrOfObjectsBeReplaced: [
{ {
textToBeReplaced: `"bin": "./bin/cli.js",`, textToBeReplaced: '"bin": "./bin/cli.js",',
textReplace: `` textReplace: ''
}, },
{ {
textToBeReplaced: `"version": "${actualVersion}",`, textToBeReplaced: `"version": "${actualVersion}",`,
textReplace: `"version": "0.0.1",` textReplace: '"version": "0.0.1",'
}, },
{ {
textToBeReplaced: `"name": "@aleleba/create-react-component-library",`, textToBeReplaced: '"name": "@aleleba/create-react-component-library",',
textReplace: `"name": "${repoName}",` textReplace: `"name": "${repoName}",`
} }
] ]
}) });
console.log(`Cleaning History of Git for ${repoName}`); console.log(`Cleaning History of Git for ${repoName}`);
const cleanGitHistory = isWin ? runCommand(cleanGitHistoryCommandWindows) : runCommand(cleanGitHistoryCommand); const cleanGitHistory = isWin ? runCommand(cleanGitHistoryCommandWindows) : runCommand(cleanGitHistoryCommand);
if(!cleanGitHistory) process.exit(-1); if(!cleanGitHistory) process.exit(-1);
console.log("Congratulations! You are ready. Follow the following commands to start"); console.log('Congratulations! You are ready. Follow the following commands to start');
console.log(`cd ${repoName}`); console.log(`cd ${repoName}`);
console.log('Create a .env file with LIBRARY_NAME=your_library_name(default: ui-library), External_CSS (optional)(Default: false), EXTERNAL_CSS_NAME=(optional)(Default: index.css)'); console.log('Create a .env file with LIBRARY_NAME=your_library_name(default: ui-library), External_CSS (optional)(Default: false), EXTERNAL_CSS_NAME=(optional)(Default: index.css)');
console.log(`Then you can run: npm start`); console.log('Then you can run: npm start');
const deleteFolders = isWin ? runCommand(deleteFoldersCommandWindows) : runCommand(deleteFoldersCommand); const deleteFolders = isWin ? runCommand(deleteFoldersCommandWindows) : runCommand(deleteFoldersCommand);
if(!deleteFolders) process.exit(-1); if(!deleteFolders) process.exit(-1);

View File

@@ -1,15 +1,15 @@
import { defineConfig } from "cypress"; import { defineConfig } from 'cypress';
import webpackConfig from './webpack.cy.config'; import webpackConfig from './webpack.cy.config';
export default defineConfig({ export default defineConfig({
component: { component: {
specPattern: 'src/**/*.cy.{js,jsx,ts,tsx}', specPattern: 'src/**/*.cy.{js,jsx,ts,tsx}',
devServer: { devServer: {
framework: "react", framework: 'react',
bundler: "webpack", bundler: 'webpack',
webpackConfig: webpackConfig, webpackConfig: webpackConfig,
}, },
viewportWidth: 1280, viewportWidth: 1280,
viewportHeight: 720, viewportHeight: 720,
}, },
}); });

View File

@@ -15,16 +15,17 @@
// *********************************************************** // ***********************************************************
// Import commands.js using ES2015 syntax: // Import commands.js using ES2015 syntax:
import './commands' import './commands';
// Alternatively you can use CommonJS syntax: // Alternatively you can use CommonJS syntax:
// require('./commands') // require('./commands')
import { mount } from 'cypress/react' import { mount } from 'cypress/react';
// Augment the Cypress namespace to include type definitions for // Augment the Cypress namespace to include type definitions for
// your custom command. // your custom command.
declare global { declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace Cypress { namespace Cypress {
interface Chainable { interface Chainable {
mount: typeof mount mount: typeof mount
@@ -32,7 +33,7 @@ declare global {
} }
} }
Cypress.Commands.add('mount', mount) Cypress.Commands.add('mount', mount);
// Example use: // Example use:
// cy.mount(<MyComponent />) // cy.mount(<MyComponent />)

50
eslint.config.mjs Normal file
View File

@@ -0,0 +1,50 @@
import js from '@eslint/js';
import tseslint from 'typescript-eslint';
import react from 'eslint-plugin-react';
import storybook from 'eslint-plugin-storybook';
import globals from 'globals';
export default tseslint.config(
{
ignores: ['node_modules/**', 'dist/**', 'build/**', 'storybook-static/**'],
},
js.configs.recommended,
...tseslint.configs.recommended,
react.configs.flat.recommended,
react.configs.flat['jsx-runtime'],
...storybook.configs['flat/recommended'],
{
settings: {
react: { version: 'detect' },
},
},
{
files: ['**/*.{js,jsx,ts,tsx}'],
languageOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
parserOptions: {
ecmaFeatures: { jsx: true },
},
globals: {
...globals.browser,
...globals.node,
},
},
rules: {
indent: ['error', 'tab'],
'linebreak-style': ['error', 'unix'],
quotes: ['error', 'single'],
semi: ['error', 'always'],
'eol-last': ['error', 'always'],
'react/prop-types': 'off',
'@typescript-eslint/no-require-imports': 'off',
},
},
{
files: ['**/*.js'],
languageOptions: {
sourceType: 'commonjs',
},
},
);

View File

@@ -6,12 +6,12 @@ const aliases = pathsToModuleNameMapper(compilerOptions.paths, {
}); });
module.exports = { module.exports = {
setupFilesAfterEnv: ['<rootDir>/setupTest.ts'], setupFilesAfterEnv: ['<rootDir>/setupTest.ts'],
testPathIgnorePatterns: ['/node_modules/', '\\.cy.(js|jsx|ts|tsx)$'], testPathIgnorePatterns: ['/node_modules/', '\\.cy.(js|jsx|ts|tsx)$'],
testEnvironment: 'jsdom', testEnvironment: 'jsdom',
moduleNameMapper: { moduleNameMapper: {
...aliases, ...aliases,
'\\.(jpg|ico|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '<rootDir>/src/__mocks__/fileMock.ts', '\\.(jpg|ico|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '<rootDir>/src/__mocks__/fileMock.ts',
'\\.(css|sass|scss|less)$': 'identity-obj-proxy' '\\.(css|sass|scss|less)$': 'identity-obj-proxy'
}, },
}; };

6239
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{ {
"name": "@aleleba/create-react-component-library", "name": "@aleleba/create-react-component-library",
"version": "1.3.2", "version": "1.4.0",
"description": "A starter kit for create a React component Library with storybook", "description": "A starter kit for create a React component Library with storybook",
"bin": "./bin/cli.js", "bin": "./bin/cli.js",
"main": "dist/index.js", "main": "dist/index.js",
@@ -16,8 +16,8 @@
"scripts": { "scripts": {
"start": "npm run storybook", "start": "npm run storybook",
"build": "webpack", "build": "webpack",
"lint": "eslint ./ --ext .js --ext .ts --ext .jsx --ext .tsx", "lint": "eslint .",
"lint:fix": "eslint ./ --ext .js --ext .ts --ext .jsx --ext .tsx --fix", "lint:fix": "eslint . --fix",
"test": "jest", "test": "jest",
"test:watch": "jest --watch", "test:watch": "jest --watch",
"storybook": "storybook dev -p 3000", "storybook": "storybook dev -p 3000",
@@ -44,59 +44,62 @@
}, },
"homepage": "https://github.com/aleleba/create-react-component-library#readme", "homepage": "https://github.com/aleleba/create-react-component-library#readme",
"devDependencies": { "devDependencies": {
"@babel/core": "^7.28.6", "@babel/core": "^7.29.7",
"@babel/preset-env": "^7.28.6", "@babel/preset-env": "^7.29.7",
"@babel/preset-react": "^7.28.5", "@babel/preset-react": "^7.29.7",
"@babel/preset-typescript": "^7.28.5", "@babel/preset-typescript": "^7.29.7",
"@babel/register": "^7.28.6", "@babel/register": "^7.29.7",
"@eslint/js": "^9.39.4",
"@mdx-js/react": "^3.1.1", "@mdx-js/react": "^3.1.1",
"@storybook/addon-docs": "^10.2.1", "@storybook/addon-docs": "^10.4.3",
"@storybook/addon-links": "^10.2.1", "@storybook/addon-links": "^10.4.3",
"@storybook/addon-styling-webpack": "^3.0.0", "@storybook/addon-styling-webpack": "^3.0.2",
"@storybook/addon-webpack5-compiler-babel": "^4.0.0", "@storybook/addon-webpack5-compiler-babel": "^4.0.1",
"@storybook/cli": "^10.2.1", "@storybook/cli": "^10.4.3",
"@storybook/preset-scss": "^1.0.3", "@storybook/preset-scss": "^1.0.3",
"@storybook/react-webpack5": "^10.2.1", "@storybook/react-webpack5": "^10.4.3",
"@testing-library/dom": "^10.4.1", "@testing-library/dom": "^10.4.1",
"@testing-library/jest-dom": "^6.9.1", "@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.2", "@testing-library/react": "^16.3.2",
"@testing-library/user-event": "^14.6.1", "@testing-library/user-event": "^14.6.1",
"@types/jest": "^30.0.0", "@types/jest": "^30.0.0",
"@types/node": "^25.0.10", "@types/node": "^25.9.2",
"@types/react": "^19.2.10", "@types/react": "^19.2.17",
"@types/react-dom": "^19.2.3", "@types/react-dom": "^19.2.3",
"@types/webpack": "^5.28.5", "@types/webpack": "^5.28.5",
"babel-loader": "^10.0.0", "babel-loader": "^10.1.1",
"clean-webpack-plugin": "^4.0.0", "clean-webpack-plugin": "^4.0.0",
"css-loader": "^7.1.3", "css-loader": "^7.1.4",
"css-minimizer-webpack-plugin": "^7.0.4", "css-minimizer-webpack-plugin": "^8.0.0",
"cypress": "^15.9.0", "cypress": "^15.17.0",
"dotenv": "^17.2.3", "dotenv": "^17.4.2",
"eslint": "^9.39.2", "eslint": "^9.39.4",
"eslint-plugin-react": "^7.37.5", "eslint-plugin-react": "^7.37.5",
"eslint-plugin-storybook": "^10.2.1", "eslint-plugin-storybook": "^10.4.3",
"eslint-webpack-plugin": "^5.0.2", "eslint-webpack-plugin": "^6.0.0",
"html-webpack-plugin": "^5.6.6", "globals": "^16.5.0",
"html-webpack-plugin": "^5.6.7",
"identity-obj-proxy": "^3.0.0", "identity-obj-proxy": "^3.0.0",
"jest": "^30.2.0", "jest": "^30.4.2",
"jest-environment-jsdom": "^30.2.0", "jest-environment-jsdom": "^30.4.1",
"jest-fetch-mock": "^3.0.3", "jest-fetch-mock": "^3.0.3",
"mini-css-extract-plugin": "^2.10.0", "mini-css-extract-plugin": "^2.10.2",
"react": "^19.2.4", "react": "^19.2.7",
"react-dom": "^19.2.4", "react-dom": "^19.2.7",
"resolve-ts-aliases": "^1.0.1", "resolve-ts-aliases": "^1.0.1",
"sass": "^1.97.3", "sass": "^1.100.0",
"sass-loader": "^16.0.6", "sass-loader": "^17.0.0",
"storybook": "^10.2.1", "storybook": "^10.4.3",
"style-loader": "^4.0.0", "style-loader": "^4.0.0",
"terser-webpack-plugin": "^5.3.16", "terser-webpack-plugin": "^5.6.1",
"ts-jest": "^29.4.6", "ts-jest": "^29.4.11",
"ts-loader": "^9.5.4", "ts-loader": "^9.6.0",
"tsconfig-paths-webpack-plugin": "^4.2.0", "tsconfig-paths-webpack-plugin": "^4.2.0",
"typescript": "^5.9.3", "typescript": "^6.0.3",
"typescript-eslint": "^8.61.0",
"url-loader": "^4.1.1", "url-loader": "^4.1.1",
"webpack": "^5.104.1", "webpack": "^5.107.2",
"webpack-cli": "^6.0.1", "webpack-cli": "^7.0.3",
"webpack-node-externals": "^3.0.0" "webpack-node-externals": "^3.0.0"
}, },
"peerDependencies": { "peerDependencies": {

View File

@@ -5,16 +5,16 @@
import '@testing-library/jest-dom'; import '@testing-library/jest-dom';
//import fetch Mock //import fetch Mock
import fetchMock from "jest-fetch-mock"; import fetchMock from 'jest-fetch-mock';
fetchMock.enableMocks(); fetchMock.enableMocks();
//Fixing Pollyfill for react-slick //Fixing Pollyfill for react-slick
window.matchMedia = window.matchMedia =
window.matchMedia || window.matchMedia ||
function() { function() {
return { return {
matches: false, matches: false,
addListener: function() {}, addListener: function() {},
removeListener: function() {} removeListener: function() {}
}; };
}; };

View File

@@ -1,8 +1,13 @@
declare module "*.svg" { declare module '*.svg' {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const content: any; const content: any;
export default content; export default content;
} }
declare module "@storybook/react" { declare module '*.scss';
export * from "@storybook/react/dist/index"; declare module '*.sass';
declare module '*.css';
declare module '@storybook/react' {
export * from '@storybook/react/dist/index';
} }

View File

@@ -1,28 +1,27 @@
import React from 'react'; import type { Meta, StoryObj } from '@storybook/react-webpack5';
import type { Meta, StoryObj } from '@storybook/react';
import { Card } from '@components'; import { Card } from '@components';
// More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export // More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
const meta: Meta<typeof Card> = { const meta: Meta<typeof Card> = {
title: 'Example/Card', title: 'Example/Card',
component: Card, component: Card,
parameters: { parameters: {
docs: { docs: {
description: { description: {
component: 'A reusable Card component for displaying content with an optional title.', component: 'A reusable Card component for displaying content with an optional title.',
}, },
}, },
}, },
argTypes: { argTypes: {
title: { title: {
control: 'text', control: 'text',
description: 'The title of the card', description: 'The title of the card',
}, },
children: { children: {
control: false, control: false,
description: 'The content to display inside the card', description: 'The content to display inside the card',
}, },
}, },
}; };
export default meta; export default meta;
@@ -30,8 +29,8 @@ type Story = StoryObj<typeof meta>;
// More on args: https://storybook.js.org/docs/react/writing-stories/args // More on args: https://storybook.js.org/docs/react/writing-stories/args
export const Basic: Story = { export const Basic: Story = {
args: { args: {
title: 'Test Title', title: 'Test Title',
children: <p>Test Content</p>, children: <p>Test Content</p>,
}, },
}; };

View File

@@ -1,5 +1,5 @@
import React, { FC } from "react"; import React, { FC } from 'react';
import "./style.scss"; import './style.scss';
type TCardProps = { type TCardProps = {
/** /**
@@ -13,13 +13,13 @@ type TCardProps = {
}; };
const Card: FC<TCardProps> = ({ title, children}) => { const Card: FC<TCardProps> = ({ title, children}) => {
return ( return (
<div className="Card"> <div className="Card">
<div className="Title">{title}</div> <div className="Title">{title}</div>
<div className="Content">{children}</div> <div className="Content">{children}</div>
</div> </div>
); );
}; };
export { Card, TCardProps } export { Card, TCardProps };

View File

@@ -1,14 +1,13 @@
import React from 'react';
import { Card } from '@components'; import { Card } from '@components';
describe('Testing Card Component', () => { describe('Testing Card Component', () => {
beforeEach(() => { beforeEach(() => {
cy.mount(<Card title='Test Title'><p>Test Content</p></Card>); cy.mount(<Card title='Test Title'><p>Test Content</p></Card>);
}) });
it('Show Title', () => { it('Show Title', () => {
cy.get('div').contains('Test Title'); cy.get('div').contains('Test Title');
}) });
it('Show Child Component', () => { it('Show Child Component', () => {
cy.get('p').contains('Test Content'); cy.get('p').contains('Test Content');
}) });
}) });

View File

@@ -1,24 +1,23 @@
import React from 'react';
import { render, screen } from '@testing-library/react'; import { render, screen } from '@testing-library/react';
import { Card } from '@components'; import { Card } from '@components';
describe('<Card/> Component', () => { describe('<Card/> Component', () => {
beforeEach(() => { beforeEach(() => {
// fetchMock.resetMocks(); // fetchMock.resetMocks();
render(<Card title='Test Title'><p>Test Content</p></Card>) render(<Card title='Test Title'><p>Test Content</p></Card>);
}); });
it('Show Title', async () => { it('Show Title', async () => {
/* fetchMock.mockResponseOnce(JSON.stringify({ /* fetchMock.mockResponseOnce(JSON.stringify({
//First Data Fetch //First Data Fetch
data: 'data' data: 'data'
})); */ })); */
expect(screen.getByText('Test Title')).toBeInTheDocument(); expect(screen.getByText('Test Title')).toBeInTheDocument();
}) });
it('Show Child Component', async () => { it('Show Child Component', async () => {
/* fetchMock.mockResponseOnce(JSON.stringify({ /* fetchMock.mockResponseOnce(JSON.stringify({
//First Data Fetch //First Data Fetch
data: 'data' data: 'data'
})); */ })); */
expect(screen.getByText('Test Content')).toBeInTheDocument(); expect(screen.getByText('Test Content')).toBeInTheDocument();
}) });
}) });

View File

@@ -1,7 +1,9 @@
{ {
"compilerOptions": { "compilerOptions": {
"ignoreDeprecations": "6.0",
"declaration": true, "declaration": true,
"declarationDir": "./dist/types", "declarationDir": "./dist/types",
"rootDir": "./src/components",
"target": "es5", "target": "es5",
"lib": [ "lib": [
"dom", "dom",
@@ -38,7 +40,8 @@
} }
}, },
"include": [ "include": [
"." "src/components",
"src/@types"
], ],
"exclude": [ "exclude": [
"node_modules", "node_modules",

View File

@@ -10,92 +10,92 @@ import ESLintPlugin from 'eslint-webpack-plugin';
import { resolveTsAliases } from 'resolve-ts-aliases'; import { resolveTsAliases } from 'resolve-ts-aliases';
const dotEnvToParse = dotenv.config(); const dotEnvToParse = dotenv.config();
const libraryName = process.env.LIBRARY_NAME ? process.env.LIBRARY_NAME : "ui-library" const libraryName = process.env.LIBRARY_NAME ? process.env.LIBRARY_NAME : 'ui-library';
const externalCss = process.env.EXTERNAL_CSS === 'true' ? true : false const externalCss = process.env.EXTERNAL_CSS === 'true' ? true : false;
const externalCssName = process.env.EXTERNAL_CSS_NAME ? process.env.EXTERNAL_CSS_NAME : 'index.css' const externalCssName = process.env.EXTERNAL_CSS_NAME ? process.env.EXTERNAL_CSS_NAME : 'index.css';
const alias = resolveTsAliases(path.resolve('tsconfig.json')); const alias = resolveTsAliases(path.resolve('tsconfig.json'));
export default { export default {
entry: './src/components/index.tsx', entry: './src/components/index.tsx',
externals: [nodeExternals()], externals: [nodeExternals()],
resolve: { resolve: {
extensions: ['.js', '.jsx','.ts','.tsx', '.json'], extensions: ['.js', '.jsx','.ts','.tsx', '.json'],
alias, alias,
}, },
mode: 'production', mode: 'production',
output: { output: {
filename: 'index.js', filename: 'index.js',
path: path.resolve(__dirname, 'dist'), path: path.resolve(__dirname, 'dist'),
library: libraryName, library: libraryName,
libraryTarget: 'umd', libraryTarget: 'umd',
globalObject: 'this', globalObject: 'this',
}, },
plugins: [ plugins: [
new CleanWebpackPlugin(), new CleanWebpackPlugin(),
...(externalCss === true ? [ ...(externalCss === true ? [
new MiniCssExtractPlugin({ new MiniCssExtractPlugin({
filename: externalCssName, filename: externalCssName,
}), }),
] : []), ] : []),
new webpack.DefinePlugin({ new webpack.DefinePlugin({
'process.env': JSON.stringify(dotEnvToParse.parsed), 'process.env': JSON.stringify(dotEnvToParse.parsed),
}), }),
new ESLintPlugin(), new ESLintPlugin(),
], ],
module: { module: {
rules: [ rules: [
{ {
test: /\.(ts|tsx)$/, test: /\.(ts|tsx)$/,
exclude: [/node_modules/, /\.test\.(ts|tsx)$/, /\.cy\.(ts|tsx)$/], exclude: [/node_modules/, /\.test\.(ts|tsx)$/, /\.cy\.(ts|tsx)$/],
use: { use: {
loader: 'ts-loader', loader: 'ts-loader',
options: {
onlyCompileBundledFiles: true,
compilerOptions: {
noEmit: false,
declaration: true,
declarationDir: './dist/types'
}
}
},
},
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: 'babel-loader',
},
{
test: /\.(css|sass|scss)$/,
use: [
externalCss === true ? MiniCssExtractPlugin.loader : 'style-loader',
{
loader: 'css-loader',
options: { options: {
modules: { onlyCompileBundledFiles: true,
namedExport: false, compilerOptions: {
exportLocalsConvention: 'as-is', noEmit: false,
auto: /\.module\.\w+$/i, declaration: true,
declarationDir: './dist/types'
}
} }
},
}, },
'sass-loader',
],
},
{
test: /\.(ttf|otf|eot|woff|woff2)$/,
loader: 'url-loader',
options: {
name: 'assets/fonts/[name].[ext]',
esModule: false,
}, },
}, {
] test: /\.(js|jsx)$/,
}, exclude: /node_modules/,
optimization: { use: 'babel-loader',
},
{
test: /\.(css|sass|scss)$/,
use: [
externalCss === true ? MiniCssExtractPlugin.loader : 'style-loader',
{
loader: 'css-loader',
options: {
modules: {
namedExport: false,
exportLocalsConvention: 'as-is',
auto: /\.module\.\w+$/i,
}
},
},
'sass-loader',
],
},
{
test: /\.(ttf|otf|eot|woff|woff2)$/,
loader: 'url-loader',
options: {
name: 'assets/fonts/[name].[ext]',
esModule: false,
},
},
]
},
optimization: {
minimize: true, minimize: true,
minimizer: [ minimizer: [
new CssMinimizerPlugin(), new CssMinimizerPlugin(),
new TerserPlugin(), new TerserPlugin(),
], ],
}, },
} };

View File

@@ -10,83 +10,83 @@ import ESLintPlugin from 'eslint-webpack-plugin';
import { resolveTsAliases } from 'resolve-ts-aliases'; import { resolveTsAliases } from 'resolve-ts-aliases';
const dotEnvToParse = dotenv.config(); const dotEnvToParse = dotenv.config();
const externalCss = process.env.EXTERNAL_CSS === 'true' ? true : false const externalCss = process.env.EXTERNAL_CSS === 'true' ? true : false;
const externalCssName = process.env.EXTERNAL_CSS_NAME ? process.env.EXTERNAL_CSS_NAME : 'index.css' const externalCssName = process.env.EXTERNAL_CSS_NAME ? process.env.EXTERNAL_CSS_NAME : 'index.css';
const alias = resolveTsAliases(path.resolve('tsconfig.json')); const alias = resolveTsAliases(path.resolve('tsconfig.json'));
export default { export default {
entry: './src/components/index.tsx', entry: './src/components/index.tsx',
resolve: { resolve: {
extensions: ['.js', '.jsx','.ts','.tsx', '.json'], extensions: ['.js', '.jsx','.ts','.tsx', '.json'],
alias, alias,
}, },
mode: 'development', mode: 'development',
output: { output: {
path: path.resolve(__dirname, 'dist'), path: path.resolve(__dirname, 'dist'),
}, },
target: 'web', target: 'web',
plugins: [ plugins: [
new CleanWebpackPlugin(), new CleanWebpackPlugin(),
...(externalCss === true ? [ ...(externalCss === true ? [
new MiniCssExtractPlugin({ new MiniCssExtractPlugin({
filename: externalCssName, filename: externalCssName,
}), }),
] : []), ] : []),
new webpack.DefinePlugin({ new webpack.DefinePlugin({
'process.env': JSON.stringify(dotEnvToParse.parsed), 'process.env': JSON.stringify(dotEnvToParse.parsed),
}), }),
new ESLintPlugin(), new ESLintPlugin(),
new HtmlWebpackPlugin({ new HtmlWebpackPlugin({
template: path.join(__dirname, 'public', 'index.html'), template: path.join(__dirname, 'public', 'index.html'),
}), }),
new webpack.ProvidePlugin({ new webpack.ProvidePlugin({
React: 'react', React: 'react',
}), }),
], ],
module: { module: {
rules: [ rules: [
{ {
test: /\.(ts|tsx)$/, test: /\.(ts|tsx)$/,
exclude: /node_modules/, exclude: /node_modules/,
use: 'ts-loader', use: 'ts-loader',
}, },
{ {
test: /\.(js|jsx)$/, test: /\.(js|jsx)$/,
exclude: /node_modules/, exclude: /node_modules/,
use: 'babel-loader', use: 'babel-loader',
},
{
test: /\.(css|sass|scss)$/,
use: [
externalCss === true ? MiniCssExtractPlugin.loader : 'style-loader',
{
loader: 'css-loader',
options: {
modules: {
namedExport: false,
exportLocalsConvention: 'as-is',
auto: /\.module\.\w+$/i,
}
},
},
'sass-loader',
],
},
{
test: /\.(ttf|otf|eot|woff|woff2)$/,
loader: 'url-loader',
options: {
name: 'assets/fonts/[name].[ext]',
esModule: false,
}, },
}, {
] test: /\.(css|sass|scss)$/,
}, use: [
optimization: { externalCss === true ? MiniCssExtractPlugin.loader : 'style-loader',
{
loader: 'css-loader',
options: {
modules: {
namedExport: false,
exportLocalsConvention: 'as-is',
auto: /\.module\.\w+$/i,
}
},
},
'sass-loader',
],
},
{
test: /\.(ttf|otf|eot|woff|woff2)$/,
loader: 'url-loader',
options: {
name: 'assets/fonts/[name].[ext]',
esModule: false,
},
},
]
},
optimization: {
minimize: true, minimize: true,
minimizer: [ minimizer: [
new CssMinimizerPlugin(), new CssMinimizerPlugin(),
new TerserPlugin(), new TerserPlugin(),
], ],
}, },
} };