diff --git a/.eslintrc.js b/.eslintrc.js index 599c3d16..da588a6a 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -9,14 +9,24 @@ module.exports = { 'plugin:jsx-a11y/recommended', 'prettier', 'plugin:prettier/recommended', + 'plugin:perfectionist/recommended-line-length', ], - plugins: ['jsx-a11y'], + plugins: ['jsx-a11y', 'perfectionist'], rules: { // 'no-unused-vars': [ // 需要使用typescript的unused,否则会对enum误报 '@typescript-eslint/no-unused-vars': [ 'error', { varsIgnorePattern: '^_', argsIgnorePattern: '^_' }, ], + 'perfectionist/sort-imports': [ + 'error', + { + type: 'line-length', + order: 'desc', + groups: [], + 'newlines-between': 'never', + }, + ], }, overrides: [ { diff --git a/.prettierrc.js b/.prettierrc.js index 46b02684..367b4f99 100644 --- a/.prettierrc.js +++ b/.prettierrc.js @@ -31,7 +31,7 @@ module.exports = { // 大括号内的首尾需要空格 bracketSpacing: true, // 标签的反尖括号需要换行 - bracketSameLine: true, + bracketSameLine: false, // 箭头函数,只有一个参数的时候,也需要括号 arrowParens: 'always', // 每个文件格式化的范围是文件的全部内容 diff --git a/internal/playground/src/app/App.tsx b/internal/playground/src/app/App.tsx index 3bfa8ebf..4581cedb 100644 --- a/internal/playground/src/app/App.tsx +++ b/internal/playground/src/app/App.tsx @@ -5,15 +5,16 @@ function App() { return (
- logo + logo

Edit src/App.tsx and save to reload.

+ > Learn React
diff --git a/internal/playground/src/index.tsx b/internal/playground/src/index.tsx index 3b81885b..19ae042f 100644 --- a/internal/playground/src/index.tsx +++ b/internal/playground/src/index.tsx @@ -1,9 +1,9 @@ -import React from 'react'; -import ReactDOM from 'react-dom/client'; import { RouterProvider } from 'react-router-dom'; -import './index.css'; +import ReactDOM from 'react-dom/client'; import '@pkg/components/index.scss'; import { router } from './router'; +import React from 'react'; +import './index.css'; // import reportWebVitals from './reportWebVitals'; const root = ReactDOM.createRoot( diff --git a/internal/playground/src/layouts/App.layout.tsx b/internal/playground/src/layouts/App.layout.tsx index 2ec99ce2..8ba6f1dd 100644 --- a/internal/playground/src/layouts/App.layout.tsx +++ b/internal/playground/src/layouts/App.layout.tsx @@ -1,9 +1,9 @@ -import React from 'react'; -import { Link, Outlet, useLocation } from 'react-router-dom'; -import styles from './App.layout.module.scss'; +import { Header, Layout, Aside, Main } from '@pkg/components'; +import { useLocation, Outlet, Link } from 'react-router-dom'; import { getClassNames } from '@tool-pack/basic'; +import styles from './App.layout.module.scss'; import { baseRouter } from '../router'; -import { Aside, Header, Layout, Main } from '@pkg/components'; +import React from 'react'; export function AppLayout(): JSX.Element { const location = useLocation(); @@ -15,7 +15,7 @@ export function AppLayout(): JSX.Element {
playground({location.pathname.replace(/^\//, '')}) - @@ -26,10 +26,11 @@ export function AppLayout(): JSX.Element {
    {baseRouter.map((item, index) => (
  • + })} + key={item.name} + > {index + 1}. {item.name} diff --git a/internal/playground/src/layouts/Error.layout.tsx b/internal/playground/src/layouts/Error.layout.tsx index fc15847d..e5d75ab8 100644 --- a/internal/playground/src/layouts/Error.layout.tsx +++ b/internal/playground/src/layouts/Error.layout.tsx @@ -1,10 +1,10 @@ -import React from 'react'; import { useRouteError } from 'react-router-dom'; +import React from 'react'; export function ErrorLayout(): JSX.Element { const err = useRouteError() as Error & { - status?: number; statusText?: string; + status?: number; }; return ( diff --git a/internal/playground/src/reportWebVitals.ts b/internal/playground/src/reportWebVitals.ts index 6071e230..a6198531 100644 --- a/internal/playground/src/reportWebVitals.ts +++ b/internal/playground/src/reportWebVitals.ts @@ -2,7 +2,7 @@ import type { ReportHandler } from 'web-vitals'; const reportWebVitals = (onPerfEntry?: ReportHandler) => { if (onPerfEntry && onPerfEntry instanceof Function) { - import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { + import('web-vitals').then(({ getTTFB, getCLS, getFID, getFCP, getLCP }) => { getCLS(onPerfEntry); getFID(onPerfEntry); getFCP(onPerfEntry); diff --git a/internal/playground/src/router.tsx b/internal/playground/src/router.tsx index 74546b69..9ec02db7 100644 --- a/internal/playground/src/router.tsx +++ b/internal/playground/src/router.tsx @@ -1,154 +1,154 @@ +import { NotFountLayout } from './layouts/NotFound.layout'; import { createBrowserRouter } from 'react-router-dom'; -import { AppLayout } from './layouts/App.layout'; import { ErrorLayout } from './layouts/Error.layout'; -import App from './app/App'; -import { NotFountLayout } from './layouts/NotFound.layout'; +import { AppLayout } from './layouts/App.layout'; import { getDemos } from './utils/getDemos'; +import App from './app/App'; export const baseRouter = [ { + element: getDemos(import.meta.glob('~/transition/demo/*.tsx')), name: 'transition 动画', path: '/transition', - element: getDemos(import.meta.glob('~/transition/demo/*.tsx')), }, { + element: getDemos(import.meta.glob('~/transition-group/demo/*.tsx')), name: 'transition-group 动画组', path: '/transition-group', - element: getDemos(import.meta.glob('~/transition-group/demo/*.tsx')), }, { + element: getDemos(import.meta.glob('~/loading/demo/*.tsx')), name: 'loading 加载中', path: '/loading', - element: getDemos(import.meta.glob('~/loading/demo/*.tsx')), }, { + element: getDemos(import.meta.glob('~/button/demo/*.tsx')), name: 'button 按钮', path: '/button', - element: getDemos(import.meta.glob('~/button/demo/*.tsx')), }, { + element: getDemos(import.meta.glob('~/layouts/demo/*.tsx')), name: 'layout 布局', path: '/layout', - element: getDemos(import.meta.glob('~/layouts/demo/*.tsx')), }, { + element: getDemos(import.meta.glob('~/divider/demo/*.tsx')), name: 'divider 分割线', path: '/divider', - element: getDemos(import.meta.glob('~/divider/demo/*.tsx')), }, { + element: getDemos(import.meta.glob('~/dialog/demo/*.tsx')), name: 'dialog 弹窗', path: '/dialog', - element: getDemos(import.meta.glob('~/dialog/demo/*.tsx')), }, { + element: getDemos(import.meta.glob('~/icon/demo/*.tsx')), name: 'icon 图标', path: '/icon', - element: getDemos(import.meta.glob('~/icon/demo/*.tsx')), }, { + element: getDemos(import.meta.glob('~/space/demo/*.tsx')), name: 'space 间距', path: '/space', - element: getDemos(import.meta.glob('~/space/demo/*.tsx')), }, { + element: getDemos(import.meta.glob('~/resizer/demo/*.tsx')), name: 'resizer 修改宽高', path: '/resizer', - element: getDemos(import.meta.glob('~/resizer/demo/*.tsx')), }, { + element: getDemos(import.meta.glob('~/drawer/demo/*.tsx')), name: 'drawer 抽屉', path: '/drawer', - element: getDemos(import.meta.glob('~/drawer/demo/*.tsx')), }, { + element: getDemos(import.meta.glob('~/message/demo/*.tsx')), name: 'message 信息', path: '/message', - element: getDemos(import.meta.glob('~/message/demo/*.tsx')), }, { + element: getDemos(import.meta.glob('~/word-balloon/demo/*.tsx')), name: 'word-balloon 文字气泡', path: '/word-balloon', - element: getDemos(import.meta.glob('~/word-balloon/demo/*.tsx')), }, { + element: getDemos(import.meta.glob('~/popover/demo/*.tsx')), name: 'popover 弹出层', path: '/popover', - element: getDemos(import.meta.glob('~/popover/demo/*.tsx')), }, { + element: getDemos(import.meta.glob('~/tooltip/demo/*.tsx')), name: 'tooltip 文字提示', path: '/tooltip', - element: getDemos(import.meta.glob('~/tooltip/demo/*.tsx')), }, { + element: getDemos(import.meta.glob('~/pop-confirm/demo/*.tsx')), name: 'pop-confirm 弹出确认框', path: '/pop-confirm', - element: getDemos(import.meta.glob('~/pop-confirm/demo/*.tsx')), }, { + element: getDemos(import.meta.glob('~/collapse-transition/demo/*.tsx')), name: 'collapse-transition 折叠动画', path: '/collapse-transition', - element: getDemos(import.meta.glob('~/collapse-transition/demo/*.tsx')), }, { + element: getDemos(import.meta.glob('~/collapse/demo/*.tsx')), name: 'collapse 折叠面板', path: '/collapse', - element: getDemos(import.meta.glob('~/collapse/demo/*.tsx')), }, { + element: getDemos(import.meta.glob('~/option/demo/*.tsx')), name: 'option 选项', path: '/option', - element: getDemos(import.meta.glob('~/option/demo/*.tsx')), }, { + element: getDemos(import.meta.glob('~/dropdown/demo/*.tsx')), name: 'dropdown 下拉菜单', path: '/dropdown', - element: getDemos(import.meta.glob('~/dropdown/demo/*.tsx')), }, { + element: getDemos(import.meta.glob('~/number-transition/demo/*.tsx')), name: 'number-transition 数值动画', path: '/number-transition', - element: getDemos(import.meta.glob('~/number-transition/demo/*.tsx')), }, { + element: getDemos(import.meta.glob('~/alert/demo/*.tsx')), name: 'alert 提示', path: '/alert', - element: getDemos(import.meta.glob('~/alert/demo/*.tsx')), }, { + element: getDemos(import.meta.glob('~/switch/demo/*.tsx')), name: 'switch 开关', path: '/switch', - element: getDemos(import.meta.glob('~/switch/demo/*.tsx')), }, { + element: getDemos(import.meta.glob('~/tag/demo/*.tsx')), name: 'tag 标签', path: '/tag', - element: getDemos(import.meta.glob('~/tag/demo/*.tsx')), }, { + element: getDemos(import.meta.glob('~/select/demo/*.tsx')), name: 'select 选择器', path: '/select', - element: getDemos(import.meta.glob('~/select/demo/*.tsx')), }, /*insert target*/ ]; export const router = createBrowserRouter([ { - path: '', - element: , - errorElement: , children: [ { - path: '/', element: , + path: '/', }, ...baseRouter, ], + errorElement: , + element: , + path: '', }, { - path: '*', element: , + path: '*', }, ]); diff --git a/internal/playground/src/utils/getDemos.tsx b/internal/playground/src/utils/getDemos.tsx index 64e3e3c7..2e41f796 100644 --- a/internal/playground/src/utils/getDemos.tsx +++ b/internal/playground/src/utils/getDemos.tsx @@ -1,5 +1,5 @@ import { Divider, Space } from '@tool-pack/react-ui'; -import React, { Suspense, useEffect } from 'react'; +import React, { useEffect, Suspense } from 'react'; import { debounce } from '@tool-pack/basic'; const scrollToHash = debounce(() => { @@ -37,7 +37,7 @@ export function getDemos(demos: Record) { })} - +

    Demo

    diff --git a/internal/playground/vite.config.ts b/internal/playground/vite.config.ts index fa3878a6..84459277 100644 --- a/internal/playground/vite.config.ts +++ b/internal/playground/vite.config.ts @@ -14,7 +14,6 @@ const components = Fs.readdirSync( */ export default defineConfig(() => { return { - cacheDir: `./.cache`, resolve: { alias: { ...pkgs.reduce( @@ -48,11 +47,12 @@ export default defineConfig(() => { // https://github.com/vitejs/vite/tree/main/packages/plugin-react react(), ], - build: { - sourcemap: true, - }, css: { devSourcemap: true, }, + build: { + sourcemap: true, + }, + cacheDir: `./.cache`, }; }); diff --git a/package.json b/package.json index e3d543f3..9a1803f8 100644 --- a/package.json +++ b/package.json @@ -81,6 +81,7 @@ "enquirer": "^2.4.1", "eslint": "^8.47.0", "eslint-config-prettier": "^9.0.0", + "eslint-plugin-perfectionist": "^2.1.0", "eslint-plugin-prettier": "^5.0.0", "esno": "^0.17.0", "execa": "^8.0.1", diff --git a/packages/components/src/alert/Alert.tsx b/packages/components/src/alert/Alert.tsx index 8013ec2d..ed999b14 100644 --- a/packages/components/src/alert/Alert.tsx +++ b/packages/components/src/alert/Alert.tsx @@ -1,19 +1,19 @@ -import React, { useState } from 'react'; -import type { AlertProps } from './alert.types'; -import { getClasses } from '@pkg/shared'; -import type { RequiredPart } from '@tool-pack/types'; -import { getClassNames } from '@tool-pack/basic'; -import { Icon } from '~/icon'; import { - CircleInfoFill, + Close as CloseIcon, CircleWarningFill, - CircleCloseFill, CircleSuccessFill, + CircleCloseFill, + CircleInfoFill, CircleInfo, - Close as CloseIcon, } from '@pkg/icons'; -import { Button } from '~/button'; import { CollapseTransition } from '~/collapse-transition'; +import type { RequiredPart } from '@tool-pack/types'; +import { getClassNames } from '@tool-pack/basic'; +import type { AlertProps } from './alert.types'; +import { getClasses } from '@pkg/shared'; +import React, { useState } from 'react'; +import { Button } from '~/button'; +import { Icon } from '~/icon'; const cls = getClasses( 'alert', @@ -22,23 +22,23 @@ const cls = getClasses( ); const defaultProps = { type: 'primary', - bordered: true, closable: false, + bordered: true, } satisfies Partial; const Icons: Record['type'], React.FC> = { - primary: CircleInfo, - info: CircleInfoFill, warning: CircleWarningFill, - error: CircleCloseFill, success: CircleSuccessFill, + error: CircleCloseFill, + info: CircleInfoFill, + primary: CircleInfo, }; export const Alert: React.FC = React.forwardRef< HTMLDivElement, AlertProps >((props, ref) => { - const { attrs, icon, type, title, bordered, closable, onClose, children } = + const { bordered, closable, children, onClose, attrs, title, icon, type } = props as RequiredPart; const [visible, setVisible] = useState(true); @@ -47,12 +47,13 @@ export const Alert: React.FC = React.forwardRef< const Body = (
    + [cls['--'].centered]: title && !children, + [cls['--'].bordered]: bordered, + })} + ref={ref} + > {icon !== null && ( {icon || } )} @@ -63,9 +64,10 @@ export const Alert: React.FC = React.forwardRef< {closable && (
, ); @@ -121,7 +121,7 @@ describe('Button', () => { test('loading right-icon', () => { expect( render( - , ).container.firstChild, diff --git a/packages/components/src/button/__tests__/ButtonContext.test.tsx b/packages/components/src/button/__tests__/ButtonContext.test.tsx index ae93a563..a5a0a3a5 100644 --- a/packages/components/src/button/__tests__/ButtonContext.test.tsx +++ b/packages/components/src/button/__tests__/ButtonContext.test.tsx @@ -1,5 +1,5 @@ +import { ButtonContext, ButtonGroup, Button } from '..'; import { render } from '@testing-library/react'; -import { Button, ButtonGroup, ButtonContext } from '..'; describe('ButtonContext', () => { test('size', () => { diff --git a/packages/components/src/button/__tests__/ButtonGroup.test.tsx b/packages/components/src/button/__tests__/ButtonGroup.test.tsx index 437011ff..7d4acd58 100644 --- a/packages/components/src/button/__tests__/ButtonGroup.test.tsx +++ b/packages/components/src/button/__tests__/ButtonGroup.test.tsx @@ -1,5 +1,5 @@ import { render } from '@testing-library/react'; -import { Button, ButtonGroup } from '..'; +import { ButtonGroup, Button } from '..'; describe('ButtonGroup', () => { test('size', () => { diff --git a/packages/components/src/button/__tests__/__snapshots__/Button.test.tsx.snap b/packages/components/src/button/__tests__/__snapshots__/Button.test.tsx.snap index 8a5cbbf7..2200b39f 100644 --- a/packages/components/src/button/__tests__/__snapshots__/Button.test.tsx.snap +++ b/packages/components/src/button/__tests__/__snapshots__/Button.test.tsx.snap @@ -2,7 +2,7 @@ exports[`Button base 1`] = ` ))} @@ -45,14 +45,16 @@ const App: React.FC = () => { + vertical + > ({String(plain)}): {types.map((type) => ( ))} @@ -65,11 +67,12 @@ const App: React.FC = () => { {types.map((type) => ( ))} @@ -84,8 +87,9 @@ const App: React.FC = () => { key={size + '_' + shape} onClick={addTimes} type="primary" + shape={shape} size={size} - shape={shape}> + > {shape} )), @@ -100,11 +104,12 @@ const Layout: React.FC[0]> = React.memo( + }} + > {props.children} ), diff --git a/packages/components/src/button/demo/disabled.tsx b/packages/components/src/button/demo/disabled.tsx index 610cefd4..8a1f6d19 100644 --- a/packages/components/src/button/demo/disabled.tsx +++ b/packages/components/src/button/demo/disabled.tsx @@ -3,8 +3,8 @@ * description: 添加 `disabled` 属性即可让按钮处于不可用状态,同时按钮样式也会改变。 */ +import { Layout as OriginLayout, Button } from '@tool-pack/react-ui'; import React from 'react'; -import { Button, Layout as OriginLayout } from '@tool-pack/react-ui'; const App: React.FC = () => ( @@ -26,11 +26,12 @@ const Layout: React.FC[0]> = React.memo( + }} + > {props.children} ), diff --git a/packages/components/src/button/demo/group.tsx b/packages/components/src/button/demo/group.tsx index 1cdf1328..66a4b3c0 100644 --- a/packages/components/src/button/demo/group.tsx +++ b/packages/components/src/button/demo/group.tsx @@ -2,32 +2,32 @@ * title: 按钮组 */ -import React from 'react'; import { + ButtonContext, + ButtonGroup, Button, Icons, - ButtonGroup, - ButtonContext, Space, Icon, } from '@tool-pack/react-ui'; +import React from 'react'; const App: React.FC = () => { const btns = [ - , - , - , - - - @@ -123,12 +124,13 @@ const App: React.FC = () => { + }} + > - diff --git a/packages/components/src/button/demo/icon.tsx b/packages/components/src/button/demo/icon.tsx index 56639260..89f4afcf 100644 --- a/packages/components/src/button/demo/icon.tsx +++ b/packages/components/src/button/demo/icon.tsx @@ -2,26 +2,26 @@ * title: 图标按钮 */ +import { Divider, Button, Icons, Space, Icon } from '@tool-pack/react-ui'; import React from 'react'; -import { Button, Icons, Space, Divider, Icon } from '@tool-pack/react-ui'; const App: React.FC = () => { return ( <> - - - - - - - diff --git a/packages/components/src/button/demo/shape.tsx b/packages/components/src/button/demo/shape.tsx index 290e36f5..412fe6d7 100644 --- a/packages/components/src/button/demo/shape.tsx +++ b/packages/components/src/button/demo/shape.tsx @@ -3,21 +3,22 @@ * description: 按钮有`none` `default` `round` `circle` 4种形状。 */ -import React from 'react'; import { Button, Layout } from '@tool-pack/react-ui'; +import React from 'react'; const App: React.FC = () => ( + overflow: 'visible', + flexWrap: 'wrap', + gap: '8px', + }} + > - diff --git a/packages/components/src/button/demo/size.tsx b/packages/components/src/button/demo/size.tsx index 756b10aa..eed81fa7 100644 --- a/packages/components/src/button/demo/size.tsx +++ b/packages/components/src/button/demo/size.tsx @@ -3,17 +3,18 @@ * description: 按钮有大、中、小三种尺寸。
通过设置 `size` 为 `large` `medium` `small` 分别把按钮设为大、中、小尺寸。若不设置 `size`,则尺寸为中。 */ -import React from 'react'; import { Button, Layout } from '@tool-pack/react-ui'; +import React from 'react'; const App: React.FC = () => ( + overflow: 'visible', + flexWrap: 'wrap', + gap: '8px', + }} + > diff --git a/packages/components/src/button/demo/type.tsx b/packages/components/src/button/demo/type.tsx index 2bec3410..82b8069f 100644 --- a/packages/components/src/button/demo/type.tsx +++ b/packages/components/src/button/demo/type.tsx @@ -3,11 +3,11 @@ * description: 按钮有六种类型:默认按钮、主按钮、成功按钮、信息按钮、警告按钮和危险按钮。主按钮在同一个操作区域最多出现一次。 */ -import React from 'react'; import { Button, Layout } from '@tool-pack/react-ui'; +import React from 'react'; const App: React.FC = () => ( - + diff --git a/packages/components/src/collapse-transition/CollapseTransition.tsx b/packages/components/src/collapse-transition/CollapseTransition.tsx index a4d10e0b..f88a30a0 100644 --- a/packages/components/src/collapse-transition/CollapseTransition.tsx +++ b/packages/components/src/collapse-transition/CollapseTransition.tsx @@ -1,27 +1,27 @@ -import React, { useCallback, useMemo, useRef } from 'react'; -import type { CollapseTransitionProps } from './collapse-transition.types'; -import { getComponentClass } from '@pkg/shared'; -import type { RequiredPart } from '@tool-pack/types'; -import { getClassNames } from '@tool-pack/basic'; import { - Transition, TRANSITION_LIFE_CIRCLE, TRANSITION_STATUS, TransitionCB, + Transition, } from '../transition'; +import type { CollapseTransitionProps } from './collapse-transition.types'; +import React, { useCallback, useMemo, useRef } from 'react'; +import type { RequiredPart } from '@tool-pack/types'; +import { getClassNames } from '@tool-pack/basic'; +import { getComponentClass } from '@pkg/shared'; const rootName = getComponentClass('collapse-transition'); export const CollapseTransition: React.FC = ( props, ) => { - const { width, on, children, ...rest } = props as RequiredPart< + const { children, width, on, ...rest } = props as RequiredPart< CollapseTransitionProps, keyof typeof defaultProps >; const memorizedSize = useRef(''); - const sizeType: 'maxWidth' | 'maxHeight' = useMemo( + const sizeType: 'maxHeight' | 'maxWidth' = useMemo( () => (width ? 'maxWidth' : 'maxHeight'), [width], ); @@ -105,15 +105,15 @@ export const CollapseTransition: React.FC = ( const Body = React.isValidElement(children) ? React.cloneElement(children as React.ReactElement, { - key: rootName, className: getClassNames( rootName, (children as React.ReactElement).props.className, { - [`${rootName}--w`]: width, [`${rootName}--h`]: !width, + [`${rootName}--w`]: width, }, ), + key: rootName, }) : children; diff --git a/packages/components/src/collapse-transition/__tests__/CollapseTransition.test.tsx b/packages/components/src/collapse-transition/__tests__/CollapseTransition.test.tsx index 6a8a30c8..5645711d 100644 --- a/packages/components/src/collapse-transition/__tests__/CollapseTransition.test.tsx +++ b/packages/components/src/collapse-transition/__tests__/CollapseTransition.test.tsx @@ -1,7 +1,7 @@ -import { render, fireEvent } from '@testing-library/react'; -import Demo from '../demo/basic'; +import { fireEvent, render } from '@testing-library/react'; import { testAttrs } from '~/testAttrs'; import { CollapseTransition } from '..'; +import Demo from '../demo/basic'; describe('CollapseTransition', () => { testAttrs(({ attrs }) => ( diff --git a/packages/components/src/collapse-transition/__tests__/__snapshots__/CollapseTransition.test.tsx.snap b/packages/components/src/collapse-transition/__tests__/__snapshots__/CollapseTransition.test.tsx.snap index 0bea5495..95bf0901 100644 --- a/packages/components/src/collapse-transition/__tests__/__snapshots__/CollapseTransition.test.tsx.snap +++ b/packages/components/src/collapse-transition/__tests__/__snapshots__/CollapseTransition.test.tsx.snap @@ -8,7 +8,7 @@ exports[`CollapseTransition basic 1`] = ` style="padding-bottom: 8px; text-align: center;" > + onClose={hide} + resizeable + > body

华丽的分割线