├── .babelrc
├── .browserslistrc
├── .editorconfig
├── .eslintignore
├── .eslintrc.cjs
├── .github
└── workflows
│ ├── ci.yaml
│ ├── deploy.yaml
│ └── release.yml
├── .gitignore
├── .husky
├── commit-msg
└── pre-commit
├── .storybook
├── main.ts
├── preview-body.html
└── preview.ts
├── .stylelintignore
├── .stylelintrc.cjs
├── .vscode
├── extensions.json
└── settings.json
├── LICENSE
├── README.md
├── __tests__
├── __snapshots__
│ └── dom.test.tsx.snap
├── dom.test.tsx
├── js.spec.tsx
└── mockfn.spec.ts
├── app.d.ts
├── commitlint.config.cjs
├── docs
├── .gitignore
├── README.md
├── babel.config.js
├── docs
│ ├── get-started
│ │ ├── _category_.json
│ │ ├── installation.md
│ │ └── markdown-features.mdx
│ └── intro.md
├── docusaurus.config.js
├── package.json
├── sidebars.js
├── src
│ ├── components
│ │ └── HomepageFeatures
│ │ │ ├── index.tsx
│ │ │ └── styles.module.css
│ ├── css
│ │ └── custom.css
│ └── pages
│ │ ├── index.module.css
│ │ ├── index.tsx
│ │ └── markdown-page.md
├── static
│ ├── .nojekyll
│ └── img
│ │ ├── docusaurus.png
│ │ ├── favicon.ico
│ │ ├── logo.svg
│ │ ├── undraw_docusaurus_mountain.svg
│ │ ├── undraw_docusaurus_react.svg
│ │ └── undraw_docusaurus_tree.svg
└── tsconfig.json
├── package.json
├── playground
├── index.html
├── package.json
├── public
│ └── favicon.ico
├── src
│ ├── main.tsx
│ ├── pages
│ │ └── home
│ │ │ └── Home.tsx
│ └── routers.tsx
├── tsconfig.json
├── vite-env.d.ts
└── vite.config.ts
├── postcss.config.cjs
├── setupTests.ts
├── src
├── components
│ ├── Demo.tsx
│ └── index.ts
├── index.ts
├── presets
│ └── index.ts
├── stories
│ ├── Button.stories.ts
│ ├── Button.tsx
│ ├── Configure.mdx
│ ├── Header.stories.ts
│ ├── Header.tsx
│ ├── Page.stories.ts
│ ├── Page.tsx
│ ├── Pkg.stories.tsx
│ ├── assets
│ │ ├── accessibility.png
│ │ ├── accessibility.svg
│ │ ├── addon-library.png
│ │ ├── assets.png
│ │ ├── context.png
│ │ ├── discord.svg
│ │ ├── docs.png
│ │ ├── figma-plugin.png
│ │ ├── github.svg
│ │ ├── share.png
│ │ ├── styling.png
│ │ ├── testing.png
│ │ ├── theming.png
│ │ ├── tutorials.svg
│ │ └── youtube.svg
│ ├── button.less
│ ├── header.scss
│ └── page.css
├── styles
│ └── main.scss
└── types.ts
├── tsconfig.json
├── tsup.config.ts
└── vite.config.ts
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | [
4 | "@babel/preset-env",
5 | {
6 | "useBuiltIns": "usage",
7 | "modules": false, // preserve ES modules.
8 | "corejs": { "version": 3, "proposals": true }
9 | }
10 | ],
11 | "@babel/preset-typescript"
12 | ],
13 | "plugins": [
14 | "@babel/plugin-transform-runtime",
15 | // https://babel.dev/docs/en/babel-plugin-transform-react-jsx
16 | [
17 | "@babel/plugin-transform-react-jsx",
18 | {
19 | // "runtime": "automatic"
20 | }
21 | ]
22 | ],
23 | "exclude": ["core-js"]
24 | }
25 |
--------------------------------------------------------------------------------
/.browserslistrc:
--------------------------------------------------------------------------------
1 | >1%
2 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | dist/*
2 | build/*
3 | node_modules/*
4 | src/assets
5 | src/**/*.css
6 | src/stories
7 | .eslintrc.cjs
8 | .stylelintrc.cjs
9 | babel.config.cjs
10 | setupTests.ts
11 | vite.config.ts
12 | postcss.config.cjs
13 | commitlint.config.cjs
14 | tsconfig.json
15 | **/*.css
16 | **/*.scss
17 | **/*.less
18 | **/*.module.css
19 | **/*.module.scss
20 | **/*.module.less
21 | __unconfig_vite.config.ts
22 |
--------------------------------------------------------------------------------
/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | /**
2 | * https://www.npmjs.com/package/eslint-config-airbnb-typescript
3 | */
4 | module.exports = {
5 | extends: [
6 | 'airbnb-base',
7 | 'airbnb-typescript',
8 | 'plugin:react-hooks/recommended',
9 | 'plugin:@typescript-eslint/recommended',
10 | 'plugin:@typescript-eslint/recommended-requiring-type-checking',
11 | 'plugin:jsx-a11y/strict',
12 | 'plugin:react/recommended',
13 | 'plugin:react/jsx-runtime',
14 | 'plugin:storybook/recommended',
15 | ],
16 | env: {
17 | es6: true,
18 | browser: true,
19 | },
20 | plugins: [
21 | '@typescript-eslint',
22 | ],
23 | parserOptions: {
24 | project: './tsconfig.json',
25 | ecmaFeatures: {
26 | jsx: true,
27 | tsx: true,
28 | },
29 | ecmaVersion: 2020,
30 | useJSXTextNode: true,
31 | sourceType: 'module',
32 | },
33 | settings: {
34 | react: {
35 | createClass: 'createReactClass',
36 | pragma: 'React',
37 | fragment: 'Fragment',
38 | version: 'detect',
39 | flowVersion: '0.53',
40 | },
41 | },
42 | rules: {
43 | // react-hooks -> https://reactjs.org/docs/hooks-rules.html
44 | 'react-hooks/rules-of-hooks': 'error',
45 | 'react-hooks/exhaustive-deps': 'off',
46 | // 代码风格
47 | 'import/prefer-default-export': 'off',
48 | 'default-param-last': 'off',
49 | 'no-else-return': 'off',
50 | 'import/extensions': 'off',
51 | 'import/order': 'off',
52 | 'import/no-cycle': 'off',
53 | 'import/no-extraneous-dependencies': 'off',
54 | 'import/no-named-as-default-member': 'off',
55 | 'linebreak-style': 'off',
56 | 'no-console': 'off',
57 | 'class-methods-use-this': 'off',
58 | 'max-classes-per-file': 'off',
59 | 'consistent-return': 'off',
60 | 'default-case': 'off',
61 | 'global-require': 'off',
62 | 'import/no-dynamic-require': 'off',
63 | 'generator-star-spacing': 'off',
64 | 'max-len': ['error', {
65 | 'code': 130
66 | }],
67 | // typescript
68 | '@typescript-eslint/no-this-alias': 'off',
69 | '@typescript-eslint/no-unsafe-argument': 'off',
70 | '@typescript-eslint/no-var-requires': 'off',
71 | '@typescript-eslint/no-inferrable-types': 'off',
72 | '@typescript-eslint/naming-convention': 'off',
73 | '@typescript-eslint/no-unnecessary-type-assertion': 'off',
74 | '@typescript-eslint/no-unused-vars': 'off',
75 | '@typescript-eslint/no-useless-constructor': 'off',
76 | '@typescript-eslint/no-use-before-define': 'off',
77 | '@typescript-eslint/no-unsafe-assignment': 'off',
78 | '@typescript-eslint/no-unsafe-member-access': 'off',
79 | '@typescript-eslint/no-unsafe-call': 'off',
80 | '@typescript-eslint/no-unsafe-return': 'off',
81 | '@typescript-eslint/restrict-template-expressions': 'off',
82 | '@typescript-eslint/await-thenable': 'off',
83 | '@typescript-eslint/unbound-method': 'off',
84 | '@typescript-eslint/restrict-plus-operands': 'off',
85 | '@typescript-eslint/no-floating-promises': 'off',
86 | '@typescript-eslint/explicit-module-boundary-types': 'off',
87 | '@typescript-eslint/no-explicit-any': 'off',
88 | '@typescript-eslint/ban-types': 'off',
89 | '@typescript-eslint/ban-ts-comment': 'off',
90 | '@typescript-eslint/no-namespace': 'off',
91 | '@typescript-eslint/no-misused-promises': 'off',
92 | '@typescript-eslint/prefer-regexp-exec': 'off',
93 | // javascript
94 | 'prefer-promise-reject-errors': 'off',
95 | 'func-names': 'off',
96 | 'no-bitwise': 'off',
97 | 'no-plusplus': 'off',
98 | 'prefer-template': 'off',
99 | 'object-curly-newline': 'off',
100 | 'no-param-reassign': 'off',
101 | 'no-restricted-globals': 'off',
102 | 'no-underscore-dangle': 'off',
103 | 'no-restricted-syntax': 'off',
104 | 'no-useless-escape': 'off',
105 | 'no-confusing-arrow': 'off',
106 | 'no-new': 'off',
107 | 'no-void': 'off',
108 | 'prefer-rest-params': 'off',
109 | 'no-async-promise-executor': 'off',
110 | 'no-case-declarations': 'off',
111 | // jsx
112 | 'jsx-a11y/aria-role': 'off',
113 | 'jsx-a11y/anchor-is-valid': 'off',
114 | 'jsx-a11y/label-has-associated-control': 'off',
115 | 'jsx-a11y/click-events-have-key-events': 'off',
116 | 'jsx-a11y/no-static-element-interactions': 'off',
117 | 'jsx-a11y/no-noninteractive-element-interactions': 'off',
118 | 'jsx-a11y/alt-text': 'off',
119 | // react
120 | 'jsx-quotes': [2, 'prefer-double'],
121 | 'react/jsx-indent': [2, 2],
122 | 'react/jsx-indent-props': [2, 2],
123 | 'react/jsx-curly-newline': [2, {
124 | multiline: 'consistent'
125 | }],
126 | 'react/jsx-max-props-per-line': [2, {
127 | maximum: 3
128 | }],
129 | 'react/jsx-fragments': [2, 'syntax'],
130 | 'react/jsx-equals-spacing': [2, 'never'],
131 | 'react/destructuring-assignment': [2, 'always'],
132 | 'react/jsx-tag-spacing': [2, {
133 | closingSlash: 'never',
134 | beforeSelfClosing: 'always',
135 | afterOpening: 'never',
136 | beforeClosing: 'allow'
137 | }],
138 | 'react/jsx-closing-bracket-location': [2, 'line-aligned'],
139 | 'react/jsx-boolean-value': [2, 'never'],
140 | 'react/self-closing-comp': [2, {
141 | component: true,
142 | html: true
143 | }],
144 | 'react/jsx-first-prop-new-line': [2, 'multiline-multiprop'],
145 | 'react/jsx-sort-props': [2, {
146 | callbacksLast: true
147 | }],
148 | 'react/jsx-wrap-multilines': [2, {
149 | declaration: 'parens-new-line',
150 | assignment: 'parens-new-line',
151 | return: 'parens-new-line',
152 | condition: 'parens-new-line',
153 | logical: 'parens-new-line',
154 | arrow: 'parens-new-line',
155 | prop: 'parens-new-line'
156 | }],
157 | 'react/jsx-one-expression-per-line': 2,
158 | 'react/jsx-filename-extension': 'off',
159 | 'react/jsx-props-no-spreading': 'off',
160 | 'react/jsx-uses-react': 'off',
161 | 'react/react-in-jsx-scope': 'off',
162 | 'react/display-name': 'off',
163 | 'arrow-parens': 'off',
164 | 'react/sort-comp': 'off',
165 | 'react/no-deprecated': 'off',
166 | 'react/button-has-type': 'off',
167 | 'react/prop-types': 'off',
168 | 'arrow-body-style': 'off',
169 | 'react/require-default-props': 'off',
170 | 'react/no-array-index-key': 'off',
171 | 'react/static-property-placement': 'off',
172 | 'react/prefer-stateless-function': 'off',
173 | 'react/state-in-constructor': 'off',
174 | 'no-nested-ternary': 'off',
175 | 'react/no-danger': 'off'
176 | }
177 | };
178 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yaml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | # push:
5 | # branches:
6 | # - main
7 |
8 | # https://frontside.com/blog/2020-05-26-github-actions-pull_request
9 | pull_request:
10 | types: [ opened, edited, synchronize, reopened ]
11 | branches:
12 | - main
13 |
14 | jobs:
15 | lint:
16 | runs-on: ubuntu-latest
17 | steps:
18 | - uses: actions/checkout@v3
19 | - name: Setup Node 18.x
20 | uses: actions/setup-node@v3
21 | with:
22 | node-version: 18.x
23 | registry-url: https://registry.npmjs.org/
24 |
25 | - name: Install
26 | run: npm i
27 |
28 | - name: Lint
29 | run: npm run lint
30 |
31 | stylelint:
32 | runs-on: ubuntu-latest
33 | steps:
34 | - uses: actions/checkout@v3
35 | - name: Setup Node 18.x
36 | uses: actions/setup-node@v3
37 | with:
38 | node-version: 18.x
39 | registry-url: https://registry.npmjs.org/
40 |
41 | - name: Install
42 | run: npm i
43 |
44 | - name: Stylelint
45 | run: npm run stylelint
46 |
47 | typecheck:
48 | runs-on: ubuntu-latest
49 | steps:
50 | - uses: actions/checkout@v3
51 | - name: Setup Node 18.x
52 | uses: actions/setup-node@v3
53 | with:
54 | node-version: 18.x
55 | registry-url: https://registry.npmjs.org/
56 |
57 | - name: Install
58 | run: npm i
59 |
60 | - name: Typecheck
61 | run: npm run typecheck
62 |
63 | test:
64 | runs-on: ubuntu-latest
65 | steps:
66 | - uses: actions/checkout@v3
67 | - name: Setup Node 18.x
68 | uses: actions/setup-node@v3
69 | with:
70 | node-version: 18.x
71 | registry-url: https://registry.npmjs.org/
72 |
73 | - name: Install
74 | run: npm i
75 |
76 | - name: Unit Test
77 | run: npm run test
78 |
--------------------------------------------------------------------------------
/.github/workflows/deploy.yaml:
--------------------------------------------------------------------------------
1 | name: 'Deploy(main)'
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 |
8 | pull_request:
9 | types: [ opened, edited, synchronize, reopened ]
10 | branches:
11 | - main
12 |
13 | jobs:
14 | check:
15 | runs-on: ubuntu-latest
16 | steps:
17 | - uses: actions/checkout@v3
18 | - uses: actions/setup-node@v3
19 | with:
20 | node-version: 18
21 |
22 | - run: npm i
23 | - run: npm test
24 | - run: npm run lint
25 | - run: npm run stylelint
26 | - run: npm run typecheck
27 |
28 | deploy:
29 | needs: check
30 | name: 'Deploy storybook'
31 | runs-on: ubuntu-latest
32 | steps:
33 | - uses: actions/checkout@v3
34 |
35 | # https://github.com/marketplace/actions/vercel-action
36 | - name: deploy to vercel
37 | uses: amondnet/vercel-action@v25
38 | with:
39 | github-token: ${{ secrets.GITHUB_TOKEN }}
40 | vercel-args: '--prod'
41 | vercel-token: ${{ secrets.VERCEL_TOKEN }}
42 | vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
43 | vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
44 |
45 | # https://github.com/marketplace/actions/netlify-deploy
46 | # - name: deploy to netlify
47 | # uses: jsmrcaga/action-netlify-deploy@v1.8.0
48 | # with:
49 | # NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_TOKEN }}
50 | # NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
51 | # NETLIFY_DEPLOY_TO_PROD: true
52 | # use_nvm: false
53 | # build_command: 'npm run build:docs'
54 | # build_directory: 'docs/build'
55 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release (main)
2 |
3 | on:
4 | push:
5 | # Sequence of patterns matched against refs/tags
6 | tags:
7 | - "v*" # push events to matching v*, i.e. v1.0, v20.15.10
8 |
9 | jobs:
10 | check:
11 | runs-on: ubuntu-latest
12 | steps:
13 | - uses: actions/checkout@v3
14 | - uses: actions/setup-node@v3
15 | with:
16 | node-version: 18
17 |
18 | - run: npm i
19 | - run: npm test
20 | - run: npm run lint
21 | - run: npm run stylelint
22 | - run: npm run typecheck
23 |
24 | publish-npm:
25 | needs: check
26 | runs-on: ubuntu-latest
27 | steps:
28 | - uses: actions/checkout@v3
29 | - uses: actions/setup-node@v3
30 | with:
31 | node-version: 18
32 |
33 | - name: Install
34 | run: npm i
35 |
36 | - name: Set registry
37 | run: |
38 | npm config set //registry.npmjs.org/:_authToken=$NODE_AUTH_TOKEN
39 | npm publish
40 | env:
41 | NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
42 |
43 | create-release:
44 | needs: publish-npm
45 | runs-on: ubuntu-latest
46 | steps:
47 | - uses: actions/checkout@v3
48 | with:
49 | fetch-depth: 0
50 |
51 | - uses: actions/setup-node@v3
52 | with:
53 | node-version: 18
54 | registry-url: https://registry.npmjs.org/
55 |
56 | - run: npx changelogithub
57 | env:
58 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
59 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .vite-ssg-dist
3 | .vite-ssg-temp
4 | *.local
5 | dist
6 | dist-ssr
7 | build
8 | node_modules
9 | .idea/
10 | *.log
11 | /coverage
12 | package-lock.json
13 | pnpm-lock.yaml
14 | yarn.lock
15 |
16 | src/index.css
17 | playground/dist
18 | storybook-static
19 |
20 | __unconfig_vite.config.ts
21 | .vercel
22 |
--------------------------------------------------------------------------------
/.husky/commit-msg:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # shellcheck source=./_/husky.sh
4 | . "$(dirname "$0")/_/husky.sh"
5 |
6 | npx --no-install commitlint --edit "$1"
7 |
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | npm run lint
2 | npm run stylelint
3 | npm run typecheck
4 |
--------------------------------------------------------------------------------
/.storybook/main.ts:
--------------------------------------------------------------------------------
1 | import type { StorybookConfig } from '@storybook/react-vite';
2 |
3 | import { join, dirname } from 'path';
4 |
5 | /**
6 | * This function is used to resolve the absolute path of a package.
7 | * It is needed in projects that use Yarn PnP or are set up within a monorepo.
8 | */
9 | function getAbsolutePath(value: string): any {
10 | return dirname(require.resolve(join(value, 'package.json')));
11 | }
12 | const config: StorybookConfig = {
13 | stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
14 | addons: [
15 | getAbsolutePath('@storybook/addon-links'),
16 | getAbsolutePath('@storybook/addon-actions'),
17 | getAbsolutePath('@storybook/addon-essentials'),
18 | getAbsolutePath('@storybook/addon-interactions'),
19 | getAbsolutePath('@storybook/addon-onboarding'),
20 | ],
21 | framework: {
22 | name: getAbsolutePath('@storybook/react-vite'),
23 | options: {},
24 | },
25 | docs: {
26 | autodocs: 'tag',
27 | },
28 | };
29 |
30 | export default config;
31 |
--------------------------------------------------------------------------------
/.storybook/preview-body.html:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/.storybook/preview.ts:
--------------------------------------------------------------------------------
1 | import type { Preview } from '@storybook/react';
2 | import '../src/styles/main.scss';
3 |
4 | const preview: Preview = {
5 | parameters: {
6 | actions: { argTypesRegex: '^on[A-Z].*' },
7 | controls: {
8 | matchers: {
9 | color: /(background|color)$/i,
10 | date: /Date$/,
11 | },
12 | },
13 | },
14 | };
15 |
16 | export default preview;
17 |
--------------------------------------------------------------------------------
/.stylelintignore:
--------------------------------------------------------------------------------
1 | dist
2 | src/index.css
3 |
--------------------------------------------------------------------------------
/.stylelintrc.cjs:
--------------------------------------------------------------------------------
1 | // https://stylelint.io/user-guide/get-started
2 | // 执行npx stylelint src/**/*.css 进行校验
3 |
4 | module.exports = {
5 | extends: [
6 | 'stylelint-config-standard',
7 | ],
8 | rules: {
9 | 'annotation-no-unknown': null,
10 | 'at-rule-no-unknown': null,
11 | 'keyframe-selector-notation': null,
12 | 'keyframe-block-no-duplicate-selectors': null,
13 | 'property-no-vendor-prefix': null,
14 | 'declaration-colon-newline-after': null,
15 | 'value-list-comma-newline-after': null,
16 | 'custom-property-pattern': null,
17 | 'color-hex-length': 'short',
18 | 'color-function-notation': null,
19 | 'alpha-value-notation': null,
20 | 'value-no-vendor-prefix': null,
21 | 'selector-class-pattern': null,
22 | 'function-url-quotes': null,
23 | 'no-descending-specificity': null,
24 | 'font-family-no-missing-generic-family-keyword': null,
25 | },
26 | overrides: [
27 | // 若项目中存在scss文件,添加以下配置
28 | {
29 | files: '**/*.scss',
30 | customSyntax: 'postcss-scss',
31 | },
32 | ],
33 | };
34 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "dbaeumer.vscode-eslint",
4 | "stylelint.vscode-stylelint"
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "editor.formatOnSave": false,
3 | "editor.formatOnPaste": false,
4 | "editor.tabSize": 2,
5 | "editor.insertSpaces": true,
6 | "editor.codeActionsOnSave": {
7 | "source.fixAll.eslint": "explicit",
8 | "source.fixAll.stylelint": "explicit"
9 | },
10 | "eslint.options": {
11 | "overrideConfigFile": "./.eslintrc.cjs"
12 | },
13 | "eslint.validate": [
14 | "javascript",
15 | "javascriptreact",
16 | "typescript",
17 | "typescriptreact"
18 | ],
19 | "stylelint.validate": [
20 | "css",
21 | "scss",
22 | "less",
23 | "postcss"
24 | ],
25 | "[html]": {
26 | "editor.defaultFormatter": "vscode.html-language-features"
27 | },
28 | "[json]": {
29 | "editor.defaultFormatter": "vscode.json-language-features"
30 | },
31 | "[jsonc]": {
32 | "editor.defaultFormatter": "vscode.json-language-features"
33 | },
34 | "[javascript]": {
35 | "editor.defaultFormatter": "vscode.typescript-language-features"
36 | },
37 | "[typescriptreact]": {
38 | "editor.defaultFormatter": "vscode.typescript-language-features"
39 | },
40 | "[typescript]": {
41 | "editor.defaultFormatter": "vscode.typescript-language-features"
42 | },
43 | "tslint.suppressWhileTypeErrorsPresent": true,
44 | "typescript.format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": true,
45 | "typescript.format.semicolons": "insert",
46 | "typescript.updateImportsOnFileMove.enabled": "always",
47 | "typescript.tsdk": "./node_modules/typescript/lib",
48 | "files.eol": "\n",
49 | }
50 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 jerrywu001
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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # README
2 |
3 | ## Features
4 |
5 | - 💻 React suport >=16.8.0
6 | - ✈️ Project init with [vite](https://vitejs.dev/)
7 | - 📦 Support cjs & esm
8 |
9 | ---
10 |
11 | - 🪖 [Github Actions](https://docs.github.com/cn/actions) support (Auto CI on pull_request / Auto Release on push tag / Auto Deploy on push & pull_request)
12 | - 🍕 Build npm package with [tsup](https://tsup.egoist.dev/)
13 | - Build-in Docusaurus
14 |
15 | > ```npm run docs```
16 |
17 | - 🍭 Built-in react dev environment
18 |
19 | > [playground](./playground/vite.config.ts) folder
20 | >
21 | > start --> ```npm run dev```
22 |
23 | - 🍔 Use [browserslistrc](./.browserslistrc)
24 | - 🪗 Build styles with sass &&[postcss](./postcss.config.js) ([postcss-nested](https://www.npmjs.com/package/postcss-nested)/ [autoprefixer](https://www.npmjs.com/package/autoprefixer) / [cssnano](https://cssnano.co/docs/getting-started/))
25 | - 🌭 [Stylelint](https://stylelint.io/) that helps you avoid errors and enforce conventions in your styles.
26 | - 🍟 [Mono repo with npm](https://dev.to/ynwd/how-to-create-react-monorepo-with-npm-workspace-webpack-and-create-react-app-2dhn)
27 | - 🎉 [TypeScript](https://www.typescriptlang.org/), of course
28 | - 🎄 Unit Testing with [Vitest](https://vitest.dev/)
29 | - 🏑 [Storybook](https://storybook.js.org/) for building UI components and pages
30 | - 🧆 [ESLint](https://eslint.org/) statically analyzes your code to quickly find problems.
31 | - ⚒ [Husky](https://typicode.github.io/husky) & [lint-staged](https://github.com/okonet/lint-staged#readme)
32 | - ☕ [Commitlint](https://commitlint.js.org) that helps your team adhering to a commit convention
33 | - 🛸 Deploy Storybook on [Netlify](https://www.netlify.com/) ---> [config](./.github/workflows/deploy.yaml)
34 | - 🥳 [MIT License](https://mit-license.org/)
35 |
36 | ## how to use
37 |
38 | replace ```custom-package-name``` with your package name
39 |
40 |
41 | ## Directory structure
42 |
43 | ```js
44 | Project
45 | ├── __tests__ # Unit Testing
46 | ├── babel.config.js # babel config
47 | ├── package.json
48 | ├── playground # dev environment folder (can use source code)
49 | │ ├── index.html
50 | │ ├── package.json
51 | │ ├── public
52 | │ ├── src
53 | │ ├── tsconfig.json
54 | │ ├── vite-env.d.ts
55 | │ └── vite.config.ts
56 | ├── postcss.config.js # build styles with postcss
57 | ├── src # Package source code
58 | │ ├── index.ts # Package source entry
59 | │ ├── stories # storybook for building UI components and pages
60 | │ ├── styles # styles for Package
61 | │ └── types.ts # ts type declaration for Package
62 | ├── tsconfig.json # ts config
63 | └── tsup.config.ts # build package with tsup
64 | ```
65 |
66 | ## How to add GITHUB_TOKEN
67 |
68 | - [add GITHUB_TOKEN](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token)
69 |
70 | ## How to add NPM_TOKEN
71 |
72 | 0. update project setting
73 |
74 | settings -> actions -> General
75 |
76 | 
77 |
78 | 1. [create npm auth token](https://docs.npmjs.com/creating-and-viewing-access-tokens)
79 | 2. then copy npm token, add to github project settings
80 |
81 | - project -> settings -> secrets -> actions -> create new token with name:NPM_TOKEN
82 |
83 | ## How to add NETLIFY_TOKEN
84 |
85 | 1. [create netlify auth token](https://app.netlify.com/user/applications#personal-access-tokens)
86 | 2. then copy netlify token, add to github project settings
87 |
88 | - project -> settings -> secrets -> actions -> create new token with name:NETLIFY_TOKEN
89 |
90 | 3. create a site on netlify
91 |
92 | 4. copy the site_id from your netlify site settings, add it to github project settings
93 |
94 | - project -> settings -> secrets -> actions -> create new token with name:NETLIFY_SITE_ID
95 |
96 | 5. Stop Build from Build settings of site
97 |
98 | 6. [build-command-javascript-heap-out-of-memory](https://answers.netlify.com/t/build-command-javascript-heap-out-of-memory/85348/6)
99 |
100 | ## How to generate VERCEL_ORG_ID / VERCEL_PROJECT_ID
101 |
102 | 1. run ```npx vercel``` in project root folder
103 | 2. open .vercel/project.json
104 | 3. copy orgId & projectId, add it to github project settings
105 |
106 | - project -> settings -> secrets -> actions -> create new token with name:VERCEL_ORG_ID & VERCEL_PROJECT_ID
107 |
108 | 4. [create vercel token](https://vercel.com/account/tokens), add it to github project settings
109 |
110 | - project -> settings -> secrets -> actions -> create new token with name:VERCEL_TOKEN
111 |
112 | 5. change project build setting
113 |
114 | 
115 |
116 | ## Sponsor
117 |
118 |
119 |
Special Sponsor
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
--------------------------------------------------------------------------------
/__tests__/__snapshots__/dom.test.tsx.snap:
--------------------------------------------------------------------------------
1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2 |
3 | exports[`dom test > testing-library/jest-dom 1`] = `
4 |
7 | `;
8 |
--------------------------------------------------------------------------------
/__tests__/dom.test.tsx:
--------------------------------------------------------------------------------
1 | import '@testing-library/jest-dom';
2 | import { describe, test, expect } from 'vitest';
3 |
4 | describe('dom test', () => {
5 | test.concurrent('testing-library/jest-dom', async () => {
6 | const div = document.createElement('div');
7 | div.id = 'adm-mask';
8 | expect(div).not.toBeNull();
9 | expect(div).toBeDefined();
10 | expect(div).toBeInstanceOf(HTMLDivElement);
11 |
12 | await document.body.appendChild(div);
13 |
14 | const mask = document.body.querySelector('#adm-mask') as HTMLElement;
15 | expect(mask).toMatchSnapshot();
16 | div.remove();
17 | expect(mask).not.toBeInTheDocument();
18 | });
19 | });
20 |
--------------------------------------------------------------------------------
/__tests__/js.spec.tsx:
--------------------------------------------------------------------------------
1 | import { test, expect } from 'vitest';
2 |
3 | test.concurrent('handles js', () => {
4 | expect(1 + 1).toBe(2);
5 | });
6 |
--------------------------------------------------------------------------------
/__tests__/mockfn.spec.ts:
--------------------------------------------------------------------------------
1 | import { vi, describe, test, expect } from 'vitest';
2 |
3 | function timer(callback) {
4 | setTimeout(() => {
5 | callback();
6 | }, 5000);
7 | }
8 |
9 | describe('mock function test', () => {
10 | test('toHaveReturnedWith', async () => {
11 | const init = { test: 'hello' };
12 | const mockFn = vi.fn().mockImplementation(() => init);
13 | // const mockFn = vi.fn(() => init);
14 |
15 | await mockFn();
16 |
17 | expect(mockFn).toBeCalledTimes(1);
18 | expect(mockFn).toHaveReturnedWith(init);
19 | expect(mockFn.mock.results[0].value).toStrictEqual(init);
20 | });
21 |
22 | test('promise resolve', async () => { // 不要使用toHaveReturnedWith
23 | // const mockFn = vi.fn().mockImplementation(apples => Promise.resolve(apples + 1));
24 | const mockFn = vi.fn(apples => Promise.resolve(apples + 1));
25 | expect(mockFn).not.toBeCalled();
26 | expect(mockFn).toBeCalledTimes(0);
27 | expect(mockFn.mock.calls.length).toBe(0);
28 |
29 | const val = await mockFn(2);
30 |
31 | expect(mockFn).toBeCalledTimes(1);
32 | expect(val).toBe(3);
33 | expect(mockFn.mock.results[0].value).toEqual(3);
34 | });
35 |
36 | test('timers', () => {
37 | vi.useFakeTimers();
38 | const mockFn = vi.fn();
39 | timer(mockFn);
40 | vi.advanceTimersByTime(5000);
41 | expect(mockFn).toBeCalled();
42 | });
43 | });
44 |
--------------------------------------------------------------------------------
/app.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'esbuild-plugin-babel' {
2 | export default function babel(build?: any): any;
3 | }
4 |
--------------------------------------------------------------------------------
/commitlint.config.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | // https://github.com/conventional-changelog/commitlint/#what-is-commitlint
3 | extends: ['@commitlint/config-conventional'],
4 | };
5 |
--------------------------------------------------------------------------------
/docs/.gitignore:
--------------------------------------------------------------------------------
1 | # Dependencies
2 | /node_modules
3 |
4 | # Production
5 | /build
6 |
7 | # Generated files
8 | .docusaurus
9 | .cache-loader
10 |
11 | # Misc
12 | .DS_Store
13 | .env.local
14 | .env.development.local
15 | .env.test.local
16 | .env.production.local
17 |
18 | npm-debug.log*
19 | yarn-debug.log*
20 | yarn-error.log*
21 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | # Website
2 |
3 | This website is built using [Docusaurus 2](https://docusaurus.io/), a modern static website generator.
4 |
5 | ### Installation
6 |
7 | ```
8 | $ yarn
9 | ```
10 |
11 | ### Local Development
12 |
13 | ```
14 | $ yarn start
15 | ```
16 |
17 | This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.
18 |
19 | ### Build
20 |
21 | ```
22 | $ yarn build
23 | ```
24 |
25 | This command generates static content into the `build` directory and can be served using any static contents hosting service.
26 |
27 | ### Deployment
28 |
29 | Using SSH:
30 |
31 | ```
32 | $ USE_SSH=true yarn deploy
33 | ```
34 |
35 | Not using SSH:
36 |
37 | ```
38 | $ GIT_USER= yarn deploy
39 | ```
40 |
41 | If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch.
42 |
--------------------------------------------------------------------------------
/docs/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [require.resolve('@docusaurus/core/lib/babel/preset')],
3 | };
4 |
--------------------------------------------------------------------------------
/docs/docs/get-started/_category_.json:
--------------------------------------------------------------------------------
1 | {
2 | "label": "Get - Started",
3 | "position": 2,
4 | "link": {
5 | "type": "generated-index",
6 | "description": " "
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/docs/docs/get-started/installation.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_position: 1
3 | ---
4 |
5 | # Installation
6 |
7 | Installation
8 |
--------------------------------------------------------------------------------
/docs/docs/get-started/markdown-features.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_position: 4
3 | ---
4 |
5 | # Markdown Features
6 |
7 | Docusaurus supports **[Markdown](https://daringfireball.net/projects/markdown/syntax)** and a few **additional features**.
8 |
9 | ## Front Matter
10 |
11 | Markdown documents have metadata at the top called [Front Matter](https://jekyllrb.com/docs/front-matter/):
12 |
13 | ```text title="my-doc.md"
14 | // highlight-start
15 | ---
16 | id: my-doc-id
17 | title: My document title
18 | description: My document description
19 | slug: /my-custom-url
20 | ---
21 | // highlight-end
22 |
23 | ## Markdown heading
24 |
25 | Markdown text with [links](./hello.md)
26 | ```
27 |
28 | ## Images
29 |
30 | Regular Markdown images are supported.
31 |
32 | You can use absolute paths to reference images in the static directory (`static/img/docusaurus.png`):
33 |
34 | ```md
35 | 
36 | ```
37 |
38 | 
39 |
40 |
41 | ## Code Blocks
42 |
43 | Markdown code blocks are supported with Syntax highlighting.
44 |
45 | ```jsx title="src/components/HelloDocusaurus.js"
46 | function HelloDocusaurus() {
47 | return (
48 | Hello, Docusaurus!
49 | )
50 | }
51 | ```
52 |
53 | ```jsx title="src/components/HelloDocusaurus.js"
54 | function HelloDocusaurus() {
55 | return Hello, Docusaurus! ;
56 | }
57 | ```
58 |
59 | ## Admonitions
60 |
61 | Docusaurus has a special syntax to create admonitions and callouts:
62 |
63 | :::tip My tip
64 |
65 | Use this awesome feature option
66 |
67 | :::
68 |
69 | :::danger Take care
70 |
71 | This action is dangerous
72 |
73 | :::
74 |
75 | :::tip My tip
76 |
77 | Use this awesome feature option
78 |
79 | :::
80 |
81 | :::danger Take care
82 |
83 | This action is dangerous
84 |
85 | :::
86 |
87 | ## MDX and React Components
88 |
89 | [MDX](https://mdxjs.com/) can make your documentation more **interactive** and allows using any **React components inside Markdown**:
90 |
91 | ```jsx
92 | export const Highlight = ({children, color}) => (
93 | {
102 | alert(`You clicked the color ${color} with label ${children}`)
103 | }}>
104 | {children}
105 |
106 | );
107 |
108 | This is Docusaurus green !
109 |
110 | This is Facebook blue !
111 | ```
112 |
113 | export const Highlight = ({children, color}) => (
114 | {
123 | alert(`You clicked the color ${color} with label ${children}`);
124 | }}>
125 | {children}
126 |
127 | );
128 |
129 | This is Docusaurus green !
130 |
131 | This is Facebook blue !
132 |
--------------------------------------------------------------------------------
/docs/docs/intro.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_position: 1
3 | ---
4 |
5 | # Component Intro
6 |
7 | Component Intro
8 |
--------------------------------------------------------------------------------
/docs/docusaurus.config.js:
--------------------------------------------------------------------------------
1 | // @ts-check
2 | // Note: type annotations allow type checking and IDEs autocompletion
3 |
4 | const lightCodeTheme = require('prism-react-renderer/themes/github');
5 | const darkCodeTheme = require('prism-react-renderer/themes/dracula');
6 |
7 | /** @type {import('@docusaurus/types').Config} */
8 | const config = {
9 | title: 'custom-package-name',
10 | tagline: 'Dinosaurs are cool',
11 | url: 'https://your-docusaurus-test-site.com',
12 | baseUrl: '/',
13 | onBrokenLinks: 'throw',
14 | onBrokenMarkdownLinks: 'warn',
15 | favicon: 'img/favicon.ico',
16 |
17 | // GitHub pages deployment config.
18 | // If you aren't using GitHub pages, you don't need these.
19 | organizationName: 'facebook', // Usually your GitHub org/user name.
20 | projectName: 'docusaurus', // Usually your repo name.
21 |
22 | // Even if you don't use internalization, you can use this field to set useful
23 | // metadata like html lang. For example, if your site is Chinese, you may want
24 | // to replace "en" with "zh-Hans".
25 | i18n: {
26 | defaultLocale: 'en',
27 | locales: ['en'],
28 | },
29 |
30 | presets: [
31 | [
32 | 'classic',
33 | /** @type {import('@docusaurus/preset-classic').Options} */
34 | ({
35 | docs: {
36 | sidebarPath: require.resolve('./sidebars.js'),
37 | // Please change this to your repo.
38 | // Remove this to remove the "edit this page" links.
39 | editUrl:
40 | 'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/',
41 | },
42 | theme: {
43 | customCss: require.resolve('./src/css/custom.css'),
44 | },
45 | }),
46 | ],
47 | ],
48 |
49 | themeConfig:
50 | /** @type {import('@docusaurus/preset-classic').ThemeConfig} */
51 | ({
52 | navbar: {
53 | title: 'custom-package-name',
54 | logo: {
55 | alt: 'custom-package-name Logo',
56 | src: 'img/logo.svg',
57 | },
58 | items: [
59 | {
60 | type: 'doc',
61 | docId: 'intro',
62 | position: 'left',
63 | label: 'Get Started',
64 | },
65 | {
66 | href: 'https://github.com/facebook/docusaurus',
67 | label: 'GitHub',
68 | position: 'right',
69 | },
70 | ],
71 | },
72 | footer: {
73 | style: 'dark',
74 | copyright: `Copyright © ${new Date().getFullYear()} My Project, Inc. Built with Docusaurus.`,
75 | },
76 | prism: {
77 | theme: lightCodeTheme,
78 | darkTheme: darkCodeTheme,
79 | },
80 | }),
81 | };
82 |
83 | module.exports = config;
84 |
--------------------------------------------------------------------------------
/docs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "docs",
3 | "version": "0.0.0",
4 | "private": true,
5 | "scripts": {
6 | "docusaurus": "docusaurus",
7 | "start": "docusaurus start",
8 | "build": "docusaurus build",
9 | "swizzle": "docusaurus swizzle",
10 | "deploy": "docusaurus deploy",
11 | "clear": "docusaurus clear",
12 | "serve": "docusaurus serve",
13 | "write-translations": "docusaurus write-translations",
14 | "write-heading-ids": "docusaurus write-heading-ids",
15 | "typecheck": "tsc"
16 | },
17 | "dependencies": {
18 | "@docusaurus/core": "^3.3.2",
19 | "@docusaurus/preset-classic": "^3.3.2",
20 | "@mdx-js/react": "^2.3.0",
21 | "clsx": "^2.1.1",
22 | "prism-react-renderer": "^1.3.5",
23 | "react": "^18.3.1",
24 | "react-dom": "^18.3.1"
25 | },
26 | "devDependencies": {
27 | "@docusaurus/module-type-aliases": "^3.3.2",
28 | "@tsconfig/docusaurus": "^2.0.3",
29 | "typescript": "^5.4.5"
30 | },
31 | "browserslist": {
32 | "production": [
33 | ">0.5%",
34 | "not dead",
35 | "not op_mini all"
36 | ],
37 | "development": [
38 | "last 1 chrome version",
39 | "last 1 firefox version",
40 | "last 1 safari version"
41 | ]
42 | },
43 | "engines": {
44 | "node": ">=16"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/docs/sidebars.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Creating a sidebar enables you to:
3 | - create an ordered group of docs
4 | - render a sidebar for each doc of that group
5 | - provide next/previous navigation
6 |
7 | The sidebars can be generated from the filesystem, or explicitly defined here.
8 |
9 | Create as many sidebars as you want.
10 | */
11 |
12 | // @ts-check
13 |
14 | /** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */
15 | const sidebars = {
16 | // By default, Docusaurus generates a sidebar from the docs folder structure
17 | tutorialSidebar: [{ type: 'autogenerated', dirName: '.' }],
18 |
19 | // But you can create a sidebar manually
20 | /*
21 | tutorialSidebar: [
22 | 'intro',
23 | 'hello',
24 | {
25 | type: 'category',
26 | label: 'Tutorial',
27 | items: ['tutorial-basics/create-a-document'],
28 | },
29 | ],
30 | */
31 | };
32 |
33 | module.exports = sidebars;
34 |
--------------------------------------------------------------------------------
/docs/src/components/HomepageFeatures/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import clsx from 'clsx';
3 | import styles from './styles.module.css';
4 |
5 | type FeatureItem = {
6 | title: string;
7 | Svg: React.ComponentType>;
8 | description: JSX.Element;
9 | };
10 |
11 | const FeatureList: FeatureItem[] = [
12 | {
13 | title: 'Easy to Use',
14 | Svg: require('@site/static/img/undraw_docusaurus_mountain.svg').default,
15 | description: (
16 | <>
17 | Docusaurus was designed from the ground up to be easily installed and
18 | used to get your website up and running quickly.
19 | >
20 | ),
21 | },
22 | {
23 | title: 'Focus on What Matters',
24 | Svg: require('@site/static/img/undraw_docusaurus_tree.svg').default,
25 | description: (
26 | <>
27 | Docusaurus lets you focus on your docs, and we'll do the chores. Go
28 | ahead and move your docs into the
29 | {' '}
30 |
31 | docs
32 |
33 | {' '}
34 | directory.
35 | >
36 | ),
37 | },
38 | {
39 | title: 'Powered by React',
40 | Svg: require('@site/static/img/undraw_docusaurus_react.svg').default,
41 | description: (
42 | <>
43 | Extend or customize your website layout by reusing React. Docusaurus can
44 | be extended while reusing the same header and footer.
45 | >
46 | ),
47 | },
48 | ];
49 |
50 | function Feature({ title, Svg, description }: FeatureItem) {
51 | return (
52 |
53 |
54 |
55 |
56 |
57 |
58 | {title}
59 |
60 |
61 | {description}
62 |
63 |
64 |
65 | );
66 | }
67 |
68 | export default function HomepageFeatures(): JSX.Element {
69 | return (
70 |
71 |
72 |
73 | {FeatureList.map((props, idx) => (
74 |
75 | ))}
76 |
77 |
78 |
79 | );
80 | }
81 |
--------------------------------------------------------------------------------
/docs/src/components/HomepageFeatures/styles.module.css:
--------------------------------------------------------------------------------
1 | .features {
2 | display: flex;
3 | align-items: center;
4 | padding: 2rem 0;
5 | width: 100%;
6 | }
7 |
8 | .featureSvg {
9 | height: 200px;
10 | width: 200px;
11 | }
12 |
--------------------------------------------------------------------------------
/docs/src/css/custom.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Any CSS included here will be global. The classic template
3 | * bundles Infima by default. Infima is a CSS framework designed to
4 | * work well for content-centric websites.
5 | */
6 |
7 | /* You can override the default Infima variables here. */
8 | :root {
9 | --ifm-color-primary: #2e8555;
10 | --ifm-color-primary-dark: #29784c;
11 | --ifm-color-primary-darker: #277148;
12 | --ifm-color-primary-darkest: #205d3b;
13 | --ifm-color-primary-light: #33925d;
14 | --ifm-color-primary-lighter: #359962;
15 | --ifm-color-primary-lightest: #3cad6e;
16 | --ifm-code-font-size: 95%;
17 | --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1);
18 | }
19 |
20 | /* For readability concerns, you should choose a lighter palette in dark mode. */
21 | [data-theme='dark'] {
22 | --ifm-color-primary: #25c2a0;
23 | --ifm-color-primary-dark: #21af90;
24 | --ifm-color-primary-darker: #1fa588;
25 | --ifm-color-primary-darkest: #1a8870;
26 | --ifm-color-primary-light: #29d5b0;
27 | --ifm-color-primary-lighter: #32d8b4;
28 | --ifm-color-primary-lightest: #4fddbf;
29 | --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3);
30 | }
31 |
--------------------------------------------------------------------------------
/docs/src/pages/index.module.css:
--------------------------------------------------------------------------------
1 | /**
2 | * CSS files with the .module.css suffix will be treated as CSS modules
3 | * and scoped locally.
4 | */
5 |
6 | .heroBanner {
7 | padding: 4rem 0;
8 | text-align: center;
9 | position: relative;
10 | overflow: hidden;
11 | }
12 |
13 | @media screen and (max-width: 996px) {
14 | .heroBanner {
15 | padding: 2rem;
16 | }
17 | }
18 |
19 | .buttons {
20 | display: flex;
21 | align-items: center;
22 | justify-content: center;
23 | }
24 |
--------------------------------------------------------------------------------
/docs/src/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import clsx from 'clsx';
3 | import Link from '@docusaurus/Link';
4 | import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
5 | import Layout from '@theme/Layout';
6 | import HomepageFeatures from '@site/src/components/HomepageFeatures';
7 |
8 | import styles from './index.module.css';
9 |
10 | function HomepageHeader() {
11 | const { siteConfig } = useDocusaurusContext();
12 | return (
13 |
31 | );
32 | }
33 |
34 | export default function Home(): JSX.Element {
35 | const { siteConfig } = useDocusaurusContext();
36 | return (
37 |
41 |
42 |
43 |
44 |
45 |
46 | );
47 | }
48 |
--------------------------------------------------------------------------------
/docs/src/pages/markdown-page.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Markdown page example
3 | ---
4 |
5 | # Markdown page example
6 |
7 | You don't need React to write simple standalone pages.
8 |
--------------------------------------------------------------------------------
/docs/static/.nojekyll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codes-templates/npm-react/cd0bec5779d0aca7c63ebb6fb37eb24225594529/docs/static/.nojekyll
--------------------------------------------------------------------------------
/docs/static/img/docusaurus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codes-templates/npm-react/cd0bec5779d0aca7c63ebb6fb37eb24225594529/docs/static/img/docusaurus.png
--------------------------------------------------------------------------------
/docs/static/img/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codes-templates/npm-react/cd0bec5779d0aca7c63ebb6fb37eb24225594529/docs/static/img/favicon.ico
--------------------------------------------------------------------------------
/docs/static/img/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/static/img/undraw_docusaurus_mountain.svg:
--------------------------------------------------------------------------------
1 |
2 | Easy to Use
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
--------------------------------------------------------------------------------
/docs/static/img/undraw_docusaurus_react.svg:
--------------------------------------------------------------------------------
1 |
2 | Powered by React
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
--------------------------------------------------------------------------------
/docs/static/img/undraw_docusaurus_tree.svg:
--------------------------------------------------------------------------------
1 |
2 | Focus on What Matters
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/docs/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | // This file is not used in compilation. It is here just for a nice editor experience.
3 | "extends": "@tsconfig/docusaurus/tsconfig.json",
4 | "compilerOptions": {
5 | "baseUrl": "."
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "custom-package-name",
3 | "version": "0.0.7",
4 | "description": "",
5 | "keywords": [],
6 | "type": "module",
7 | "homepage": "https://github.com/codes-templates/npm-react#readme",
8 | "bugs": {
9 | "url": "https://github.com/codes-templates/npm-react/issues"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "git+https://github.com/codes-templates/npm-react.git"
14 | },
15 | "license": "MIT",
16 | "author": "jerrywu001 <57242263@163.com>",
17 | "sideEffects": [
18 | "dist/index.css"
19 | ],
20 | "main": "./dist/index.js",
21 | "module": "./dist/index.mjs",
22 | "types": "./dist/index.d.ts",
23 | "exports": {
24 | ".": {
25 | "types": "./dist/index.d.ts",
26 | "import": "./dist/index.mjs",
27 | "require": "./dist/index.js"
28 | },
29 | "./*": [
30 | "./*",
31 | "./*.d.ts"
32 | ]
33 | },
34 | "typesVersions": {
35 | "*": {
36 | "*": [
37 | "./dist/*",
38 | "./*"
39 | ]
40 | }
41 | },
42 | "files": [
43 | "dist",
44 | "package.json",
45 | "README.md",
46 | "global.d.ts",
47 | "*.d.ts"
48 | ],
49 | "workspaces": [
50 | "playground",
51 | "docs"
52 | ],
53 | "scripts": {
54 | "storybook": "storybook dev -p 6006",
55 | "build": "tsup && npm run build:css",
56 | "dev": "npm run dev -w playground",
57 | "dev:use-bundle": "run-p tsup-w dev-pack",
58 | "docs": "npm run start -w docs",
59 | "build:docs": "npm run build -w docs",
60 | "build:css": "npm run build:scss && npm run build:postcss && rimraf rf ./src/index.css",
61 | "build:scss": "sass --no-source-map --style=compressed src/styles/main.scss src/index.css",
62 | "build:postcss": "postcss src/index.css -o dist/index.css",
63 | "build:vite": "vite build && npm run build:css",
64 | "build:storybook": "cross-env NO_DTS=1 storybook build",
65 | "preview:docs": "npm run serve -w docs",
66 | "lint": "eslint --ext .ts,.tsx ./src",
67 | "tsup-w": "tsup --watch",
68 | "dev-pack": "npm run dev:usepack -w playground",
69 | "prepare": "chmod a+x .husky/* && husky",
70 | "prepublishOnly": "npm run build",
71 | "release": "bumpp --commit --tag --push",
72 | "stylelint": "stylelint \"src/**/*.{css,scss}\"",
73 | "test": "vitest",
74 | "test:ui": "vitest --ui",
75 | "typecheck": "tsc --noEmit"
76 | },
77 | "dependencies": {
78 | "@babel/runtime": "^7.24.5",
79 | "core-js": "^3.37.1"
80 | },
81 | "devDependencies": {
82 | "@babel/plugin-transform-runtime": "^7.24.3",
83 | "@commitlint/cli": "^19.3.0",
84 | "@commitlint/config-conventional": "^19.2.2",
85 | "@rollup/plugin-babel": "^6.0.4",
86 | "@storybook/addon-essentials": "^8.1.1",
87 | "@storybook/addon-interactions": "^8.1.1",
88 | "@storybook/addon-links": "^8.1.1",
89 | "@storybook/addon-onboarding": "^8.1.1",
90 | "@storybook/blocks": "^8.1.1",
91 | "@storybook/react": "^8.1.1",
92 | "@storybook/react-vite": "^8.1.1",
93 | "@storybook/test": "^8.1.1",
94 | "@swc/core": "^1.5.7",
95 | "@testing-library/jest-dom": "^6.4.5",
96 | "@testing-library/react": "^15.0.7",
97 | "@testing-library/user-event": "^14.5.2",
98 | "@types/react": "^18.3.2",
99 | "@types/react-dom": "^18.3.0",
100 | "@typescript-eslint/eslint-plugin": "^7.9.0",
101 | "@typescript-eslint/parser": "^7.9.0",
102 | "@vitest/ui": "^1.6.0",
103 | "babel-loader": "^9.1.3",
104 | "browserslist-to-esbuild": "^2.1.1",
105 | "bumpp": "^9.4.1",
106 | "cross-env": "^7.0.3",
107 | "cssnano": "^7.0.1",
108 | "esbuild-plugin-babel": "^0.2.3",
109 | "eslint": "^8.57.0",
110 | "eslint-config-airbnb-base": "^15.0.0",
111 | "eslint-config-airbnb-typescript": "^18.0.0",
112 | "eslint-plugin-import": "^2.29.1",
113 | "eslint-plugin-jsx-a11y": "^6.8.0",
114 | "eslint-plugin-react": "^7.34.1",
115 | "eslint-plugin-react-hooks": "^4.6.2",
116 | "eslint-plugin-storybook": "^0.8.0",
117 | "husky": "^9.0.11",
118 | "jsdom": "^24.0.0",
119 | "less": "^4.2.0",
120 | "npm-run-all": "^4.1.5",
121 | "path": "^0.12.7",
122 | "postcss": "^8.4.38",
123 | "postcss-cli": "^11.0.0",
124 | "postcss-flexbugs-fixes": "^5.0.2",
125 | "postcss-nested": "^6.0.1",
126 | "postcss-preset-env": "^9.5.13",
127 | "postcss-scss": "^4.0.9",
128 | "react": "^18.3.1",
129 | "react-dom": "^18.3.1",
130 | "react-element-to-jsx-string": "^15.0.0",
131 | "rimraf": "^5.0.7",
132 | "sass": "^1.77.1",
133 | "storybook": "^8.1.1",
134 | "stylelint": "^15.11.0",
135 | "stylelint-config-standard": "^34.0.0",
136 | "tsup": "^8.0.2",
137 | "typescript": "^5.4.5",
138 | "vite": "^5.2.11",
139 | "vite-plugin-dts": "^3.9.1",
140 | "vitest": "^1.6.0"
141 | },
142 | "peerDependencies": {
143 | "react": "^16.8.0 || ^17 || ^18",
144 | "react-dom": "^16.8.0 || ^17 || ^18"
145 | },
146 | "engines": {
147 | "node": ">=18",
148 | "npm": ">=9"
149 | }
150 | }
151 |
--------------------------------------------------------------------------------
/playground/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/playground/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "playground",
3 | "version": "1.0.0",
4 | "type": "module",
5 | "scripts": {
6 | "build": "tsc && vite build",
7 | "dev": "vite --host --open",
8 | "dev:usepack": "cross-env USEPACK=true vite --host --port 5000 --open",
9 | "preview": "vite preview",
10 | "typecheck": "tsc --noEmit"
11 | },
12 | "dependencies": {
13 | "react-router": "^6.23.1",
14 | "react-router-dom": "^6.23.1"
15 | },
16 | "devDependencies": {
17 | "@types/react-router": "^5.1.20",
18 | "@types/react-router-dom": "^5.3.3",
19 | "@vitejs/plugin-react": "^4.2.1",
20 | "cross-env": "^7.0.3"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/playground/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codes-templates/npm-react/cd0bec5779d0aca7c63ebb6fb37eb24225594529/playground/public/favicon.ico
--------------------------------------------------------------------------------
/playground/src/main.tsx:
--------------------------------------------------------------------------------
1 | import App from './routers';
2 | import React from 'react';
3 | import ReactDOM from 'react-dom/client';
4 |
5 | // eslint-disable-next-line import/no-relative-packages
6 | import '../../src/styles/main.scss'; // 不要修改或删除
7 |
8 | const root = document.getElementById('root')!;
9 |
10 | ReactDOM.createRoot(root).render( );
11 |
--------------------------------------------------------------------------------
/playground/src/pages/home/Home.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Demo, REACT_TEST } from 'custom-package-name';
3 |
4 | export default function Home() {
5 | return (
6 |
7 | home
8 | {' '}
9 |
10 | { REACT_TEST.demo }
11 |
12 |
13 |
14 | );
15 | }
16 |
--------------------------------------------------------------------------------
/playground/src/routers.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/dot-notation */
2 | /* eslint-disable @typescript-eslint/no-shadow */
3 | /* eslint-disable react/jsx-one-expression-per-line */
4 | import Home from './pages/home/Home';
5 | import { BrowserRouter as Router, Navigate } from 'react-router-dom';
6 | import React, { useEffect } from 'react';
7 | import {
8 | Route,
9 | Routes,
10 | useLocation,
11 | useNavigationType,
12 | } from 'react-router';
13 |
14 | // https://reactrouter.com/docs/en/v6
15 |
16 | function AppRoutes() {
17 | const location = useLocation();
18 |
19 | return (
20 |
21 | } index />
22 | } path="/home" />
23 |
24 | );
25 | }
26 |
27 | export default function App() {
28 | return (
29 |
30 |
31 |
32 | );
33 | }
34 |
35 | function AppContainer() {
36 | const location = useLocation();
37 | const action = useNavigationType();
38 |
39 | useEffect(() => {
40 | const { pathname = '', search = '' } = location;
41 | console.log(`router mode: ${action}, url: ${pathname}${search}`);
42 | });
43 |
44 | return (
45 |
46 | );
47 | }
48 |
49 | export enum Action {
50 | Pop = 'POP',
51 | Push = 'PUSH',
52 | Replace = 'REPLACE',
53 | }
54 |
--------------------------------------------------------------------------------
/playground/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": ".",
4 | "target": "esnext",
5 | "module": "esnext",
6 | "moduleResolution": "Node",
7 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
8 | "skipDefaultLibCheck": true,
9 | "noEmit": true,
10 | "sourceMap": true,
11 | "allowJs": true,
12 | "skipLibCheck": true,
13 | "strictNullChecks": true,
14 | "esModuleInterop": true,
15 | "ignoreDeprecations": "5.0",
16 | "allowSyntheticDefaultImports": true,
17 | "strict": true,
18 | "forceConsistentCasingInFileNames": true,
19 | "noUnusedLocals": false,
20 | "noFallthroughCasesInSwitch": true,
21 | "noImplicitReturns": false,
22 | "noImplicitThis": true,
23 | "noImplicitAny": false,
24 | "importHelpers": false,
25 | "resolveJsonModule": true,
26 | "isolatedModules": false,
27 | "emitDecoratorMetadata": true,
28 | "experimentalDecorators": true,
29 | "jsx": "react",
30 | "paths": {
31 | "@/*": [
32 | "src/*"
33 | ],
34 | "custom-package-name": [
35 | "../src"
36 | ],
37 | "custom-package-name/*": [
38 | "../src/*"
39 | ]
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/playground/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | // eslint-disable-next-line @typescript-eslint/triple-slash-reference
2 | ///
3 | ///
4 |
--------------------------------------------------------------------------------
/playground/vite.config.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | import path from 'path';
4 | import { defineConfig } from 'vite';
5 | import react from '@vitejs/plugin-react';
6 |
7 | export default defineConfig({
8 | resolve: {
9 | alias: {
10 | '@/': `${path.resolve(__dirname, 'src')}/`,
11 | 'custom-package-name': path.resolve(__dirname, process.env.USEPACK === 'true' ? '../dist' : '../src'),
12 | },
13 | },
14 | build: {
15 | sourcemap: true,
16 | },
17 | plugins: [
18 | react(),
19 | ],
20 | });
21 |
--------------------------------------------------------------------------------
/postcss.config.cjs:
--------------------------------------------------------------------------------
1 | // https://cssnano.co/docs/getting-started/
2 |
3 | module.exports = {
4 | plugins: [
5 | require('cssnano')({
6 | preset: 'default',
7 | }),
8 | require('postcss-nested'),
9 | require('postcss-flexbugs-fixes'), // https://github.com/luisrudge/postcss-flexbugs-fixes#readme
10 | require('postcss-preset-env')({
11 | autoprefixer: {
12 | grid: false,
13 | },
14 | }),
15 | ]
16 | }
17 |
--------------------------------------------------------------------------------
/setupTests.ts:
--------------------------------------------------------------------------------
1 | import '@testing-library/jest-dom';
2 |
--------------------------------------------------------------------------------
/src/components/Demo.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 |
3 | const test = null;
4 |
5 | export function Demo() {
6 | const [count] = useState(0);
7 | const b = '5'.padStart(2, '1');
8 | const c = test ?? 'hello';
9 | const d = {} as Record;
10 |
11 | return (
12 |
13 |
14 | count in jsx component:
15 | {' '}
16 | {count}
17 |
18 |
19 | {b}
20 |
21 |
22 | {c}
23 |
24 |
25 | test `?.`
26 | {' '}
27 | {d?.name}
28 |
29 |
30 | );
31 | }
32 |
--------------------------------------------------------------------------------
/src/components/index.ts:
--------------------------------------------------------------------------------
1 | export * from './Demo';
2 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | export * from './types'; // can not delete
2 | export * from './presets';
3 | export * from './components';
4 |
--------------------------------------------------------------------------------
/src/presets/index.ts:
--------------------------------------------------------------------------------
1 | import { TEST_REACT } from '../types';
2 |
3 | export const REACT_TEST: TEST_REACT = {
4 | demo: 'hello world',
5 | };
6 |
--------------------------------------------------------------------------------
/src/stories/Button.stories.ts:
--------------------------------------------------------------------------------
1 | import type { Meta, StoryObj } from '@storybook/react';
2 |
3 | import { Button } from './Button';
4 |
5 | // More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
6 | const meta = {
7 | title: 'Example/Button',
8 | component: Button,
9 | parameters: {
10 | // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/react/configure/story-layout
11 | layout: 'centered',
12 | },
13 | // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/react/writing-docs/autodocs
14 | tags: ['autodocs'],
15 | // More on argTypes: https://storybook.js.org/docs/react/api/argtypes
16 | argTypes: {
17 | backgroundColor: { control: 'color' },
18 | },
19 | } satisfies Meta;
20 |
21 | export default meta;
22 | type Story = StoryObj;
23 |
24 | // More on writing stories with args: https://storybook.js.org/docs/react/writing-stories/args
25 | export const Primary: Story = {
26 | args: {
27 | primary: true,
28 | label: 'Button',
29 | },
30 | };
31 |
32 | export const Secondary: Story = {
33 | args: {
34 | label: 'Button',
35 | },
36 | };
37 |
38 | export const Large: Story = {
39 | args: {
40 | size: 'large',
41 | label: 'Button',
42 | },
43 | };
44 |
45 | export const Small: Story = {
46 | args: {
47 | size: 'small',
48 | label: 'Button',
49 | },
50 | };
51 |
52 | export const Warning: Story = {
53 | args: {
54 | primary: true,
55 | label: 'Delete now',
56 | backgroundColor: 'red',
57 | }
58 | };
59 |
--------------------------------------------------------------------------------
/src/stories/Button.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import './button.less';
3 |
4 | interface ButtonProps {
5 | /**
6 | * Is this the principal call to action on the page?
7 | */
8 | primary?: boolean;
9 | /**
10 | * What background color to use
11 | */
12 | backgroundColor?: string;
13 | /**
14 | * How large should the button be?
15 | */
16 | size?: 'small' | 'medium' | 'large';
17 | /**
18 | * Button contents
19 | */
20 | label: string;
21 | /**
22 | * Optional click handler
23 | */
24 | onClick?: () => void;
25 | }
26 |
27 | /**
28 | * Primary UI component for user interaction
29 | */
30 | export const Button = ({
31 | primary = false,
32 | size = 'medium',
33 | backgroundColor,
34 | label,
35 | ...props
36 | }: ButtonProps) => {
37 | const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary';
38 |
39 | return (
40 |
46 | {label}
47 |
48 | );
49 | };
50 |
--------------------------------------------------------------------------------
/src/stories/Configure.mdx:
--------------------------------------------------------------------------------
1 | import { Meta } from "@storybook/blocks";
2 |
3 | import Github from "./assets/github.svg";
4 | import Discord from "./assets/discord.svg";
5 | import Youtube from "./assets/youtube.svg";
6 | import Tutorials from "./assets/tutorials.svg";
7 | import Styling from "./assets/styling.png";
8 | import Context from "./assets/context.png";
9 | import Assets from "./assets/assets.png";
10 | import Docs from "./assets/docs.png";
11 | import Share from "./assets/share.png";
12 | import FigmaPlugin from "./assets/figma-plugin.png";
13 | import Testing from "./assets/testing.png";
14 | import Accessibility from "./assets/accessibility.png";
15 | import Theming from "./assets/theming.png";
16 | import AddonLibrary from "./assets/addon-library.png";
17 |
18 | export const RightArrow = () =>
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | # Configure your project
39 |
40 | Because Storybook works separately from your app, you'll need to configure it for your specific stack and setup. Below, explore guides for configuring Storybook with popular frameworks and tools. If you get stuck, learn how you can ask for help from our community.
41 |
42 |
43 |
44 |
48 |
Add styling and CSS
49 |
Like with web applications, there are many ways to include CSS within Storybook. Learn more about setting up styling within Storybook.
50 |
Learn more
54 |
55 |
56 |
60 |
Provide context and mocking
61 |
Often when a story doesn't render, it's because your component is expecting a specific environment or context (like a theme provider) to be available.
62 |
Learn more
66 |
67 |
68 |
69 |
70 |
Load assets and resources
71 |
To link static files (like fonts) to your projects and stories, use the
72 | `staticDirs` configuration option to specify folders to load when
73 | starting Storybook.
74 |
Learn more
78 |
79 |
80 |
81 |
82 |
83 |
84 | # Do more with Storybook
85 |
86 | Now that you know the basics, let's explore other parts of Storybook that will improve your experience. This list is just to get you started. You can customise Storybook in many ways to fit your needs.
87 |
88 |
89 |
90 |
91 |
92 |
93 |
Autodocs
94 |
Auto-generate living,
95 | interactive reference documentation from your components and stories.
96 |
Learn more
100 |
101 |
102 |
103 |
Publish to Chromatic
104 |
Publish your Storybook to review and collaborate with your entire team.
105 |
Learn more
109 |
110 |
111 |
112 |
Figma Plugin
113 |
Embed your stories into Figma to cross-reference the design and live
114 | implementation in one place.
115 |
Learn more
119 |
120 |
121 |
122 |
Testing
123 |
Use stories to test a component in all its variations, no matter how
124 | complex.
125 |
Learn more
129 |
130 |
131 |
132 |
Accessibility
133 |
Automatically test your components for a11y issues as you develop.
134 |
Learn more
138 |
139 |
140 |
141 |
Theming
142 |
Theme Storybook's UI to personalize it to your project.
143 |
Learn more
147 |
148 |
149 |
150 |
151 |
152 |
153 |
Addons
154 |
Integrate your tools with Storybook to connect workflows.
155 |
Discover all addons
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 | Join our contributors building the future of UI development.
169 |
170 |
Star on GitHub
174 |
175 |
176 |
177 |
185 |
186 |
187 |
188 |
189 | Watch tutorials, feature previews and interviews.
190 |
191 |
Watch on YouTube
195 |
196 |
197 |
198 |
199 |
Follow guided walkthroughs on for key workflows.
200 |
201 |
Discover tutorials
205 |
206 |
207 |
208 |
365 |
--------------------------------------------------------------------------------
/src/stories/Header.stories.ts:
--------------------------------------------------------------------------------
1 | import type { Meta, StoryObj } from '@storybook/react';
2 |
3 | import { Header } from './Header';
4 |
5 | const meta = {
6 | title: 'Example/Header',
7 | component: Header,
8 | // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/react/writing-docs/autodocs
9 | tags: ['autodocs'],
10 | parameters: {
11 | // More on how to position stories at: https://storybook.js.org/docs/react/configure/story-layout
12 | layout: 'fullscreen',
13 | },
14 | } satisfies Meta;
15 |
16 | export default meta;
17 | type Story = StoryObj;
18 |
19 | export const LoggedIn: Story = {
20 | args: {
21 | user: {
22 | name: 'Jane Doe',
23 | },
24 | onLogin: () => {},
25 | onLogout: () => {},
26 | onCreateAccount: () => {},
27 | },
28 | };
29 |
30 | export const LoggedOut = {} as Story;
31 |
--------------------------------------------------------------------------------
/src/stories/Header.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import { Button } from './Button';
4 | import './header.scss';
5 |
6 | type User = {
7 | name: string;
8 | };
9 |
10 | interface HeaderProps {
11 | user?: User;
12 | onLogin: () => void;
13 | onLogout: () => void;
14 | onCreateAccount: () => void;
15 | }
16 |
17 | export const Header = ({ user, onLogin, onLogout, onCreateAccount }: HeaderProps) => (
18 |
56 | );
57 |
--------------------------------------------------------------------------------
/src/stories/Page.stories.ts:
--------------------------------------------------------------------------------
1 | import type { Meta, StoryObj } from '@storybook/react';
2 | import { within, userEvent } from '@storybook/test';
3 |
4 | import { Page } from './Page';
5 |
6 | const meta = {
7 | title: 'Example/Page',
8 | component: Page,
9 | parameters: {
10 | // More on how to position stories at: https://storybook.js.org/docs/react/configure/story-layout
11 | layout: 'fullscreen',
12 | },
13 | } satisfies Meta;
14 |
15 | export default meta;
16 | type Story = StoryObj;
17 |
18 | export const LoggedOut: Story = {};
19 |
20 | // More on interaction testing: https://storybook.js.org/docs/react/writing-tests/interaction-testing
21 | export const LoggedIn: Story = {
22 | play: async ({ canvasElement }) => {
23 | const canvas = within(canvasElement);
24 | const loginButton = await canvas.getByRole('button', {
25 | name: /Log in/i,
26 | });
27 | await userEvent.click(loginButton);
28 | },
29 | };
30 |
--------------------------------------------------------------------------------
/src/stories/Page.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Demo, REACT_TEST } from 'custom-package-name';
3 |
4 | import { Header } from './Header';
5 | import './page.css';
6 |
7 | type User = {
8 | name: string;
9 | };
10 |
11 | function Pkg() {
12 | return (
13 |
14 | home
15 | {' '}
16 |
17 | { REACT_TEST.demo }
18 |
19 |
20 |
21 | );
22 | }
23 |
24 | export const Page: React.FC = () => {
25 | const [user, setUser] = React.useState();
26 |
27 | return (
28 |
29 | setUser({ name: 'Jane Doe' })}
32 | onLogout={() => setUser(undefined)}
33 | onCreateAccount={() => setUser({ name: 'Jane Doe' })}
34 | />
35 |
36 |
37 | Pages in Storybook
38 |
39 | We recommend building UIs with a{' '}
40 |
41 | component-driven
42 | {' '}
43 | process starting with atomic components and ending with pages.
44 |
45 |
46 | Render pages with mock data. This makes it easy to build and review page states without
47 | needing to navigate to them in your app. Here are some handy patterns for managing page
48 | data in Storybook:
49 |
50 |
51 |
52 | Use a higher-level connected component. Storybook helps you compose such data from the
53 | "args" of child component stories
54 |
55 |
56 | Assemble data in the page component from your services. You can mock these services out
57 | using Storybook.
58 |
59 |
60 |
61 | Get a guided tutorial on component-driven development at{' '}
62 |
63 | Storybook tutorials
64 |
65 | . Read more in the{' '}
66 |
67 | docs
68 |
69 | .
70 |
71 |
72 |
Tip Adjust the width of the canvas with the{' '}
73 |
74 |
75 |
80 |
81 |
82 | Viewports addon in the toolbar
83 |
84 |
85 |
86 |
87 | );
88 | };
89 |
--------------------------------------------------------------------------------
/src/stories/Pkg.stories.tsx:
--------------------------------------------------------------------------------
1 | import { Demo } from 'custom-package-name';
2 | import React from 'react';
3 |
4 | export default {
5 | title: 'UsePkg',
6 | };
7 |
8 | export const Pkg = (): React.JSX.Element => ;
9 |
--------------------------------------------------------------------------------
/src/stories/assets/accessibility.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codes-templates/npm-react/cd0bec5779d0aca7c63ebb6fb37eb24225594529/src/stories/assets/accessibility.png
--------------------------------------------------------------------------------
/src/stories/assets/accessibility.svg:
--------------------------------------------------------------------------------
1 |
2 | Accessibility
3 |
4 |
5 |
--------------------------------------------------------------------------------
/src/stories/assets/addon-library.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codes-templates/npm-react/cd0bec5779d0aca7c63ebb6fb37eb24225594529/src/stories/assets/addon-library.png
--------------------------------------------------------------------------------
/src/stories/assets/assets.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codes-templates/npm-react/cd0bec5779d0aca7c63ebb6fb37eb24225594529/src/stories/assets/assets.png
--------------------------------------------------------------------------------
/src/stories/assets/context.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codes-templates/npm-react/cd0bec5779d0aca7c63ebb6fb37eb24225594529/src/stories/assets/context.png
--------------------------------------------------------------------------------
/src/stories/assets/discord.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/stories/assets/docs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codes-templates/npm-react/cd0bec5779d0aca7c63ebb6fb37eb24225594529/src/stories/assets/docs.png
--------------------------------------------------------------------------------
/src/stories/assets/figma-plugin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codes-templates/npm-react/cd0bec5779d0aca7c63ebb6fb37eb24225594529/src/stories/assets/figma-plugin.png
--------------------------------------------------------------------------------
/src/stories/assets/github.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/stories/assets/share.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codes-templates/npm-react/cd0bec5779d0aca7c63ebb6fb37eb24225594529/src/stories/assets/share.png
--------------------------------------------------------------------------------
/src/stories/assets/styling.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codes-templates/npm-react/cd0bec5779d0aca7c63ebb6fb37eb24225594529/src/stories/assets/styling.png
--------------------------------------------------------------------------------
/src/stories/assets/testing.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codes-templates/npm-react/cd0bec5779d0aca7c63ebb6fb37eb24225594529/src/stories/assets/testing.png
--------------------------------------------------------------------------------
/src/stories/assets/theming.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codes-templates/npm-react/cd0bec5779d0aca7c63ebb6fb37eb24225594529/src/stories/assets/theming.png
--------------------------------------------------------------------------------
/src/stories/assets/tutorials.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/stories/assets/youtube.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/src/stories/button.less:
--------------------------------------------------------------------------------
1 | .storybook-button {
2 | font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
3 | font-weight: 700;
4 | border: 0;
5 | border-radius: 3em;
6 | cursor: pointer;
7 | display: inline-block;
8 | line-height: 1;
9 | }
10 |
11 | .storybook-button--primary {
12 | color: white;
13 | background-color: #1ea7fd;
14 | }
15 |
16 | .storybook-button--secondary {
17 | color: #333;
18 | background-color: transparent;
19 | box-shadow: rgba(0, 0, 0, 0.15) 0 0 0 1px inset;
20 | }
21 |
22 | .storybook-button--small {
23 | font-size: 12px;
24 | padding: 10px 16px;
25 | }
26 |
27 | .storybook-button--medium {
28 | font-size: 14px;
29 | padding: 11px 20px;
30 | }
31 |
32 | .storybook-button--large {
33 | font-size: 16px;
34 | padding: 12px 24px;
35 | }
36 |
--------------------------------------------------------------------------------
/src/stories/header.scss:
--------------------------------------------------------------------------------
1 | .storybook-header {
2 | font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
3 | border-bottom: 1px solid rgba(0, 0, 0, 0.1);
4 | padding: 15px 20px;
5 | display: flex;
6 | align-items: center;
7 | justify-content: space-between;
8 | }
9 |
10 | .storybook-header svg {
11 | display: inline-block;
12 | vertical-align: top;
13 | }
14 |
15 | .storybook-header h1 {
16 | font-weight: 700;
17 | font-size: 20px;
18 | line-height: 1;
19 | margin: 6px 0 6px 10px;
20 | display: inline-block;
21 | vertical-align: top;
22 | }
23 |
24 | .storybook-header button + button {
25 | margin-left: 10px;
26 | }
27 |
28 | .storybook-header .welcome {
29 | color: #333;
30 | font-size: 14px;
31 | margin-right: 10px;
32 | }
33 |
--------------------------------------------------------------------------------
/src/stories/page.css:
--------------------------------------------------------------------------------
1 | .storybook-page {
2 | font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
3 | font-size: 14px;
4 | line-height: 24px;
5 | padding: 48px 20px;
6 | margin: 0 auto;
7 | max-width: 600px;
8 | color: #333;
9 | }
10 |
11 | .storybook-page h2 {
12 | font-weight: 700;
13 | font-size: 32px;
14 | line-height: 1;
15 | margin: 0 0 4px;
16 | display: inline-block;
17 | vertical-align: top;
18 | }
19 |
20 | .storybook-page p {
21 | margin: 1em 0;
22 | }
23 |
24 | .storybook-page a {
25 | text-decoration: none;
26 | color: #1ea7fd;
27 | }
28 |
29 | .storybook-page ul {
30 | padding-left: 30px;
31 | margin: 1em 0;
32 | }
33 |
34 | .storybook-page li {
35 | margin-bottom: 8px;
36 | }
37 |
38 | .storybook-page .tip {
39 | display: inline-block;
40 | border-radius: 1em;
41 | font-size: 11px;
42 | line-height: 12px;
43 | font-weight: 700;
44 | background: #e7fdd8;
45 | color: #66bf3c;
46 | padding: 4px 12px;
47 | margin-right: 10px;
48 | vertical-align: top;
49 | }
50 |
51 | .storybook-page .tip-wrapper {
52 | font-size: 13px;
53 | line-height: 20px;
54 | margin-top: 40px;
55 | margin-bottom: 40px;
56 | }
57 |
58 | .storybook-page .tip-wrapper svg {
59 | display: inline-block;
60 | height: 12px;
61 | width: 12px;
62 | margin-right: 4px;
63 | vertical-align: top;
64 | margin-top: 3px;
65 | }
66 |
67 | .storybook-page .tip-wrapper svg path {
68 | fill: #1ea7fd;
69 | }
70 |
--------------------------------------------------------------------------------
/src/styles/main.scss:
--------------------------------------------------------------------------------
1 | .demo {
2 | color: #333;
3 | user-select: none;
4 | }
5 |
--------------------------------------------------------------------------------
/src/types.ts:
--------------------------------------------------------------------------------
1 | export interface TEST_REACT {
2 | demo: string;
3 | }
4 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": ".",
4 | "target": "ESNext",
5 | "useDefineForClassFields": true,
6 | "module": "ESNext",
7 | "moduleResolution": "Node",
8 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
9 | "skipDefaultLibCheck": true,
10 | "noEmit": true,
11 | "sourceMap": true,
12 | "allowJs": true,
13 | "skipLibCheck": true,
14 | "strictNullChecks": true,
15 | "esModuleInterop": true,
16 | "allowSyntheticDefaultImports": true,
17 | "strict": true,
18 | "forceConsistentCasingInFileNames": true,
19 | "noUnusedLocals": true,
20 | "noFallthroughCasesInSwitch": true,
21 | "noImplicitReturns": false,
22 | "noImplicitThis": true,
23 | "noImplicitAny": false,
24 | "importHelpers": false,
25 | "resolveJsonModule": true,
26 | "isolatedModules": false,
27 | "jsx": "react",
28 | "paths": {
29 | "custom-package-name": [
30 | "./src"
31 | ],
32 | "custom-package-name/*": [
33 | "./src/*"
34 | ],
35 | "@site/*": ["./docs/*"]
36 | }
37 | },
38 | "include": [
39 | "**/*"
40 | ],
41 | "exclude": [
42 | "node_modules",
43 | "build",
44 | "dist",
45 | "__unconfig_vite.config.ts"
46 | ]
47 | }
48 |
--------------------------------------------------------------------------------
/tsup.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'tsup';
2 | import babel from 'esbuild-plugin-babel';
3 |
4 | // https://esbuild.github.io/
5 |
6 | export default defineConfig({
7 | name: 'tsup',
8 | entry: [
9 | './src/index.ts',
10 | ],
11 | outExtension({ format }) {
12 | const extension = format === 'esm' ? '.mjs' : '.js';
13 | return {
14 | js: extension,
15 | };
16 | },
17 | target: 'es6',
18 | format: [
19 | 'cjs',
20 | 'esm',
21 | ],
22 | shims: false,
23 | clean: true,
24 | treeshake: true,
25 | dts: './src/index.ts',
26 | sourcemap: false,
27 | splitting: false,
28 | minify: true,
29 | esbuildPlugins: [
30 | babel(),
31 | ],
32 | });
33 |
--------------------------------------------------------------------------------
/vite.config.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
4 | import dts from 'vite-plugin-dts';
5 | import path from 'path';
6 | import { UserConfig, defineConfig, loadEnv } from 'vite';
7 | import browserslistToEsbuild from 'browserslist-to-esbuild';
8 | import { getBabelOutputPlugin } from '@rollup/plugin-babel';
9 | import pkg from './package.json';
10 |
11 | const resolvePath = (pathName: string) => path.resolve(__dirname, pathName);
12 |
13 | // vite config can not read babel.config.js🤣🤣🤣
14 | export default defineConfig(({ mode }: UserConfig ) => {
15 | const env = loadEnv(mode as string, process.cwd(), '');
16 |
17 | return {
18 | resolve: {
19 | alias: {
20 | 'custom-package-name': resolvePath('./src/index.ts'),
21 | 'custom-package-name/': resolvePath('../src/'),
22 | },
23 | },
24 | build: {
25 | minify: true,
26 | lib: {
27 | fileName: (type) => {
28 | if (type === 'es') return 'index.mjs';
29 | if (type === 'cjs') return 'index.js';
30 | return 'index.js';
31 | },
32 | entry: resolvePath('src/index.ts'),
33 | formats: ['es', 'cjs'],
34 | },
35 | target: browserslistToEsbuild(),
36 | sourcemap: false,
37 | rollupOptions: {
38 | plugins: [
39 | // https://www.npmjs.com/package/@rollup/plugin-babel
40 | getBabelOutputPlugin({
41 | configFile: path.resolve(__dirname, '.babelrc'),
42 | filename: '.babelrc',
43 | }),
44 | ],
45 | output: {
46 | exports: 'named',
47 | },
48 | external: [
49 | ...Object.keys(pkg.dependencies), // if exist
50 | ...Object.keys(pkg.devDependencies),
51 | ...Object.keys(pkg.peerDependencies),
52 | ],
53 | },
54 | },
55 | plugins: [
56 | env?.NO_DTS !== '1'
57 | ?
58 | // https://www.npmjs.com/package/vite-plugin-dts
59 | dts({
60 | include: 'src',
61 | exclude: ['src/stories/**/**', '**/*.stories.tsx'],
62 | rollupTypes: true,
63 | afterBuild: () => {
64 | // do something else
65 | },
66 | })
67 | : null,
68 | ],
69 | // https://github.com/vitest-dev/vitest
70 | test: {
71 | globals: true,
72 | environment: 'jsdom',
73 | setupFiles: ['./setupTests.ts'],
74 | transformMode: {
75 | web: [/.[tj]sx$/],
76 | },
77 | },
78 | } as UserConfig;
79 | });
80 |
--------------------------------------------------------------------------------