├── .nvmrc ├── src ├── lib │ ├── index.ts │ └── CounterDemo │ │ ├── index.ts │ │ ├── __snapshots__ │ │ ├── useLogic.spec.ts.snap │ │ └── Counter.spec.tsx.snap │ │ ├── useLogic.ts │ │ ├── Counter.mdx │ │ ├── Counter.stories.ts │ │ ├── Counter.module.css │ │ ├── Counter.tsx │ │ ├── useLogic.spec.ts │ │ └── Counter.spec.tsx ├── vite-env.d.ts ├── setupTests.ts ├── env │ └── App │ │ ├── App.tsx │ │ └── index.css └── main.tsx ├── .husky ├── pre-commit └── pre-push ├── templates └── Component │ ├── index.ts │ ├── useLogic.ts │ ├── TemplateName.mdx │ ├── TemplateName.module.css │ ├── TemplateName.tsx │ ├── TemplateName.stories.tsx │ ├── useLogic.spec.ts │ └── TemplateName.spec.tsx ├── design ├── logo.ai ├── logo.jpg └── logo.png ├── .lintstagedrc ├── tsconfig.node.json ├── tsconfig.linter.json ├── .storybook ├── preview.ts └── main.ts ├── .gitignore ├── index.html ├── renovate.json ├── jest.config.mjs ├── .stylelintrc ├── tsconfig.json ├── generate-react-cli.json ├── LICENSE ├── public └── vite.svg ├── vite.config.ts ├── .github └── workflows │ ├── merge-jobs.yml │ ├── pull-request-jobs.yml │ └── pages.yml ├── package.json ├── README.md ├── eslint.config.js └── .editorconfig /.nvmrc: -------------------------------------------------------------------------------- 1 | 20 2 | -------------------------------------------------------------------------------- /src/lib/index.ts: -------------------------------------------------------------------------------- 1 | export {Counter} from './CounterDemo'; 2 | -------------------------------------------------------------------------------- /src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | pnpm run lint-staged 2 | pnpm run lint:types 3 | -------------------------------------------------------------------------------- /.husky/pre-push: -------------------------------------------------------------------------------- 1 | CI=true pnpm run test --passWithNoTests --silent 2 | -------------------------------------------------------------------------------- /src/lib/CounterDemo/index.ts: -------------------------------------------------------------------------------- 1 | export {Counter} from './Counter.tsx'; 2 | -------------------------------------------------------------------------------- /templates/Component/index.ts: -------------------------------------------------------------------------------- 1 | export {TemplateName} from './TemplateName.tsx'; 2 | -------------------------------------------------------------------------------- /design/logo.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/morewings/react-library-template/HEAD/design/logo.ai -------------------------------------------------------------------------------- /design/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/morewings/react-library-template/HEAD/design/logo.jpg -------------------------------------------------------------------------------- /design/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/morewings/react-library-template/HEAD/design/logo.png -------------------------------------------------------------------------------- /.lintstagedrc: -------------------------------------------------------------------------------- 1 | { 2 | "*.{js,ts,tsx}": [ 3 | "eslint --fix" 4 | ], 5 | "*.css": [ 6 | "stylelint --fix --quiet" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /src/setupTests.ts: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // learn more: https://github.com/testing-library/jest-dom 3 | import '@testing-library/jest-dom'; 4 | -------------------------------------------------------------------------------- /src/lib/CounterDemo/__snapshots__/useLogic.spec.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`lib > Counter > useLogic renders 1`] = ` 4 | { 5 | "count": 0, 6 | "incrementCount": [Function], 7 | } 8 | `; 9 | -------------------------------------------------------------------------------- /tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true 8 | }, 9 | "include": ["vite.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /src/env/App/App.tsx: -------------------------------------------------------------------------------- 1 | import type {FC} from 'react'; 2 | 3 | import {Counter} from '@/lib'; 4 | import './index.css'; 5 | 6 | const App: FC = () => { 7 | return ( 8 |
9 | 10 |
11 | ); 12 | }; 13 | 14 | export default App; 15 | -------------------------------------------------------------------------------- /tsconfig.linter.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends" : "./tsconfig.json", 3 | "include": [ 4 | "**/*.stories.*", 5 | "*.config.*", 6 | "src", 7 | ".storybook/*.ts", 8 | ".eslintrc.cjs", 9 | "templates/**/*.ts", 10 | "templates/**/*.tsx" 11 | ], 12 | "exclude": ["./dist/**"] 13 | } 14 | -------------------------------------------------------------------------------- /src/lib/CounterDemo/useLogic.ts: -------------------------------------------------------------------------------- 1 | import {useState} from 'react'; 2 | 3 | const useLogic = (initialState: number) => { 4 | const [count, setCount] = useState(initialState); 5 | return { 6 | count, 7 | incrementCount: () => setCount(count + 1), 8 | }; 9 | }; 10 | 11 | export default useLogic; 12 | -------------------------------------------------------------------------------- /templates/Component/useLogic.ts: -------------------------------------------------------------------------------- 1 | import {useState} from 'react'; 2 | 3 | const useLogic = (initialState: number) => { 4 | const [count, setCount] = useState(initialState); 5 | return { 6 | count, 7 | incrementCount: () => setCount(count + 1), 8 | }; 9 | }; 10 | 11 | export default useLogic; 12 | -------------------------------------------------------------------------------- /.storybook/preview.ts: -------------------------------------------------------------------------------- 1 | import type {Preview} from '@storybook/react-vite'; 2 | 3 | const preview: Preview = { 4 | parameters: { 5 | controls: { 6 | matchers: { 7 | color: /(background|color)$/i, 8 | date: /Date$/i, 9 | }, 10 | }, 11 | }, 12 | }; 13 | 14 | export default preview; 15 | -------------------------------------------------------------------------------- /src/env/App/index.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | text-rendering: optimizelegibility; 4 | } 5 | 6 | body { 7 | align-items: center; 8 | display: flex; 9 | flex-direction: row; 10 | justify-content: center; 11 | margin: 0; 12 | min-height: 100vh; 13 | min-width: 320px; 14 | } 15 | -------------------------------------------------------------------------------- /src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | 4 | import App from '@/env/App/App.tsx'; 5 | 6 | // eslint-disable-next-line ssr-friendly/no-dom-globals-in-module-scope 7 | ReactDOM.createRoot(document.getElementById('root')!).render( 8 | 9 | 10 | 11 | ); 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | storybook-static 26 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React + TS 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:recommended" 5 | ], 6 | "schedule": [ 7 | "before 4am on the first day of the month" 8 | ], 9 | "hostRules": [ 10 | { 11 | "matchHost": "api.github.com", 12 | "concurrentRequestLimit": 23 13 | } 14 | ], 15 | "baseBranchPatterns": [ 16 | "master", 17 | "tailwind" 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /templates/Component/TemplateName.mdx: -------------------------------------------------------------------------------- 1 | import { Meta, ArgTypes, Story, Canvas, Source, Markdown, Primary } from "@storybook/addon-docs/blocks"; 2 | import {TemplateName} from './TemplateName.tsx'; 3 | import * as TemplateNameStories from "./TemplateName.stories.tsx"; 4 | 5 | 6 | 7 | # TemplateName 8 | 9 | Text tba. 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/lib/CounterDemo/__snapshots__/Counter.spec.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`lib > Counter renders without crashing 1`] = ` 4 | 5 |
6 |

7 | Counter 8 |

9 | 14 |
15 | Total value: 16 | 17 | 6 18 | 19 |
20 |
21 |
22 | `; 23 | -------------------------------------------------------------------------------- /jest.config.mjs: -------------------------------------------------------------------------------- 1 | import {kitchen} from 'alias-kitchen'; 2 | 3 | export default { 4 | preset: 'ts-jest', 5 | testEnvironment: 'jest-environment-jsdom', 6 | transform: { 7 | '^.+\\.tsx?$': 'ts-jest', 8 | // process `*.tsx` files with `ts-jest` 9 | }, 10 | moduleNameMapper: { 11 | ...kitchen({recipe: 'jest'}), 12 | '\\.(gif|ttf|eot|svg|png|jpg)$': 'identity-obj-proxy', 13 | '\\.css$': 'identity-obj-proxy', 14 | }, 15 | modulePathIgnorePatterns: ['/templates/'], 16 | setupFilesAfterEnv: ['/src/setupTests.ts'], 17 | }; 18 | -------------------------------------------------------------------------------- /src/lib/CounterDemo/Counter.mdx: -------------------------------------------------------------------------------- 1 | import { Meta, ArgTypes, Story } from "@storybook/addon-docs/blocks"; 2 | import * as CounterStories from './Counter.stories'; 3 | import { Counter } from "./Counter"; 4 | 5 | 6 | 7 | # Example Component Demo 8 | 9 | ## Counter props 10 | 11 | 12 | 13 | ## Description 14 | 15 | `Counter` component provides user basic interface to increment counter by one. 16 | 17 | ## Demo 18 | 19 | 20 | 21 | ## With initial value 22 | 23 | This is another example with initial value 24 | 25 | 26 | -------------------------------------------------------------------------------- /.stylelintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "stylelint-config-standard", 4 | "stylelint-prettier/recommended" 5 | ], 6 | "rules": { 7 | "function-calc-no-unspaced-operator": true, 8 | "order/order": [ 9 | "custom-properties", 10 | "declarations" 11 | ], 12 | "order/properties-alphabetical-order": true, 13 | "property-no-vendor-prefix": true, 14 | "media-feature-name-no-vendor-prefix": true, 15 | "at-rule-no-vendor-prefix": true, 16 | "selector-no-vendor-prefix": true, 17 | "max-nesting-depth": 3, 18 | "selector-max-compound-selectors": 5 19 | }, 20 | "plugins": [ 21 | "stylelint-order" 22 | ], 23 | "ignoreFiles": ["**/*.snap"] 24 | } 25 | -------------------------------------------------------------------------------- /.storybook/main.ts: -------------------------------------------------------------------------------- 1 | import type {StorybookConfig} from '@storybook/react-vite'; 2 | import {withoutVitePlugins} from '@storybook/builder-vite'; 3 | 4 | const config: StorybookConfig = { 5 | stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'], 6 | addons: ['@storybook/addon-links', '@storybook/addon-docs'], 7 | framework: { 8 | name: '@storybook/react-vite', 9 | options: {}, 10 | }, 11 | async viteFinal(config) { 12 | return { 13 | ...config, 14 | plugins: await withoutVitePlugins(config.plugins, ['vite:dts']), 15 | }; 16 | }, 17 | typescript: { 18 | reactDocgen: 'react-docgen-typescript', 19 | }, 20 | }; 21 | export default config; 22 | -------------------------------------------------------------------------------- /src/lib/CounterDemo/Counter.stories.ts: -------------------------------------------------------------------------------- 1 | import type {Meta, StoryObj} from '@storybook/react-vite'; 2 | 3 | import {Counter} from './Counter'; 4 | 5 | const meta = { 6 | title: 'Example/Counter', 7 | component: Counter, 8 | parameters: { 9 | // More on how to position stories at: https://storybook.js.org/docs/react/configure/story-layout 10 | layout: 'fullscreen', 11 | }, 12 | } as Meta; 13 | 14 | export default meta; 15 | type Story = StoryObj; 16 | 17 | export const ExampleCounter: Story = { 18 | args: { 19 | initialValue: 0, 20 | }, 21 | }; 22 | 23 | export const ExampleCounterWithInitialValue: Story = { 24 | args: { 25 | initialValue: 11, 26 | }, 27 | }; 28 | -------------------------------------------------------------------------------- /src/lib/CounterDemo/Counter.module.css: -------------------------------------------------------------------------------- 1 | .counter { 2 | border: 1px solid lightgray; 3 | font-family: sans-serif; 4 | margin: 36px 24px; 5 | padding: 24px; 6 | text-align: center; 7 | width: 240px; 8 | } 9 | 10 | .header { 11 | font-size: 24px; 12 | font-weight: normal; 13 | margin: 0 0 12px; 14 | } 15 | 16 | .button { 17 | background: lightseagreen; 18 | border: none; 19 | border-radius: 5px; 20 | color: white; 21 | cursor: pointer; 22 | display: block; 23 | font-size: 16px; 24 | margin: 0 auto 24px; 25 | padding: 12px 24px; 26 | text-shadow: 1px 1px 1px rgb(0 0 0 / 50%); 27 | } 28 | 29 | .button:active { 30 | left: 1px; 31 | position: relative; 32 | top: 1px; 33 | } 34 | -------------------------------------------------------------------------------- /templates/Component/TemplateName.module.css: -------------------------------------------------------------------------------- 1 | .template-name { 2 | border: 1px solid lightgray; 3 | font-family: sans-serif; 4 | margin: 36px 24px; 5 | padding: 24px; 6 | text-align: center; 7 | width: 240px; 8 | } 9 | 10 | .header { 11 | font-size: 24px; 12 | font-weight: normal; 13 | margin: 0 0 12px; 14 | } 15 | 16 | .button { 17 | background: lightseagreen; 18 | border: none; 19 | border-radius: 5px; 20 | color: white; 21 | cursor: pointer; 22 | display: block; 23 | font-size: 16px; 24 | margin: 0 auto 24px; 25 | padding: 12px 24px; 26 | text-shadow: 1px 1px 1px rgb(0 0 0 / 50%); 27 | } 28 | 29 | .button:active { 30 | left: 1px; 31 | position: relative; 32 | top: 1px; 33 | } 34 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | "allowSyntheticDefaultImports": true, 9 | 10 | /* Bundler mode */ 11 | "moduleResolution": "bundler", 12 | "allowImportingTsExtensions": true, 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "noEmit": true, 16 | "jsx": "react-jsx", 17 | 18 | /* Linting */ 19 | "strict": true, 20 | "noUnusedLocals": true, 21 | "noUnusedParameters": true, 22 | "noFallthroughCasesInSwitch": true, 23 | 24 | /* Aliases */ 25 | "paths": { 26 | "@/*": ["./src/*"] 27 | } 28 | }, 29 | "include": ["src", "templates/**/*.ts", "templates/**/*.tsx"], 30 | "exclude": ["**/*.stories.*"], 31 | "references": [{ "path": "./tsconfig.node.json" }] 32 | } 33 | -------------------------------------------------------------------------------- /generate-react-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "usesTypeScript": true, 3 | "usesCssModule": true, 4 | "cssPreprocessor": "css", 5 | "testLibrary": "Testing Library", 6 | "component": { 7 | "default": { 8 | "path": "src/lib", 9 | "withLazy": false, 10 | "withStory": true, 11 | "withStyle": true, 12 | "withTest": false, 13 | "withIndex": true, 14 | "withMdx": true, 15 | "withHook": true, 16 | "withHookTest": true, 17 | "customTemplates": { 18 | "component": "templates/Component/TemplateName.tsx", 19 | "style": "templates/Component/TemplateName.module.css", 20 | "story": "templates/Component/TemplateName.stories.tsx", 21 | "index": "templates/Component/index.ts", 22 | "mdx": "templates/Component/TemplateName.mdx", 23 | "test": "templates/Component/TemplateName.spec.tsx", 24 | "hook": "templates/Component/useLogic.ts", 25 | "hookTest": "templates/Component/useLogic.spec.ts" 26 | } 27 | } 28 | }, 29 | "usesStyledComponents": false 30 | } 31 | -------------------------------------------------------------------------------- /src/lib/CounterDemo/Counter.tsx: -------------------------------------------------------------------------------- 1 | import type {FC} from 'react'; 2 | import {useEffect} from 'react'; 3 | import {throttle} from 'lodash'; 4 | 5 | import classes from './Counter.module.css'; 6 | import useLogic from './useLogic'; 7 | 8 | export type Props = { 9 | /** Set initial value */ 10 | initialValue?: number; 11 | }; 12 | 13 | export const Counter: FC = ({initialValue = 0}) => { 14 | const {count, incrementCount} = useLogic(initialValue); 15 | 16 | useEffect(() => { 17 | const runner = throttle(() => { 18 | console.log('throttle'); 19 | }, 10); 20 | runner(); 21 | }, []); 22 | 23 | return ( 24 |
25 |

Counter

26 | 29 |
30 | Total value: {count} 31 |
32 |
33 | ); 34 | }; 35 | -------------------------------------------------------------------------------- /templates/Component/TemplateName.tsx: -------------------------------------------------------------------------------- 1 | import type {FC} from 'react'; 2 | import {useEffect} from 'react'; 3 | import {throttle} from 'lodash'; 4 | 5 | import classes from './TemplateName.module.css'; 6 | import useLogic from './useLogic'; 7 | 8 | export type Props = { 9 | /** Set initial value */ 10 | initialValue?: number; 11 | }; 12 | 13 | export const TemplateName: FC = ({initialValue = 0}) => { 14 | const {count, incrementCount} = useLogic(initialValue); 15 | 16 | useEffect(() => { 17 | const runner = throttle(() => { 18 | console.log('throttle'); 19 | }, 10); 20 | runner(); 21 | }, []); 22 | return ( 23 |
24 |

Counter

25 | 28 |
29 | Total value: {count} 30 |
31 |
32 | ); 33 | }; 34 | -------------------------------------------------------------------------------- /templates/Component/TemplateName.stories.tsx: -------------------------------------------------------------------------------- 1 | import type {Meta, StoryObj} from '@storybook/react-vite'; 2 | 3 | import {TemplateName} from './TemplateName'; 4 | 5 | const meta = { 6 | title: 'Example/TemplateName', 7 | component: TemplateName, 8 | parameters: { 9 | // More on how to position stories at: https://storybook.js.org/docs/react/configure/story-layout 10 | layout: 'fullscreen', 11 | }, 12 | } as Meta; 13 | 14 | export default meta; 15 | type Story = StoryObj; 16 | 17 | export const Primary: Story = { 18 | render: args => { 19 | return ; 20 | }, 21 | args: {}, 22 | }; 23 | 24 | export const WithCode: Story = { 25 | render: args => { 26 | // here comes the code 27 | return ; 28 | }, 29 | }; 30 | 31 | WithCode.args = {}; 32 | 33 | WithCode.argTypes = {}; 34 | 35 | WithCode.parameters = { 36 | docs: { 37 | source: { 38 | language: 'tsx', 39 | type: 'code', 40 | }, 41 | }, 42 | }; 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Dima Vyshniakov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/lib/CounterDemo/useLogic.spec.ts: -------------------------------------------------------------------------------- 1 | import {renderHook, act} from '@testing-library/react'; 2 | 3 | import useLogic from './useLogic'; 4 | 5 | describe('lib > Counter > useLogic', () => { 6 | const initialValue = 0; 7 | it('renders', () => { 8 | /** 9 | * Render hook, using testing-library utility 10 | * @see https://testing-library.com/docs/react-testing-library/api#renderhook 11 | */ 12 | const {result} = renderHook(() => useLogic(initialValue)); 13 | 14 | expect(result.current).toMatchSnapshot(); 15 | }); 16 | it('increments value', () => { 17 | /** 18 | * Render hook, using testing-library utility 19 | * @see https://testing-library.com/docs/react-testing-library/api#renderhook 20 | */ 21 | const {result} = renderHook(() => useLogic(initialValue)); 22 | 23 | /** 24 | * Wrap state update with act 25 | * @see https://fb.me/react-wrap-tests-with-act 26 | */ 27 | act(() => { 28 | result.current.incrementCount(); 29 | }); 30 | 31 | expect(result.current.count).toBe(initialValue + 1); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /templates/Component/useLogic.spec.ts: -------------------------------------------------------------------------------- 1 | import {renderHook, act} from '@testing-library/react'; 2 | 3 | import useLogic from './useLogic'; 4 | 5 | describe('lib > Counter > useLogic', () => { 6 | const initialValue = 0; 7 | it('renders', () => { 8 | /** 9 | * Render hook, using testing-library utility 10 | * @see https://testing-library.com/docs/react-testing-library/api#renderhook 11 | */ 12 | const {result} = renderHook(() => useLogic(initialValue)); 13 | 14 | expect(result.current).toMatchSnapshot(); 15 | }); 16 | it('increments value', () => { 17 | /** 18 | * Render hook, using testing-library utility 19 | * @see https://testing-library.com/docs/react-testing-library/api#renderhook 20 | */ 21 | const {result} = renderHook(() => useLogic(initialValue)); 22 | 23 | /** 24 | * Wrap state update with act 25 | * @see https://fb.me/react-wrap-tests-with-act 26 | */ 27 | act(() => { 28 | result.current.incrementCount(); 29 | }); 30 | 31 | expect(result.current.count).toBe(initialValue + 1); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import {resolve} from 'path'; 2 | 3 | import {defineConfig} from 'vite'; 4 | import react from '@vitejs/plugin-react'; 5 | import {kitchen} from 'alias-kitchen'; 6 | import external from '@yelo/rollup-node-external'; 7 | import dts from 'vite-plugin-dts'; 8 | import postcssPresetEnv from 'postcss-preset-env'; 9 | 10 | // https://vitejs.dev/config/ 11 | export default defineConfig({ 12 | resolve: { 13 | alias: kitchen({recipe: 'rollup'}), 14 | }, 15 | plugins: [react(), dts({rollupTypes: true, exclude: ['**/*.stories.(ts|tsx)']})], 16 | build: { 17 | sourcemap: true, 18 | lib: { 19 | // Could also be a dictionary or array of multiple entry points 20 | entry: resolve(__dirname, 'src/lib/index.ts'), 21 | name: 'Library name', 22 | // the proper extensions will be added 23 | fileName: 'index', 24 | }, 25 | rollupOptions: { 26 | // make sure to externalize deps that shouldn't be bundled 27 | // into your library 28 | external: external(), 29 | output: { 30 | // Provide global variables to use in the UMD build 31 | // for externalized deps 32 | globals: { 33 | react: 'React', 34 | }, 35 | }, 36 | }, 37 | }, 38 | css: { 39 | modules: { 40 | localsConvention: 'camelCase', 41 | }, 42 | postcss: { 43 | plugins: [postcssPresetEnv({stage: 1})], 44 | }, 45 | }, 46 | }); 47 | -------------------------------------------------------------------------------- /.github/workflows/merge-jobs.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 3 | 4 | name: Post-merge tasks 5 | 6 | on: 7 | push: 8 | branches: [ master ] 9 | 10 | jobs: 11 | build-publish: 12 | 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: Cancel Workflow Action 17 | uses: styfle/cancel-workflow-action@0.12.1 18 | with: 19 | access_token: ${{ github.token }} 20 | 21 | - name: Checkout 22 | uses: actions/checkout@v4 23 | 24 | - name: Read .nvmrc 25 | run: echo "NVMRC=$(cat .nvmrc)" >> $GITHUB_ENV 26 | id: nvm 27 | 28 | - name: Use Node.js ${{ env.NVMRC }} 29 | uses: actions/setup-node@v4 30 | with: 31 | node-version: ${{ env.NVMRC }} 32 | 33 | - name: Install pnpm 34 | uses: pnpm/action-setup@v4 35 | with: 36 | version: 10 37 | run_install: false 38 | 39 | - name: Get pnpm store directory 40 | shell: bash 41 | run: echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV 42 | 43 | - name: Setup pnpm cache 44 | uses: actions/cache@v4 45 | with: 46 | path: ${{ env.STORE_PATH }} 47 | key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} 48 | restore-keys: | 49 | ${{ runner.os }}-pnpm-store- 50 | 51 | - name: Run merge tasks 52 | run: | 53 | pnpm install 54 | 55 | # - name: Publish NPM package 56 | # uses: JS-DevTools/npm-publish@v3 57 | # with: 58 | # token: ${{ secrets.NPM_TOKEN }} 59 | -------------------------------------------------------------------------------- /.github/workflows/pull-request-jobs.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 3 | 4 | name: Node.js CI 5 | 6 | on: 7 | pull_request: 8 | branches: [ master ] 9 | 10 | jobs: 11 | lint-test: 12 | 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: Cancel Workflow Action 17 | uses: styfle/cancel-workflow-action@0.12.1 18 | with: 19 | access_token: ${{ github.token }} 20 | 21 | - name: Checkout 22 | uses: actions/checkout@v4 23 | 24 | - name: Read .nvmrc 25 | run: echo "NVMRC=$(cat .nvmrc)" >> $GITHUB_ENV 26 | id: nvm 27 | 28 | - name: Use Node.js ${{ env.NVMRC }} 29 | uses: actions/setup-node@v4 30 | with: 31 | node-version: ${{ env.NVMRC }} 32 | 33 | - name: Install pnpm 34 | uses: pnpm/action-setup@v4 35 | with: 36 | version: 10 37 | run_install: false 38 | 39 | - name: Get pnpm store directory 40 | shell: bash 41 | run: echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV 42 | 43 | - name: Setup pnpm cache 44 | uses: actions/cache@v4 45 | with: 46 | path: ${{ env.STORE_PATH }} 47 | key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} 48 | restore-keys: | 49 | ${{ runner.os }}-pnpm-store- 50 | 51 | - name: Run test tasks 52 | run: | 53 | pnpm install 54 | pnpm run lint:code --quiet 55 | pnpm run lint:style --quiet 56 | pnpm run test --silent 57 | pnpm run start:docs --smoke-test --quiet 58 | pnpm run build 59 | pnpm run generate:component Foo --dry-run 60 | -------------------------------------------------------------------------------- /src/lib/CounterDemo/Counter.spec.tsx: -------------------------------------------------------------------------------- 1 | import {render, fireEvent} from '@testing-library/react'; 2 | 3 | import {Counter} from './Counter'; 4 | 5 | describe('lib > Counter', () => { 6 | /** 7 | * Jest hook which runs before each test, 8 | * @see https://jestjs.io/docs/en/api#beforeeachfn-timeout 9 | */ 10 | beforeEach(() => {}); 11 | 12 | it('renders without crashing', () => { 13 | /** 14 | * `asFragment`: 15 | * @see https://testing-library.com/docs/react-testing-library/api#asfragment 16 | * `baseElement`: 17 | * @see https://testing-library.com/docs/react-testing-library/api#baseelement 18 | */ 19 | const {asFragment, baseElement} = render(); 20 | 21 | /** 22 | * Basic snapshot test to make sure, that rendered component 23 | * matches expected footprint. 24 | */ 25 | expect(asFragment()).toMatchSnapshot(); 26 | 27 | /** More precise test for counter value */ 28 | expect(baseElement.querySelector('strong')!.textContent).toBe('6'); // 6 is value we expect, we need to convert Number to String, because HTMLElement textContent method returns string value 29 | }); 30 | 31 | it('changes counter value on button click', () => { 32 | const value = 1; 33 | 34 | /** 35 | * `getByRole`: 36 | * @see https://testing-library.com/docs/dom-testing-library/api-queries#byrole 37 | */ 38 | const {getByRole, baseElement} = render(); 39 | 40 | /** 41 | * Search for the button and make testing library click on it 42 | * @see https://testing-library.com/docs/react-testing-library/cheatsheet#events 43 | */ 44 | fireEvent.click(getByRole('button')); 45 | 46 | /** Check if counter was incremented */ 47 | expect(baseElement.querySelector('strong')!.textContent).toBe(`${value + 1}`); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /templates/Component/TemplateName.spec.tsx: -------------------------------------------------------------------------------- 1 | import {render, fireEvent} from '@testing-library/react'; 2 | 3 | import {TemplateName} from './TemplateName'; 4 | 5 | describe('lib > TemplateName', () => { 6 | /** 7 | * Jest hook which runs before each test, 8 | * @see https://jestjs.io/docs/en/api#beforeeachfn-timeout 9 | */ 10 | beforeEach(() => {}); 11 | 12 | it('renders without crashing', () => { 13 | /** 14 | * `asFragment`: 15 | * @see https://testing-library.com/docs/react-testing-library/api#asfragment 16 | * `baseElement`: 17 | * @see https://testing-library.com/docs/react-testing-library/api#baseelement 18 | */ 19 | const {asFragment, baseElement} = render(); 20 | 21 | /** 22 | * Basic snapshot test to make sure, that rendered component 23 | * matches expected footprint. 24 | */ 25 | expect(asFragment()).toMatchSnapshot(); 26 | 27 | /** More precise test for counter value */ 28 | expect(baseElement.querySelector('strong')!.textContent).toBe('6'); // 6 is value we expect, we need to convert Number to String, because HTMLElement textContent method returns string value 29 | }); 30 | 31 | it('changes counter value on button click', () => { 32 | const value = 1; 33 | 34 | /** 35 | * `getByRole`: 36 | * @see https://testing-library.com/docs/dom-testing-library/api-queries#byrole 37 | */ 38 | const {getByRole, baseElement} = render(); 39 | 40 | /** 41 | * Search for the button and make testing library click on it 42 | * @see https://testing-library.com/docs/react-testing-library/cheatsheet#events 43 | */ 44 | fireEvent.click(getByRole('button')); 45 | 46 | /** Check if counter was incremented */ 47 | expect(baseElement.querySelector('strong')!.textContent).toBe(`${value + 1}`); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /.github/workflows/pages.yml: -------------------------------------------------------------------------------- 1 | # Simple workflow for deploying static content to GitHub Pages 2 | name: Deploy to GitHub Pages 3 | 4 | on: 5 | # Runs on pushes targeting the default branch 6 | push: 7 | branches: ["master"] 8 | 9 | # Allows you to run this workflow manually from the Actions tab 10 | workflow_dispatch: 11 | 12 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 13 | permissions: 14 | contents: read 15 | pages: write 16 | id-token: write 17 | 18 | # Allow one concurrent deployment 19 | concurrency: 20 | group: "pages" 21 | cancel-in-progress: true 22 | 23 | jobs: 24 | # Single deploy job since we're just deploying 25 | deploy: 26 | environment: 27 | name: github-pages 28 | url: ${{ steps.deployment.outputs.page_url }} 29 | runs-on: ubuntu-latest 30 | steps: 31 | - name: Cancel Workflow Action 32 | uses: styfle/cancel-workflow-action@0.12.1 33 | with: 34 | access_token: ${{ github.token }} 35 | 36 | - name: Checkout 37 | uses: actions/checkout@v4 38 | 39 | - name: Read .nvmrc 40 | run: echo "NVMRC=$(cat .nvmrc)" >> $GITHUB_ENV 41 | id: nvm 42 | 43 | - name: Use Node.js ${{ env.NVMRC }} 44 | uses: actions/setup-node@v4 45 | with: 46 | node-version: ${{ env.NVMRC }} 47 | 48 | - name: Install pnpm 49 | uses: pnpm/action-setup@v4 50 | with: 51 | version: 10 52 | run_install: false 53 | 54 | - name: Get pnpm store directory 55 | shell: bash 56 | run: echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV 57 | 58 | - name: Setup pnpm cache 59 | uses: actions/cache@v4 60 | with: 61 | path: ${{ env.STORE_PATH }} 62 | key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} 63 | restore-keys: | 64 | ${{ runner.os }}-pnpm-store- 65 | 66 | - name: Build docs 67 | run: | 68 | pnpm install 69 | pnpm run build:docs --quiet 70 | 71 | - name: Setup Pages 72 | uses: actions/configure-pages@v5 73 | 74 | - name: Upload artifact 75 | uses: actions/upload-pages-artifact@v3 76 | with: 77 | path: './storybook-static' 78 | 79 | - name: Deploy to GitHub Pages 80 | id: deployment 81 | uses: actions/deploy-pages@v4 82 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-library-template", 3 | "homepage": "https://morewings.github.io/react-library-template/", 4 | "private": false, 5 | "version": "0.1.0", 6 | "type": "module", 7 | "files": [ 8 | "dist" 9 | ], 10 | "main": "./dist/index.umd.cjs", 11 | "module": "./dist/index.js", 12 | "types": "./dist/index.d.ts", 13 | "sideEffects": false, 14 | "exports": { 15 | ".": { 16 | "import": "./dist/index.js", 17 | "require": "./dist/index.umd.cjs" 18 | } 19 | }, 20 | "keywords": [ 21 | "react", 22 | "template", 23 | "react-testing-library", 24 | "testing-library", 25 | "eslint", 26 | "npm", 27 | "rollup", 28 | "stylelint", 29 | "library", 30 | "package", 31 | "vite", 32 | "css-modules", 33 | "typescript" 34 | ], 35 | "description": "Missing React, typescript NPM library creation template", 36 | "scripts": { 37 | "dev": "vite", 38 | "clean:lib": "rm -rf dist", 39 | "build:lib": "vite build", 40 | "build": "run-s clean:lib build:lib", 41 | "lint:code": "eslint src/** --report-unused-disable-directives", 42 | "fix:code": "run-s 'lint:code --fix'", 43 | "lint:types": "tsc --pretty --noEmit", 44 | "lint:style": "stylelint ./src/**/*.css", 45 | "fix:style": "run-s 'lint:style --fix'", 46 | "test": "jest", 47 | "preview": "vite preview", 48 | "start:docs": "storybook dev -p 6006", 49 | "build:docs": "storybook build", 50 | "generate:component": "npx generate-react-cli component", 51 | "prepare": "is-ci || husky", 52 | "lint-staged": "lint-staged" 53 | }, 54 | "peerDependencies": { 55 | "react": ">=18.2.0", 56 | "react-dom": ">=18.2.0" 57 | }, 58 | "dependencies": { 59 | "lodash": "^4.17.21" 60 | }, 61 | "devDependencies": { 62 | "@eslint/compat": "1.3.1", 63 | "@eslint/eslintrc": "3.3.3", 64 | "@eslint/js": "9.31.0", 65 | "@storybook/addon-docs": "10.0.7", 66 | "@storybook/addon-links": "10.0.7", 67 | "@storybook/builder-vite": "10.0.7", 68 | "@storybook/react-vite": "10.0.7", 69 | "@testing-library/jest-dom": "6.6.3", 70 | "@testing-library/react": "16.3.0", 71 | "@types/jest": "30.0.0", 72 | "@types/lodash": "4.17.21", 73 | "@types/react": "19.1.8", 74 | "@types/react-dom": "19.1.6", 75 | "@typescript-eslint/eslint-plugin": "8.46.1", 76 | "@typescript-eslint/parser": "8.46.1", 77 | "@vitejs/plugin-react": "4.7.0", 78 | "@yelo/rollup-node-external": "1.0.1", 79 | "alias-kitchen": "0.2.4", 80 | "eslint": "9.31.0", 81 | "eslint-config-prettier": "10.1.8", 82 | "eslint-plugin-import": "2.32.0", 83 | "eslint-plugin-prettier": "5.5.4", 84 | "eslint-plugin-react": "7.37.5", 85 | "eslint-plugin-react-hooks": "5.2.0", 86 | "eslint-plugin-react-refresh": "0.4.24", 87 | "eslint-plugin-ssr-friendly": "1.3.0", 88 | "eslint-plugin-storybook": "10.0.7", 89 | "generate-react-cli": "8.4.9", 90 | "husky": "9.1.7", 91 | "identity-obj-proxy": "3.0.0", 92 | "is-ci": "4.1.0", 93 | "jest": "30.0.5", 94 | "jest-environment-jsdom": "30.0.5", 95 | "lint-staged": "16.1.2", 96 | "npm-run-all2": "8.0.4", 97 | "postcss": "8.5.6", 98 | "postcss-preset-env": "10.2.4", 99 | "prettier": "3.6.2", 100 | "react": "19.1.0", 101 | "react-docgen-typescript": "2.4.0", 102 | "react-dom": "19.1.0", 103 | "storybook": "10.0.7", 104 | "stylelint": "16.22.0", 105 | "stylelint-config-standard": "38.0.0", 106 | "stylelint-order": "7.0.0", 107 | "stylelint-prettier": "5.0.3", 108 | "ts-jest": "29.4.0", 109 | "ts-node": "10.9.2", 110 | "typescript": "5.8.3", 111 | "typescript-eslint": "8.46.1", 112 | "vite": "7.1.11", 113 | "vite-plugin-dts": "4.5.4" 114 | }, 115 | "pnpm": { 116 | "onlyBuiltDependencies": [ 117 | "esbuild", 118 | "unrs-resolver" 119 | ] 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![CI](https://github.com/morewings/react-library-template/actions/workflows/merge-jobs.yml/badge.svg)](https://github.com/morewings/react-library-template/actions/workflows/merge-jobs.yml) 2 | [![Storybook deploy](https://github.com/morewings/react-library-template/actions/workflows/pages.yml/badge.svg)](https://github.com/morewings/react-library-template/actions/workflows/pages.yml) 3 | [![Use this template](https://img.shields.io/badge/use%20this-template-blue?logo=githu)](https://github.com/morewings/react-library-template/generate) 4 | 5 | # React Library Template 6 | 7 | [![NPM library Create React App template logo](./design/logo.jpg)](#) 8 | 9 | This template repository is your shortcut to building awesome React components and libraries! 10 | 11 | Forget about the tedious setup – we've got you covered. Focus on writing your code, and let this template handle the rest. 12 | 13 | ## Features 14 | 15 | - **TypeScript & JavaScript**: Write your code in the language you prefer. 16 | - **Blazing fast**: **pnpm** for speedy package management and **Vite** for lightning-fast builds. 17 | - **Husky** enforces pre-commit hooks, **Eslint** and **Stylelint** will keep your code tidy and consistent. 18 | - **Jest** and **react-testing-library** help you write robust tests. 19 | - **Storybook** lets you create interactive demos and docs for your components. 20 | - **Optional Tailwind CSS**: If you're into it, you can easily enable Tailwind CSS for styling. 21 | 22 | See it in action: [Demo Storybook](https://morewings.github.io/react-library-template/) 23 | 24 | This template is your starting point for building high-quality React libraries. Clone it, customize it, and let's build something amazing! 25 | 26 | ## Quickstart 27 | 28 | ### Prerequisites 29 | 30 | 1. Install **Node** >= 20.x. 31 | 2. Install **pnpm**. E.g. `corepack prepare pnpm@latest --activate`. 32 | 33 | 34 | ### Installation 35 | 36 | Manually clone repo or use `degit`. 37 | 38 | ```shell script 39 | # With CSS Modules config 40 | npx degit github:morewings/react-library-template my-library 41 | # With Tailwind CSS config 42 | npx degit github:morewings/react-library-template#tailwind my-library 43 | cd ./my-library 44 | pnpm i 45 | ``` 46 | 47 | 48 | ## Enable Tailwind CSS 49 | 50 | You can find all changes at this [PR](https://github.com/morewings/react-library-template/pull/161) and [tailwind](https://github.com/morewings/react-library-template/tree/tailwind) branch. 51 | 52 | ## Improve tree shaking 53 | 54 | The default settings allow modern bundlers such as Vite and esbuild successfully tree-shake unused modules from the bundle. 55 | Unfortunately there are problems with Next.js and Webpack not capable to tree-shake single file ES Module. 56 | 57 | In order to fix this enable `preserveModules` setting in Rollup options. 58 | 59 | ```ts 60 | import {defineConfig} from 'vite'; 61 | 62 | export default defineConfig(() => ({ 63 | // ... 64 | build: { 65 | lib: { 66 | // ... 67 | fileName: (format, entryName) => { 68 | // Create entry file(s) inside the bundle 69 | if (entryName === 'src/lib/index') { 70 | return `index.${format === 'es' ? 'js' : 'cjs'}`; 71 | // Organize external dependencies which included in the bundle 72 | } else if (entryName.includes('node_modules')) { 73 | return `external/module.${format === 'es' ? 'js' : 'cjs'}` 74 | } 75 | // Keep other modules in places 76 | return `${entryName}.${format === 'es' ? 'js' : 'cjs'}`; 77 | }, 78 | // Change bundle formats to ES Modules and commonJS. 79 | // UMD bundle will not work with preserveModules:true 80 | formats: ['es', 'cjs'], 81 | }, 82 | rollupOptions: { 83 | // ... 84 | output: { 85 | // ... 86 | preserveModules: true, 87 | }, 88 | }, 89 | }, 90 | })); 91 | 92 | ``` 93 | 94 | You can find all changes at corresponding [PR](https://github.com/morewings/react-library-template/pull/352) and [tree-shaking](https://github.com/morewings/react-library-template/tree/tree-shaking) branch. 95 | -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | 3 | import eslint from '@eslint/js'; 4 | import eslintTS from 'typescript-eslint'; 5 | import tsParser from '@typescript-eslint/parser'; 6 | import pluginImport from 'eslint-plugin-import'; 7 | import pluginSSRFriendly from 'eslint-plugin-ssr-friendly'; 8 | import pluginPrettier from 'eslint-plugin-prettier'; 9 | import pluginTypescript from '@typescript-eslint/eslint-plugin'; 10 | import pluginReactRefresh from 'eslint-plugin-react-refresh'; 11 | import configReactRecommended from 'eslint-plugin-react/configs/recommended.js'; 12 | import configReactJSXRuntime from 'eslint-plugin-react/configs/jsx-runtime.js'; 13 | import pluginReactHooks from 'eslint-plugin-react-hooks'; 14 | import {fixupPluginRules} from '@eslint/compat'; 15 | import configPrettierRecommended from 'eslint-plugin-prettier/recommended'; 16 | 17 | export default [ 18 | eslint.configs.recommended, 19 | ...eslintTS.configs.recommended, 20 | ...eslintTS.configs.stylistic, 21 | configReactRecommended, 22 | configReactJSXRuntime, 23 | configPrettierRecommended, 24 | { 25 | files: ['**/*.{js,ts,tsx,cjs}'], 26 | linterOptions: { 27 | reportUnusedDisableDirectives: 'error', 28 | }, 29 | languageOptions: { 30 | parser: tsParser, 31 | parserOptions: { 32 | ecmaFeatures: {modules: true}, 33 | ecmaVersion: 'latest', 34 | project: './tsconfig.linter.json', 35 | }, 36 | }, 37 | settings: { 38 | react: { 39 | version: 'detect', 40 | }, 41 | }, 42 | plugins: { 43 | import: pluginImport, 44 | prettier: pluginPrettier, 45 | '@typescript-eslint': pluginTypescript, 46 | 'react-refresh': pluginReactRefresh, 47 | 'react-hooks': fixupPluginRules(pluginReactHooks), 48 | 'ssr-friendly': fixupPluginRules(pluginSSRFriendly), 49 | }, 50 | rules: { 51 | ...pluginReactHooks.configs.recommended.rules, 52 | ...pluginSSRFriendly.configs.recommended.rules, 53 | /** 54 | * Allow empty arrow functions `() => {}`, while keeping other empty functions restricted 55 | * @see https://eslint.org/docs/latest/rules/no-empty-function#allow-arrowfunctions 56 | */ 57 | '@typescript-eslint/no-empty-function': ['error', {allow: ['arrowFunctions']}], 58 | '@typescript-eslint/ban-ts-comment': 1, 59 | 'no-const-assign': 'error', 60 | /** Restrict imports from devDependencies since they are not included in library build. peerDependencies are ok */ 61 | 'import/no-extraneous-dependencies': [ 62 | 'error', 63 | { 64 | devDependencies: false, 65 | peerDependencies: true, 66 | }, 67 | ], 68 | /** 69 | * Enforce import order with empty lines between import group 70 | * @see https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/order.md 71 | */ 72 | 'import/order': [ 73 | 'error', 74 | { 75 | groups: ['builtin', 'external', 'internal', ['parent', 'sibling', 'index']], 76 | pathGroups: [ 77 | { 78 | pattern: '@/**', 79 | group: 'internal', 80 | }, 81 | ], 82 | 'newlines-between': 'always', 83 | }, 84 | ], 85 | /** 86 | * Disallow combined module and type imports like this `import React, {FC} from 'react'`. 87 | * Eslint will try to split into type and module imports instead 88 | * @see https://typescript-eslint.io/rules/consistent-type-imports/ 89 | */ 90 | '@typescript-eslint/consistent-type-imports': 'error', 91 | 'import/no-cycle': 'error', 92 | 'prettier/prettier': [ 93 | 'error', 94 | { 95 | semi: true, 96 | singleQuote: true, 97 | jsxSingleQuote: false, 98 | trailingComma: 'es5', 99 | bracketSpacing: false, 100 | jsxBracketSameLine: true, 101 | arrowParens: 'avoid', 102 | }, 103 | ], 104 | /* Required by vite */ 105 | 'react-refresh/only-export-components': ['warn', {allowConstantExport: true}], 106 | '@typescript-eslint/consistent-type-definitions': ['error', 'type'], 107 | /** 108 | * Allow unused variables with names stating with '_' 109 | * @see https://eslint.org/docs/latest/rules/no-unused-vars 110 | * @see https://typescript-eslint.io/rules/no-unused-vars/ 111 | */ 112 | '@typescript-eslint/no-unused-vars': [ 113 | 'error', 114 | { 115 | argsIgnorePattern: '^_', 116 | varsIgnorePattern: '^_', 117 | caughtErrorsIgnorePattern: '^_', 118 | ignoreRestSiblings: true, 119 | args: 'after-used', 120 | }, 121 | ], 122 | }, 123 | }, 124 | /* Allow devDependencies imports for tests and config files */ 125 | { 126 | files: [ 127 | '**/*.spec.*', 128 | '**/testUtils/*.{js,jsx,ts,tsx}', 129 | '*/*.{js,jsx,ts,tsx}', 130 | '**/setupTests.ts', 131 | '**/*.stories.*', 132 | '*.config.{js,ts}', 133 | ], 134 | plugins: { 135 | import: pluginImport, 136 | }, 137 | rules: { 138 | 'import/no-extraneous-dependencies': [ 139 | 'error', 140 | { 141 | devDependencies: true, 142 | peerDependencies: true, 143 | }, 144 | ], 145 | }, 146 | }, 147 | /* Disable `environment` directory imports for library files */ 148 | { 149 | files: ['src/lib/**/*.{js,jsx,ts,tsx}'], 150 | rules: { 151 | 'no-restricted-imports': [ 152 | 'error', 153 | { 154 | patterns: [ 155 | { 156 | group: ['**/environment/**'], 157 | message: 'Imports from environment directory are forbidden in the library files.', 158 | }, 159 | ], 160 | }, 161 | ], 162 | }, 163 | }, 164 | /* Disable `template` directory imports for all files */ 165 | { 166 | files: ['src/**/*.{js,jsx,ts,tsx}'], 167 | rules: { 168 | 'no-restricted-imports': [ 169 | 'error', 170 | { 171 | patterns: [ 172 | { 173 | group: ['**/templates/**'], 174 | message: 'Imports from templates directory are forbidden.', 175 | }, 176 | ], 177 | }, 178 | ], 179 | }, 180 | }, 181 | /** 182 | * Disable rules of hooks for story files in order to have better story code display. 183 | * @see TemplateName.stories.tsx 184 | */ 185 | { 186 | files: ['**/*.stories.*'], 187 | rules: { 188 | 'react-hooks/rules-of-hooks': 'off', 189 | }, 190 | }, 191 | { 192 | ignores: ['**/*.snap'], 193 | }, 194 | ]; 195 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | charset = utf-8 3 | end_of_line = lf 4 | indent_size = 4 5 | indent_style = space 6 | insert_final_newline = true 7 | max_line_length = 120 8 | tab_width = 4 9 | trim_trailing_whitespace = true 10 | ij_continuation_indent_size = 8 11 | ij_formatter_off_tag = @formatter:off 12 | ij_formatter_on_tag = @formatter:on 13 | ij_formatter_tags_enabled = true 14 | ij_smart_tabs = false 15 | ij_visual_guides = 16 | ij_wrap_on_typing = false 17 | 18 | [*.css] 19 | ij_css_align_closing_brace_with_properties = false 20 | ij_css_blank_lines_around_nested_selector = 1 21 | ij_css_blank_lines_between_blocks = 1 22 | ij_css_block_comment_add_space = false 23 | ij_css_brace_placement = end_of_line 24 | ij_css_enforce_quotes_on_format = false 25 | ij_css_hex_color_long_format = false 26 | ij_css_hex_color_lower_case = false 27 | ij_css_hex_color_short_format = false 28 | ij_css_hex_color_upper_case = false 29 | ij_css_keep_blank_lines_in_code = 2 30 | ij_css_keep_indents_on_empty_lines = false 31 | ij_css_keep_single_line_blocks = false 32 | ij_css_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow 33 | ij_css_space_after_colon = true 34 | ij_css_space_before_opening_brace = true 35 | ij_css_use_double_quotes = true 36 | ij_css_value_alignment = do_not_align 37 | 38 | [*.feature] 39 | indent_size = 2 40 | ij_gherkin_keep_indents_on_empty_lines = false 41 | 42 | [*.less] 43 | ij_less_align_closing_brace_with_properties = false 44 | ij_less_blank_lines_around_nested_selector = 1 45 | ij_less_blank_lines_between_blocks = 1 46 | ij_less_block_comment_add_space = false 47 | ij_less_brace_placement = 0 48 | ij_less_enforce_quotes_on_format = false 49 | ij_less_hex_color_long_format = false 50 | ij_less_hex_color_lower_case = false 51 | ij_less_hex_color_short_format = false 52 | ij_less_hex_color_upper_case = false 53 | ij_less_keep_blank_lines_in_code = 2 54 | ij_less_keep_indents_on_empty_lines = false 55 | ij_less_keep_single_line_blocks = false 56 | ij_less_line_comment_add_space = false 57 | ij_less_line_comment_at_first_column = false 58 | ij_less_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow 59 | ij_less_space_after_colon = true 60 | ij_less_space_before_opening_brace = true 61 | ij_less_use_double_quotes = true 62 | ij_less_value_alignment = 0 63 | 64 | [*.sass] 65 | ij_sass_align_closing_brace_with_properties = false 66 | ij_sass_blank_lines_around_nested_selector = 1 67 | ij_sass_blank_lines_between_blocks = 1 68 | ij_sass_brace_placement = 0 69 | ij_sass_enforce_quotes_on_format = false 70 | ij_sass_hex_color_long_format = false 71 | ij_sass_hex_color_lower_case = false 72 | ij_sass_hex_color_short_format = false 73 | ij_sass_hex_color_upper_case = false 74 | ij_sass_keep_blank_lines_in_code = 2 75 | ij_sass_keep_indents_on_empty_lines = false 76 | ij_sass_keep_single_line_blocks = false 77 | ij_sass_line_comment_add_space = false 78 | ij_sass_line_comment_at_first_column = false 79 | ij_sass_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow 80 | ij_sass_space_after_colon = true 81 | ij_sass_space_before_opening_brace = true 82 | ij_sass_use_double_quotes = true 83 | ij_sass_value_alignment = 0 84 | 85 | [*.scss] 86 | ij_scss_align_closing_brace_with_properties = false 87 | ij_scss_blank_lines_around_nested_selector = 1 88 | ij_scss_blank_lines_between_blocks = 1 89 | ij_scss_block_comment_add_space = false 90 | ij_scss_brace_placement = 0 91 | ij_scss_enforce_quotes_on_format = false 92 | ij_scss_hex_color_long_format = false 93 | ij_scss_hex_color_lower_case = false 94 | ij_scss_hex_color_short_format = false 95 | ij_scss_hex_color_upper_case = false 96 | ij_scss_keep_blank_lines_in_code = 2 97 | ij_scss_keep_indents_on_empty_lines = false 98 | ij_scss_keep_single_line_blocks = false 99 | ij_scss_line_comment_add_space = false 100 | ij_scss_line_comment_at_first_column = false 101 | ij_scss_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow 102 | ij_scss_space_after_colon = true 103 | ij_scss_space_before_opening_brace = true 104 | ij_scss_use_double_quotes = true 105 | ij_scss_value_alignment = 0 106 | 107 | [*.vue] 108 | indent_size = 2 109 | tab_width = 2 110 | ij_continuation_indent_size = 2 111 | ij_visual_guides = 80 112 | ij_vue_indent_children_of_top_level = template 113 | ij_vue_interpolation_new_line_after_start_delimiter = false 114 | ij_vue_interpolation_new_line_before_end_delimiter = false 115 | ij_vue_interpolation_wrap = off 116 | ij_vue_keep_indents_on_empty_lines = false 117 | ij_vue_spaces_within_interpolation_expressions = true 118 | 119 | [.editorconfig] 120 | ij_editorconfig_align_group_field_declarations = false 121 | ij_editorconfig_space_after_colon = false 122 | ij_editorconfig_space_after_comma = true 123 | ij_editorconfig_space_before_colon = false 124 | ij_editorconfig_space_before_comma = false 125 | ij_editorconfig_spaces_around_assignment_operators = true 126 | 127 | [{*.ant,*.fxml,*.jhm,*.jnlp,*.jrxml,*.rng,*.tld,*.wsdl,*.xml,*.xsd,*.xsl,*.xslt,*.xul}] 128 | ij_xml_align_attributes = true 129 | ij_xml_align_text = false 130 | ij_xml_attribute_wrap = normal 131 | ij_xml_block_comment_add_space = false 132 | ij_xml_block_comment_at_first_column = true 133 | ij_xml_keep_blank_lines = 2 134 | ij_xml_keep_indents_on_empty_lines = false 135 | ij_xml_keep_line_breaks = true 136 | ij_xml_keep_line_breaks_in_text = true 137 | ij_xml_keep_whitespaces = false 138 | ij_xml_keep_whitespaces_around_cdata = preserve 139 | ij_xml_keep_whitespaces_inside_cdata = false 140 | ij_xml_line_comment_at_first_column = true 141 | ij_xml_space_after_tag_name = false 142 | ij_xml_space_around_equals_in_attribute = false 143 | ij_xml_space_inside_empty_tag = false 144 | ij_xml_text_wrap = normal 145 | 146 | [{*.ats,*.cts,*.mts,*.ts,*tsx}] 147 | ij_continuation_indent_size = 4 148 | ij_visual_guides = 80 149 | ij_typescript_align_imports = false 150 | ij_typescript_align_multiline_array_initializer_expression = false 151 | ij_typescript_align_multiline_binary_operation = false 152 | ij_typescript_align_multiline_chained_methods = false 153 | ij_typescript_align_multiline_extends_list = false 154 | ij_typescript_align_multiline_for = true 155 | ij_typescript_align_multiline_parameters = true 156 | ij_typescript_align_multiline_parameters_in_calls = false 157 | ij_typescript_align_multiline_ternary_operation = false 158 | ij_typescript_align_object_properties = 0 159 | ij_typescript_align_union_types = false 160 | ij_typescript_align_var_statements = 0 161 | ij_typescript_array_initializer_new_line_after_left_brace = false 162 | ij_typescript_array_initializer_right_brace_on_new_line = false 163 | ij_typescript_array_initializer_wrap = off 164 | ij_typescript_assignment_wrap = off 165 | ij_typescript_binary_operation_sign_on_next_line = false 166 | ij_typescript_binary_operation_wrap = off 167 | ij_typescript_blacklist_imports = rxjs/Rx,node_modules/**,**/node_modules/**,@angular/material,@angular/material/typings/** 168 | ij_typescript_blank_lines_after_imports = 1 169 | ij_typescript_blank_lines_around_class = 1 170 | ij_typescript_blank_lines_around_field = 0 171 | ij_typescript_blank_lines_around_field_in_interface = 0 172 | ij_typescript_blank_lines_around_function = 1 173 | ij_typescript_blank_lines_around_method = 1 174 | ij_typescript_blank_lines_around_method_in_interface = 1 175 | ij_typescript_block_brace_style = end_of_line 176 | ij_typescript_block_comment_add_space = false 177 | ij_typescript_block_comment_at_first_column = true 178 | ij_typescript_call_parameters_new_line_after_left_paren = false 179 | ij_typescript_call_parameters_right_paren_on_new_line = false 180 | ij_typescript_call_parameters_wrap = off 181 | ij_typescript_catch_on_new_line = false 182 | ij_typescript_chained_call_dot_on_new_line = true 183 | ij_typescript_class_brace_style = end_of_line 184 | ij_typescript_comma_on_new_line = false 185 | ij_typescript_do_while_brace_force = never 186 | ij_typescript_else_on_new_line = false 187 | ij_typescript_enforce_trailing_comma = whenmultiline 188 | ij_typescript_enum_constants_wrap = on_every_item 189 | ij_typescript_extends_keyword_wrap = off 190 | ij_typescript_extends_list_wrap = off 191 | ij_typescript_field_prefix = _ 192 | ij_typescript_file_name_style = relaxed 193 | ij_typescript_finally_on_new_line = false 194 | ij_typescript_for_brace_force = never 195 | ij_typescript_for_statement_new_line_after_left_paren = false 196 | ij_typescript_for_statement_right_paren_on_new_line = false 197 | ij_typescript_for_statement_wrap = off 198 | ij_typescript_force_quote_style = true 199 | ij_typescript_force_semicolon_style = true 200 | ij_typescript_function_expression_brace_style = end_of_line 201 | ij_typescript_if_brace_force = never 202 | ij_typescript_import_merge_members = global 203 | ij_typescript_import_prefer_absolute_path = global 204 | ij_typescript_import_sort_members = true 205 | ij_typescript_import_sort_module_name = false 206 | ij_typescript_import_use_node_resolution = true 207 | ij_typescript_imports_wrap = on_every_item 208 | ij_typescript_indent_case_from_switch = true 209 | ij_typescript_indent_chained_calls = true 210 | ij_typescript_indent_package_children = 0 211 | ij_typescript_jsdoc_include_types = false 212 | ij_typescript_jsx_attribute_value = braces 213 | ij_typescript_keep_blank_lines_in_code = 2 214 | ij_typescript_keep_first_column_comment = true 215 | ij_typescript_keep_indents_on_empty_lines = false 216 | ij_typescript_keep_line_breaks = true 217 | ij_typescript_keep_simple_blocks_in_one_line = false 218 | ij_typescript_keep_simple_methods_in_one_line = false 219 | ij_typescript_line_comment_add_space = true 220 | ij_typescript_line_comment_at_first_column = false 221 | ij_typescript_method_brace_style = end_of_line 222 | ij_typescript_method_call_chain_wrap = off 223 | ij_typescript_method_parameters_new_line_after_left_paren = false 224 | ij_typescript_method_parameters_right_paren_on_new_line = false 225 | ij_typescript_method_parameters_wrap = off 226 | ij_typescript_object_literal_wrap = on_every_item 227 | ij_typescript_object_types_wrap = on_every_item 228 | ij_typescript_parentheses_expression_new_line_after_left_paren = false 229 | ij_typescript_parentheses_expression_right_paren_on_new_line = false 230 | ij_typescript_place_assignment_sign_on_next_line = false 231 | ij_typescript_prefer_as_type_cast = false 232 | ij_typescript_prefer_explicit_types_function_expression_returns = false 233 | ij_typescript_prefer_explicit_types_function_returns = false 234 | ij_typescript_prefer_explicit_types_vars_fields = false 235 | ij_typescript_prefer_parameters_wrap = false 236 | ij_typescript_property_prefix = 237 | ij_typescript_reformat_c_style_comments = false 238 | ij_typescript_space_after_colon = true 239 | ij_typescript_space_after_comma = true 240 | ij_typescript_space_after_dots_in_rest_parameter = false 241 | ij_typescript_space_after_generator_mult = true 242 | ij_typescript_space_after_property_colon = true 243 | ij_typescript_space_after_quest = true 244 | ij_typescript_space_after_type_colon = true 245 | ij_typescript_space_after_unary_not = false 246 | ij_typescript_space_before_async_arrow_lparen = true 247 | ij_typescript_space_before_catch_keyword = true 248 | ij_typescript_space_before_catch_left_brace = true 249 | ij_typescript_space_before_catch_parentheses = true 250 | ij_typescript_space_before_class_lbrace = true 251 | ij_typescript_space_before_class_left_brace = true 252 | ij_typescript_space_before_colon = true 253 | ij_typescript_space_before_comma = false 254 | ij_typescript_space_before_do_left_brace = true 255 | ij_typescript_space_before_else_keyword = true 256 | ij_typescript_space_before_else_left_brace = true 257 | ij_typescript_space_before_finally_keyword = true 258 | ij_typescript_space_before_finally_left_brace = true 259 | ij_typescript_space_before_for_left_brace = true 260 | ij_typescript_space_before_for_parentheses = true 261 | ij_typescript_space_before_for_semicolon = false 262 | ij_typescript_space_before_function_left_parenth = false 263 | ij_typescript_space_before_generator_mult = false 264 | ij_typescript_space_before_if_left_brace = true 265 | ij_typescript_space_before_if_parentheses = true 266 | ij_typescript_space_before_method_call_parentheses = false 267 | ij_typescript_space_before_method_left_brace = true 268 | ij_typescript_space_before_method_parentheses = false 269 | ij_typescript_space_before_property_colon = false 270 | ij_typescript_space_before_quest = true 271 | ij_typescript_space_before_switch_left_brace = true 272 | ij_typescript_space_before_switch_parentheses = true 273 | ij_typescript_space_before_try_left_brace = true 274 | ij_typescript_space_before_type_colon = false 275 | ij_typescript_space_before_unary_not = false 276 | ij_typescript_space_before_while_keyword = true 277 | ij_typescript_space_before_while_left_brace = true 278 | ij_typescript_space_before_while_parentheses = true 279 | ij_typescript_spaces_around_additive_operators = true 280 | ij_typescript_spaces_around_arrow_function_operator = true 281 | ij_typescript_spaces_around_assignment_operators = true 282 | ij_typescript_spaces_around_bitwise_operators = true 283 | ij_typescript_spaces_around_equality_operators = true 284 | ij_typescript_spaces_around_logical_operators = true 285 | ij_typescript_spaces_around_multiplicative_operators = true 286 | ij_typescript_spaces_around_relational_operators = true 287 | ij_typescript_spaces_around_shift_operators = true 288 | ij_typescript_spaces_around_unary_operator = false 289 | ij_typescript_spaces_within_array_initializer_brackets = false 290 | ij_typescript_spaces_within_brackets = false 291 | ij_typescript_spaces_within_catch_parentheses = false 292 | ij_typescript_spaces_within_for_parentheses = false 293 | ij_typescript_spaces_within_if_parentheses = false 294 | ij_typescript_spaces_within_imports = false 295 | ij_typescript_spaces_within_interpolation_expressions = false 296 | ij_typescript_spaces_within_method_call_parentheses = false 297 | ij_typescript_spaces_within_method_parentheses = false 298 | ij_typescript_spaces_within_object_literal_braces = false 299 | ij_typescript_spaces_within_object_type_braces = false 300 | ij_typescript_spaces_within_parentheses = false 301 | ij_typescript_spaces_within_switch_parentheses = false 302 | ij_typescript_spaces_within_type_assertion = false 303 | ij_typescript_spaces_within_union_types = true 304 | ij_typescript_spaces_within_while_parentheses = false 305 | ij_typescript_special_else_if_treatment = true 306 | ij_typescript_ternary_operation_signs_on_next_line = false 307 | ij_typescript_ternary_operation_wrap = off 308 | ij_typescript_union_types_wrap = on_every_item 309 | ij_typescript_use_chained_calls_group_indents = false 310 | ij_typescript_use_double_quotes = false 311 | ij_typescript_use_explicit_js_extension = auto 312 | ij_typescript_use_path_mapping = always 313 | ij_typescript_use_public_modifier = false 314 | ij_typescript_use_semicolon_after_statement = true 315 | ij_typescript_var_declaration_wrap = normal 316 | ij_typescript_while_brace_force = never 317 | ij_typescript_while_on_new_line = false 318 | ij_typescript_wrap_comments = false 319 | 320 | [{*.bash,*.sh,*.zsh}] 321 | indent_size = 2 322 | tab_width = 2 323 | ij_shell_binary_ops_start_line = false 324 | ij_shell_keep_column_alignment_padding = false 325 | ij_shell_minify_program = false 326 | ij_shell_redirect_followed_by_space = false 327 | ij_shell_switch_cases_indented = false 328 | ij_shell_use_unix_line_separator = true 329 | 330 | [{*.cjs,*.js,*.js }] 331 | indent_size = 4 332 | tab_width = 4 333 | ij_continuation_indent_size = 4 334 | ij_visual_guides = 80 335 | ij_javascript_align_imports = false 336 | ij_javascript_align_multiline_array_initializer_expression = false 337 | ij_javascript_align_multiline_binary_operation = false 338 | ij_javascript_align_multiline_chained_methods = false 339 | ij_javascript_align_multiline_extends_list = false 340 | ij_javascript_align_multiline_for = true 341 | ij_javascript_align_multiline_parameters = true 342 | ij_javascript_align_multiline_parameters_in_calls = false 343 | ij_javascript_align_multiline_ternary_operation = false 344 | ij_javascript_align_object_properties = 0 345 | ij_javascript_align_union_types = false 346 | ij_javascript_align_var_statements = 0 347 | ij_javascript_array_initializer_new_line_after_left_brace = false 348 | ij_javascript_array_initializer_right_brace_on_new_line = false 349 | ij_javascript_array_initializer_wrap = off 350 | ij_javascript_assignment_wrap = off 351 | ij_javascript_binary_operation_sign_on_next_line = false 352 | ij_javascript_binary_operation_wrap = off 353 | ij_javascript_blacklist_imports = rxjs/Rx,node_modules/**,**/node_modules/**,@angular/material,@angular/material/typings/** 354 | ij_javascript_blank_lines_after_imports = 1 355 | ij_javascript_blank_lines_around_class = 1 356 | ij_javascript_blank_lines_around_field = 0 357 | ij_javascript_blank_lines_around_function = 1 358 | ij_javascript_blank_lines_around_method = 1 359 | ij_javascript_block_brace_style = end_of_line 360 | ij_javascript_block_comment_add_space = false 361 | ij_javascript_block_comment_at_first_column = true 362 | ij_javascript_call_parameters_new_line_after_left_paren = false 363 | ij_javascript_call_parameters_right_paren_on_new_line = false 364 | ij_javascript_call_parameters_wrap = off 365 | ij_javascript_catch_on_new_line = false 366 | ij_javascript_chained_call_dot_on_new_line = true 367 | ij_javascript_class_brace_style = end_of_line 368 | ij_javascript_comma_on_new_line = false 369 | ij_javascript_do_while_brace_force = never 370 | ij_javascript_else_on_new_line = false 371 | ij_javascript_enforce_trailing_comma = whenmultiline 372 | ij_javascript_extends_keyword_wrap = off 373 | ij_javascript_extends_list_wrap = off 374 | ij_javascript_field_prefix = _ 375 | ij_javascript_file_name_style = relaxed 376 | ij_javascript_finally_on_new_line = false 377 | ij_javascript_for_brace_force = never 378 | ij_javascript_for_statement_new_line_after_left_paren = false 379 | ij_javascript_for_statement_right_paren_on_new_line = false 380 | ij_javascript_for_statement_wrap = off 381 | ij_javascript_force_quote_style = true 382 | ij_javascript_force_semicolon_style = true 383 | ij_javascript_function_expression_brace_style = end_of_line 384 | ij_javascript_if_brace_force = never 385 | ij_javascript_import_merge_members = global 386 | ij_javascript_import_prefer_absolute_path = true 387 | ij_javascript_import_sort_members = true 388 | ij_javascript_import_sort_module_name = false 389 | ij_javascript_import_use_node_resolution = true 390 | ij_javascript_imports_wrap = on_every_item 391 | ij_javascript_indent_case_from_switch = true 392 | ij_javascript_indent_chained_calls = true 393 | ij_javascript_indent_package_children = 0 394 | ij_javascript_jsx_attribute_value = braces 395 | ij_javascript_keep_blank_lines_in_code = 2 396 | ij_javascript_keep_first_column_comment = true 397 | ij_javascript_keep_indents_on_empty_lines = false 398 | ij_javascript_keep_line_breaks = true 399 | ij_javascript_keep_simple_blocks_in_one_line = false 400 | ij_javascript_keep_simple_methods_in_one_line = false 401 | ij_javascript_line_comment_add_space = true 402 | ij_javascript_line_comment_at_first_column = false 403 | ij_javascript_method_brace_style = end_of_line 404 | ij_javascript_method_call_chain_wrap = off 405 | ij_javascript_method_parameters_new_line_after_left_paren = false 406 | ij_javascript_method_parameters_right_paren_on_new_line = false 407 | ij_javascript_method_parameters_wrap = off 408 | ij_javascript_object_literal_wrap = on_every_item 409 | ij_javascript_object_types_wrap = on_every_item 410 | ij_javascript_parentheses_expression_new_line_after_left_paren = false 411 | ij_javascript_parentheses_expression_right_paren_on_new_line = false 412 | ij_javascript_place_assignment_sign_on_next_line = false 413 | ij_javascript_prefer_as_type_cast = false 414 | ij_javascript_prefer_explicit_types_function_expression_returns = false 415 | ij_javascript_prefer_explicit_types_function_returns = false 416 | ij_javascript_prefer_explicit_types_vars_fields = false 417 | ij_javascript_prefer_parameters_wrap = false 418 | ij_javascript_property_prefix = 419 | ij_javascript_reformat_c_style_comments = false 420 | ij_javascript_space_after_colon = true 421 | ij_javascript_space_after_comma = true 422 | ij_javascript_space_after_dots_in_rest_parameter = false 423 | ij_javascript_space_after_generator_mult = true 424 | ij_javascript_space_after_property_colon = true 425 | ij_javascript_space_after_quest = true 426 | ij_javascript_space_after_type_colon = true 427 | ij_javascript_space_after_unary_not = false 428 | ij_javascript_space_before_async_arrow_lparen = true 429 | ij_javascript_space_before_catch_keyword = true 430 | ij_javascript_space_before_catch_left_brace = true 431 | ij_javascript_space_before_catch_parentheses = true 432 | ij_javascript_space_before_class_lbrace = true 433 | ij_javascript_space_before_class_left_brace = true 434 | ij_javascript_space_before_colon = true 435 | ij_javascript_space_before_comma = false 436 | ij_javascript_space_before_do_left_brace = true 437 | ij_javascript_space_before_else_keyword = true 438 | ij_javascript_space_before_else_left_brace = true 439 | ij_javascript_space_before_finally_keyword = true 440 | ij_javascript_space_before_finally_left_brace = true 441 | ij_javascript_space_before_for_left_brace = true 442 | ij_javascript_space_before_for_parentheses = true 443 | ij_javascript_space_before_for_semicolon = false 444 | ij_javascript_space_before_function_left_parenth = false 445 | ij_javascript_space_before_generator_mult = false 446 | ij_javascript_space_before_if_left_brace = true 447 | ij_javascript_space_before_if_parentheses = true 448 | ij_javascript_space_before_method_call_parentheses = false 449 | ij_javascript_space_before_method_left_brace = true 450 | ij_javascript_space_before_method_parentheses = false 451 | ij_javascript_space_before_property_colon = false 452 | ij_javascript_space_before_quest = true 453 | ij_javascript_space_before_switch_left_brace = true 454 | ij_javascript_space_before_switch_parentheses = true 455 | ij_javascript_space_before_try_left_brace = true 456 | ij_javascript_space_before_type_colon = false 457 | ij_javascript_space_before_unary_not = false 458 | ij_javascript_space_before_while_keyword = true 459 | ij_javascript_space_before_while_left_brace = true 460 | ij_javascript_space_before_while_parentheses = true 461 | ij_javascript_spaces_around_additive_operators = true 462 | ij_javascript_spaces_around_arrow_function_operator = true 463 | ij_javascript_spaces_around_assignment_operators = true 464 | ij_javascript_spaces_around_bitwise_operators = true 465 | ij_javascript_spaces_around_equality_operators = true 466 | ij_javascript_spaces_around_logical_operators = true 467 | ij_javascript_spaces_around_multiplicative_operators = true 468 | ij_javascript_spaces_around_relational_operators = true 469 | ij_javascript_spaces_around_shift_operators = true 470 | ij_javascript_spaces_around_unary_operator = false 471 | ij_javascript_spaces_within_array_initializer_brackets = false 472 | ij_javascript_spaces_within_brackets = false 473 | ij_javascript_spaces_within_catch_parentheses = false 474 | ij_javascript_spaces_within_for_parentheses = false 475 | ij_javascript_spaces_within_if_parentheses = false 476 | ij_javascript_spaces_within_imports = false 477 | ij_javascript_spaces_within_interpolation_expressions = false 478 | ij_javascript_spaces_within_method_call_parentheses = false 479 | ij_javascript_spaces_within_method_parentheses = false 480 | ij_javascript_spaces_within_object_literal_braces = false 481 | ij_javascript_spaces_within_object_type_braces = false 482 | ij_javascript_spaces_within_parentheses = false 483 | ij_javascript_spaces_within_switch_parentheses = false 484 | ij_javascript_spaces_within_type_assertion = false 485 | ij_javascript_spaces_within_union_types = true 486 | ij_javascript_spaces_within_while_parentheses = false 487 | ij_javascript_special_else_if_treatment = true 488 | ij_javascript_ternary_operation_signs_on_next_line = false 489 | ij_javascript_ternary_operation_wrap = off 490 | ij_javascript_union_types_wrap = on_every_item 491 | ij_javascript_use_chained_calls_group_indents = false 492 | ij_javascript_use_double_quotes = false 493 | ij_javascript_use_explicit_js_extension = auto 494 | ij_javascript_use_path_mapping = always 495 | ij_javascript_use_public_modifier = false 496 | ij_javascript_use_semicolon_after_statement = true 497 | ij_javascript_var_declaration_wrap = normal 498 | ij_javascript_while_brace_force = never 499 | ij_javascript_while_on_new_line = false 500 | ij_javascript_wrap_comments = false 501 | 502 | [{*.har,*.jsb2,*.jsb3,*.json,.babelrc,.babelrc.dist,.eslintrc,.lintstagedrc,.mdx.eslintrc,.prettierrc,.stylelintrc,bowerrc,jest.config}] 503 | indent_size = 2 504 | ij_json_array_wrapping = split_into_lines 505 | ij_json_keep_blank_lines_in_code = 0 506 | ij_json_keep_indents_on_empty_lines = false 507 | ij_json_keep_line_breaks = true 508 | ij_json_keep_trailing_comma = false 509 | ij_json_object_wrapping = split_into_lines 510 | ij_json_property_alignment = do_not_align 511 | ij_json_space_after_colon = true 512 | ij_json_space_after_comma = true 513 | ij_json_space_before_colon = false 514 | ij_json_space_before_comma = false 515 | ij_json_spaces_within_braces = false 516 | ij_json_spaces_within_brackets = false 517 | ij_json_wrap_long_lines = false 518 | 519 | [{*.htm,*.html,*.ng,*.sht,*.shtm,*.shtml}] 520 | indent_size = 2 521 | tab_width = 2 522 | ij_continuation_indent_size = 2 523 | ij_visual_guides = 80 524 | ij_html_add_new_line_before_tags = body,div,p,form,h1,h2,h3 525 | ij_html_align_attributes = true 526 | ij_html_align_text = false 527 | ij_html_attribute_wrap = normal 528 | ij_html_block_comment_add_space = false 529 | ij_html_block_comment_at_first_column = true 530 | ij_html_do_not_align_children_of_min_lines = 0 531 | ij_html_do_not_break_if_inline_tags = title,h1,h2,h3,h4,h5,h6,p 532 | ij_html_do_not_indent_children_of_tags = html,body,thead,tbody,tfoot 533 | ij_html_enforce_quotes = true 534 | ij_html_inline_tags = a,abbr,acronym,b,basefont,bdo,big,br,cite,cite,code,dfn,em,font,i,img,input,kbd,label,q,s,samp,select,small,span,strike,strong,sub,sup,textarea,tt,u,var 535 | ij_html_keep_blank_lines = 2 536 | ij_html_keep_indents_on_empty_lines = false 537 | ij_html_keep_line_breaks = true 538 | ij_html_keep_line_breaks_in_text = true 539 | ij_html_keep_whitespaces = false 540 | ij_html_keep_whitespaces_inside = span,pre,textarea 541 | ij_html_line_comment_at_first_column = true 542 | ij_html_new_line_after_last_attribute = never 543 | ij_html_new_line_before_first_attribute = never 544 | ij_html_quote_style = single 545 | ij_html_remove_new_line_before_tags = br 546 | ij_html_space_after_tag_name = false 547 | ij_html_space_around_equality_in_attribute = false 548 | ij_html_space_inside_empty_tag = true 549 | ij_html_text_wrap = normal 550 | 551 | [{*.http,*.rest}] 552 | indent_size = 0 553 | ij_continuation_indent_size = 4 554 | ij_http-request_call_parameters_wrap = normal 555 | ij_http-request_method_parameters_wrap = split_into_lines 556 | ij_http-request_space_before_comma = true 557 | ij_http-request_spaces_around_assignment_operators = true 558 | 559 | [{*.markdown,*.md}] 560 | ij_markdown_force_one_space_after_blockquote_symbol = true 561 | ij_markdown_force_one_space_after_header_symbol = true 562 | ij_markdown_force_one_space_after_list_bullet = true 563 | ij_markdown_force_one_space_between_words = true 564 | ij_markdown_format_tables = true 565 | ij_markdown_insert_quote_arrows_on_wrap = true 566 | ij_markdown_keep_indents_on_empty_lines = false 567 | ij_markdown_keep_line_breaks_inside_text_blocks = true 568 | ij_markdown_max_lines_around_block_elements = 1 569 | ij_markdown_max_lines_around_header = 1 570 | ij_markdown_max_lines_between_paragraphs = 1 571 | ij_markdown_min_lines_around_block_elements = 1 572 | ij_markdown_min_lines_around_header = 1 573 | ij_markdown_min_lines_between_paragraphs = 1 574 | ij_markdown_wrap_text_if_long = true 575 | ij_markdown_wrap_text_inside_blockquotes = true 576 | 577 | [{*.yaml,*.yml}] 578 | indent_size = 2 579 | ij_yaml_align_values_properties = do_not_align 580 | ij_yaml_autoinsert_sequence_marker = true 581 | ij_yaml_block_mapping_on_new_line = false 582 | ij_yaml_indent_sequence_value = true 583 | ij_yaml_keep_indents_on_empty_lines = false 584 | ij_yaml_keep_line_breaks = true 585 | ij_yaml_sequence_on_new_line = false 586 | ij_yaml_space_before_colon = false 587 | ij_yaml_spaces_within_braces = true 588 | ij_yaml_spaces_within_brackets = true 589 | --------------------------------------------------------------------------------