From bbf3205145ccb4155e9a74c9b3f68f5b9c393577 Mon Sep 17 00:00:00 2001 From: wangdicoder Date: Sun, 19 Apr 2026 20:57:50 +1000 Subject: [PATCH 1/4] refactor: rename component --- apps/docs/public/llms-full.txt | 14 +- apps/docs/public/llms.txt | 2 +- .../containers/components/component-icons.tsx | 2 +- apps/docs/src/routers.tsx | 4 +- packages/extract/src/extract-components.ts | 2 +- packages/mcp/src/data/components.json | 610 +++++++++++++----- packages/mcp/src/data/icons.json | 1 + packages/mcp/src/data/tokens.json | 4 + packages/react/CHANGELOG.md | 2 +- packages/react/README.md | 2 +- packages/react/src/index.ts | 4 +- .../__snapshots__/quick-actions.test.tsx.snap | 55 ++ .../__tests__/quick-actions.test.tsx | 184 ++++++ .../react/src/quick-actions/demo/Basic.tsx | 17 + .../react/src/quick-actions/demo/Click.tsx | 16 + .../demo/CustomIcon.tsx | 14 +- .../src/quick-actions/demo/Direction.tsx | 31 + .../{speed-dial => quick-actions}/index.md | 36 +- packages/react/src/quick-actions/index.tsx | 12 + .../index.zh_CN.md | 14 +- .../quick-actions-action.tsx} | 14 +- .../quick-actions/quick-actions-context.ts | 10 + .../quick-actions.tsx} | 18 +- .../style/index.scss | 82 +-- .../style/index.tsx | 0 .../{speed-dial => quick-actions}/types.ts | 12 +- .../__snapshots__/speed-dial.test.tsx.snap | 55 -- .../speed-dial/__tests__/speed-dial.test.tsx | 184 ------ packages/react/src/speed-dial/demo/Basic.tsx | 17 - packages/react/src/speed-dial/demo/Click.tsx | 16 - .../react/src/speed-dial/demo/Direction.tsx | 31 - packages/react/src/speed-dial/index.tsx | 12 - .../src/speed-dial/speed-dial-context.ts | 10 - packages/react/src/style/_component.scss | 2 +- packages/tokens/CHANGELOG.md | 2 +- .../{speed-dial.json => quick-actions.json} | 50 +- packages/tokens/source/themes/dark.json | 14 +- 37 files changed, 941 insertions(+), 614 deletions(-) create mode 100644 packages/react/src/quick-actions/__tests__/__snapshots__/quick-actions.test.tsx.snap create mode 100644 packages/react/src/quick-actions/__tests__/quick-actions.test.tsx create mode 100644 packages/react/src/quick-actions/demo/Basic.tsx create mode 100644 packages/react/src/quick-actions/demo/Click.tsx rename packages/react/src/{speed-dial => quick-actions}/demo/CustomIcon.tsx (56%) create mode 100644 packages/react/src/quick-actions/demo/Direction.tsx rename packages/react/src/{speed-dial => quick-actions}/index.md (61%) create mode 100644 packages/react/src/quick-actions/index.tsx rename packages/react/src/{speed-dial => quick-actions}/index.zh_CN.md (91%) rename packages/react/src/{speed-dial/speed-dial-action.tsx => quick-actions/quick-actions-action.tsx} (75%) create mode 100644 packages/react/src/quick-actions/quick-actions-context.ts rename packages/react/src/{speed-dial/speed-dial.tsx => quick-actions/quick-actions.tsx} (86%) rename packages/react/src/{speed-dial => quick-actions}/style/index.scss (52%) rename packages/react/src/{speed-dial => quick-actions}/style/index.tsx (100%) rename packages/react/src/{speed-dial => quick-actions}/types.ts (66%) delete mode 100644 packages/react/src/speed-dial/__tests__/__snapshots__/speed-dial.test.tsx.snap delete mode 100644 packages/react/src/speed-dial/__tests__/speed-dial.test.tsx delete mode 100644 packages/react/src/speed-dial/demo/Basic.tsx delete mode 100644 packages/react/src/speed-dial/demo/Click.tsx delete mode 100644 packages/react/src/speed-dial/demo/Direction.tsx delete mode 100644 packages/react/src/speed-dial/index.tsx delete mode 100644 packages/react/src/speed-dial/speed-dial-context.ts rename packages/tokens/source/components/{speed-dial.json => quick-actions.json} (76%) diff --git a/apps/docs/public/llms-full.txt b/apps/docs/public/llms-full.txt index ac9c1c6ac..93f698b44 100644 --- a/apps/docs/public/llms-full.txt +++ b/apps/docs/public/llms-full.txt @@ -1874,29 +1874,29 @@ export interface SpaceProps extends BaseProps, React.PropsWithRef, 'children'> { icon?: React.ReactNode; openIcon?: React.ReactNode; - direction?: SpeedDialDirection; + direction?: QuickActionsDirection; open?: boolean; - trigger?: SpeedDialTrigger; + trigger?: QuickActionsTrigger; onOpen?: () => void; onClose?: () => void; disabled?: boolean; children?: React.ReactNode; } -export interface SpeedDialActionProps +export interface QuickActionsActionProps extends BaseProps, Omit, 'children'> { icon: React.ReactNode; diff --git a/apps/docs/public/llms.txt b/apps/docs/public/llms.txt index 62f40a98f..1da838fcd 100644 --- a/apps/docs/public/llms.txt +++ b/apps/docs/public/llms.txt @@ -81,7 +81,7 @@ Components that accept sizes use: `'sm' | 'md' | 'lg'` - **Dropdown** — Drop-down list with menu items. - **Menu** — Navigation menu with dropdown support. Props: `mode` (`'horizontal'|'vertical'|'inline'`). - **Pagination** — Page through data sets. Props: `total`, `current`, `pageSize`, `onChange`. -- **SpeedDial** — Floating action button expanding to actions. +- **QuickActions** — Floating action button expanding to actions. - **Steps** — Wizard-like numbered step navigation. ### Data Display diff --git a/apps/docs/src/containers/components/component-icons.tsx b/apps/docs/src/containers/components/component-icons.tsx index 5096fcd30..833fc3ae2 100644 --- a/apps/docs/src/containers/components/component-icons.tsx +++ b/apps/docs/src/containers/components/component-icons.tsx @@ -29,7 +29,7 @@ const icons: Record = { dropdown: () => , menu: () => , pagination: () => , - 'speed-dial': () => , + 'quick-actions': () => , steps: () => , // Data Display diff --git a/apps/docs/src/routers.tsx b/apps/docs/src/routers.tsx index 904c6bdf2..fd41cd40b 100755 --- a/apps/docs/src/routers.tsx +++ b/apps/docs/src/routers.tsx @@ -161,7 +161,7 @@ const c = { keyboard: ll(() => import('../../../packages/react/src/keyboard/index.md'), () => import('../../../packages/react/src/keyboard/index.zh_CN.md')), sticky: ll(() => import('../../../packages/react/src/sticky/index.md'), () => import('../../../packages/react/src/sticky/index.zh_CN.md')), select: ll(() => import('../../../packages/react/src/select/index.md'), () => import('../../../packages/react/src/select/index.zh_CN.md')), - speedDial: ll(() => import('../../../packages/react/src/speed-dial/index.md'), () => import('../../../packages/react/src/speed-dial/index.zh_CN.md')), + quickActions: ll(() => import('../../../packages/react/src/quick-actions/index.md'), () => import('../../../packages/react/src/quick-actions/index.zh_CN.md')), anchor: ll(() => import('../../../packages/react/src/anchor/index.md'), () => import('../../../packages/react/src/anchor/index.zh_CN.md')), autoComplete: ll(() => import('../../../packages/react/src/auto-complete/index.md'), () => import('../../../packages/react/src/auto-complete/index.zh_CN.md')), inputOTP: ll(() => import('../../../packages/react/src/input-otp/index.md'), () => import('../../../packages/react/src/input-otp/index.zh_CN.md')), @@ -251,7 +251,7 @@ export const getComponentMenu = (s: SiteLocale): RouterItem[] => { { title: 'Dropdown', route: 'dropdown', component: pick(c.dropdown, z) }, { title: 'Menu', route: 'menu', component: pick(c.menu, z) }, { title: 'Pagination', route: 'pagination', component: pick(c.pagination, z) }, - { title: 'SpeedDial', route: 'speed-dial', component: pick(c.speedDial, z) }, + { title: 'QuickActions', route: 'quick-actions', component: pick(c.quickActions, z) }, { title: 'Steps', route: 'steps', component: pick(c.steps, z) }, ], }, diff --git a/packages/extract/src/extract-components.ts b/packages/extract/src/extract-components.ts index 54ae684f0..eb7f0a8b7 100644 --- a/packages/extract/src/extract-components.ts +++ b/packages/extract/src/extract-components.ts @@ -18,7 +18,7 @@ export const CATEGORY_MAP: Record = { waterfall: 'Layout', anchor: 'Navigation', breadcrumb: 'Navigation', dropdown: 'Navigation', - menu: 'Navigation', pagination: 'Navigation', 'speed-dial': 'Navigation', + menu: 'Navigation', pagination: 'Navigation', 'quick-actions': 'Navigation', steps: 'Navigation', avatar: 'Data Display', badge: 'Data Display', calendar: 'Data Display', diff --git a/packages/mcp/src/data/components.json b/packages/mcp/src/data/components.json index aa9a18c88..2f2c94dd3 100644 --- a/packages/mcp/src/data/components.json +++ b/packages/mcp/src/data/components.json @@ -2233,8 +2233,8 @@ "name": "Descriptions", "dirName": "descriptions", "category": "Data Display", - "description": "Display multiple read-only fields in groups.", - "descriptionZh": "成组展示多个只读字段。", + "description": "Display grouped read-only fields with responsive columns and explicit span rules.", + "descriptionZh": "以响应式列布局展示成组只读字段。", "props": [ { "name": "title", @@ -2242,6 +2242,18 @@ "required": false, "description": "" }, + { + "name": "extra", + "type": "React.ReactNode", + "required": false, + "description": "" + }, + { + "name": "footer", + "type": "React.ReactNode", + "required": false, + "description": "" + }, { "name": "bordered", "type": "boolean", @@ -2249,8 +2261,8 @@ "description": "" }, { - "name": "column", - "type": "number", + "name": "columns", + "type": "ResponsiveValue", "required": false, "description": "" }, @@ -2272,6 +2284,54 @@ "required": false, "description": "" }, + { + "name": "separator", + "type": "React.ReactNode", + "required": false, + "description": "" + }, + { + "name": "items", + "type": "DescriptionsItemType[]", + "required": false, + "description": "" + }, + { + "name": "empty", + "type": "React.ReactNode", + "required": false, + "description": "" + }, + { + "name": "semantic", + "type": "'auto' | 'table' | 'list'", + "required": false, + "description": "" + }, + { + "name": "labelAlign", + "type": "'start' | 'center' | 'end'", + "required": false, + "description": "" + }, + { + "name": "contentAlign", + "type": "'start' | 'center' | 'end'", + "required": false, + "description": "" + }, + { + "name": "labelRender", + "type": "(item: DescriptionsItemType, index: number) => React.ReactNode", + "required": false, + "description": "" + }, + { + "name": "contentRender", + "type": "(item: DescriptionsItemType, index: number) => React.ReactNode", + "required": false, + "description": "" + }, { "name": "style", "type": "CSSProperties", @@ -2294,23 +2354,39 @@ "demos": [ { "name": "Basic", - "code": "import React from 'react';\nimport { Descriptions } from '@tiny-design/react';\n\nexport default function BasicDemo() {\n return (\n \n React\n 0200004567\n Sydney, Australia\n Great\n 456P+HW Camperdown, New South Wales\n \n );\n}" + "code": "import React from 'react';\nimport { Button, Descriptions, Tag } from '@tiny-design/react';\n\nexport default function BasicDemo() {\n return (\n Edit}\n columns={2}\n footer={Last synced 2 minutes ago}>\n Tiny Studio\n Australia Southeast\n Core}>\n Product Ops\n \n tiny.design\n \n Shared component workspace for tokens, docs, charts, and platform-specific UI packages.\n \n \n );\n}\n" }, { "name": "Border", - "code": "import React from 'react';\nimport { Descriptions, Badge } from '@tiny-design/react';\n\nexport default function BorderDemo() {\n return (\n \n Cloud Database\n Prepaid\n YES\n 2018-04-24 18:00:00\n \n 2019-04-24 18:00:00\n \n \n \n Running\n \n $80.00\n $20.00\n $60.00\n \n Data disk type: MongoDB\n
\n Database version: 3.4\n
\n Package: dds.mongo.mid\n
\n Storage space: 10 GB\n
\n Replication factor: 3\n
\n Region: East China 1\n
\n
\n );\n}" + "code": "import React from 'react';\nimport { Badge, Descriptions } from '@tiny-design/react';\n\nexport default function BorderDemo() {\n return (\n \n \n Running\n \n ),\n span: 'fill',\n },\n { key: 'amount', label: 'Amount', content: '$80.00' },\n { key: 'discount', label: 'Discount', content: '$20.00' },\n { key: 'total', label: 'Receipts', content: '$60.00' },\n {\n key: 'config',\n label: 'Config',\n span: 'fill',\n content: 'MongoDB / 3 replicas / 10 GB',\n },\n ]}\n />\n );\n}\n" + }, + { + "name": "EmptyHidden", + "code": "import React from 'react';\nimport { Descriptions } from '@tiny-design/react';\n\nexport default function EmptyHiddenDemo() {\n return (\n \n );\n}\n" + }, + { + "name": "RenderAlign", + "code": "import React from 'react';\nimport { Descriptions, Tag } from '@tiny-design/react';\n\nexport default function RenderAlignDemo() {\n return (\n (\n \n {item.label}\n \n )}\n contentRender={(item) => {\n if (item.key === 'severity') {\n return High;\n }\n\n return item.content;\n }}\n />\n );\n}\n" + }, + { + "name": "Semantic", + "code": "import React from 'react';\nimport { Descriptions } from '@tiny-design/react';\n\nexport default function SemanticDemo() {\n return (\n
\n \n \n
\n );\n}\n" + }, + { + "name": "Separator", + "code": "import React from 'react';\nimport { Descriptions } from '@tiny-design/react';\n\nexport default function SeparatorDemo() {\n return (\n \n );\n}\n" }, { "name": "Size", - "code": "import React from 'react';\nimport { Descriptions, Radio } from '@tiny-design/react';\n\ntype DemoSize = 'sm' | 'md' | 'lg';\n\nexport default function SizeDemo() {\n const [size, setSize] = React.useState('md');\n\n return (\n
\n setSize(val as DemoSize)} value={size}>\n Small\n Medium\n Large\n \n
\n
\n \n Cloud Database\n Prepaid\n 18:00:00\n $80.00\n $20.00\n $60.00\n \n Data disk type: MongoDB\n
\n Database version: 3.4\n
\n Package: dds.mongo.mid\n
\n Storage space: 10 GB\n
\n Replication factor: 3\n
\n Region: East China 1\n
\n
\n
\n
\n \n Cloud Database\n Prepaid\n 18:00:00\n $80.00\n $20.00\n $60.00\n \n
\n );\n}\n" + "code": "import React from 'react';\nimport { Descriptions } from '@tiny-design/react';\n\nexport default function SizeDemo() {\n return (\n \n );\n}\n" }, { "name": "Vertical", - "code": "import React from 'react';\nimport { Descriptions } from '@tiny-design/react';\n\nexport default function VerticalDemo() {\n return (\n \n React\n 0200004567\n Sydney, Australia\n Great\n 456P+HW Camperdown, New South Wales\n \n );\n}" + "code": "import React from 'react';\nimport { Descriptions } from '@tiny-design/react';\n\nexport default function VerticalDemo() {\n return (\n \n );\n}\n" }, { "name": "VerticalBorder", - "code": "import React from 'react';\nimport { Descriptions, Badge } from '@tiny-design/react';\n\nexport default function VerticalBorderDemo() {\n return (\n \n Cloud Database\n Prepaid\n YES\n 2018-04-24 18:00:00\n \n 2019-04-24 18:00:00\n \n \n \n Running\n \n $80.00\n $20.00\n $60.00\n \n Data disk type: MongoDB\n
\n Database version: 3.4\n
\n Package: dds.mongo.mid\n
\n Storage space: 10 GB\n
\n Replication factor: 3\n
\n Region: East China 1\n
\n
\n );\n}" + "code": "import React from 'react';\nimport { Descriptions } from '@tiny-design/react';\n\nexport default function VerticalBorderDemo() {\n return (\n \n );\n}\n" } ] }, @@ -3147,7 +3223,7 @@ }, { "name": "placeholder", - "type": "string", + "type": "React.ReactNode", "required": false, "description": "" }, @@ -3183,7 +3259,7 @@ }, { "name": "fallback", - "type": "string", + "type": "React.ReactNode", "required": false, "description": "" }, @@ -3193,6 +3269,18 @@ "required": false, "description": "" }, + { + "name": "imageClassName", + "type": "string", + "required": false, + "description": "" + }, + { + "name": "imageStyle", + "type": "CSSProperties", + "required": false, + "description": "" + }, { "name": "style", "type": "CSSProperties", @@ -3215,15 +3303,27 @@ "demos": [ { "name": "Basic", - "code": "import React from 'react';\nimport { Image } from '@tiny-design/react';\n\nexport default function BasicDemo() {\n return ;\n}" + "code": "import React from 'react';\nimport { Image } from '@tiny-design/react';\n\nexport default function BasicDemo() {\n return (\n \n );\n}\n" + }, + { + "name": "CustomFallback", + "code": "import React from 'react';\nimport { Flex, Image } from '@tiny-design/react';\n\nconst fallbackStyle: React.CSSProperties = {\n width: '100%',\n height: '100%',\n color: '#475569',\n background:\n 'radial-gradient(circle at top, rgba(59, 130, 246, 0.12), rgba(148, 163, 184, 0.12) 45%, rgba(248, 250, 252, 1) 100%)',\n fontSize: 14,\n textAlign: 'center',\n};\n\nexport default function CustomFallbackDemo() {\n return (\n \n Image unavailable\n The asset could not be loaded.\n \n }\n />\n );\n}\n" }, { "name": "Fallback", - "code": "import React from 'react';\nimport { Image } from '@tiny-design/react';\n\nexport default function FallbackDemo() {\n return ;\n}" + "code": "import React from 'react';\nimport { Image } from '@tiny-design/react';\n\nexport default function FallbackDemo() {\n return ;\n}\n" + }, + { + "name": "ImageStyle", + "code": "import React from 'react';\nimport { Flex, Image, Radio, Select, Switch } from '@tiny-design/react';\n\nconst OBJECT_FIT_OPTIONS = ['cover', 'contain', 'fill', 'none', 'scale-down'] as const;\n\nfunction createSvgDataUrl(svg: string): string {\n return `data:image/svg+xml;utf8,${encodeURIComponent(svg.trim())}`;\n}\n\nfunction createTallPoster(): string {\n return createSvgDataUrl(`\n \n \n \n \n \n \n \n \n \n TOP\n CENTER\n BOTTOM\n \n `);\n}\n\nfunction createStretchChart(): string {\n return createSvgDataUrl(`\n \n \n \n \n \n \n \n \n \n CIRCLE\n SQUARE\n \n `);\n}\n\nfunction createSmallBadge(): string {\n return createSvgDataUrl(`\n \n \n \n \n \n 96×64\n \n `);\n}\n\nconst focusOptions = [\n { label: 'Center', value: 'center center' },\n { label: 'Top section', value: 'center 15%' },\n { label: 'Bottom section', value: 'center 85%' },\n];\n\nconst tallSrc = createTallPoster();\nconst chartSrc = createStretchChart();\nconst smallSrc = createSmallBadge();\n\nconst checkerboardStyle: React.CSSProperties = {\n boxShadow: '0 8px 24px rgba(15, 23, 42, 0.12)',\n backgroundColor: '#e2e8f0',\n backgroundImage:\n 'linear-gradient(45deg, rgba(148, 163, 184, 0.18) 25%, transparent 25%), linear-gradient(-45deg, rgba(148, 163, 184, 0.18) 25%, transparent 25%), linear-gradient(45deg, transparent 75%, rgba(148, 163, 184, 0.18) 75%), linear-gradient(-45deg, transparent 75%, rgba(148, 163, 184, 0.18) 75%)',\n backgroundSize: '18px 18px',\n backgroundPosition: '0 0, 0 9px, 9px -9px, -9px 0',\n};\n\nconst captionStyle: React.CSSProperties = {\n fontSize: 12,\n color: '#64748b',\n lineHeight: 1.5,\n};\n\nexport default function ImageStyleDemo() {\n const [objectFit, setObjectFit] = React.useState<(typeof OBJECT_FIT_OPTIONS)[number]>('cover');\n const [objectPosition, setObjectPosition] = React.useState('center center');\n const [round, setRound] = React.useState(false);\n const previewWidth = round ? 160 : 240;\n const previewHeight = round ? 160 : 120;\n\n return (\n \n \n
\n
objectFit
\n setObjectFit(value as (typeof OBJECT_FIT_OPTIONS)[number])}>\n {OBJECT_FIT_OPTIONS.map((option) => (\n \n {option}\n \n ))}\n \n
\n\n
\n
Focal point
\n