diff --git a/.dumirc.ts b/.dumirc.ts index 9b28d80..11706cb 100644 --- a/.dumirc.ts +++ b/.dumirc.ts @@ -1,16 +1,16 @@ -import { defineConfig } from 'dumi' +import { defineConfig } from 'dumi' import { resolve } from 'path' export default defineConfig({ themeConfig: { - name: 'Nova', + name: 'RustUI', logo: false, nav: [ { title: '指南', link: '/guide' }, { title: '组件', link: '/components' }, ], socialLinks: { - github: 'https://github.com/donghym/PikaUI', + github: 'https://github.com/donghym/RustUI', }, sidebarGroupModePath: true, }, @@ -23,12 +23,12 @@ export default defineConfig({ { type: 'component', dir: 'src/components/layout' }, { type: 'component', dir: 'src/components/nav' }, { type: 'component', dir: 'src/components/entry' }, - { type: 'component', dir: 'src/components/feedback' }, { type: 'component', dir: 'src/components/display' }, + { type: 'component', dir: 'src/components/feedback' }, ], }, alias: { - '@Pika/ui': resolve(__dirname, 'src'), + 'RustUI': resolve(__dirname, 'src'), }, outputPath: 'dist-docs', }) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..85c7302 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 RustUI Contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index e69de29..961d135 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,422 @@ +# RustUI + +A modern React component library. + +## Install + +```bash +npm install rustui +``` + +```bash +pnpm add rustui +``` + +```bash +yarn add rustui +``` + +## Usage + +```tsx +import { Button, Input, Modal } from 'rustui' +import 'rustui/styles' + +function App() { + return ( +
+ + +
+ ) +} +``` + +## Theme + +RustUI supports light and dark themes via `ConfigProvider`: + +```tsx +import { ConfigProvider } from 'rustui' + +function App() { + return ( + + {/* your app */} + + ) +} +``` + +## Components + +### Common + +| Component | Description | +|-----------|-------------| +| `Button` | Button component with multiple variants and sizes | +| `Icon` | Icon component with 100+ built-in icons | +| `Typography` | Typography with Text, Title, Paragraph, Link | +| `Affix` | Affix component to fix element on scroll | +| `Anchor` | Anchor navigation with links | +| `App` | App wrapper providing Message, Modal, Notification context | +| `BackTop` | Back to top button | +| `ConfigProvider` | Global configuration provider for theme and locale | +| `FloatButton` | Floating action button with group support | +| `Watermark` | Watermark overlay | + +### Layout + +| Component | Description | +|-----------|-------------| +| `Layout` | Page layout with Header, Footer, Content, Sider | +| `Divider` | Divider line | +| `Flex` | Flexbox layout | +| `HStack` | Horizontal stack layout | +| `VStack` | Vertical stack layout | +| `Row` / `Col` | Grid system with 24 columns | +| `Masonry` | Masonry/waterfall layout | +| `Space` | Consistent spacing between elements | +| `Splitter` | Resizable split panels | +| `Stack` | Stack layout | + +### Navigation + +| Component | Description | +|-----------|-------------| +| `Breadcrumb` | Breadcrumb navigation | +| `Dropdown` | Dropdown menu | +| `Menu` | Navigation menu | +| `Pagination` | Pagination controls | +| `Steps` | Step-by-step navigation | +| `Tabs` | Tabbed content | + +### Data Entry + +| Component | Description | +|-----------|-------------| +| `Form` | Form with validation support | +| `Input` | Text input with password and search variants | +| `TextArea` | Multi-line text input | +| `InputNumber` | Numeric input with step controls | +| `AutoComplete` | Input with autocomplete suggestions | +| `Select` | Dropdown selector | +| `Cascader` | Cascading selector | +| `TreeSelect` | Tree-structured selector | +| `Checkbox` | Checkbox with group support | +| `Radio` | Radio button with group support | +| `Switch` | Toggle switch | +| `Slider` | Slider input | +| `Transfer` | Dual-list transfer | +| `DatePicker` | Date picker | +| `RangePicker` | Date range picker | +| `TimePicker` | Time picker | +| `Upload` | File upload with drag support | +| `Rate` | Star rating | +| `Mention` | @ mention input | + +### Feedback + +| Component | Description | +|-----------|-------------| +| `Alert` | Alert banner | +| `Drawer` | Side drawer panel | +| `Message` | Global message toast | +| `Modal` | Dialog modal | +| `Notification` | Notification notification box | +| `Popconfirm` | Popover confirmation | +| `Progress` | Progress indicator | +| `Result` | Result page | +| `Skeleton` | Content placeholder skeleton | +| `Spin` | Loading spinner | + +### Display + +| Component | Description | +|-----------|-------------| +| `Avatar` / `AvatarGroup` | User avatar with group | +| `Badge` / `BadgeRibbon` | Status badge and ribbon | +| `Tag` / `CheckableTag` | Tag label | +| `Tooltip` | Tooltip on hover | +| `Popover` | Popover card | +| `Card` / `CardGrid` / `CardMeta` | Content card | +| `Empty` | Empty state placeholder | +| `Statistic` / `StatisticTimer` | Statistic number display | +| `Collapse` | Collapsible panels | +| `Timeline` | Timeline display | +| `Descriptions` | Key-value description list | +| `Segmented` | Segmented control | +| `Table` | Data table with sorting, filtering, selection | +| `Tree` | Tree view | +| `Carousel` | Image/content carousel | +| `Image` / `ImagePreviewGroup` | Image with preview | +| `Calendar` | Calendar view | +| `QRCode` | QR code generator | +| `Tour` | Guided tour | +| `List` | Data list | + +## API Reference + +### Button + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `variant` | `'primary' \| 'default' \| 'dashed' \| 'text' \| 'link'` | `'default'` | Button style variant | +| `size` | `'small' \| 'middle' \| 'large'` | `'middle'` | Button size | +| `disabled` | `boolean` | `false` | Whether the button is disabled | +| `loading` | `boolean` | `false` | Show loading spinner | +| `danger` | `boolean` | `false` | Danger style | +| `block` | `boolean` | `false` | Full width button | +| `icon` | `ReactNode` | - | Icon element | +| `onClick` | `(e: MouseEvent) => void` | - | Click handler | + +### Input + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `value` | `string` | - | Input value (controlled) | +| `defaultValue` | `string` | - | Default value | +| `placeholder` | `string` | - | Placeholder text | +| `size` | `'small' \| 'middle' \| 'large'` | `'middle'` | Input size | +| `status` | `'default' \| 'error' \| 'warning'` | `'default'` | Validation status | +| `disabled` | `boolean` | `false` | Whether the input is disabled | +| `readOnly` | `boolean` | `false` | Read only | +| `prefix` | `ReactNode` | - | Prefix icon/element | +| `suffix` | `ReactNode` | - | Suffix icon/element | +| `onChange` | `(e: ChangeEvent) => void` | - | Change handler | + +### Modal + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `open` | `boolean` | `false` | Whether the modal is visible | +| `title` | `ReactNode` | - | Modal title | +| `footer` | `ReactNode \| null` | - | Footer content, `null` to hide | +| `size` | `'small' \| 'middle' \| 'large'` | `'middle'` | Modal size | +| `closable` | `boolean` | `true` | Show close button | +| `centered` | `boolean` | `false` | Vertically center the modal | +| `mask` | `boolean` | `true` | Show mask overlay | +| `maskClosable` | `boolean` | `true` | Close on mask click | +| `keyboard` | `boolean` | `true` | Close on ESC key | +| `confirmLoading` | `boolean` | `false` | Loading state for confirm button | +| `okText` | `ReactNode` | - | Confirm button text | +| `cancelText` | `ReactNode` | - | Cancel button text | +| `onOk` | `(e: MouseEvent) => void` | - | Confirm handler | +| `onCancel` | `(e: MouseEvent) => void` | - | Cancel handler | + +### Form + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `initialValues` | `Record` | - | Initial form values | +| `onFinish` | `(values: Record) => void` | - | Submit handler (validation passed) | +| `onFinishFailed` | `(errors: FormErrorInfo) => void` | - | Submit handler (validation failed) | +| `layout` | `'horizontal' \| 'vertical' \| 'inline'` | `'horizontal'` | Form layout | + +#### Form.Item + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `name` | `string` | - | Field name | +| `label` | `ReactNode` | - | Field label | +| `rules` | `ValidationRule[]` | - | Validation rules | +| `required` | `boolean` | `false` | Whether the field is required | + +### Select + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `value` | `string \| string[]` | - | Selected value (controlled) | +| `options` | `SelectOption[]` | - | Options list | +| `mode` | `'single' \| 'multiple' \| 'tags'` | `'single'` | Selection mode | +| `placeholder` | `string` | - | Placeholder text | +| `size` | `'small' \| 'middle' \| 'large'` | `'middle'` | Select size | +| `disabled` | `boolean` | `false` | Whether the select is disabled | +| `showSearch` | `boolean` | `false` | Enable search filtering | +| `showClear` | `boolean` | `false` | Show clear button | +| `onChange` | `(value, option) => void` | - | Change handler | + +### Table + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `dataSource` | `T[]` | `[]` | Data array | +| `columns` | `ColumnType[]` | - | Column definitions | +| `size` | `'small' \| 'middle' \| 'large'` | `'middle'` | Table size | +| `variant` | `'bordered' \| 'borderless'` | `'bordered'` | Table variant | +| `loading` | `boolean` | `false` | Loading state | +| `rowKey` | `string \| ((record) => string)` | - | Row key field | +| `rowSelection` | `RowSelectionConfig` | - | Row selection config | +| `pagination` | `PaginationConfig \| false` | - | Pagination config | + +### Message + +```tsx +import { Message } from 'rustui' + +Message.success('Operation completed') +Message.error('Something went wrong') +Message.warning('Warning message') +Message.info('Info message') +Message.loading('Loading...') +``` + +| Method | Description | +|--------|-------------| +| `Message.success(content, duration?)` | Success message | +| `Message.error(content, duration?)` | Error message | +| `Message.warning(content, duration?)` | Warning message | +| `Message.info(content, duration?)` | Info message | +| `Message.loading(content, duration?)` | Loading message | + +### Notification + +```tsx +import { Notification } from 'rustui' + +Notification.open({ message: 'Title', description: 'Description' }) +Notification.success({ message: 'Success', description: 'Operation completed' }) +``` + +### Icon + +RustUI includes 100+ built-in icons. All icons follow the `XxxOutlined` / `XxxFilled` / `XxxTwoTone` naming convention: + +```tsx +import { SearchOutlined, StarFilled, HeartTwoTone } from 'rustui' + + + + +``` + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `spin` | `boolean` | `false` | Rotate icon animation | +| `rotate` | `number` | `0` | Rotation degrees | +| `style` | `CSSProperties` | - | Custom styles | +| `onClick` | `(e: MouseEvent) => void` | - | Click handler | + +Custom icon from SVG: + +```tsx +import { Icon } from 'rustui' + +const SvgIcon = () => ( + ...} /> +) +``` + +Icon from iconfont: + +```tsx +import { createFromIconfontCN } from 'rustui' + +const IconFont = createFromIconfontCN({ + scriptUrl: '//at.alicdn.com/t/font_xxx.js' +}) +``` + +### ConfigProvider + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `theme` | `'light' \| 'dark'` | `'light'` | Theme mode | +| `locale` | `Locale` | - | Locale configuration | +| `prefixCls` | `string` | - | CSS class prefix | + +### DatePicker + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `value` | `string \| null` | - | Selected date value (controlled), format `YYYY-MM-DD` | +| `defaultValue` | `string \| null` | - | Default date value | +| `placeholder` | `string` | `'选择日期'` | Placeholder text | +| `size` | `'small' \| 'middle' \| 'large'` | `'middle'` | Picker size | +| `status` | `'default' \| 'error' \| 'warning'` | `'default'` | Validation status | +| `disabled` | `boolean` | `false` | Whether the picker is disabled | +| `showTime` | `boolean` | `false` | Show time selection | +| `disabledDate` | `(date: Date) => boolean` | - | Disable specific dates | +| `onChange` | `(value: string, date: Date) => void` | - | Date change handler | + +### Upload + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `action` | `string` | - | Upload URL | +| `method` | `string` | `'post'` | HTTP method | +| `accept` | `string` | - | Accepted file types | +| `multiple` | `boolean` | `false` | Allow multiple file selection | +| `draggable` | `boolean` | `false` | Enable drag-and-drop upload | +| `disabled` | `boolean` | `false` | Whether the upload is disabled | +| `size` | `'small' \| 'middle' \| 'large'` | `'middle'` | Upload area size | +| `showUploadList` | `boolean` | `true` | Show file list | +| `fileList` | `UploadFile[]` | - | File list (controlled) | +| `defaultFileList` | `UploadFile[]` | `[]` | Default file list | +| `maxCount` | `number` | - | Max upload count | +| `onChange` | `(file: UploadFile, fileList: UploadFile[]) => void` | - | File status change handler | +| `onRemove` | `(file: UploadFile) => boolean \| void` | - | File remove handler, return `false` to prevent | +| `beforeUpload` | `(file: File, fileList: File[]) => boolean \| void \| Promise` | - | Pre-upload hook, return `false` to cancel | + +#### UploadFile + +| Field | Type | Description | +|-------|------|-------------| +| `uid` | `string` | Unique file identifier | +| `name` | `string` | File name | +| `status` | `'pending' \| 'uploading' \| 'success' \| 'error'` | Upload status | +| `percent` | `number` | Upload progress (0-100) | +| `url` | `string` | File access URL | +| `response` | `unknown` | Upload response data | +| `error` | `string` | Error message | + +### Drawer + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `open` | `boolean` | `false` | Whether the drawer is visible | +| `title` | `ReactNode` | - | Drawer title | +| `footer` | `ReactNode \| null` | - | Footer content, `null` to hide | +| `placement` | `'top' \| 'right' \| 'bottom' \| 'left'` | `'right'` | Drawer placement | +| `size` | `'small' \| 'middle' \| 'large'` | `'middle'` | Drawer size (378/480/736px) | +| `width` | `number \| string` | - | Custom width (for left/right placement) | +| `height` | `number \| string` | - | Custom height (for top/bottom placement) | +| `closable` | `boolean` | `true` | Show close button | +| `closeIcon` | `ReactNode` | - | Custom close icon | +| `mask` | `boolean` | `true` | Show mask overlay | +| `maskClosable` | `boolean` | `true` | Close on mask click | +| `keyboard` | `boolean` | `true` | Close on ESC key | +| `loading` | `boolean` | `false` | Loading state | +| `extra` | `ReactNode` | - | Extra content in header | +| `destroyOnClose` | `boolean` | `false` | Destroy content when closed | +| `forceRender` | `boolean` | `false` | Force render content even when hidden | +| `push` | `boolean \| { distance?: number \| string }` | `false` | Push behavior when nested drawers | +| `zIndex` | `number` | - | Z-index of the drawer | +| `onClose` | `(e: MouseEvent) => void` | - | Close handler | +| `afterOpenChange` | `(open: boolean) => void` | - | Callback after open state changed | + +## Development + +```bash +# Install dependencies +pnpm install + +# Start dev server +pnpm dev + +# Build +pnpm build + +# Run tests +pnpm test + +# Lint +pnpm lint + +# Format +pnpm format +``` + +## License + +MIT diff --git a/docs/components/index.md b/docs/components/index.md index 67c52aa..908784e 100644 --- a/docs/components/index.md +++ b/docs/components/index.md @@ -1,4 +1,4 @@ ---- +--- nav: 组件 title: 组件总览 --- @@ -299,7 +299,7 @@ title: 组件总览 # 组件总览 -Pika UI 提供了丰富的组件库,覆盖通用、布局、导航、数据录入、数据展示和反馈等场景。 +RustUI 提供了丰富的组件库,覆盖通用、布局、导航、数据录入、数据展示和反馈等场景。 ## 通用 10 个组件 @@ -415,8 +415,8 @@ Pika UI 提供了丰富的组件库,覆盖通用、布局、导航、数据录
- Pika - Pika + RustUI + RustUI Content Area
diff --git a/docs/guide/getting-started.md b/docs/guide/getting-started.md index 1c2a907..43ea192 100644 --- a/docs/guide/getting-started.md +++ b/docs/guide/getting-started.md @@ -1,4 +1,4 @@ ---- +--- nav: 指南 title: 快速开始 --- @@ -8,21 +8,21 @@ title: 快速开始 ## 安装 ```bash -npm install @Pika/ui +npm install rustui ``` ## 使用 ```tsx -import { Button } from '@Pika/ui' +import { Button } from 'RustUI' export default () => ( ) ``` ## 主题 -Pika UI 支持通过 CSS 变量进行主题定制。 +RustUI 支持通过 CSS 变量进行主题定制。 diff --git a/docs/guide/introduce.en-US.md b/docs/guide/introduce.en-US.md index e2fa5a4..c1973a5 100644 --- a/docs/guide/introduce.en-US.md +++ b/docs/guide/introduce.en-US.md @@ -1,9 +1,9 @@ ---- +--- nav: Guide title: Introduction --- -# Pika UI +# RustUI AI-Native component library for modern visualization. @@ -17,19 +17,19 @@ AI-Native component library for modern visualization. ## Installation ```bash -npm install @Pika/ui +npm install rustui # or -pnpm add @Pika/ui +pnpm add rustui ``` ## Quick Start ```tsx -import { Button } from '@Pika/ui' +import { Button } from 'RustUI' export default () => ( ) ``` diff --git a/docs/guide/introduce.md b/docs/guide/introduce.md index 387cb50..18def4f 100644 --- a/docs/guide/introduce.md +++ b/docs/guide/introduce.md @@ -1,9 +1,9 @@ ---- +--- nav: 指南 title: 介绍 --- -# Pika UI +# RustUI AI-Native 组件库,为现代可视化应用构建而生。 @@ -17,19 +17,19 @@ AI-Native 组件库,为现代可视化应用构建而生。 ## 安装 ```bash -npm install @Pika/ui +npm install rustui # 或 -pnpm add @Pika/ui +pnpm add rustui ``` ## 快速开始 ```tsx -import { Button } from '@Pika/ui' +import { Button } from 'RustUI' export default () => ( ) ``` diff --git a/docs/index.md b/docs/index.md index 652f65a..96ac278 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,7 +1,7 @@ ---- -title: Pika UI +--- +title: RustUI hero: - title: Pika UI + title: RustUI description: AI-Native 组件库,为现代可视化应用构建而生 actions: - text: 开始使用 diff --git a/npminstall-debug.log b/npminstall-debug.log new file mode 100644 index 0000000..47aaa31 --- /dev/null +++ b/npminstall-debug.log @@ -0,0 +1,218 @@ +{ + root: 'F:\\project\\Pika', + registry: 'https://registry.npmmirror.com', + pkgs: [ + { + name: 'npm', + version: 'latest', + type: 'tag', + alias: undefined, + arg: [Result] + } + ], + production: false, + cacheStrict: false, + cacheDir: 'C:\\Users\\donghym\\.npminstall_tarball', + env: { + npm_config_registry: 'https://registry.npmmirror.com', + npm_config_argv: '{"remain":[],"cooked":["--fix-bug-versions","--china","--userconfig=C:\\\\Users\\\\donghym\\\\.cnpmrc","--disturl=https://cdn.npmmirror.com/binaries/node","--registry=https://registry.npmmirror.com","-g","npm"],"original":["--fix-bug-versions","--china","--userconfig=C:\\\\Users\\\\donghym\\\\.cnpmrc","--disturl=https://cdn.npmmirror.com/binaries/node","--registry=https://registry.npmmirror.com","-g","npm"]}', + npm_config_user_agent: 'npminstall/7.12.0 npm/? node/v25.2.1 win32 x64', + npm_config_cache: 'C:\\Users\\donghym\\.npminstall_tarball', + NODE: 'G:\\Program Files (x86)\\node\\node.exe', + npm_node_execpath: 'G:\\Program Files (x86)\\node\\node.exe', + npm_execpath: 'C:\\Users\\donghym\\AppData\\Roaming\\npm\\node_modules\\cnpm\\node_modules\\npminstall\\bin\\install.js', + npm_config_userconfig: 'C:\\Users\\donghym\\.cnpmrc', + npm_config_disturl: 'https://cdn.npmmirror.com/binaries/node', + npm_config_r: 'https://registry.npmmirror.com', + COREPACK_NPM_REGISTRY: 'https://registry.npmmirror.com', + EDGEDRIVER_CDNURL: 'https://npmmirror.com/mirrors/edgedriver', + NODEJS_ORG_MIRROR: 'https://cdn.npmmirror.com/binaries/node', + NVM_NODEJS_ORG_MIRROR: 'https://cdn.npmmirror.com/binaries/node', + PHANTOMJS_CDNURL: 'https://cdn.npmmirror.com/binaries/phantomjs', + CHROMEDRIVER_CDNURL: 'https://cdn.npmmirror.com/binaries/chromedriver', + OPERADRIVER_CDNURL: 'https://cdn.npmmirror.com/binaries/operadriver', + CYPRESS_DOWNLOAD_PATH_TEMPLATE: 'https://cdn.npmmirror.com/binaries/cypress/${version}/${platform}-${arch}/cypress.zip', + ELECTRON_MIRROR: 'https://cdn.npmmirror.com/binaries/electron/', + ELECTRON_BUILDER_BINARIES_MIRROR: 'https://cdn.npmmirror.com/binaries/electron-builder-binaries/', + SASS_BINARY_SITE: 'https://cdn.npmmirror.com/binaries/node-sass', + SWC_BINARY_SITE: 'https://cdn.npmmirror.com/binaries/node-swc', + NWJS_URLBASE: 'https://cdn.npmmirror.com/binaries/nwjs/v', + PUPPETEER_DOWNLOAD_HOST: 'https://cdn.npmmirror.com/binaries/chrome-for-testing', + PUPPETEER_DOWNLOAD_BASE_URL: 'https://cdn.npmmirror.com/binaries/chrome-for-testing', + PUPPETEER_CHROME_DOWNLOAD_BASE_URL: 'https://cdn.npmmirror.com/binaries/chrome-for-testing', + PUPPETEER_CHROME_HEADLESS_SHELL_DOWNLOAD_BASE_URL: 'https://cdn.npmmirror.com/binaries/chrome-for-testing', + PLAYWRIGHT_DOWNLOAD_HOST: 'https://cdn.npmmirror.com/binaries/playwright', + PLAYWRIGHT_CHROMIUM_DOWNLOAD_HOST: 'https://cdn.npmmirror.com/binaries/chrome-for-testing', + SENTRYCLI_CDNURL: 'https://cdn.npmmirror.com/binaries/sentry-cli', + SAUCECTL_INSTALL_BINARY_MIRROR: 'https://cdn.npmmirror.com/binaries/saucectl', + RE2_DOWNLOAD_MIRROR: 'https://cdn.npmmirror.com/binaries/node-re2', + RE2_DOWNLOAD_SKIP_PATH: 'true', + PRISMA_ENGINES_MIRROR: 'https://cdn.npmmirror.com/binaries/prisma', + npm_config_better_sqlite3_binary_host: 'https://cdn.npmmirror.com/binaries/better-sqlite3', + npm_config_isolated_vm_binary_host: 'https://cdn.npmmirror.com/binaries/isolated-vm', + npm_config_keytar_binary_host: 'https://cdn.npmmirror.com/binaries/keytar', + npm_config_sharp_binary_host: 'https://cdn.npmmirror.com/binaries/sharp', + npm_config_sharp_libvips_binary_host: 'https://cdn.npmmirror.com/binaries/sharp-libvips', + npm_config_robotjs_binary_host: 'https://cdn.npmmirror.com/binaries/robotjs', + npm_config_gl_binary_host: 'https://cdn.npmmirror.com/binaries/gl', + RIPGREP_PREBUILT_BINARIES_MIRROR: 'https://registry.npmmirror.com/-/binary/ripgrep-prebuilt' + }, + binaryMirrors: { + ENVS: { + COREPACK_NPM_REGISTRY: 'https://registry.npmmirror.com', + EDGEDRIVER_CDNURL: 'https://npmmirror.com/mirrors/edgedriver', + NODEJS_ORG_MIRROR: 'https://cdn.npmmirror.com/binaries/node', + NVM_NODEJS_ORG_MIRROR: 'https://cdn.npmmirror.com/binaries/node', + PHANTOMJS_CDNURL: 'https://cdn.npmmirror.com/binaries/phantomjs', + CHROMEDRIVER_CDNURL: 'https://cdn.npmmirror.com/binaries/chromedriver', + OPERADRIVER_CDNURL: 'https://cdn.npmmirror.com/binaries/operadriver', + CYPRESS_DOWNLOAD_PATH_TEMPLATE: 'https://cdn.npmmirror.com/binaries/cypress/${version}/${platform}-${arch}/cypress.zip', + ELECTRON_MIRROR: 'https://cdn.npmmirror.com/binaries/electron/', + ELECTRON_BUILDER_BINARIES_MIRROR: 'https://cdn.npmmirror.com/binaries/electron-builder-binaries/', + SASS_BINARY_SITE: 'https://cdn.npmmirror.com/binaries/node-sass', + SWC_BINARY_SITE: 'https://cdn.npmmirror.com/binaries/node-swc', + NWJS_URLBASE: 'https://cdn.npmmirror.com/binaries/nwjs/v', + PUPPETEER_DOWNLOAD_HOST: 'https://cdn.npmmirror.com/binaries/chrome-for-testing', + PUPPETEER_DOWNLOAD_BASE_URL: 'https://cdn.npmmirror.com/binaries/chrome-for-testing', + PUPPETEER_CHROME_DOWNLOAD_BASE_URL: 'https://cdn.npmmirror.com/binaries/chrome-for-testing', + PUPPETEER_CHROME_HEADLESS_SHELL_DOWNLOAD_BASE_URL: 'https://cdn.npmmirror.com/binaries/chrome-for-testing', + PLAYWRIGHT_DOWNLOAD_HOST: 'https://cdn.npmmirror.com/binaries/playwright', + PLAYWRIGHT_CHROMIUM_DOWNLOAD_HOST: 'https://cdn.npmmirror.com/binaries/chrome-for-testing', + SENTRYCLI_CDNURL: 'https://cdn.npmmirror.com/binaries/sentry-cli', + SAUCECTL_INSTALL_BINARY_MIRROR: 'https://cdn.npmmirror.com/binaries/saucectl', + RE2_DOWNLOAD_MIRROR: 'https://cdn.npmmirror.com/binaries/node-re2', + RE2_DOWNLOAD_SKIP_PATH: 'true', + PRISMA_ENGINES_MIRROR: 'https://cdn.npmmirror.com/binaries/prisma', + npm_config_better_sqlite3_binary_host: 'https://cdn.npmmirror.com/binaries/better-sqlite3', + npm_config_isolated_vm_binary_host: 'https://cdn.npmmirror.com/binaries/isolated-vm', + npm_config_keytar_binary_host: 'https://cdn.npmmirror.com/binaries/keytar', + npm_config_sharp_binary_host: 'https://cdn.npmmirror.com/binaries/sharp', + npm_config_sharp_libvips_binary_host: 'https://cdn.npmmirror.com/binaries/sharp-libvips', + npm_config_robotjs_binary_host: 'https://cdn.npmmirror.com/binaries/robotjs', + npm_config_gl_binary_host: 'https://cdn.npmmirror.com/binaries/gl', + RIPGREP_PREBUILT_BINARIES_MIRROR: 'https://registry.npmmirror.com/-/binary/ripgrep-prebuilt' + }, + '@ali/s2': { host: 'https://cdn.npmmirror.com/binaries/looksgood-s2' }, + sharp: { replaceHostFiles: [Array], replaceHostMap: [Object] }, + '@tensorflow/tfjs-node': { + replaceHostFiles: [Array], + replaceHostRegExpMap: [Object], + replaceHostMap: [Object] + }, + cypress: { + host: 'https://cdn.npmmirror.com/binaries/cypress', + newPlatforms: [Object] + }, + 'utf-8-validate': { + host: 'https://cdn.npmmirror.com/binaries/utf-8-validate/v{version}' + }, + xprofiler: { + remote_path: './xprofiler/v{version}/', + host: 'https://cdn.npmmirror.com/binaries' + }, + leveldown: { host: 'https://cdn.npmmirror.com/binaries/leveldown/v{version}' }, + couchbase: { host: 'https://cdn.npmmirror.com/binaries/couchbase/v{version}' }, + gl: { host: 'https://cdn.npmmirror.com/binaries/gl/v{version}' }, + sqlite3: { + host: 'https://cdn.npmmirror.com/binaries/sqlite3', + remote_path: 'v{version}' + }, + '@journeyapps/sqlcipher': { host: 'https://cdn.npmmirror.com/binaries' }, + grpc: { + host: 'https://cdn.npmmirror.com/binaries', + remote_path: '{name}/v{version}' + }, + 'grpc-tools': { host: 'https://cdn.npmmirror.com/binaries' }, + wrtc: { + host: 'https://cdn.npmmirror.com/binaries', + remote_path: '{name}/v{version}' + }, + fsevents: { host: 'https://cdn.npmmirror.com/binaries/fsevents' }, + nodejieba: { host: 'https://cdn.npmmirror.com/binaries/nodejieba' }, + canvas: { + host: 'https://cdn.npmmirror.com/binaries/canvas', + remote_path: 'v{version}' + }, + 'skia-canvas': { host: 'https://cdn.npmmirror.com/binaries/skia-canvas' }, + 'flow-bin': { + replaceHost: 'https://github.com/facebook/flow/releases/download/v', + host: 'https://cdn.npmmirror.com/binaries/flow/v' + }, + 'jpegtran-bin': { + replaceHost: [Array], + host: 'https://cdn.npmmirror.com/binaries/jpegtran-bin' + }, + 'cwebp-bin': { + replaceHost: [Array], + host: 'https://cdn.npmmirror.com/binaries/cwebp-bin' + }, + 'zopflipng-bin': { + replaceHost: [Array], + host: 'https://cdn.npmmirror.com/binaries/zopflipng-bin' + }, + 'optipng-bin': { + replaceHost: [Array], + host: 'https://cdn.npmmirror.com/binaries/optipng-bin' + }, + mozjpeg: { + replaceHost: [Array], + host: 'https://cdn.npmmirror.com/binaries/mozjpeg-bin' + }, + gifsicle: { + replaceHost: [Array], + host: 'https://cdn.npmmirror.com/binaries/gifsicle-bin' + }, + 'pngquant-bin': { + replaceHost: [Array], + host: 'https://cdn.npmmirror.com/binaries/pngquant-bin', + replaceHostMap: [Object] + }, + 'pngcrush-bin': { + replaceHost: [Array], + host: 'https://cdn.npmmirror.com/binaries/pngcrush-bin' + }, + 'jpeg-recompress-bin': { + replaceHost: [Array], + host: 'https://cdn.npmmirror.com/binaries/jpeg-recompress-bin' + }, + 'advpng-bin': { + replaceHost: [Array], + host: 'https://cdn.npmmirror.com/binaries/advpng-bin' + }, + 'pngout-bin': { + replaceHost: [Array], + host: 'https://cdn.npmmirror.com/binaries/pngout-bin' + }, + 'jpegoptim-bin': { + replaceHost: [Array], + host: 'https://cdn.npmmirror.com/binaries/jpegoptim-bin' + }, + argon2: { host: 'https://cdn.npmmirror.com/binaries/argon2' }, + 'ali-zeromq': { host: 'https://cdn.npmmirror.com/binaries/ali-zeromq' }, + 'ali-usb_ctl': { host: 'https://cdn.npmmirror.com/binaries/ali-usb_ctl' }, + 'gdal-async': { host: 'https://cdn.npmmirror.com/binaries/node-gdal-async' }, + 'libpg-query': { host: 'https://cdn.npmmirror.com/binaries' } + }, + forbiddenLicenses: null, + flatten: false, + proxy: undefined, + prune: false, + disableFallbackStore: false, + workspacesMap: Map(0) {}, + enableWorkspace: false, + workspaceRoot: 'F:\\project\\Pika', + isWorkspaceRoot: true, + isWorkspacePackage: false, + offline: false, + strictSSL: true, + ignoreScripts: false, + foregroundScripts: false, + ignoreOptionalDependencies: false, + detail: true, + forceLinkLatest: false, + trace: false, + engineStrict: false, + registryOnly: false, + client: false, + autoFixVersion: [Function: autoFixVersion] +} \ No newline at end of file diff --git a/package.json b/package.json index 36a54f8..b36a9df 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { - "name": "@Pika/ui", + "name": "rustui", "version": "0.0.1", - "description": "AI-Native component library for modern visualization", + "description": "RustUI - A modern React component library", "type": "module", "main": "dist/cjs/index.js", "module": "dist/esm/index.js", @@ -11,7 +11,7 @@ "import": "./dist/esm/index.js", "require": "./dist/cjs/index.js" }, - "./styles": "./src/global.css" + "./styles": "./dist/esm/global.css" }, "files": [ "dist" @@ -28,6 +28,7 @@ "lint": "eslint src --ext .ts,.tsx", "format": "prettier --write \"src/**/*.{ts,tsx,css}\"", "prepare": "husky", + "prepublishOnly": "pnpm build", "changeset": "changeset", "release": "changeset publish" }, @@ -44,26 +45,33 @@ "react": ">=18", "react-dom": ">=18" }, + "packageManager": "pnpm@9.15.0", "devEngines": { "packageManager": { "name": "pnpm", - "version": "^11.2.2", - "onFail": "download" + "version": "9.15.0", + "onFail": "warn" } }, "keywords": [ - "Pika", + "rustui", "ui", "components", "react", - "visualization" + "component-library" ], - "author": "", + "author": "donghy.top", "license": "MIT", - "dependencies": { - "@ant-design/icons": "^6.2.5", - "react": "^19.2.6", - "react-dom": "^19.2.6" + "repository": { + "type": "git", + "url": "http://110.42.255.239:3000/admin/RustUI.git" + }, + "bugs": { + "url": "http://110.42.255.239:3000/admin/RustUI/issues" + }, + "homepage": "http://110.42.255.239:3000/admin/RustUI", + "publishConfig": { + "access": "public" }, "devDependencies": { "@changesets/cli": "^2.31.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 162b6ed..606d884 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -207,14 +207,11 @@ importers: .: dependencies: - '@ant-design/icons': - specifier: ^6.2.5 - version: 6.2.5(react-dom@19.2.6(react@19.2.6))(react@19.2.6) react: - specifier: ^19.2.6 + specifier: '>=18' version: 19.2.6 react-dom: - specifier: ^19.2.6 + specifier: '>=18' version: 19.2.6(react@19.2.6) devDependencies: '@changesets/cli': @@ -332,9 +329,6 @@ packages: '@ant-design/colors@7.2.1': resolution: {integrity: sha512-lCHDcEzieu4GA3n8ELeZ5VQ8pKQAWcGGLRTQ50aQM2iqPpq2evTxER84jfdPvsPAtEcZ7m44NI45edFMo8oOYQ==} - '@ant-design/colors@8.0.1': - resolution: {integrity: sha512-foPVl0+SWIslGUtD/xBr1p9U4AKzPhNYEseXYRRo5QSzGACYZrQbe11AYJbYfAWnWSpGBx6JjBmSeugUsD9vqQ==} - '@ant-design/cssinjs-utils@1.1.3': resolution: {integrity: sha512-nOoQMLW1l+xR1Co8NFVYiP8pZp3VjIIzqV6D6ShYF2ljtdwWJn5WSsH+7kvCktXL/yhEtWURKOfH5Xz/gzlwsg==} peerDependencies: @@ -357,10 +351,6 @@ packages: resolution: {integrity: sha512-y2217gk4NqL35giHl72o6Zzqji9O7vHh9YmhUVkPtAOpoTCH4uWxo/pr4VE8t0+ChEPs0qo4eJRC5Q1eXWo3vA==} engines: {node: '>=8.x'} - '@ant-design/fast-color@3.0.1': - resolution: {integrity: sha512-esKJegpW4nckh0o6kV3Tkb7NPIZYbPnnFxmQDUmL08ukXZAvV85TZBr70eGuke/CIArLaP6aw8lt9KILjnWuOw==} - engines: {node: '>=8.x'} - '@ant-design/icons-svg@4.4.2': resolution: {integrity: sha512-vHbT+zJEVzllwP+CM+ul7reTEfBR0vgxFe7+lREAsAA7YGsYpboiq2sQNeQeRvh09GfQgs/GyFEvZpJ9cLXpXA==} @@ -384,13 +374,6 @@ packages: react: '>=16.0.0' react-dom: '>=16.0.0' - '@ant-design/icons@6.2.5': - resolution: {integrity: sha512-0hKtoKqTjGFOndUyJLJmC9Cg6k4rEO7rLo6xmgbNJH+/ZX1C57RVals2v1j1knHl9n7Q+sBOveTvn931wLOCKw==} - engines: {node: '>=8'} - peerDependencies: - react: '>=16.0.0' - react-dom: '>=16.0.0' - '@ant-design/react-slick@1.1.2': resolution: {integrity: sha512-EzlvzE6xQUBrZuuhSAFTdsr4P2bBBHGZwKFemEfq8gIGyIQCxalYfZW/T2ORbtQx5rU69o+WycP3exY/7T1hGA==} peerDependencies: @@ -2077,12 +2060,6 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' - '@rc-component/util@1.11.1': - resolution: {integrity: sha512-awVlI3ub2vqfqkYxOBc/uQ0efm3jw0wcrhtO/YWLyZfxiKXczKwNbVuhlnyxytDt7H9pbbVQiqr+O6MLATtRYg==} - peerDependencies: - react: '>=18.0.0' - react-dom: '>=18.0.0' - '@reactflow/background@11.3.14': resolution: {integrity: sha512-Gewd7blEVT5Lh6jqrvOgd4G6Qk17eGKQfsDXgyRSqM+CTwDqRldG2LsWN4sNeno6sbqVIC2fZ+rAUBFA9ZEUDA==} peerDependencies: @@ -5771,9 +5748,6 @@ packages: resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} engines: {node: '>= 0.4'} - is-mobile@5.0.0: - resolution: {integrity: sha512-Tz/yndySvLAEXh+Uk8liFCxOwVH6YutuR74utvOcu7I9Di+DwM0mtdPVZNaVvvBUM2OXxne/NhOs1zAO7riusQ==} - is-negative-zero@2.0.3: resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} engines: {node: '>= 0.4'} @@ -9475,10 +9449,6 @@ snapshots: dependencies: '@ant-design/fast-color': 2.0.6 - '@ant-design/colors@8.0.1': - dependencies: - '@ant-design/fast-color': 3.0.1 - '@ant-design/cssinjs-utils@1.1.3(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@ant-design/cssinjs': 1.23.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) @@ -9515,8 +9485,6 @@ snapshots: dependencies: '@babel/runtime': 7.29.7 - '@ant-design/fast-color@3.0.1': {} - '@ant-design/icons-svg@4.4.2': {} '@ant-design/icons@4.0.0(react@19.2.6)': @@ -9548,15 +9516,6 @@ snapshots: react: 19.2.6 react-dom: 19.2.6(react@19.2.6) - '@ant-design/icons@6.2.5(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@ant-design/colors': 8.0.1 - '@ant-design/icons-svg': 4.4.2 - '@rc-component/util': 1.11.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - clsx: 2.1.1 - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - '@ant-design/react-slick@1.1.2(react@19.2.6)': dependencies: '@babel/runtime': 7.29.7 @@ -11211,13 +11170,6 @@ snapshots: react: 19.2.6 react-dom: 19.2.6(react@19.2.6) - '@rc-component/util@1.11.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - is-mobile: 5.0.0 - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - react-is: 18.2.0 - '@reactflow/background@11.3.14(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@reactflow/core': 11.11.4(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) @@ -16034,8 +15986,6 @@ snapshots: is-map@2.0.3: {} - is-mobile@5.0.0: {} - is-negative-zero@2.0.3: {} is-number-object@1.1.1: diff --git a/src/components/Button/index.md b/src/components/Button/index.md index 5a3ad7e..e8de41d 100644 --- a/src/components/Button/index.md +++ b/src/components/Button/index.md @@ -1,7 +1,8 @@ ---- -nav: false +--- +nav: 组件 group: 通用 title: Button 按钮 +order: 0 description: 用于触发操作的按钮组件。 --- @@ -14,7 +15,7 @@ description: 用于触发操作的按钮组件。 * title: 基础按钮 * description: 使用 `variant` 切换按钮风格。 */ -import { Button } from '@nova/ui/components/Button' +import { Button } from 'RustUI' export default () => ( ``` diff --git a/src/components/common/Affix/Affix.tsx b/src/components/common/Affix/Affix.tsx index 91866bb..53371f7 100644 --- a/src/components/common/Affix/Affix.tsx +++ b/src/components/common/Affix/Affix.tsx @@ -59,16 +59,7 @@ const Affix: React.FC = ({ if (!wrapperEl || !placeholderEl) return - const wrapperRect = wrapperEl.getBoundingClientRect() - const containerRect = container === window - ? { top: 0 } - : (container as HTMLElement).getBoundingClientRect() - - const containerTop = container === window ? 0 : containerRect.top - if (position === 'top') { - const targetTop = containerTop + offset - const shouldAffix = scrollTop + wrapperRect.height > targetTop + (container === window ? scrollTop : 0) const elementTop = getOffsetTop(placeholderEl) const shouldAffixByPosition = elementTop - offset <= scrollTop @@ -81,7 +72,6 @@ const Affix: React.FC = ({ } } else { const viewportHeight = window.innerHeight - const shouldAffix = scrollTop + viewportHeight < containerTop + offset + wrapperRect.height + scrollTop const placeholderBottom = getOffsetTop(placeholderEl) + placeholderEl.offsetHeight if (placeholderBottom - offset <= scrollTop + viewportHeight && !affixed) { diff --git a/src/components/common/Affix/index.md b/src/components/common/Affix/index.md index 1a12663..e776fe9 100644 --- a/src/components/common/Affix/index.md +++ b/src/components/common/Affix/index.md @@ -1,4 +1,4 @@ ---- +--- nav: 组件 group: 通用 title: Affix 固钉 @@ -22,7 +22,7 @@ description: 用于将元素固定在屏幕上,不随页面滚动而消失。 在下方容器中滚动,按钮会固定在容器顶部。 ```tsx -import { Affix, Button } from '@Pika/ui'; +import { Affix, Button } from 'RustUI'; export default () => (
( 通过 `offset` 设置固定时距离容器顶部的偏移量。 ```tsx -import { Affix, Button } from '@Pika/ui'; +import { Affix, Button } from 'RustUI'; export default () => (
( 通过 `position="bottom"` 将元素固定在底部。 ```tsx -import { Affix, Button } from '@Pika/ui'; +import { Affix, Button } from 'RustUI'; export default () => (
( ```tsx import { useState } from 'react'; -import { Affix, Button } from '@Pika/ui'; +import { Affix, Button } from 'RustUI'; export default () => { const [affixed, setAffixed] = useState(false); diff --git a/src/components/common/Anchor/index.md b/src/components/common/Anchor/index.md index 6155b24..7015137 100644 --- a/src/components/common/Anchor/index.md +++ b/src/components/common/Anchor/index.md @@ -1,4 +1,4 @@ ---- +--- nav: 组件 group: 导航 title: Anchor 锚点 @@ -22,7 +22,7 @@ description: 页面锚点导航组件,用于在长页面中通过链接快速 最简单的锚点用法,通过 `Anchor.Link` 设置锚点链接。 ```tsx -import { Anchor } from '@Pika/ui'; +import { Anchor } from 'RustUI'; export default () => ( @@ -38,7 +38,7 @@ export default () => ( 通过 `targetOffset` 设置锚点滚动到目标位置时的偏移量,适用于页面有固定头部的情况。 ```tsx -import { Anchor } from '@Pika/ui'; +import { Anchor } from 'RustUI'; export default () => ( @@ -54,7 +54,7 @@ export default () => ( 通过 `className` 和 `style` 自定义锚点导航的外观。 ```tsx -import { Anchor } from '@Pika/ui'; +import { Anchor } from 'RustUI'; export default () => ( ( 通过 `direction="horizontal"` 设置横向锚点导航,适用于顶部导航栏等场景。 ```tsx -import { Anchor } from '@Pika/ui'; +import { Anchor } from 'RustUI'; export default () => ( diff --git a/src/components/common/App/App.test.tsx b/src/components/common/App/App.test.tsx index 49a4d1e..6278bc4 100644 --- a/src/components/common/App/App.test.tsx +++ b/src/components/common/App/App.test.tsx @@ -1,6 +1,6 @@ import React from 'react' import { render, screen } from '@testing-library/react' -import { describe, it, expect } from 'vitest' +import { describe, it, expect, vi } from 'vitest' import { App, useApp } from './App' describe('App', () => { @@ -95,4 +95,38 @@ describe('App', () => { const { container } = render(Content) expect(container.firstChild).toBeInTheDocument() }) + + it('modal.confirm returns destroy method', () => { + let modalRef: { destroy: () => void } | undefined + function TestChild() { + const { modal } = useApp() + modalRef = modal.confirm({ title: 'Test', content: 'Test content' }) + return test + } + render( + + + , + ) + expect(modalRef).toBeDefined() + expect(typeof modalRef!.destroy).toBe('function') + modalRef!.destroy() + }) + + it('message methods call Message static API', async () => { + const { Message } = await import('../../feedback/message/Message') + const messageSpy = vi.spyOn(Message, 'success') + function TestChild() { + const { message } = useApp() + message.success('test message') + return test + } + render( + + + , + ) + expect(messageSpy).toHaveBeenCalledWith('test message') + messageSpy.mockRestore() + }) }) diff --git a/src/components/common/App/App.tsx b/src/components/common/App/App.tsx index 60b7181..516f6a0 100644 --- a/src/components/common/App/App.tsx +++ b/src/components/common/App/App.tsx @@ -1,72 +1,43 @@ -import React, { forwardRef, createContext, useContext, useMemo } from 'react' +import React, { forwardRef, createContext, useContext, useMemo, useState, useCallback, useEffect } from 'react' import type { ReactNode } from 'react' +import { Message } from '../../feedback/message/Message' +import { Notification } from '../../feedback/notification/Notification' +import { Modal } from '../../feedback/modal/Modal' +import type { MessageInstance } from '../../feedback/message/Message' +import type { NotificationInstance, NotificationOptions } from '../../feedback/notification/Notification' import styles from './App.module.css' -/** - * Message 静态方法接口 - */ export interface MessageStatic { - /** 成功消息 */ - success: (content: string) => void - /** 错误消息 */ - error: (content: string) => void - /** 信息消息 */ - info: (content: string) => void - /** 警告消息 */ - warning: (content: string) => void - /** 加载中消息 */ - loading: (content: string) => void + success: (content: string) => MessageInstance + error: (content: string) => MessageInstance + info: (content: string) => MessageInstance + warning: (content: string) => MessageInstance + loading: (content: string) => MessageInstance } -/** - * Modal 静态方法接口 - */ export interface ModalStatic { - /** 信息弹窗 */ - info: (config: Record) => void - /** 成功弹窗 */ - success: (config: Record) => void - /** 错误弹窗 */ - error: (config: Record) => void - /** 警告弹窗 */ - warning: (config: Record) => void - /** 确认弹窗 */ - confirm: (config: Record) => void + info: (config: Record) => { destroy: () => void } + success: (config: Record) => { destroy: () => void } + error: (config: Record) => { destroy: () => void } + warning: (config: Record) => { destroy: () => void } + confirm: (config: Record) => { destroy: () => void } } -/** - * Notification 静态方法接口 - */ export interface NotificationStatic { - /** 成功通知 */ - success: (config: Record) => void - /** 错误通知 */ - error: (config: Record) => void - /** 信息通知 */ - info: (config: Record) => void - /** 警告通知 */ - warning: (config: Record) => void - /** 打开通知 */ - open: (config: Record) => void + success: (config: NotificationOptions) => NotificationInstance + error: (config: NotificationOptions) => NotificationInstance + info: (config: NotificationOptions) => NotificationInstance + warning: (config: NotificationOptions) => NotificationInstance + open: (config: NotificationOptions) => NotificationInstance } -/** - * App 上下文属性接口 - */ export interface AppContextProps { - /** Message 实例 */ message: MessageStatic - /** Modal 实例 */ modal: ModalStatic - /** Notification 实例 */ notification: NotificationStatic } -/** - * App 组件属性接口 - */ export interface AppProps { - /** 子组件 */ children?: ReactNode } @@ -80,40 +51,116 @@ function useApp(): AppContextProps { return ctx } -const noop = () => {} - -const defaultMessage: MessageStatic = { - success: noop, - error: noop, - info: noop, - warning: noop, - loading: noop, +interface ModalState { + id: string + open: boolean + config: Record } -const defaultModal: ModalStatic = { - info: noop, - success: noop, - error: noop, - warning: noop, - confirm: noop, -} +let modalIdCounter = 0 -const defaultNotification: NotificationStatic = { - success: noop, - error: noop, - info: noop, - warning: noop, - open: noop, +function ImperativeModal({ + config, + onClose, +}: { + config: Record + onClose: () => void +}) { + const [open, setOpen] = useState(false) + + useEffect(() => { + requestAnimationFrame(() => setOpen(true)) + }, []) + + const handleClose = useCallback(() => { + setOpen(false) + setTimeout(onClose, 300) + }, [onClose]) + + const handleOk = useCallback((e: React.MouseEvent) => { + const onOk = config.onOk as ((e: React.MouseEvent) => void) | undefined + if (onOk) { + onOk(e) + } else { + handleClose() + } + }, [config, handleClose]) + + const handleCancel = useCallback((e: React.MouseEvent) => { + const onCancel = config.onCancel as ((e: React.MouseEvent) => void) | undefined + if (onCancel) { + onCancel(e) + } else { + handleClose() + } + }, [config, handleClose]) + + return ( + + {(config.content ?? config.message) as ReactNode} + + ) } const App = forwardRef(({ children }, ref) => { + const [modals, setModals] = useState([]) + + const addModal = useCallback((config: Record) => { + const id = `app-modal-${++modalIdCounter}` + setModals((prev) => [...prev, { id, open: true, config }]) + return { + destroy: () => { + setModals((prev) => prev.filter((m) => m.id !== id)) + }, + } + }, []) + + const removeModal = useCallback((id: string) => { + setModals((prev) => prev.filter((m) => m.id !== id)) + }, []) + + const messageStatic = useMemo(() => ({ + success: (content: string) => Message.success(content), + error: (content: string) => Message.error(content), + info: (content: string) => Message.info(content), + warning: (content: string) => Message.warning(content), + loading: (content: string) => Message.loading(content), + }), []) + + const modalStatic = useMemo(() => ({ + info: (config) => addModal({ ...config, _type: 'info' }), + success: (config) => addModal({ ...config, _type: 'success' }), + error: (config) => addModal({ ...config, _type: 'error' }), + warning: (config) => addModal({ ...config, _type: 'warning' }), + confirm: (config) => addModal({ ...config, _type: 'confirm' }), + }), [addModal]) + + const notificationStatic = useMemo(() => ({ + success: (config) => Notification.success(config), + error: (config) => Notification.error(config), + info: (config) => Notification.info(config), + warning: (config) => Notification.warning(config), + open: (config) => Notification.show(config), + }), []) + const contextValue = useMemo( () => ({ - message: defaultMessage, - modal: defaultModal, - notification: defaultNotification, + message: messageStatic, + modal: modalStatic, + notification: notificationStatic, }), - [], + [messageStatic, modalStatic, notificationStatic], ) return ( @@ -121,6 +168,13 @@ const App = forwardRef(({ children }, ref) => {
{children}
+ {modals.map((m) => ( + removeModal(m.id)} + /> + ))} ) }) diff --git a/src/components/common/App/index.md b/src/components/common/App/index.md index 82dd13a..39eeab3 100644 --- a/src/components/common/App/index.md +++ b/src/components/common/App/index.md @@ -1,4 +1,4 @@ ---- +--- nav: 组件 group: 通用 title: App 包裹组件 @@ -23,7 +23,7 @@ description: 提供全局上下文包裹的组件,用于在应用顶层提供 使用 `App` 包裹应用内容,提供全局上下文。 ```tsx -import { App } from '@Pika/ui'; +import { App } from 'RustUI'; export default () => ( @@ -37,7 +37,7 @@ export default () => ( 通过 `App.useApp()` 获取 `message`、`modal`、`notification` 实例,在组件内部调用静态方法。 ```tsx -import { App, Button, Space } from '@Pika/ui'; +import { App, Button, Space } from 'RustUI'; const Inner = () => { const { message, modal, notification } = App.useApp(); @@ -75,7 +75,7 @@ export default () => ( `App` 支持嵌套使用,内层 `App` 可以拥有独立的上下文。适用于微前端或局部区域需要独立消息场景。 ```tsx -import { App, Button } from '@Pika/ui'; +import { App, Button } from 'RustUI'; const SubApp = () => { const { message } = App.useApp(); diff --git a/src/components/common/BackTop/index.md b/src/components/common/BackTop/index.md index 1e22dea..79a93f6 100644 --- a/src/components/common/BackTop/index.md +++ b/src/components/common/BackTop/index.md @@ -1,4 +1,4 @@ ---- +--- nav: 组件 group: 通用 title: BackTop 回到顶部 @@ -22,7 +22,7 @@ description: 当页面滚动时提供返回顶部的快捷按钮组件。 页面滚动超过一定高度时,右下角出现回到顶部按钮。在下方容器中滚动查看效果。 ```tsx -import { BackTop } from '@Pika/ui'; +import { BackTop } from 'RustUI'; export default () => (
( 通过 `style` 和 `className` 自定义回到顶部按钮的外观,也可以通过 `children` 自定义按钮内容。 ```tsx -import { BackTop } from '@Pika/ui'; +import { BackTop } from 'RustUI'; export default () => (
( 通过 `visibilityHeight` 设置按钮显示的滚动高度阈值。设置为 `0` 时按钮始终显示。 ```tsx -import { BackTop } from '@Pika/ui'; +import { BackTop } from 'RustUI'; export default () => (
(
@@ -39,7 +39,7 @@ export default () => ( 按钮支持 `solid`、`outline`、`dashed`、`filled`、`text`、`link`、`ghost` 七种变体。 ```tsx -import { Button } from '@Pika/ui'; +import { Button } from 'RustUI'; export default () => (
@@ -59,7 +59,7 @@ export default () => ( 支持 `small`、`middle`、`large` 三种尺寸。 ```tsx -import { Button } from '@Pika/ui'; +import { Button } from 'RustUI'; export default () => (
@@ -75,7 +75,7 @@ export default () => ( 支持 `default`(中等圆角)、`round`(大圆角)、`pill`(胶囊形)、`circle`(正圆)四种形状。 ```tsx -import { Button } from '@Pika/ui'; +import { Button } from 'RustUI'; export default () => (
@@ -92,7 +92,7 @@ export default () => ( 除了 `primary` 和 `danger`,还支持多种预设颜色。 ```tsx -import { Button } from '@Pika/ui'; +import { Button } from 'RustUI'; export default () => (
@@ -111,7 +111,7 @@ export default () => ( 添加 `loading` 属性即可让按钮处于加载状态。 ```tsx -import { Button } from '@Pika/ui'; +import { Button } from 'RustUI'; export default () => (
@@ -127,7 +127,7 @@ export default () => ( 通过 `icon` 属性添加图标,`iconPosition` 控制图标位置。 ```tsx -import { Button } from '@Pika/ui'; +import { Button } from 'RustUI'; export default () => (
@@ -144,7 +144,7 @@ export default () => ( 添加 `disabled` 属性即可让按钮处于不可用状态。 ```tsx -import { Button } from '@Pika/ui'; +import { Button } from 'RustUI'; export default () => (
@@ -160,7 +160,7 @@ export default () => ( 添加 `fullWidth` 属性使按钮宽度 100%。 ```tsx -import { Button } from '@Pika/ui'; +import { Button } from 'RustUI'; export default () => (
@@ -175,7 +175,7 @@ export default () => ( 参照 Apple Store 的按钮风格,使用大圆角按钮组合。 ```tsx -import { Button } from '@Pika/ui'; +import { Button } from 'RustUI'; export default () => (
diff --git a/src/components/common/ConfigProvider/index.md b/src/components/common/ConfigProvider/index.md index 27f0f4a..cc336ca 100644 --- a/src/components/common/ConfigProvider/index.md +++ b/src/components/common/ConfigProvider/index.md @@ -1,7 +1,8 @@ ---- +--- nav: 组件 -group: 通用 +group: 其他 title: ConfigProvider 全局配置 +order: 0 description: 为应用提供统一的全局化配置,包括主题、国际化、组件默认行为等。 --- @@ -23,7 +24,7 @@ description: 为应用提供统一的全局化配置,包括主题、国际化 使用 `ConfigProvider` 包裹应用,通过 `theme` 配置主题色。 ```tsx -import { ConfigProvider, Button } from '@Pika/ui'; +import { ConfigProvider, Button } from 'RustUI'; export default () => ( @@ -37,7 +38,7 @@ export default () => ( 通过 `theme.token` 设置设计令牌,通过 `theme.components` 配置组件级别的默认样式。 ```tsx -import { ConfigProvider, Button, Input } from '@Pika/ui'; +import { ConfigProvider, Button, Input } from 'RustUI'; export default () => ( ( 通过 `prefixCls` 和 `iconPrefixCls` 自定义组件和图标的 CSS 类名前缀,适用于需要避免样式冲突的场景。 ```tsx -import { ConfigProvider, Button } from '@Pika/ui'; +import { ConfigProvider, Button } from 'RustUI'; export default () => ( ( 通过 `theme.algorithm` 设置暗色主题算法,实现全局暗色模式切换。 ```tsx -import { ConfigProvider, Button, Space } from '@Pika/ui'; +import { ConfigProvider, Button, Space } from 'RustUI'; export default () => ( diff --git a/src/components/common/FloatButton/index.md b/src/components/common/FloatButton/index.md index c4469f9..ed0c720 100644 --- a/src/components/common/FloatButton/index.md +++ b/src/components/common/FloatButton/index.md @@ -1,7 +1,8 @@ ---- +--- nav: 组件 group: 通用 title: FloatButton 悬浮按钮 +order: 1 description: 悬浮在页面边缘的操作按钮组件,提供快速访问功能的入口。 --- @@ -22,7 +23,7 @@ description: 悬浮在页面边缘的操作按钮组件,提供快速访问功 最简单的悬浮按钮,通过 `icon` 设置图标。 ```tsx -import { FloatButton } from '@Pika/ui'; +import { FloatButton } from 'RustUI'; export default () => (
@@ -36,7 +37,7 @@ export default () => ( 使用 `FloatButton.Group` 创建浮动按钮组,通过 `trigger` 设置展开方式,`placement` 设置展开方向。 ```tsx -import { FloatButton } from '@Pika/ui'; +import { FloatButton } from 'RustUI'; export default () => (
@@ -60,7 +61,7 @@ export default () => ( 使用 `FloatButton.BackTop` 实现回到顶部功能,支持自定义显示高度和滚动动画时长。 ```tsx -import { FloatButton } from '@Pika/ui'; +import { FloatButton } from 'RustUI'; export default () => (
@@ -79,7 +80,7 @@ export default () => ( 通过 `trigger` 属性设置浮动按钮组的触发方式,支持 `click` 和 `hover`。 ```tsx -import { FloatButton } from '@Pika/ui'; +import { FloatButton } from 'RustUI'; export default () => (
@@ -103,7 +104,7 @@ export default () => ( 通过 `badge` 属性为浮动按钮添加徽标提示。 ```tsx -import { FloatButton } from '@Pika/ui'; +import { FloatButton } from 'RustUI'; export default () => (
diff --git a/src/components/common/Icon/index.md b/src/components/common/Icon/index.md index 186a2b9..e50ee51 100644 --- a/src/components/common/Icon/index.md +++ b/src/components/common/Icon/index.md @@ -1,7 +1,8 @@ ---- +--- nav: 组件 group: 通用 title: Icon 图标 +order: 2 description: 语义化的图标组件,内置大量预设图标,同时支持自定义 SVG 图标。 --- @@ -19,7 +20,7 @@ description: 语义化的图标组件,内置大量预设图标,同时支持 ### 图标列表 -Pika 内置了大量预设图标,按分类展示如下。 +RustUI 内置了大量预设图标,按分类展示如下。 ```tsx import { @@ -38,7 +39,7 @@ import { GithubOutlined, ShoppingCartOutlined, MessageOutlined, EnvironmentOutlined, StarFilled, HeartFilled, CheckCircleFilled, CloseCircleFilled, StarTwoTone, HeartTwoTone, CheckCircleTwoTone, -} from '@Pika/ui'; +} from 'RustUI'; const IconItem = ({ children, name }: { children: React.ReactNode; name: string }) => (
@@ -153,7 +154,7 @@ export default () => ( 可以使用 `Icon` 组件配合自定义 SVG 组件使用。 ```tsx -import { Icon } from '@Pika/ui'; +import { Icon } from 'RustUI'; const HeartSvg = () => ( @@ -180,7 +181,7 @@ export default () => ( 通过 `rotate` 属性设置图标旋转角度,通过 `spin` 属性设置图标旋转动画。 ```tsx -import { SearchOutlined, LoadingOutlined, SettingOutlined } from '@Pika/ui'; +import { SearchOutlined, LoadingOutlined, SettingOutlined } from 'RustUI'; export default () => (
@@ -202,7 +203,7 @@ import { SearchOutlined, HeartOutlined, StarOutlined, CheckCircleFilled, CloseCircleFilled, StarTwoTone, HeartTwoTone, -} from '@Pika/ui'; +} from 'RustUI'; export default () => (
@@ -222,7 +223,7 @@ export default () => ( 通过 `createFromIconfontCN` 使用 Iconfont 平台上的图标。 ```tsx -import { createFromIconfontCN } from '@Pika/ui'; +import { createFromIconfontCN } from 'RustUI'; const IconFont = createFromIconfontCN({ scriptUrl: '//at.alicdn.com/t/font_8d5l8fzk5b87iudi.js', diff --git a/src/components/common/Typography/index.md b/src/components/common/Typography/index.md index 4e3fd90..e53dbda 100644 --- a/src/components/common/Typography/index.md +++ b/src/components/common/Typography/index.md @@ -1,7 +1,8 @@ ---- +--- nav: 组件 group: 通用 title: Typography 排版 +order: 3 description: 文本排版组件,提供标题、段落、文本、列表等常用排版功能,便于快速构建文档型页面。 --- @@ -23,7 +24,7 @@ description: 文本排版组件,提供标题、段落、文本、列表等常 最简单的文本展示,使用 `Typography.Text` 显示行内文本。 ```tsx -import { Typography } from '@Pika/ui'; +import { Typography } from 'RustUI'; export default () => ( Typography Text @@ -35,16 +36,16 @@ export default () => ( 使用 `Typography.Title` 展示不同级别的标题,支持 1-5 级。 ```tsx -import { Typography } from '@Pika/ui'; +import { Typography } from 'RustUI'; export default () => ( - <> +
一级标题 二级标题 三级标题 四级标题 五级标题 - +
) ``` @@ -53,27 +54,21 @@ export default () => ( 使用 `Typography.Paragraph` 展示段落,`Typography.Text` 展示行内文本,支持 `strong`、`italic`、`underline`、`delete`、`mark`、`code`、`keyboard` 等样式修饰。 ```tsx -import { Typography } from '@Pika/ui'; +import { Typography } from 'RustUI'; export default () => ( - <> +
这是一个段落文本,用于展示较长的内容描述。 加粗文本 -
斜体文本 -
下划线文本 -
删除线文本 -
标记文本 -
代码文本 -
键盘文本 - +
) ``` @@ -82,12 +77,11 @@ export default () => ( 通过 `showCopy` 属性使文本可复制,支持自定义复制内容和图标。 ```tsx -import { Typography } from '@Pika/ui'; +import { Typography } from 'RustUI'; export default () => ( - <> +
点击复制此文本 -
( > 显示文本与复制内容不同 - +
) ``` @@ -105,14 +99,14 @@ export default () => ( 通过 `editable` 属性使文本可编辑,支持自定义编辑回调和触发方式。 ```tsx -import { Typography } from '@Pika/ui'; +import { Typography } from 'RustUI'; import { useState } from 'react'; export default () => { const [text, setText] = useState('点击编辑此文本'); return ( - <> +
{ > {text} -
{ > 点击图标或文本均可编辑 - +
); } ``` @@ -139,12 +132,11 @@ export default () => { 通过 `ellipsis` 属性实现文本省略,支持单行和多行省略,以及展开/收起功能。 ```tsx -import { Typography } from '@Pika/ui'; +import { Typography } from 'RustUI'; export default () => ( - <> +
这是一段很长的文本内容,当超出容器宽度时会自动省略显示 -
( 适用于内容较长但需要节省空间的场景,如列表描述、文章摘要等。 用户可以点击展开按钮查看完整文本,也可以再次点击收起。 - +
) ``` diff --git a/src/components/common/Watermark/Watermark.test.tsx b/src/components/common/Watermark/Watermark.test.tsx index 56da0d9..d5c8b73 100644 --- a/src/components/common/Watermark/Watermark.test.tsx +++ b/src/components/common/Watermark/Watermark.test.tsx @@ -1,4 +1,4 @@ -import React from 'react' +import React from 'react' import { render, screen } from '@testing-library/react' import { describe, it, expect, vi, beforeAll } from 'vitest' import { Watermark } from './Watermark' @@ -23,7 +23,7 @@ beforeAll(() => { describe('Watermark', () => { it('renders children', () => { render( - +
Hello
, ) @@ -33,7 +33,7 @@ describe('Watermark', () => { it('renders with text content', () => { const { container } = render( - +
Content
, ) @@ -44,7 +44,7 @@ describe('Watermark', () => { it('renders with multiple content lines', () => { const { container } = render( - +
Content
, ) @@ -56,7 +56,7 @@ describe('Watermark', () => { it('applies custom font settings', () => { const { container } = render(
Content
@@ -69,7 +69,7 @@ describe('Watermark', () => { it('applies custom zIndex', () => { const { container } = render( - +
Content
, ) @@ -90,7 +90,7 @@ describe('Watermark', () => { it('applies custom gap and offset', () => { const { container } = render( - +
Content
, ) @@ -100,7 +100,7 @@ describe('Watermark', () => { it('applies custom rotate', () => { const { container } = render( - +
Content
, ) diff --git a/src/components/common/Watermark/index.md b/src/components/common/Watermark/index.md index a026c61..41c0bb1 100644 --- a/src/components/common/Watermark/index.md +++ b/src/components/common/Watermark/index.md @@ -1,7 +1,8 @@ ---- +--- nav: 组件 -group: 通用 +group: 反馈 title: Watermark 水印 +order: 10 description: 水印组件,用于在页面或容器上添加文字或图片水印,起到标识和保护内容的作用。 --- @@ -23,10 +24,10 @@ description: 水印组件,用于在页面或容器上添加文字或图片水 最简单的水印用法,通过 `content` 设置水印文字。 ```tsx -import { Watermark } from '@Pika/ui'; +import { Watermark } from 'RustUI'; export default () => ( - +
Content with Watermark
) @@ -37,10 +38,10 @@ export default () => ( 通过将 `content` 设置为数组,实现多行水印效果。 ```tsx -import { Watermark } from '@Pika/ui'; +import { Watermark } from 'RustUI'; export default () => ( - +

机密文件

此文档仅限内部使用,请勿外传。

@@ -54,7 +55,7 @@ export default () => ( 通过 `image` 属性设置图片水印,优先级高于 `content`。 ```tsx -import { Watermark } from '@Pika/ui'; +import { Watermark } from 'RustUI'; export default () => ( ( 通过 `font`、`gap`、`offset`、`rotate` 等属性自定义水印的样式和布局。 ```tsx -import { Watermark } from '@Pika/ui'; +import { Watermark } from 'RustUI'; export default () => ( ( -
- - - - -
-) -``` - ### 头像类型 头像支持图片、图标和文字三种类型,通过 `src`、`icon`、`children` 分别设置。 ```tsx -import { Avatar } from '@Pika/ui'; +import { Avatar } from 'RustUI'; export default () => (
- + 👤} /> U + Z 👤} /> - U + U +
+) +``` + +### 头像尺寸 + +头像提供三种预设尺寸和自定义像素尺寸,可通过 `size` 和 `pixelSize` 属性设置。 + +```tsx +import { Avatar } from 'RustUI'; + +export default () => ( +
+ + + + + +
+) +``` + +### 自定义颜色 + +通过 `style` 属性设置头像的背景色,适用于文字和图标头像。 + +```tsx +import { Avatar } from 'RustUI'; + +export default () => ( +
+ U + L + I + K + A + B + C + D
) ``` @@ -58,22 +82,23 @@ export default () => ( 使用 `AvatarGroup` 展示一组头像,支持通过 `max` 属性控制显示数量。 ```tsx -import { Avatar, AvatarGroup } from '@Pika/ui'; +import { Avatar, AvatarGroup } from 'RustUI'; export default () => (
- - - - + + + + + +2 - - - - - + + + + +
) diff --git a/src/components/display/badge/index.md b/src/components/display/badge/index.md index 8721481..ea910ec 100644 --- a/src/components/display/badge/index.md +++ b/src/components/display/badge/index.md @@ -1,7 +1,8 @@ ---- +--- nav: 组件 group: 数据展示 title: Badge 徽标 +order: 1 description: 徽标组件,用于在图标、按钮、头像等元素上显示数字或状态标记。 --- @@ -23,7 +24,7 @@ description: 徽标组件,用于在图标、按钮、头像等元素上显示 不包裹任何子元素,Badge 作为独立元素使用。 ```tsx -import { Badge } from '@Pika/ui'; +import { Badge } from 'RustUI'; export default () => (
@@ -40,7 +41,7 @@ export default () => ( 包裹子元素展示数字徽标,支持 `overflowCount` 设置数字溢出阈值。 ```tsx -import { Badge, Avatar } from '@Pika/ui'; +import { Badge, Avatar } from 'RustUI'; export default () => (
@@ -65,7 +66,7 @@ export default () => ( 通过 `dot` 属性设置只显示小红点,用于简单的提示场景。 ```tsx -import { Badge, Avatar } from '@Pika/ui'; +import { Badge, Avatar } from 'RustUI'; export default () => (
@@ -87,7 +88,7 @@ export default () => ( 通过 `status` 属性设置不同状态的徽标点,支持 `default`、`success`、`warning`、`error`、`info` 五种状态。 ```tsx -import { Badge } from '@Pika/ui'; +import { Badge } from 'RustUI'; export default () => (
diff --git a/src/components/display/calendar/index.md b/src/components/display/calendar/index.md index 84eafa3..cb4cd88 100644 --- a/src/components/display/calendar/index.md +++ b/src/components/display/calendar/index.md @@ -1,7 +1,8 @@ ---- +--- nav: 组件 group: 数据展示 title: Calendar 日历 +order: 2 description: 日历组件,用于按月份展示日期,支持自定义日期内容和日期选择。 --- @@ -23,7 +24,7 @@ description: 日历组件,用于按月份展示日期,支持自定义日期 基本日历用法,支持受控和非受控两种模式。 ```tsx -import { Calendar } from '@Pika/ui'; +import { Calendar } from 'RustUI'; export default () => ( @@ -35,7 +36,7 @@ export default () => ( 通过 `cellRender` 自定义日期单元格内容,常用于展示日程信息。 ```tsx -import { Calendar } from '@Pika/ui'; +import { Calendar } from 'RustUI'; export default () => ( ( 通过 `fullscreen={false}` 设置为卡片模式,适合嵌入页面中使用。 ```tsx -import { Calendar } from '@Pika/ui'; +import { Calendar } from 'RustUI'; export default () => ( diff --git a/src/components/display/card/index.md b/src/components/display/card/index.md index 263fdb8..d8a70a4 100644 --- a/src/components/display/card/index.md +++ b/src/components/display/card/index.md @@ -1,7 +1,8 @@ ---- +--- nav: 组件 group: 数据展示 title: Card 卡片 +order: 3 description: 卡片组件,通用的信息容器,支持标题、操作区、封面图等多种样式。 --- @@ -23,7 +24,7 @@ description: 卡片组件,通用的信息容器,支持标题、操作区、 通过 `actions` 属性设置卡片底部的操作组。 ```tsx -import { Card } from '@Pika/ui'; +import { Card } from 'RustUI'; export default () => ( ( 使用 `Card.Grid` 在卡片内部展示栅格布局,适合展示同类的多项内容。 ```tsx -import { Card } from '@Pika/ui'; +import { Card } from 'RustUI'; export default () => ( @@ -61,7 +62,7 @@ export default () => ( 通过 `loading` 属性设置卡片加载状态,加载时会显示骨架屏。 ```tsx -import { Card } from '@Pika/ui'; +import { Card } from 'RustUI'; export default () => ( @@ -75,7 +76,7 @@ export default () => ( 在卡片内部嵌套使用 `Card.Meta` 展示更丰富的信息,如头像、标题和描述。 ```tsx -import { Card, Avatar } from '@Pika/ui'; +import { Card, Avatar } from 'RustUI'; export default () => ( diff --git a/src/components/display/carousel/index.md b/src/components/display/carousel/index.md index 7a5c50b..8e26fbf 100644 --- a/src/components/display/carousel/index.md +++ b/src/components/display/carousel/index.md @@ -1,7 +1,8 @@ ---- +--- nav: 组件 group: 数据展示 title: Carousel 走马灯 +order: 4 description: 走马灯组件,用于轮播展示多张图片或内容,支持自动播放、指示器等功能。 --- @@ -23,7 +24,7 @@ description: 走马灯组件,用于轮播展示多张图片或内容,支持 通过 `autoplay` 和 `autoplaySpeed` 设置自动播放和播放速度。 ```tsx -import { Carousel } from '@Pika/ui'; +import { Carousel } from 'RustUI'; export default () => ( @@ -39,7 +40,7 @@ export default () => ( 通过 `effect="fade"` 设置渐显切换效果。 ```tsx -import { Carousel } from '@Pika/ui'; +import { Carousel } from 'RustUI'; export default () => ( @@ -55,7 +56,7 @@ export default () => ( 通过 `dotPlacement` 设置指示点位置,支持 `top`、`bottom`、`start`、`end` 四个方向。 ```tsx -import { Carousel } from '@Pika/ui'; +import { Carousel } from 'RustUI'; export default () => ( diff --git a/src/components/display/collapse/index.md b/src/components/display/collapse/index.md index a7acf16..cc99061 100644 --- a/src/components/display/collapse/index.md +++ b/src/components/display/collapse/index.md @@ -1,7 +1,8 @@ ---- +--- nav: 组件 group: 数据展示 title: Collapse 折叠面板 +order: 5 description: 折叠面板组件,用于将一组内容区域折叠隐藏,点击标题展开查看详情。 --- @@ -23,7 +24,7 @@ description: 折叠面板组件,用于将一组内容区域折叠隐藏,点 通过 `accordion` 属性设置手风琴模式,同一时间只能展开一个面板。 ```tsx -import { Collapse } from '@Pika/ui'; +import { Collapse } from 'RustUI'; export default () => ( ( 折叠面板支持嵌套使用,实现多层级的内容展示。 ```tsx -import { Collapse } from '@Pika/ui'; +import { Collapse } from 'RustUI'; export default () => ( ( 通过 `variant` 属性设置面板样式,支持 `outlined`、`borderless`、`ghost` 三种风格。 ```tsx -import { Collapse } from '@Pika/ui'; +import { Collapse } from 'RustUI'; export default () => (
diff --git a/src/components/display/descriptions/Descriptions.test.tsx b/src/components/display/descriptions/Descriptions.test.tsx index be1d0ee..db96bfe 100644 --- a/src/components/display/descriptions/Descriptions.test.tsx +++ b/src/components/display/descriptions/Descriptions.test.tsx @@ -1,10 +1,10 @@ -import React from 'react' +import React from 'react' import { render, screen } from '@testing-library/react' import { describe, it, expect } from 'vitest' import { Descriptions } from './index' const items = [ - { key: '1', label: 'Name', children: 'Pika' }, + { key: '1', label: 'Name', children: 'RustUI' }, { key: '2', label: 'Version', children: '1.0.0' }, { key: '3', label: 'Status', children: 'Active' }, ] @@ -13,7 +13,7 @@ describe('Descriptions', () => { it('renders with data items', () => { const { container } = render() expect(container.textContent).toContain('Name') - expect(container.textContent).toContain('Pika') + expect(container.textContent).toContain('RustUI') expect(container.textContent).toContain('Version') expect(container.textContent).toContain('1.0.0') }) @@ -102,7 +102,7 @@ describe('Descriptions', () => { it('renders with filled span', () => { const filledItems = [ - { key: '1', label: 'Name', children: 'Pika' }, + { key: '1', label: 'Name', children: 'RustUI' }, { key: '2', label: 'Full', children: 'Fills remaining', span: 'filled' as const }, ] const { container } = render() diff --git a/src/components/display/descriptions/index.md b/src/components/display/descriptions/index.md index 36770d3..b965a24 100644 --- a/src/components/display/descriptions/index.md +++ b/src/components/display/descriptions/index.md @@ -1,7 +1,8 @@ ---- +--- nav: 组件 group: 数据展示 title: Descriptions 描述列表 +order: 6 description: 描述列表组件,用于展示成组的只读字段信息,如商品详情、用户信息等。 --- @@ -23,7 +24,7 @@ description: 描述列表组件,用于展示成组的只读字段信息,如 通过 `variant="outlined"` 设置带边框的描述列表样式。 ```tsx -import { Descriptions } from '@Pika/ui'; +import { Descriptions } from 'RustUI'; export default () => ( ( 通过 `column` 属性设置响应式列数,支持对象形式配置不同断点的列数。 ```tsx -import { Descriptions } from '@Pika/ui'; +import { Descriptions } from 'RustUI'; export default () => ( ( column={{ 576: 1, 768: 2, 992: 3 }} data={[ { key: '1', label: '商品名称', children: '无线蓝牙耳机' }, - { key: '2', label: '品牌', children: 'Pika' }, + { key: '2', label: '品牌', children: 'RustUI' }, { key: '3', label: '价格', children: '¥299.00' }, { key: '4', label: '库存', children: '1000' }, { key: '5', label: '分类', children: '数码配件' }, @@ -68,7 +69,7 @@ export default () => ( 通过 `size` 属性设置描述列表的尺寸,支持 `small`、`middle`、`large` 三种尺寸。 ```tsx -import { Descriptions } from '@Pika/ui'; +import { Descriptions } from 'RustUI'; export default () => (
diff --git a/src/components/display/empty/index.md b/src/components/display/empty/index.md index de8826a..3aadfd2 100644 --- a/src/components/display/empty/index.md +++ b/src/components/display/empty/index.md @@ -1,7 +1,8 @@ ---- +--- nav: 组件 group: 数据展示 title: Empty 空状态 +order: 7 description: 空状态组件,用于在没有数据时提供友好的占位提示和引导。 --- @@ -23,7 +24,7 @@ description: 空状态组件,用于在没有数据时提供友好的占位提 通过 `description` 属性自定义空状态的描述文本。 ```tsx -import { Empty } from '@Pika/ui'; +import { Empty } from 'RustUI'; export default () => (
@@ -38,7 +39,7 @@ export default () => ( 通过 `image` 属性自定义空状态的图片,支持使用内置图片类型或自定义元素。 ```tsx -import { Empty } from '@Pika/ui'; +import { Empty } from 'RustUI'; export default () => (
@@ -53,7 +54,7 @@ export default () => ( 通过 `children` 添加底部操作区内容,引导用户进行下一步操作。 ```tsx -import { Empty, Button } from '@Pika/ui'; +import { Empty, Button } from 'RustUI'; export default () => ( diff --git a/src/components/display/image/index.md b/src/components/display/image/index.md index c6b314b..93dbb0b 100644 --- a/src/components/display/image/index.md +++ b/src/components/display/image/index.md @@ -1,7 +1,8 @@ ---- +--- nav: 组件 group: 数据展示 title: Image 图片 +order: 8 description: 图片组件,支持图片预览、占位图、加载失败等功能。 --- @@ -23,7 +24,7 @@ description: 图片组件,支持图片预览、占位图、加载失败等功 通过 `preview` 属性开启图片预览功能,点击图片可放大查看。 ```tsx -import { Image } from '@Pika/ui'; +import { Image } from 'RustUI'; export default () => (
@@ -46,7 +47,7 @@ export default () => ( 通过 `placeholder` 属性设置图片加载中的占位内容。 ```tsx -import { Image } from '@Pika/ui'; +import { Image } from 'RustUI'; export default () => ( ( 通过 `fallback` 属性设置图片加载失败时的替代图片。 ```tsx -import { Image } from '@Pika/ui'; +import { Image } from 'RustUI'; export default () => (
diff --git a/src/components/display/list/index.md b/src/components/display/list/index.md index 658379c..4cd64e5 100644 --- a/src/components/display/list/index.md +++ b/src/components/display/list/index.md @@ -1,7 +1,8 @@ ---- +--- nav: 组件 group: 数据展示 title: List 列表 +order: 9 description: 列表组件,用于展示一组有序或无序的数据,支持多种样式和布局。 --- @@ -23,7 +24,7 @@ description: 列表组件,用于展示一组有序或无序的数据,支持 使用 `data` 和 `renderItem` 渲染基础列表,配合 `List.Item` 和 `List.Item.Meta` 展示丰富的列表项。 ```tsx -import { List, Avatar } from '@Pika/ui'; +import { List, Avatar } from 'RustUI'; const data = [ { title: '列表项一', description: '这是列表项一的描述信息' }, @@ -53,7 +54,7 @@ export default () => ( ```tsx import { useState } from 'react'; -import { List, Avatar, Button } from '@Pika/ui'; +import { List, Avatar, Button } from 'RustUI'; const allData = Array.from({ length: 12 }, (_, i) => ({ title: `列表项 ${i + 1}`, @@ -105,7 +106,7 @@ export default () => { 通过 `itemLayout="vertical"` 设置竖排列表布局,适合展示带图片的丰富内容。 ```tsx -import { List } from '@Pika/ui'; +import { List } from 'RustUI'; const data = [ { title: '文章一', description: '这是文章一的摘要内容,竖排布局适合展示较长的描述信息。', image: 'https://picsum.photos/seed/art1/272/160' }, diff --git a/src/components/display/popover/Popover.tsx b/src/components/display/popover/Popover.tsx index 09432dd..35a2344 100644 --- a/src/components/display/popover/Popover.tsx +++ b/src/components/display/popover/Popover.tsx @@ -1,7 +1,7 @@ import React, { forwardRef, useCallback } from 'react' import type { CSSProperties, ReactNode, ReactElement } from 'react' import { createPortal } from 'react-dom' -import { usePikaContext } from '../../shared/hooks/usePikaContext' +import { useFoxContext } from '../../shared/hooks/usePikaContext' import { useOverlay } from '../../shared/overlay/useOverlay' import type { OverlayPlacement } from '../../shared/overlay/placement' import { cn, getSemanticProps } from '../../shared/utils' @@ -87,7 +87,7 @@ const Popover = forwardRef( }, ref, ) => { - const { resolvePopupContainer, resolveZIndex } = usePikaContext() + const { resolvePopupContainer, resolveZIndex } = useFoxContext() const resolveContainer = useCallback( (node: HTMLElement) => resolvePopupContainer(node, getPopupContainer), diff --git a/src/components/display/popover/index.md b/src/components/display/popover/index.md index 8983799..2f574ee 100644 --- a/src/components/display/popover/index.md +++ b/src/components/display/popover/index.md @@ -1,7 +1,8 @@ ---- +--- nav: 组件 group: 数据展示 title: Popover 气泡卡片 +order: 10 description: 气泡卡片组件,点击或悬停后弹出浮层,展示更多内容或操作。 --- @@ -23,7 +24,7 @@ description: 气泡卡片组件,点击或悬停后弹出浮层,展示更多 通过 `trigger` 属性设置触发方式,支持 `hover`、`focus`、`click`、`contextMenu` 四种方式。 ```tsx -import { Popover, Button } from '@Pika/ui'; +import { Popover, Button } from 'RustUI'; const content = (
@@ -52,7 +53,7 @@ export default () => ( 通过 `placement` 属性设置气泡卡片的位置,支持 12 个方向。 ```tsx -import { Popover, Button } from '@Pika/ui'; +import { Popover, Button } from 'RustUI'; export default () => (
@@ -70,7 +71,7 @@ export default () => ( 通过 `mouseEnterDelay` 和 `mouseLeaveDelay` 设置鼠标移入移出的延迟时间,避免频繁触发。 ```tsx -import { Popover, Button } from '@Pika/ui'; +import { Popover, Button } from 'RustUI'; export default () => ( >> 0 function nextBit(): number { diff --git a/src/components/display/qrcode/index.md b/src/components/display/qrcode/index.md index ed61fd1..5725b30 100644 --- a/src/components/display/qrcode/index.md +++ b/src/components/display/qrcode/index.md @@ -1,7 +1,8 @@ ---- +--- nav: 组件 group: 数据展示 title: QRCode 二维码 +order: 11 description: 二维码生成组件,用于将文本或链接转换为二维码图片。 --- @@ -23,14 +24,14 @@ description: 二维码生成组件,用于将文本或链接转换为二维码 通过 `size` 和 `pixelSize` 属性设置二维码尺寸。 ```tsx -import { QRCode } from '@Pika/ui'; +import { QRCode } from 'RustUI'; export default () => (
- - - - + + + +
) ``` @@ -40,13 +41,13 @@ export default () => ( 通过 `color` 和 `bgColor` 属性自定义二维码的前景色和背景色。 ```tsx -import { QRCode } from '@Pika/ui'; +import { QRCode } from 'RustUI'; export default () => (
- - - + + +
) ``` @@ -56,18 +57,18 @@ export default () => ( 通过 `icon` 属性在二维码中心添加图标,`iconSize` 设置图标大小,`errorLevel` 设置容错级别。 ```tsx -import { QRCode } from '@Pika/ui'; +import { QRCode } from 'RustUI'; export default () => (
( ```tsx import { useRef } from 'react'; -import { QRCode, Button } from '@Pika/ui'; +import { QRCode, Button } from 'RustUI'; export default () => { const ref = useRef(null); @@ -100,7 +101,7 @@ export default () => { return (
- +
); diff --git a/src/components/display/segmented/index.md b/src/components/display/segmented/index.md index ebdd69d..b74ffaa 100644 --- a/src/components/display/segmented/index.md +++ b/src/components/display/segmented/index.md @@ -1,7 +1,8 @@ ---- +--- nav: 组件 group: 数据展示 title: Segmented 分段控制器 +order: 12 description: 分段控制器组件,用于在多个选项之间切换,支持图标和文字展示。 --- @@ -23,7 +24,7 @@ description: 分段控制器组件,用于在多个选项之间切换,支持 通过 `data` 中的 `icon` 属性为选项添加图标。 ```tsx -import { Segmented } from '@Pika/ui'; +import { Segmented } from 'RustUI'; export default () => ( ( 通过 `data` 中的 `disabled` 属性禁用单个选项,或通过组件的 `disabled` 属性禁用整个分段器。 ```tsx -import { Segmented } from '@Pika/ui'; +import { Segmented } from 'RustUI'; export default () => (
@@ -72,7 +73,7 @@ export default () => ( 通过 `data` 中的 `label` 属性自定义选项的渲染内容。 ```tsx -import { Segmented } from '@Pika/ui'; +import { Segmented } from 'RustUI'; export default () => ( (
@@ -48,7 +49,7 @@ export default () => ( 通过 `prefix` 和 `suffix` 属性设置数值的前缀和后缀。 ```tsx -import { Statistic } from '@Pika/ui'; +import { Statistic } from 'RustUI'; export default () => (
@@ -78,7 +79,7 @@ export default () => ( 将 Statistic 嵌入 Card 中,形成卡片统计样式,适合仪表盘场景。 ```tsx -import { Statistic, Card } from '@Pika/ui'; +import { Statistic, Card } from 'RustUI'; export default () => (
diff --git a/src/components/display/table/index.md b/src/components/display/table/index.md index 7316c13..fa38ee2 100644 --- a/src/components/display/table/index.md +++ b/src/components/display/table/index.md @@ -1,7 +1,8 @@ ---- +--- nav: 组件 group: 数据展示 title: Table 表格 +order: 14 description: 表格组件,用于展示结构化数据,支持排序、筛选、分页、合并单元格等功能。 --- @@ -23,7 +24,7 @@ description: 表格组件,用于展示结构化数据,支持排序、筛选 通过 `rowSelection` 属性设置行选择功能,支持 `checkbox` 和 `radio` 两种选择模式。 ```tsx -import { Table } from '@Pika/ui'; +import { Table } from 'RustUI'; const data = [ { key: '1', name: '张三', age: 32, address: '北京市朝阳区' }, @@ -52,7 +53,7 @@ export default () => ( 通过 `sorter` 属性设置列的排序功能,支持布尔值和自定义比较函数。 ```tsx -import { Table } from '@Pika/ui'; +import { Table } from 'RustUI'; const data = [ { key: '1', name: '张三', age: 32, score: 85 }, @@ -78,7 +79,7 @@ export default () => ( 通过 `scroll` 属性设置表格滚动区域,`y` 设置纵向滚动高度实现固定表头。 ```tsx -import { Table } from '@Pika/ui'; +import { Table } from 'RustUI'; const data = Array.from({ length: 20 }, (_, i) => ({ key: String(i + 1), @@ -105,7 +106,7 @@ export default () => ( 通过 `childrenColumnName` 设置子节点字段名,表格会自动识别树形结构并展示缩进。 ```tsx -import { Table } from '@Pika/ui'; +import { Table } from 'RustUI'; const data = [ { diff --git a/src/components/display/tag/index.md b/src/components/display/tag/index.md index 5f889f5..aaa7357 100644 --- a/src/components/display/tag/index.md +++ b/src/components/display/tag/index.md @@ -1,7 +1,8 @@ ---- +--- nav: 组件 group: 数据展示 title: Tag 标签 +order: 15 description: 标签组件,用于信息标记和分类,支持多种颜色、可关闭、可选择等功能。 --- @@ -23,7 +24,7 @@ description: 标签组件,用于信息标记和分类,支持多种颜色、 通过 `status` 属性设置标签的语义化颜色,通过 `color` 属性自定义颜色。 ```tsx -import { Tag } from '@Pika/ui'; +import { Tag } from 'RustUI'; export default () => (
@@ -46,7 +47,7 @@ export default () => ( ```tsx import { useState } from 'react'; -import { Tag } from '@Pika/ui'; +import { Tag } from 'RustUI'; export default () => { const [tags, setTags] = useState(['标签一', '标签二', '标签三', '标签四']); @@ -73,7 +74,7 @@ export default () => { ```tsx import { useState } from 'react'; -import { CheckableTag } from '@Pika/ui'; +import { CheckableTag } from 'RustUI'; const tags = ['电影', '书籍', '音乐', '运动', '旅行']; @@ -108,7 +109,7 @@ export default () => { 通过 `size` 属性设置标签尺寸,支持 `small`、`middle`、`large` 三种尺寸。 ```tsx -import { Tag } from '@Pika/ui'; +import { Tag } from 'RustUI'; export default () => (
diff --git a/src/components/display/timeline/index.md b/src/components/display/timeline/index.md index 6d39313..dbff189 100644 --- a/src/components/display/timeline/index.md +++ b/src/components/display/timeline/index.md @@ -1,7 +1,8 @@ ---- +--- nav: 组件 group: 数据展示 title: Timeline 时间轴 +order: 16 description: 时间轴组件,用于按时间顺序展示一组事件,支持自定义节点样式。 --- @@ -23,7 +24,7 @@ description: 时间轴组件,用于按时间顺序展示一组事件,支持 通过 `dot` 属性自定义节点内容,通过 `color` 属性设置节点颜色。 ```tsx -import { Timeline } from '@Pika/ui'; +import { Timeline } from 'RustUI'; export default () => ( ( 通过 `mode="alternate"` 设置交替展现模式,时间轴节点左右交替显示。 ```tsx -import { Timeline } from '@Pika/ui'; +import { Timeline } from 'RustUI'; export default () => ( ( 通过 `mode="right"` 设置时间线在右侧展示。 ```tsx -import { Timeline } from '@Pika/ui'; +import { Timeline } from 'RustUI'; export default () => ( ( }, ref, ) => { - const { resolvePopupContainer, resolveZIndex } = usePikaContext() + const { resolvePopupContainer, resolveZIndex } = useFoxContext() const resolveContainer = useCallback( (node: HTMLElement) => resolvePopupContainer(node, getPopupContainer), diff --git a/src/components/display/tooltip/index.md b/src/components/display/tooltip/index.md index ab2627d..e629bcf 100644 --- a/src/components/display/tooltip/index.md +++ b/src/components/display/tooltip/index.md @@ -1,95 +1,191 @@ ---- +--- nav: 组件 group: 数据展示 title: Tooltip 文字提示 +order: 17 description: 文字提示组件,鼠标悬停时显示简单的提示信息,支持多个方向。 --- # Tooltip 文字提示 -文字提示组件,鼠标悬停时显示简单的提示信息,支持多个方向。 +简单的文字提示气泡框。 ## 何时使用 -- 需要展示元素的详细说明时 -- 需要展示操作提示时 -- 需要展示缩略信息时 +- 鼠标移入则显示提示,移出消失,气泡浮层不承载复杂文本和操作 +- 可用来代替系统默认的 `title` 提示,提供一个按钮/文字/操作的文案解释 - 需要比 Popover 更简单的提示时 ## 代码演示 +### 基本 + +最简单的用法。 + +```tsx +import { Tooltip, Button } from 'RustUI'; + +export default () => ( + + + +) +``` + ### 位置 -通过 `placement` 属性设置提示框的位置,支持 12 个方向。 +位置有 12 个方向。 ```tsx -import { Tooltip, Button } from '@Pika/ui'; +import { Tooltip, Button } from 'RustUI'; -const positions = [ - 'top', 'topLeft', 'topRight', - 'bottom', 'bottomLeft', 'bottomRight', - 'left', 'leftTop', 'leftBottom', - 'right', 'rightTop', 'rightBottom', -] as const; +export default () => { + const btnStyle: React.CSSProperties = { + width: 80, + display: 'inline-flex', + justifyContent: 'center', + } -export default () => ( -
- {positions.map((pos) => ( - - - - ))} -
-) + return ( +
+
+ + + + + + + + + +
+
+ + + + + + +
+
+ + + + + + +
+
+ + + + + + +
+
+ + + + + + + + + +
+
+ ) +} ``` -### 箭头指向 +### 箭头展示 -通过 `arrow` 和 `showArrow` 属性控制箭头的显示和指向。 +支持显示、隐藏以及将箭头保持居中定位。 ```tsx -import { Tooltip, Button } from '@Pika/ui'; +import { Tooltip, Button } from 'RustUI'; export default () => ( -
- - +
+ + - + + + + - - -
) ``` -### 彩色文字提示 +### 多彩文字提示 -通过 `color` 属性设置提示框的背景色。 +我们添加了多种预设色彩的文字提示样式,用作不同场景使用。如果预设色彩无法满足需求,还可以自定义颜色。 ```tsx -import { Tooltip, Button } from '@Pika/ui'; +import { Tooltip, Button } from 'RustUI'; + +const presetColors = [ + 'pink', 'red', 'yellow', 'orange', 'cyan', + 'green', 'blue', 'purple', 'geekblue', 'magenta', + 'volcano', 'gold', 'lime', +] + +const colorMap: Record = { + pink: '#eb2f96', + red: '#f5222d', + yellow: '#fadb14', + orange: '#fa8c16', + cyan: '#13c2c2', + green: '#52c41a', + blue: '#1677ff', + purple: '#722ed1', + geekblue: '#2f54eb', + magenta: '#eb2f96', + volcano: '#fa541c', + gold: '#faad14', + lime: '#a0d911', +} + +const customColors = ['#f50', '#2db7f5', '#87d068', '#108ee9'] export default () => ( -
- - - - - - - - - - - - +
+
+ {presetColors.map((color) => ( + + + + ))} +
+
+ {customColors.map((color) => ( + + + + ))} +
) ``` +### 禁用 + +通过设置 `title={null}` 或者 `title=""` 可以禁用 Tooltip。 + +```tsx +import { Tooltip, Button } from 'RustUI'; + +export default () => ( + + + +) +``` + ## API ### Tooltip diff --git a/src/components/display/tour/index.md b/src/components/display/tour/index.md index c8966fd..51a2936 100644 --- a/src/components/display/tour/index.md +++ b/src/components/display/tour/index.md @@ -1,7 +1,8 @@ ---- +--- nav: 组件 group: 数据展示 title: Tour 漫游式引导 +order: 18 description: 漫游式引导组件,用于引导用户浏览页面功能,逐步介绍产品特性。 --- @@ -24,7 +25,7 @@ description: 漫游式引导组件,用于引导用户浏览页面功能,逐 ```tsx import { useState } from 'react'; -import { Tour, Button } from '@Pika/ui'; +import { Tour, Button } from 'RustUI'; export default () => { const [open, setOpen] = useState(false); @@ -52,7 +53,7 @@ export default () => { ```tsx import { useState } from 'react'; -import { Tour, Button } from '@Pika/ui'; +import { Tour, Button } from 'RustUI'; export default () => { const [open, setOpen] = useState(false); @@ -80,7 +81,7 @@ export default () => { ```tsx import { useState } from 'react'; -import { Tour, Button } from '@Pika/ui'; +import { Tour, Button } from 'RustUI'; export default () => { const [open, setOpen] = useState(false); diff --git a/src/components/display/tree/Tree.module.css b/src/components/display/tree/Tree.module.css index d90484c..cd157e0 100644 --- a/src/components/display/tree/Tree.module.css +++ b/src/components/display/tree/Tree.module.css @@ -9,12 +9,13 @@ .node { display: flex; align-items: center; - height: 24px; + height: 28px; padding: 0 4px; cursor: pointer; user-select: none; border-radius: var(--nv-radius-sm, 4px); transition: background var(--nv-motion-fast, 0.15s) var(--nv-motion-ease-out, ease-out); + margin: 0; } .node:hover { @@ -22,11 +23,11 @@ } .node[data-selected] { - background: #e6f4ff; + background: var(--nv-color-primary-bg, #f0f0ff); } .node[data-selected]:hover { - background: #bae0ff; + background: var(--nv-color-primary-bg-hover, #e0e0ff); } .node[data-disabled] { @@ -43,7 +44,7 @@ display: inline-flex; flex-shrink: 0; width: 24px; - height: 24px; + height: 28px; position: relative; } @@ -53,7 +54,7 @@ top: 0; bottom: 0; left: 11px; - border-left: 1px solid var(--nv-border-color, #d9d9d9); + border-left: 1px solid var(--nv-color-border, #d9d9d9); } .indent[data-show-line][data-last]::before { @@ -65,7 +66,7 @@ left: 11px; top: 0; bottom: 0; - border-left: 1px solid var(--nv-border-color, #d9d9d9); + border-left: 1px solid var(--nv-color-border, #d9d9d9); } .switcher { @@ -74,11 +75,16 @@ justify-content: center; flex-shrink: 0; width: 24px; - height: 24px; + height: 28px; cursor: pointer; color: rgba(0, 0, 0, 0.45); transition: transform var(--nv-motion-fast, 0.15s) var(--nv-motion-ease-out, ease-out); transform: rotate(0deg); + border-radius: var(--nv-radius-sm, 4px); +} + +.switcher:hover { + background: rgba(0, 0, 0, 0.04); } .switcher[data-expanded] { @@ -90,6 +96,10 @@ color: rgba(0, 0, 0, 0.25); } +.switcher[data-leaf]:hover { + background: transparent; +} + .switcher[data-leaf][data-show-leaf-icon] { color: rgba(0, 0, 0, 0.45); } @@ -101,14 +111,18 @@ flex-shrink: 0; width: 16px; height: 16px; - margin: 0 4px; - border: 1px solid var(--nv-border-color, #d9d9d9); + margin: 0 6px 0 2px; + border: 1px solid var(--nv-color-border, #d9d9d9); border-radius: var(--nv-radius-sm, 4px); background: var(--nv-color-bg, #ffffff); cursor: pointer; transition: all var(--nv-motion-fast, 0.15s) ease; } +.checkbox:hover { + border-color: var(--nv-color-primary, #6c5ce7); +} + .checkbox[data-checked] { background: var(--nv-color-primary, #6c5ce7); border-color: var(--nv-color-primary, #6c5ce7); @@ -121,10 +135,14 @@ .checkbox[data-disabled] { background: var(--nv-color-bg-secondary, #f5f5f5); - border-color: var(--nv-border-color, #d9d9d9); + border-color: var(--nv-color-border, #d9d9d9); cursor: not-allowed; } +.checkbox[data-disabled]:hover { + border-color: var(--nv-color-border, #d9d9d9); +} + .checkboxCheck { color: white; font-size: 10px; @@ -147,6 +165,8 @@ white-space: nowrap; padding: 0 4px; color: var(--nv-color-text, rgba(0, 0, 0, 0.88)); + border-radius: var(--nv-radius-sm, 4px); + transition: background var(--nv-motion-fast, 0.15s) var(--nv-motion-ease-out, ease-out); } .title[data-disabled] { @@ -158,7 +178,7 @@ align-items: center; justify-content: center; flex-shrink: 0; - margin-right: 4px; + margin-right: 6px; color: rgba(0, 0, 0, 0.45); } @@ -168,8 +188,9 @@ justify-content: center; flex-shrink: 0; width: 24px; - height: 24px; + height: 28px; animation: nv-tree-spin 1s linear infinite; + color: var(--nv-color-primary, #6c5ce7); } @keyframes nv-tree-spin { @@ -192,8 +213,7 @@ .directory .title[data-selected] { background: var(--nv-color-primary, #6c5ce7); color: #fff; - border-radius: var(--nv-radius-sm, 4px); - padding: 0 4px; + padding: 0 6px; } .directory .switcher[data-leaf] { diff --git a/src/components/display/tree/Tree.tsx b/src/components/display/tree/Tree.tsx index d16a10f..cd5f1d8 100644 --- a/src/components/display/tree/Tree.tsx +++ b/src/components/display/tree/Tree.tsx @@ -263,7 +263,7 @@ function flattenTree( disabled: !!nodeDisabled, selectable: nodeSelectable, disableCheckbox: nodeDisableCheckbox ?? false, - checkable: nodeCheckable ?? false, + checkable: nodeCheckable, isLeaf, level, expanded: isExpanded, @@ -1051,7 +1051,7 @@ const Tree = forwardRef( return visibleNodes.map(renderNode) } - const ITEM_HEIGHT = 24 + const ITEM_HEIGHT = 28 const totalHeight = visibleNodes.length * ITEM_HEIGHT const visibleCount = Math.ceil(height / ITEM_HEIGHT) + 2 const startIndex = Math.floor(scrollTop / ITEM_HEIGHT) diff --git a/src/components/display/tree/index.md b/src/components/display/tree/index.md index 1dae6a4..d8a4c61 100644 --- a/src/components/display/tree/index.md +++ b/src/components/display/tree/index.md @@ -1,7 +1,8 @@ ---- +--- nav: 组件 group: 数据展示 title: Tree 树形控件 +order: 19 description: 树形控件组件,用于展示层级数据,支持展开、选中、拖拽等功能。 --- @@ -20,32 +21,41 @@ description: 树形控件组件,用于展示层级数据,支持展开、选 ### 基本用法 -最简单的用法,展示可展开、可选中、可勾选的树形结构。 +最简单的用法,展示可勾选、可选中、默认展开等功能。 ```tsx -import { Tree } from '@Pika/ui'; +import { Tree } from 'RustUI'; const treeData = [ { - key: '0', - title: '根节点', + key: '0-0', + title: 'parent 1', children: [ - { key: '0-0', title: '子节点 0-0' }, - { key: '0-1', title: '子节点 0-1' }, { - key: '0-2', - title: '子节点 0-2', + key: '0-0-0', + title: 'parent 1-0', children: [ - { key: '0-2-0', title: '叶子节点 0-2-0' }, - { key: '0-2-1', title: '叶子节点 0-2-1' }, + { key: '0-0-0-0', title: 'leaf' }, + { key: '0-0-0-1', title: 'leaf' }, ], }, + { + key: '0-0-1', + title: 'parent 1-1', + children: [{ key: '0-0-1-0', title: 'sss' }], + }, ], }, ]; export default () => ( - + ) ``` @@ -54,7 +64,7 @@ export default () => ( 通过 `checkable` 属性使树节点支持勾选,父子节点关联选中。 ```tsx -import { Tree } from '@Pika/ui'; +import { Tree } from 'RustUI'; const treeData = [ { @@ -120,57 +130,52 @@ export default () => ( ```tsx import { useState } from 'react'; -import { Tree } from '@Pika/ui'; +import { Tree } from 'RustUI'; const treeData = [ { - key: '0', - title: '前端技术', + key: '0-0', + title: 'parent 1', children: [ { - key: '0-0', - title: 'React', + key: '0-0-0', + title: 'parent 1-0', children: [ - { key: '0-0-0', title: 'React Router' }, - { key: '0-0-1', title: 'Redux' }, - { key: '0-0-2', title: 'Next.js' }, + { key: '0-0-0-0', title: 'leaf' }, + { key: '0-0-0-1', title: 'leaf' }, + { key: '0-0-0-2', title: 'leaf' }, ], }, { - key: '0-1', - title: 'Vue', + key: '0-0-1', + title: 'parent 1-1', children: [ - { key: '0-1-0', title: 'Vue Router' }, - { key: '0-1-1', title: 'Pinia' }, - { key: '0-1-2', title: 'Nuxt.js' }, + { key: '0-0-1-0', title: 'leaf' }, + { key: '0-0-1-1', title: 'leaf' }, ], }, - { key: '0-2', title: 'Angular' }, - ], - }, - { - key: '1', - title: '后端技术', - children: [ - { key: '1-0', title: 'Node.js' }, - { key: '1-1', title: 'Python' }, - { key: '1-2', title: 'Java' }, - { key: '1-3', title: 'Go' }, + { key: '0-0-2', title: 'leaf' }, ], }, ]; export default () => { - const [expandedKeys, setExpandedKeys] = useState(['0']); + const [expandedKeys, setExpandedKeys] = useState(['0-0']); const [selectedKeys, setSelectedKeys] = useState([]); const [checkedKeys, setCheckedKeys] = useState([]); return ( -
-
- 展开:{expandedKeys.join(', ') || '无'}  |  - 选中:{selectedKeys.join(', ') || '无'}  |  - 勾选:{checkedKeys.join(', ') || '无'} +
+
+ + 展开: {expandedKeys.join(', ') || '无'} + + + 选中: {selectedKeys.join(', ') || '无'} + + + 勾选: {checkedKeys.join(', ') || '无'} +
{ ```tsx import { useState } from 'react'; -import { Tree } from '@Pika/ui'; +import { Tree, Input } from 'RustUI'; const treeData = [ { @@ -232,20 +237,12 @@ export default () => { const [searchValue, setSearchValue] = useState(''); return ( -
- + setSearchValue(e.target.value)} - style={{ - marginBottom: 12, - padding: '6px 12px', - border: '1px solid #d9d9d9', - borderRadius: 6, - width: 220, - fontSize: 14, - outline: 'none', - }} + style={{ width: 240 }} /> { 通过 `variant="directory"` 设置目录树模式,自动展示文件夹图标。 ```tsx -import { Tree } from '@Pika/ui'; +import { Tree } from 'RustUI'; const treeData = [ { - key: 'src', - title: 'src', + key: '0-0', + title: 'parent 1', children: [ { - key: 'components', - title: 'components', + key: '0-0-0', + title: 'parent 1-0', children: [ - { key: 'Button.tsx', title: 'Button.tsx', isLeaf: true }, - { key: 'Input.tsx', title: 'Input.tsx', isLeaf: true }, - { key: 'Modal.tsx', title: 'Modal.tsx', isLeaf: true }, + { key: '0-0-0-0', title: 'leaf', isLeaf: true }, + { key: '0-0-0-1', title: 'leaf', isLeaf: true }, + { key: '0-0-0-2', title: 'leaf', isLeaf: true }, ], }, { - key: 'pages', - title: 'pages', + key: '0-0-1', + title: 'parent 1-1', children: [ - { key: 'Home.tsx', title: 'Home.tsx', isLeaf: true }, - { key: 'About.tsx', title: 'About.tsx', isLeaf: true }, - { key: 'Dashboard.tsx', title: 'Dashboard.tsx', isLeaf: true }, + { key: '0-0-1-0', title: 'leaf', isLeaf: true }, + { key: '0-0-1-1', title: 'leaf', isLeaf: true }, ], }, { - key: 'hooks', - title: 'hooks', - children: [ - { key: 'useAuth.ts', title: 'useAuth.ts', isLeaf: true }, - { key: 'useFetch.ts', title: 'useFetch.ts', isLeaf: true }, - ], + key: '0-0-2', + title: 'parent 1-2', + isLeaf: true, }, - { key: 'App.tsx', title: 'App.tsx', isLeaf: true }, - { key: 'index.tsx', title: 'index.tsx', isLeaf: true }, ], }, { - key: 'public', - title: 'public', + key: '0-1', + title: 'parent 2', children: [ - { key: 'index.html', title: 'index.html', isLeaf: true }, - { key: 'favicon.ico', title: 'favicon.ico', isLeaf: true }, - { key: 'logo.svg', title: 'logo.svg', isLeaf: true }, + { key: '0-1-0', title: 'leaf', isLeaf: true }, + { key: '0-1-1', title: 'leaf', isLeaf: true }, ], }, - { key: 'package.json', title: 'package.json', isLeaf: true }, - { key: 'tsconfig.json', title: 'tsconfig.json', isLeaf: true }, - { key: 'README.md', title: 'README.md', isLeaf: true }, ]; export default () => ( @@ -318,6 +305,7 @@ export default () => ( data={treeData} variant="directory" defaultExpandAll + multiple /> ) ``` @@ -327,23 +315,23 @@ export default () => ( 通过 `draggable` 属性开启节点拖拽功能。 ```tsx -import { Tree } from '@Pika/ui'; +import { Tree } from 'RustUI'; const treeData = [ { - key: '0', - title: '节点一', + key: '0-0', + title: 'parent 1', children: [ - { key: '0-0', title: '子节点 0-0' }, - { key: '0-1', title: '子节点 0-1' }, + { key: '0-0-0', title: 'leaf 1' }, + { key: '0-0-1', title: 'leaf 2' }, ], }, { - key: '1', - title: '节点二', + key: '0-1', + title: 'parent 2', children: [ - { key: '1-0', title: '子节点 1-0' }, - { key: '1-1', title: '子节点 1-1' }, + { key: '0-1-0', title: 'leaf 3' }, + { key: '0-1-1', title: 'leaf 4' }, ], }, ]; @@ -353,6 +341,7 @@ export default () => ( data={treeData} draggable defaultExpandAll + blockNode onDrop={(info) => { console.log('拖拽放置', info); }} @@ -365,33 +354,31 @@ export default () => ( 通过 `showLine` 属性显示树节点之间的连接线。 ```tsx -import { Tree } from '@Pika/ui'; +import { Tree } from 'RustUI'; const treeData = [ { - key: '0', - title: '组织架构', + key: '0-0', + title: 'parent 1', children: [ { - key: '0-0', - title: '技术部', + key: '0-0-0', + title: 'parent 1-0', children: [ - { key: '0-0-0', title: '前端组' }, - { key: '0-0-1', title: '后端组' }, - { key: '0-0-2', title: '测试组' }, + { key: '0-0-0-0', title: 'leaf' }, + { key: '0-0-0-1', title: 'leaf' }, ], }, { - key: '0-1', - title: '产品部', + key: '0-0-1', + title: 'parent 1-1', children: [ - { key: '0-1-0', title: '产品设计' }, - { key: '0-1-1', title: '用户研究' }, + { key: '0-0-1-0', title: 'leaf' }, ], }, { - key: '0-2', - title: '运营部', + key: '0-0-2', + title: 'leaf', }, ], }, @@ -400,7 +387,7 @@ const treeData = [ export default () => ( ) @@ -411,25 +398,25 @@ export default () => ( 通过 `disabled` 属性禁用单个节点,使其不可选中和不可勾选。 ```tsx -import { Tree } from '@Pika/ui'; +import { Tree } from 'RustUI'; const treeData = [ { - key: '0', - title: '可用节点', + key: '0-0', + title: 'parent 1', children: [ - { key: '0-0', title: '子节点 0-0' }, - { key: '0-1', title: '禁用节点', disabled: true }, - { key: '0-2', title: '子节点 0-2' }, + { key: '0-0-0', title: 'leaf' }, + { key: '0-0-1', title: 'disabled leaf', disabled: true }, + { key: '0-0-2', title: 'leaf' }, ], }, { - key: '1', - title: '禁用分支', + key: '0-1', + title: 'disabled parent', disabled: true, children: [ - { key: '1-0', title: '子节点 1-0' }, - { key: '1-1', title: '子节点 1-1' }, + { key: '0-1-0', title: 'leaf' }, + { key: '0-1-1', title: 'leaf' }, ], }, ]; @@ -443,6 +430,43 @@ export default () => ( ) ``` +### 占据整行 + +通过 `blockNode` 属性使节点占据整行宽度。 + +```tsx +import { Tree } from 'RustUI'; + +const treeData = [ + { + key: '0-0', + title: 'parent 1', + children: [ + { + key: '0-0-0', + title: 'parent 1-0', + children: [ + { key: '0-0-0-0', title: 'leaf' }, + { key: '0-0-0-1', title: 'leaf' }, + ], + }, + { + key: '0-0-1', + title: 'parent 1-1', + }, + ], + }, +]; + +export default () => ( + +) +``` + ## API | 属性 | 说明 | 类型 | 默认值 | diff --git a/src/components/entry/auto-complete/index.md b/src/components/entry/auto-complete/index.md index 5ae902a..b84d02b 100644 --- a/src/components/entry/auto-complete/index.md +++ b/src/components/entry/auto-complete/index.md @@ -1,7 +1,8 @@ ---- +--- nav: 组件 group: 数据录入 title: AutoComplete 自动完成 +order: 0 description: 输入框自动完成组件,在用户输入时提供相关的输入建议,提升输入效率。 --- @@ -21,7 +22,7 @@ description: 输入框自动完成组件,在用户输入时提供相关的输 ### 基本用法 ```tsx -import { AutoComplete } from '@Pika/ui'; +import { AutoComplete } from 'RustUI'; export default () => ( ( 通过 `renderOption` 自定义选项的渲染内容。 ```tsx -import { AutoComplete } from '@Pika/ui'; +import { AutoComplete } from 'RustUI'; export default () => ( ( 默认情况下,`filterOption` 为 `true`,会进行不区分大小写的过滤。设置为 `false` 可关闭过滤。 ```tsx -import { AutoComplete } from '@Pika/ui'; +import { AutoComplete } from 'RustUI'; export default () => ( ( ```tsx import { useState } from 'react'; -import { AutoComplete } from '@Pika/ui'; +import { AutoComplete } from 'RustUI'; export default () => { const [options, setOptions] = useState([]); diff --git a/src/components/entry/cascader/Cascader.tsx b/src/components/entry/cascader/Cascader.tsx index dbe6b12..ad4a4c7 100644 --- a/src/components/entry/cascader/Cascader.tsx +++ b/src/components/entry/cascader/Cascader.tsx @@ -1,43 +1,28 @@ -import React, { useState, useCallback, useEffect, useRef, type FC, type ReactNode } from 'react' +import React, { useState, useCallback, useRef, type FC, type ReactNode } from 'react' import { inputTokens } from '../tokens' import { useClickOutside } from '../../shared/hooks/useClickOutside' import type { DataEntrySelectableProps } from '../common' import styles from './Cascader.module.css' -/** - * 级联选择器选项接口 - */ export interface CascaderOption { - /** 选项值 */ value: string | number - /** 选项标签 */ label: string | ReactNode - /** 是否禁用 */ disabled?: boolean - /** 子选项 */ children?: CascaderOption[] } -/** - * 级联选择器组件属性接口 - */ export interface CascaderProps extends DataEntrySelectableProps { - /** 当前值(受控模式) */ value?: Array | null - /** 默认值(非受控模式) */ defaultValue?: Array | null - /** 选项数据 */ data?: CascaderOption[] - /** 选项数据(别名) */ options?: CascaderOption[] - /** 是否选择任意级即改变值 */ changeOnSelect?: boolean - /** 次级菜单展开方式:点击或悬停 */ expandTrigger?: 'click' | 'hover' - /** 选择完成后的回调 */ onChange?: (value: Array, selectedOptions: CascaderOption[]) => void } +const EMPTY_OPTIONS: CascaderOption[] = [] + const Cascader: FC = ({ value, defaultValue = [], @@ -45,7 +30,7 @@ const Cascader: FC = ({ disabled = false, size = 'middle', status = 'default', - data = [], + data = EMPTY_OPTIONS, options, showSearch = false, showClear = false, @@ -55,12 +40,20 @@ const Cascader: FC = ({ className, style, }) => { + const cascaderData = options ?? data const [isOpen, setIsOpen] = useState(false) const [internalValue, setInternalValue] = useState>(defaultValue ?? []) - const cascaderData = options ?? data - const [activeOptions, setActiveOptions] = useState([cascaderData]) + const [expandedColumns, setExpandedColumns] = useState([]) const [searchValue, setSearchValue] = useState('') const wrapperRef = useRef(null) + const prevDataRef = useRef(cascaderData) + + if (prevDataRef.current !== cascaderData) { + prevDataRef.current = cascaderData + setExpandedColumns([]) + } + + const activeOptions = [cascaderData, ...expandedColumns] useClickOutside(wrapperRef, () => setIsOpen(false), isOpen) @@ -69,6 +62,7 @@ const Cascader: FC = ({ const height = inputTokens.height[size] const fontSize = inputTokens.fontSize[size] + const paddingInline = inputTokens.paddingInline[size] const radius = inputTokens.radius[size] const findOption = (val: string | number, opts: CascaderOption[]): CascaderOption | null => { @@ -109,8 +103,7 @@ const Cascader: FC = ({ onChange?.(newValue, selectedOpts) if (option.children && option.children.length > 0) { - const newActiveOptions = [...activeOptions.slice(0, level + 1), option.children] - setActiveOptions(newActiveOptions) + setExpandedColumns((prev) => [...prev.slice(0, level), option.children!]) } else { setIsOpen(false) setSearchValue('') @@ -121,7 +114,7 @@ const Cascader: FC = ({ setSearchValue('') } }, - [currentValue, activeOptions, isControlled, onChange, changeOnSelect] + [currentValue, isControlled, onChange, changeOnSelect, getSelectedOptions] ) const handleClear = (e: React.MouseEvent) => { @@ -134,18 +127,13 @@ const Cascader: FC = ({ const handlePanelMouseEnter = (option: CascaderOption, level: number) => { if (expandTrigger === 'hover' && option.children) { - const newActiveOptions = [...activeOptions.slice(0, level + 1), option.children] - setActiveOptions(newActiveOptions) + setExpandedColumns((prev) => [...prev.slice(0, level), option.children!]) } } const selectedOptions = getSelectedOptions(currentValue) const displayText = selectedOptions.map((opt) => opt.label).join(' / ') - useEffect(() => { - setActiveOptions([cascaderData]) - }, [cascaderData]) - const renderOptions = (opts: CascaderOption[], level: number) => (
{opts.map((option) => { @@ -180,7 +168,7 @@ const Cascader: FC = ({
!disabled && setIsOpen(!isOpen)} > ( ( 通过 `defaultValue` 设置默认选中的级联值。 ```tsx -import { Cascader } from '@Pika/ui'; +import { Cascader } from 'RustUI'; export default () => ( ( 通过选项的 `disabled` 属性禁用特定选项。 ```tsx -import { Cascader } from '@Pika/ui'; +import { Cascader } from 'RustUI'; export default () => ( ( 通过 `changeOnSelect` 实现选择任意级别即改变值。 ```tsx -import { Cascader } from '@Pika/ui'; +import { Cascader } from 'RustUI'; export default () => ( ( 通过 `showSearch` 启用搜索功能。 ```tsx -import { Cascader } from '@Pika/ui'; +import { Cascader } from 'RustUI'; export default () => ( ( style={{ width: handleSize, height: handleSize, - transform: isChecked ? `translateX(${parseInt(width) - parseInt(handleSize) - 2}px)` : 'translateX(2px)', + transform: isChecked ? `translateX(${parseInt(width) - parseInt(handleSize) - 2}px) translateY(-50%)` : 'translateX(2px) translateY(-50%)', }} /> {loading && } diff --git a/src/components/entry/choice/index.md b/src/components/entry/choice/index.md index a6e4411..cac093f 100644 --- a/src/components/entry/choice/index.md +++ b/src/components/entry/choice/index.md @@ -1,7 +1,8 @@ ---- +--- nav: 组件 group: 数据录入 title: Checkbox 多选框 / Radio 单选框 / Switch 开关 +order: 2 description: 多选框、单选框和开关组件,用于在一组选项中进行选择或切换状态的交互组件。 --- @@ -20,16 +21,14 @@ description: 多选框、单选框和开关组件,用于在一组选项中进 ### 基本用法 ```tsx -import { Checkbox, Radio, Switch } from '@Pika/ui'; +import { Checkbox, Radio, Switch } from 'RustUI'; export default () => ( - <> +
Checkbox -
Radio -
- +
) ``` @@ -38,7 +37,7 @@ export default () => ( 使用 `Checkbox.Group` 进行多选组合。 ```tsx -import { Checkbox } from '@Pika/ui'; +import { Checkbox } from 'RustUI'; export default () => ( ( ```tsx import { useState } from 'react'; -import { Checkbox } from '@Pika/ui'; +import { Checkbox } from 'RustUI'; export default () => { const [checked, setChecked] = useState(false); @@ -75,22 +74,18 @@ export default () => { 通过 `disabled` 属性禁用多选框。 ```tsx -import { Checkbox, Radio, Switch } from '@Pika/ui'; +import { Checkbox, Radio, Switch } from 'RustUI'; export default () => ( - <> +
禁用多选框 -
禁用且选中 -
禁用单选框 -
-
- +
) ``` @@ -100,7 +95,7 @@ export default () => ( ```tsx import { useState } from 'react'; -import { Checkbox } from '@Pika/ui'; +import { Checkbox } from 'RustUI'; const options = [ { value: 'apple', label: '苹果' }, @@ -119,7 +114,7 @@ export default () => { }; return ( - <> +
{ > 全选 -
setCheckedList(val as string[])} /> - +
); } ``` @@ -143,7 +137,7 @@ export default () => { 使用 `Radio.Group` 进行单选组合。 ```tsx -import { Radio } from '@Pika/ui'; +import { Radio } from 'RustUI'; export default () => ( ( 通过 `layout` 属性设置竖向排列。 ```tsx -import { Radio } from '@Pika/ui'; +import { Radio } from 'RustUI'; export default () => ( ( 通过 `checkedText` 和 `uncheckedText` 为 Switch 添加文字。 ```tsx -import { Switch } from '@Pika/ui'; +import { Switch } from 'RustUI'; export default () => ( - <> +
-
- +
) ``` @@ -198,7 +191,7 @@ export default () => ( 通过 `loading` 属性设置加载状态。 ```tsx -import { Switch } from '@Pika/ui'; +import { Switch } from 'RustUI'; export default () => ( diff --git a/src/components/entry/common.ts b/src/components/entry/common.ts index ba525ff..b00c4a8 100644 --- a/src/components/entry/common.ts +++ b/src/components/entry/common.ts @@ -1,38 +1,27 @@ import type { CSSProperties } from 'react' -import type { PikaSize, PikaStatus } from '../shared/types/common' +import type { FoxSize, FoxStatus } from '../shared/types/common' -export type DataEntrySize = PikaSize +export type DataEntrySize = FoxSize -export type DataEntryStatus = PikaStatus +export type DataEntryStatus = FoxStatus export interface DataEntryBaseProps { - /** 控件尺寸 */ size?: DataEntrySize - /** 是否禁用 */ disabled?: boolean - /** 自定义类名 */ className?: string - /** 自定义样式 */ style?: CSSProperties } export interface DataEntryInputProps extends DataEntryBaseProps { - /** 控件状态 */ status?: DataEntryStatus - /** 占位符文本 */ placeholder?: string - /** 当前值 */ value?: unknown - /** 默认值 */ defaultValue?: unknown } export interface DataEntryTextualProps extends DataEntryInputProps { - /** 是否只读 */ readOnly?: boolean - /** 获取焦点回调 */ onFocus?: () => void - /** 失去焦点回调 */ onBlur?: () => void } diff --git a/src/components/entry/date-picker/index.md b/src/components/entry/date-picker/index.md index b8aaf7d..8f2b5fb 100644 --- a/src/components/entry/date-picker/index.md +++ b/src/components/entry/date-picker/index.md @@ -1,7 +1,8 @@ ---- +--- nav: 组件 group: 数据录入 title: DatePicker 日期选择器 +order: 3 description: 日期选择组件,用于选择日期、日期范围、月份、季度、年份等时间相关的选择。 --- @@ -21,7 +22,7 @@ description: 日期选择组件,用于选择日期、日期范围、月份、 ### 基本用法 ```tsx -import { DatePicker } from '@Pika/ui'; +import { DatePicker } from 'RustUI'; export default () => ( @@ -33,7 +34,7 @@ export default () => ( 通过 `showTime` 属性启用时间选择。 ```tsx -import { DatePicker } from '@Pika/ui'; +import { DatePicker } from 'RustUI'; export default () => ( @@ -45,7 +46,7 @@ export default () => ( 通过 `disabledDate` 函数禁用特定日期。 ```tsx -import { DatePicker } from '@Pika/ui'; +import { DatePicker } from 'RustUI'; export default () => ( ( ```tsx import { useState } from 'react'; -import { DatePicker, Space, Button } from '@Pika/ui'; +import { DatePicker, Space, Button } from 'RustUI'; export default () => { const [value, setValue] = useState(null); diff --git a/src/components/entry/form/Form.module.css b/src/components/entry/form/Form.module.css index 030dbe3..2ab30ba 100644 --- a/src/components/entry/form/Form.module.css +++ b/src/components/entry/form/Form.module.css @@ -5,9 +5,7 @@ } .form[data-layout="horizontal"] { - flex-direction: row; - flex-wrap: wrap; - align-items: flex-start; + flex-direction: column; } .form[data-layout="vertical"] { @@ -18,15 +16,19 @@ flex-direction: row; flex-wrap: wrap; gap: var(--nv-space-md, 12px); + align-items: flex-start; } .form[data-layout="inline"] .formItem { flex-direction: row; + align-items: center; } .form[data-layout="inline"] .label { width: auto; padding-right: var(--nv-space-sm, 8px); + padding-top: 0; + line-height: var(--nv-line-height-control, 32px); } .form[data-layout="inline"] .content { @@ -44,6 +46,11 @@ align-items: flex-start; } +.formItem-inline { + flex-direction: row; + align-items: center; +} + .label { font-size: var(--nv-font-size-md, 14px); font-weight: 500; @@ -63,6 +70,7 @@ .label[data-layout="horizontal"] { width: var(--nv-form-label-width, 120px); padding-right: var(--nv-space-md, 12px); + padding-top: var(--nv-label-padding-top, 5px); flex-shrink: 0; } @@ -74,7 +82,9 @@ .required { color: var(--nv-color-error, #ff4d4f); - margin-right: 2px; + margin-right: 4px; + font-family: SimSun, sans-serif; + line-height: 1; } .content { @@ -82,12 +92,14 @@ display: flex; flex-direction: column; gap: var(--nv-space-xxs, 2px); + min-width: 0; } .content-horizontal { flex: 1; display: flex; flex-direction: column; + min-width: 0; } .helpText { @@ -95,6 +107,8 @@ color: var(--nv-color-text-tertiary, rgba(0, 0, 0, 0.45)); line-height: 1.5; margin-top: var(--nv-space-xxs, 2px); + min-height: 0; + transition: color 0.3s; } .helpText[data-status="error"] { diff --git a/src/components/entry/form/Form.tokens.css b/src/components/entry/form/Form.tokens.css index f6e4632..65d74e9 100644 --- a/src/components/entry/form/Form.tokens.css +++ b/src/components/entry/form/Form.tokens.css @@ -1,13 +1,22 @@ .form { --nv-form-label-width: 120px; --nv-space-xxs: 2px; + --nv-space-xs: 4px; --nv-space-sm: 8px; --nv-space-md: 12px; + --nv-space-lg: 16px; + --nv-space-xl: 24px; --nv-font-size-xs: 12px; + --nv-font-size-sm: 13px; --nv-font-size-md: 14px; + --nv-line-height-control: 32px; + --nv-label-padding-top: 5px; --nv-color-text: rgba(0, 0, 0, 0.88); + --nv-color-text-secondary: rgba(0, 0, 0, 0.65); --nv-color-text-tertiary: rgba(0, 0, 0, 0.45); --nv-color-error: #ff4d4f; --nv-color-warning: #faad14; --nv-color-primary: #6c5ce7; + --nv-color-success: #52c41a; + --nv-border-radius: 6px; } diff --git a/src/components/entry/form/Form.tsx b/src/components/entry/form/Form.tsx index c263f7a..7defd67 100644 --- a/src/components/entry/form/Form.tsx +++ b/src/components/entry/form/Form.tsx @@ -463,8 +463,16 @@ const FormItem: FC = ({ const showError = showValidateMessage && touched && errors.length > 0 const showHelpText = helpText || showError + const formItemClassName = [ + styles.formItem, + styles[`formItem-${layout}`], + className, + ] + .filter(Boolean) + .join(' ') + return ( -
+
{label && (