From 17653bb57f11310139d8683feeb791fc21867e96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Tue, 20 May 2025 19:20:17 +0800 Subject: [PATCH 01/14] feat: add 'horizontal-alternate' --- src/Step.tsx | 28 +++++++++++++++++----------- src/Steps.tsx | 19 ++++++++++++++----- tests/alternate.test.tsx | 18 ++++++++++++++++++ 3 files changed, 49 insertions(+), 16 deletions(-) create mode 100644 tests/alternate.test.tsx diff --git a/src/Step.tsx b/src/Step.tsx index 85606d5..9e72380 100644 --- a/src/Step.tsx +++ b/src/Step.tsx @@ -5,6 +5,10 @@ import KeyCode from '@rc-component/util/lib/KeyCode'; import type { Status, StepItem, StepsProps } from './Steps'; import Rail from './Rail'; +function hasContent(value: T) { + return value !== undefined && value !== null; +} + export interface StepProps { // style prefixCls?: string; @@ -18,12 +22,6 @@ export interface StepProps { index: number; last: boolean; - // stepIndex?: number; - // stepNumber?: number; - // title?: React.ReactNode; - // subTitle?: React.ReactNode; - // description?: React.ReactNode; - // render iconRender?: StepsProps['iconRender']; icon?: React.ReactNode; @@ -115,6 +113,9 @@ export default function Step(props: StepProps) { // ========================= Render ========================= const mergedStatus = status || 'wait'; + const hasTitle = hasContent(title); + const hasSubTitle = hasContent(subTitle); + const classString = cls( itemCls, `${itemCls}-${mergedStatus}`, @@ -122,11 +123,14 @@ export default function Step(props: StepProps) { [`${itemCls}-custom`]: icon, [`${itemCls}-active`]: active, [`${itemCls}-disabled`]: disabled === true, + [`${itemCls}-empty-header`]: !hasTitle && !hasSubTitle, }, className, classNames.item, ); + // !hasContent(title) && !hasContent(subTitle) && `${itemCls}-header-empty` + const wrapperNode = (
@@ -134,10 +138,12 @@ export default function Step(props: StepProps) {
-
- {title} -
- {subTitle && ( + {hasTitle && ( +
+ {title} +
+ )} + {hasSubTitle && (
)}
- {mergedContent && ( + {hasContent(mergedContent) && (
{ + if (isVertical) { + return titlePlacement === 'horizontal' || titlePlacement === 'horizontal-alternate' + ? titlePlacement + : 'horizontal'; + } + + return titlePlacement === 'vertical' || titlePlacement === 'horizontal' + ? titlePlacement + : 'horizontal'; + }, [isVertical, titlePlacement]); // ============================= styles ============================= const classString = cls( diff --git a/tests/alternate.test.tsx b/tests/alternate.test.tsx new file mode 100644 index 0000000..41a8529 --- /dev/null +++ b/tests/alternate.test.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import Steps from '../src'; + +describe('Steps.alternate', () => { + it('should have empty className', () => { + const { container } = render(); + + expect(container.querySelector('.rc-steps-item')).toHaveClass('rc-steps-item-empty-header'); + }); + + it('', () => { + const { container } = render( + , + ); + expect(container.querySelector('.rc-steps')).toHaveClass('rc-steps-title-horizontal-alternate'); + }); +}); From f0f723e0d1a4ec7107c28e2fa40df2b536dad391 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Tue, 20 May 2025 19:22:35 +0800 Subject: [PATCH 02/14] chore: bump version to 1.2.0-alpha.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7d3e0a3..aae2905 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@rc-component/steps", - "version": "1.1.0", + "version": "1.2.0-alpha.0", "description": "steps ui component for react", "keywords": [ "react", From e17adebf44da083089d72c148a3b1c7f5f0d3cef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Wed, 21 May 2025 10:56:07 +0800 Subject: [PATCH 03/14] test: update name --- tests/alternate.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/alternate.test.tsx b/tests/alternate.test.tsx index 41a8529..3de4091 100644 --- a/tests/alternate.test.tsx +++ b/tests/alternate.test.tsx @@ -9,7 +9,7 @@ describe('Steps.alternate', () => { expect(container.querySelector('.rc-steps-item')).toHaveClass('rc-steps-item-empty-header'); }); - it('', () => { + it('horizontal-alternate orientation support', () => { const { container } = render( , ); From 4b1886f3b9fe0567c1910bf146dbf4cc816c7ff9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Thu, 22 May 2025 11:00:05 +0800 Subject: [PATCH 04/14] chore: support rail reverse --- src/Step.tsx | 13 ++++++++++--- src/UnstableContext.ts | 11 +++++++++++ src/index.ts | 1 + 3 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 src/UnstableContext.ts diff --git a/src/Step.tsx b/src/Step.tsx index 9e72380..5000264 100644 --- a/src/Step.tsx +++ b/src/Step.tsx @@ -4,6 +4,7 @@ import cls from 'classnames'; import KeyCode from '@rc-component/util/lib/KeyCode'; import type { Status, StepItem, StepsProps } from './Steps'; import Rail from './Rail'; +import { UnstableContext } from './UnstableContext'; function hasContent(value: T) { return value !== undefined && value !== null; @@ -57,6 +58,9 @@ export default function Step(props: StepProps) { const itemCls = `${prefixCls}-item`; + // ==================== Internal Context ==================== + const { railFollowPrevStatus } = React.useContext(UnstableContext); + // ========================== Data ========================== const { onClick: onItemClick, @@ -129,8 +133,6 @@ export default function Step(props: StepProps) { classNames.item, ); - // !hasContent(title) && !hasContent(subTitle) && `${itemCls}-header-empty` - const wrapperNode = (
@@ -154,7 +156,12 @@ export default function Step(props: StepProps) { )} {!last && ( - + )}
{hasContent(mergedContent) && ( diff --git a/src/UnstableContext.ts b/src/UnstableContext.ts new file mode 100644 index 0000000..d755313 --- /dev/null +++ b/src/UnstableContext.ts @@ -0,0 +1,11 @@ +import * as React from 'react'; + +export interface UnstableContextProps { + /** + * Used for Timeline component `reverse` prop. + * Safe to remove if refactor. + */ + railFollowPrevStatus?: boolean; +} + +export const UnstableContext = React.createContext({}); diff --git a/src/index.ts b/src/index.ts index 8c5e175..22f5a76 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,4 +3,5 @@ import Step from './Step'; export { Step }; export type { StepsProps }; +export { UnstableContext } from './UnstableContext'; export default Steps; From 88aca1005bcdbcda82cd616a9f8d49460647a66a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Thu, 22 May 2025 11:01:36 +0800 Subject: [PATCH 05/14] chore: bump version to 1.2.0-alpha.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index aae2905..b27f74f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@rc-component/steps", - "version": "1.2.0-alpha.0", + "version": "1.2.0-alpha.1", "description": "steps ui component for react", "keywords": [ "react", From 2815305e8a4c7a86c7749ab83ba379f06226e7cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Tue, 27 May 2025 16:53:35 +0800 Subject: [PATCH 06/14] chore: clean up --- src/Steps.tsx | 15 +++------------ tests/alternate.test.tsx | 18 ------------------ 2 files changed, 3 insertions(+), 30 deletions(-) delete mode 100644 tests/alternate.test.tsx diff --git a/src/Steps.tsx b/src/Steps.tsx index 4fe8d54..09476ee 100644 --- a/src/Steps.tsx +++ b/src/Steps.tsx @@ -55,7 +55,7 @@ export interface StepsProps { // layout orientation?: 'horizontal' | 'vertical'; - titlePlacement?: 'horizontal' | 'vertical' | 'horizontal-alternate'; + titlePlacement?: 'horizontal' | 'vertical'; // data status?: Status; @@ -102,17 +102,8 @@ export default function Steps(props: StepsProps) { // ============================= layout ============================= const isVertical = orientation === 'vertical'; const mergedOrientation = isVertical ? 'vertical' : 'horizontal'; - const mergeTitlePlacement = React.useMemo(() => { - if (isVertical) { - return titlePlacement === 'horizontal' || titlePlacement === 'horizontal-alternate' - ? titlePlacement - : 'horizontal'; - } - - return titlePlacement === 'vertical' || titlePlacement === 'horizontal' - ? titlePlacement - : 'horizontal'; - }, [isVertical, titlePlacement]); + const mergeTitlePlacement = + !isVertical && titlePlacement === 'vertical' ? 'vertical' : 'horizontal'; // ============================= styles ============================= const classString = cls( diff --git a/tests/alternate.test.tsx b/tests/alternate.test.tsx deleted file mode 100644 index 3de4091..0000000 --- a/tests/alternate.test.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import React from 'react'; -import { render } from '@testing-library/react'; -import Steps from '../src'; - -describe('Steps.alternate', () => { - it('should have empty className', () => { - const { container } = render(); - - expect(container.querySelector('.rc-steps-item')).toHaveClass('rc-steps-item-empty-header'); - }); - - it('horizontal-alternate orientation support', () => { - const { container } = render( - , - ); - expect(container.querySelector('.rc-steps')).toHaveClass('rc-steps-title-horizontal-alternate'); - }); -}); From d24474d1c44d2259bded601933211dc597c73be7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Tue, 3 Jun 2025 16:48:05 +0800 Subject: [PATCH 07/14] chore: support components --- src/Context.ts | 10 ++++++++++ src/Step.tsx | 17 ++++++++++++++--- src/StepIcon.tsx | 27 +++++++++++++++++++++++++++ src/Steps.tsx | 31 +++++++++++++++++++++++++++---- 4 files changed, 78 insertions(+), 7 deletions(-) create mode 100644 src/Context.ts create mode 100644 src/StepIcon.tsx diff --git a/src/Context.ts b/src/Context.ts new file mode 100644 index 0000000..ed1f46e --- /dev/null +++ b/src/Context.ts @@ -0,0 +1,10 @@ +import * as React from 'react'; +import type { StepsProps } from './Steps'; + +export interface StepsContextProps { + prefixCls: string; + classNames: NonNullable; + styles: NonNullable; +} + +export const StepsContext = React.createContext(null!); diff --git a/src/Step.tsx b/src/Step.tsx index 5000264..08c43e9 100644 --- a/src/Step.tsx +++ b/src/Step.tsx @@ -5,6 +5,7 @@ import KeyCode from '@rc-component/util/lib/KeyCode'; import type { Status, StepItem, StepsProps } from './Steps'; import Rail from './Rail'; import { UnstableContext } from './UnstableContext'; +import StepIcon from './StepIcon'; function hasContent(value: T) { return value !== undefined && value !== null; @@ -133,11 +134,21 @@ export default function Step(props: StepProps) { classNames.item, ); + let iconNode = ; + if (iconRender) { + iconNode = iconRender(iconNode, { + ...renderInfo, + components: { + icon: StepIcon, + }, + }) as React.ReactElement; + } + const wrapperNode = (
-
- {iconRender?.(renderInfo)} -
+ {/* Icon */} + {iconNode} +
{hasTitle && ( diff --git a/src/StepIcon.tsx b/src/StepIcon.tsx new file mode 100644 index 0000000..c12a56f --- /dev/null +++ b/src/StepIcon.tsx @@ -0,0 +1,27 @@ +import * as React from 'react'; +import cls from 'classnames'; +import { StepsContext } from './Context'; +import pickAttrs from '@rc-component/util/lib/pickAttrs'; + +export type StepIconProps = React.HTMLAttributes; + +const StepIcon = React.forwardRef((props, ref) => { + const { className, style, ...restProps } = props; + const { prefixCls, classNames, styles } = React.useContext(StepsContext); + + const itemCls = `${prefixCls}-item`; + + return ( +
+ ); +}); + +export default StepIcon; diff --git a/src/Steps.tsx b/src/Steps.tsx index 09476ee..9ff9f84 100644 --- a/src/Steps.tsx +++ b/src/Steps.tsx @@ -2,9 +2,13 @@ import cls from 'classnames'; import React from 'react'; import Step from './Step'; +import { StepsContext, type StepsContextProps } from './Context'; +import type StepIcon from './StepIcon'; export type Status = 'error' | 'process' | 'finish' | 'wait'; +const EmptyObject = {}; + export type SemanticName = | 'root' | 'item' @@ -65,7 +69,14 @@ export interface StepsProps { onChange?: (current: number) => void; // render - iconRender?: (info: RenderInfo) => React.ReactNode; + iconRender?: ( + originNode: React.ReactElement, + info: RenderInfo & { + components: { + icon: typeof StepIcon; + }; + }, + ) => React.ReactNode; itemRender?: (originNode: React.ReactElement, info: RenderInfo) => React.ReactNode; itemWrapperRender?: (originNode: React.ReactElement) => React.ReactNode; } @@ -76,8 +87,8 @@ export default function Steps(props: StepsProps) { prefixCls = 'rc-steps', style, className, - classNames = {}, - styles = {}, + classNames = EmptyObject as NonNullable, + styles = EmptyObject as NonNullable, rootClassName, // layout @@ -143,6 +154,16 @@ export default function Steps(props: StepsProps) { } }; + // ============================ contexts ============================ + const stepIconContext = React.useMemo( + () => ({ + prefixCls, + classNames, + styles, + }), + [prefixCls, classNames, styles], + ); + // ============================= render ============================= const renderStep = (item: StepItem, index: number) => { const stepIndex = initial + index; @@ -186,7 +207,9 @@ export default function Steps(props: StepsProps) { }} {...restProps} > - {mergedItems.map(renderStep)} + + {mergedItems.map(renderStep)} +
); } From cae5fc388c5621571e3f8e98d11a5c0255ccffa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Tue, 3 Jun 2025 16:49:09 +0800 Subject: [PATCH 08/14] chore: bump version to 1.2.0-alpha.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b27f74f..1ace64f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@rc-component/steps", - "version": "1.2.0-alpha.1", + "version": "1.2.0-alpha.2", "description": "steps ui component for react", "keywords": [ "react", From e40e2c9fa66c15d42076ac57368bfefbf2895ae2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Tue, 3 Jun 2025 17:34:03 +0800 Subject: [PATCH 09/14] test: add test case --- src/Step.tsx | 2 +- src/StepIcon.tsx | 6 ++++-- src/Steps.tsx | 2 +- tests/index.test.tsx | 19 +++++++++++++++++++ 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/Step.tsx b/src/Step.tsx index 08c43e9..6603f96 100644 --- a/src/Step.tsx +++ b/src/Step.tsx @@ -139,7 +139,7 @@ export default function Step(props: StepProps) { iconNode = iconRender(iconNode, { ...renderInfo, components: { - icon: StepIcon, + Icon: StepIcon, }, }) as React.ReactElement; } diff --git a/src/StepIcon.tsx b/src/StepIcon.tsx index c12a56f..dcac9e9 100644 --- a/src/StepIcon.tsx +++ b/src/StepIcon.tsx @@ -6,7 +6,7 @@ import pickAttrs from '@rc-component/util/lib/pickAttrs'; export type StepIconProps = React.HTMLAttributes; const StepIcon = React.forwardRef((props, ref) => { - const { className, style, ...restProps } = props; + const { className, style, children, ...restProps } = props; const { prefixCls, classNames, styles } = React.useContext(StepsContext); const itemCls = `${prefixCls}-item`; @@ -20,7 +20,9 @@ const StepIcon = React.forwardRef((props, ref) => ...styles.itemIcon, ...style, }} - /> + > + {children} +
); }); diff --git a/src/Steps.tsx b/src/Steps.tsx index 9ff9f84..cd059d3 100644 --- a/src/Steps.tsx +++ b/src/Steps.tsx @@ -73,7 +73,7 @@ export interface StepsProps { originNode: React.ReactElement, info: RenderInfo & { components: { - icon: typeof StepIcon; + Icon: typeof StepIcon; }; }, ) => React.ReactNode; diff --git a/tests/index.test.tsx b/tests/index.test.tsx index 9647480..cc59327 100644 --- a/tests/index.test.tsx +++ b/tests/index.test.tsx @@ -344,4 +344,23 @@ describe('Steps', () => { expect(container.querySelector('.rc-steps-item')).toBeTruthy(); expect(container.querySelector('.rc-steps-item > .bamboo')).toBeTruthy(); }); + + it('iconRender', () => { + const { container } = render( + { + return little; + }} + />, + ); + + const iconEle = container.querySelector('.rc-steps-item-icon')!; + expect(iconEle).toHaveClass('bamboo'); + expect(iconEle.textContent).toBe('little'); + }); }); From dccf281349210558ee6f1cdb99c2f128c00f29d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Tue, 3 Jun 2025 17:37:36 +0800 Subject: [PATCH 10/14] chore: bump version to 1.2.0-alpha.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1ace64f..1c24d4e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@rc-component/steps", - "version": "1.2.0-alpha.2", + "version": "1.2.0-alpha.3", "description": "steps ui component for react", "keywords": [ "react", From c6b7a46b945474579df6dd5f8df68809a80b4b3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Tue, 3 Jun 2025 18:25:23 +0800 Subject: [PATCH 11/14] feat: item support semantic --- src/Rail.tsx | 15 +++------ src/Step.tsx | 72 +++++++++++++++++++++++++++++++++-------- src/StepIcon.tsx | 12 ++++++- src/Steps.tsx | 13 ++++++++ tests/semantic.test.tsx | 67 ++++++++++++++++++++++++++++++++++++-- 5 files changed, 152 insertions(+), 27 deletions(-) diff --git a/src/Rail.tsx b/src/Rail.tsx index 85503c3..5850146 100644 --- a/src/Rail.tsx +++ b/src/Rail.tsx @@ -1,23 +1,18 @@ import * as React from 'react'; import cls from 'classnames'; -import type { Status, StepsProps } from './Steps'; +import type { Status } from './Steps'; export interface RailProps { prefixCls: string; - classNames: StepsProps['classNames']; - styles: StepsProps['styles']; + className: string; + style: React.CSSProperties; status: Status; } export default function Rail(props: RailProps) { - const { prefixCls, classNames, styles, status } = props; + const { prefixCls, className, style, status } = props; const railCls = `${prefixCls}-rail`; // ============================= render ============================= - return ( -
- ); + return
; } diff --git a/src/Step.tsx b/src/Step.tsx index 6603f96..156ec27 100644 --- a/src/Step.tsx +++ b/src/Step.tsx @@ -5,7 +5,7 @@ import KeyCode from '@rc-component/util/lib/KeyCode'; import type { Status, StepItem, StepsProps } from './Steps'; import Rail from './Rail'; import { UnstableContext } from './UnstableContext'; -import StepIcon from './StepIcon'; +import StepIcon, { StepIconSemanticContext } from './StepIcon'; function hasContent(value: T) { return value !== undefined && value !== null; @@ -75,6 +75,9 @@ export default function Step(props: StepProps) { className, style, + classNames: itemClassNames = {}, + styles: itemStyles = {}, + ...restItemProps } = data; @@ -132,6 +135,7 @@ export default function Step(props: StepProps) { }, className, classNames.item, + itemClassNames.root, ); let iconNode = ; @@ -145,22 +149,60 @@ export default function Step(props: StepProps) { } const wrapperNode = ( -
+
{/* Icon */} - {iconNode} - -
-
+ + {iconNode} + + +
+
{hasTitle && ( -
+
{title}
)} {hasSubTitle && (
{subTitle}
@@ -169,16 +211,19 @@ export default function Step(props: StepProps) { {!last && ( )}
{hasContent(mergedContent) && (
{mergedContent}
@@ -194,6 +239,7 @@ export default function Step(props: StepProps) { className={classString} style={{ ...styles.item, + ...itemStyles.root, ...style, }} > diff --git a/src/StepIcon.tsx b/src/StepIcon.tsx index dcac9e9..ea2bd07 100644 --- a/src/StepIcon.tsx +++ b/src/StepIcon.tsx @@ -3,11 +3,20 @@ import cls from 'classnames'; import { StepsContext } from './Context'; import pickAttrs from '@rc-component/util/lib/pickAttrs'; +export interface StepIconSemanticContextProps { + className?: string; + style?: React.CSSProperties; +} + +export const StepIconSemanticContext = React.createContext({}); + export type StepIconProps = React.HTMLAttributes; const StepIcon = React.forwardRef((props, ref) => { const { className, style, children, ...restProps } = props; + const { prefixCls, classNames, styles } = React.useContext(StepsContext); + const { className: itemClassName, style: itemStyle } = React.useContext(StepIconSemanticContext); const itemCls = `${prefixCls}-item`; @@ -15,9 +24,10 @@ const StepIcon = React.forwardRef((props, ref) =>
diff --git a/src/Steps.tsx b/src/Steps.tsx index cd059d3..7c1ce8d 100644 --- a/src/Steps.tsx +++ b/src/Steps.tsx @@ -21,6 +21,17 @@ export type SemanticName = | 'itemIcon' | 'itemRail'; +export type ItemSemanticName = + | 'root' + | 'wrapper' + | 'header' + | 'title' + | 'subtitle' + | 'section' + | 'content' + | 'icon' + | 'rail'; + export type StepItem = { /** @deprecated Please use `content` instead. */ description?: React.ReactNode; @@ -30,6 +41,8 @@ export type StepItem = { status?: Status; subTitle?: React.ReactNode; title?: React.ReactNode; + classNames?: Partial>; + styles?: Partial>; } & Pick, 'onClick' | 'className' | 'style'>; export type StepIconRender = (info: { diff --git a/tests/semantic.test.tsx b/tests/semantic.test.tsx index d84b735..dd7888a 100644 --- a/tests/semantic.test.tsx +++ b/tests/semantic.test.tsx @@ -1,7 +1,7 @@ import React from 'react'; -import { render, fireEvent } from '@testing-library/react'; +import { render } from '@testing-library/react'; import Steps, { type StepsProps } from '../src'; -import type { SemanticName } from '../src/Steps'; +import type { ItemSemanticName, SemanticName } from '../src/Steps'; describe('Steps.Semantic', () => { const renderSteps = (props: Partial) => ( @@ -9,7 +9,7 @@ describe('Steps.Semantic', () => { items={Array.from({ length: 3 }, (_, index) => ({ title: `Step ${index + 1}`, subTitle: `SubTitle ${index + 1}`, - description: `Description ${index + 1}`, + content: `Content ${index + 1}`, }))} {...props} /> @@ -73,4 +73,65 @@ describe('Steps.Semantic', () => { expect(element).toHaveStyle(style); }); }); + + it('item semantic structure', () => { + const classNames: Record = { + root: 'custom-root', + wrapper: 'custom-wrapper', + header: 'custom-header', + title: 'custom-title', + subtitle: 'custom-subtitle', + section: 'custom-section', + content: 'custom-content', + icon: 'custom-icon', + rail: 'custom-rail', + }; + + const classNamesTargets: Record = { + root: 'rc-steps-item', + wrapper: 'rc-steps-item-wrapper', + header: 'rc-steps-item-header', + title: 'rc-steps-item-title', + subtitle: 'rc-steps-item-subtitle', + section: 'rc-steps-item-section', + content: 'rc-steps-item-content', + icon: 'rc-steps-item-icon', + rail: 'rc-steps-item-rail', + }; + + const styles: Record> = { + root: { color: 'red' }, + wrapper: { color: 'green' }, + header: { color: 'orange' }, + title: { color: 'pink' }, + subtitle: { color: 'cyan' }, + section: { color: 'purple' }, + content: { color: 'magenta' }, + icon: { color: 'yellow' }, + rail: { color: 'lime' }, + }; + + const { container } = render( + renderSteps({ + items: Array.from({ length: 2 }, (_, index) => ({ + title: `Title ${index + 1}`, + subTitle: `SubTitle ${index + 1}`, + content: `Content ${index + 1}`, + classNames, + styles, + })), + }), + ); + + Object.keys(classNames).forEach((key) => { + const className = classNames[key as SemanticName]; + const oriClassName = classNamesTargets[key as SemanticName]; + const style = styles[key as SemanticName]; + + const element = container.querySelector(`.${className}`); + expect(element).toBeTruthy(); + expect(element).toHaveClass(oriClassName); + expect(element).toHaveStyle(style); + }); + }); }); From aab80fee4541c45b2b1fbda1089a9326af837c68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Tue, 3 Jun 2025 18:26:03 +0800 Subject: [PATCH 12/14] chore: bump version to 1.2.0-alpha.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1c24d4e..eb15d51 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@rc-component/steps", - "version": "1.2.0-alpha.3", + "version": "1.2.0-alpha.4", "description": "steps ui component for react", "keywords": [ "react", From 844b3cdc0296c153ac9b033450bbbadc803f8950 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Tue, 3 Jun 2025 20:15:37 +0800 Subject: [PATCH 13/14] refactor: use ol instead --- src/Step.tsx | 8 +- src/Steps.tsx | 6 +- tests/__snapshots__/index.test.tsx.snap | 236 ++++++++++++------------ 3 files changed, 125 insertions(+), 125 deletions(-) diff --git a/src/Step.tsx b/src/Step.tsx index 156ec27..a305f97 100644 --- a/src/Step.tsx +++ b/src/Step.tsx @@ -98,8 +98,8 @@ export default function Step(props: StepProps) { const accessibilityProps: { role?: string; tabIndex?: number; - onClick?: React.MouseEventHandler; - onKeyDown?: React.KeyboardEventHandler; + onClick?: React.MouseEventHandler; + onKeyDown?: React.KeyboardEventHandler; } = {}; if (clickable) { @@ -233,7 +233,7 @@ export default function Step(props: StepProps) { ); let stepNode: React.ReactNode = ( -
{itemWrapperRender ? itemWrapperRender(wrapperNode) : wrapperNode} -
+ ); if (itemRender) { diff --git a/src/Steps.tsx b/src/Steps.tsx index 7c1ce8d..f928208 100644 --- a/src/Steps.tsx +++ b/src/Steps.tsx @@ -43,7 +43,7 @@ export type StepItem = { title?: React.ReactNode; classNames?: Partial>; styles?: Partial>; -} & Pick, 'onClick' | 'className' | 'style'>; +} & Pick, 'onClick' | 'className' | 'style'>; export type StepIconRender = (info: { index: number; @@ -212,7 +212,7 @@ export default function Steps(props: StepsProps) { }; return ( -
{mergedItems.map(renderStep)} -
+ ); } diff --git a/tests/__snapshots__/index.test.tsx.snap b/tests/__snapshots__/index.test.tsx.snap index 3bbe2ee..0141179 100644 --- a/tests/__snapshots__/index.test.tsx.snap +++ b/tests/__snapshots__/index.test.tsx.snap @@ -1,10 +1,10 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Steps render renders correctly 1`] = ` -
-
-
-
+
  • -
    -
    +
  • -
    -
    +
  • -
    -
    + + `; exports[`Steps render renders current correctly 1`] = ` -
    -
    -
    -
    +
  • -
    -
    +
  • -
    -
    +
  • -
    -
    + + `; exports[`Steps render renders progressDot correctly 1`] = ` -
    -
    -
    -
    +
  • -
    -
    +
  • -
    -
    +
  • -
    -
    + + `; exports[`Steps render renders progressDot function correctly 1`] = ` -
    -
    -
    -
    +
  • -
    -
    +
  • -
    -
    +
  • -
    -
    + + `; exports[`Steps render renders status correctly 1`] = ` -
    -
    -
    -
    +
  • - -
    +
  • - -
    +
  • - - + + `; exports[`Steps render renders step with description 1`] = ` -
    -
    -
    -
    +
  • - -
    +
  • - -
    +
  • - - + + `; exports[`Steps render renders step with description and status 1`] = ` -
    -
    -
    -
    +
  • - -
    +
  • - -
    +
  • - - + + `; exports[`Steps render renders stepIcon function correctly 1`] = ` -
    -
    -
    -
    +
  • - -
    +
  • - -
    +
  • - - + + `; exports[`Steps render renders titlePlacement correctly 1`] = ` -
    -
    -
    -
    +
  • - -
    +
  • - -
    +
  • - - + + `; exports[`Steps render renders vertical correctly 1`] = ` -
    -
    -
    -
    +
  • - -
    +
  • - -
    +
  • - - + + `; exports[`Steps render renders with falsy children 1`] = ` -
    -
    -
    -
    +
  • - -
    +
  • - -
    +
  • - - + + `; exports[`Steps should render customIcon correctly 1`] = ` -
    -
    -
    -
    +
  • - -
    +
  • - - + + `; From 57f2848fc1291230bfb4491fcafd4fcef1f66b11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Wed, 4 Jun 2025 11:32:54 +0800 Subject: [PATCH 14/14] chore: bump version to 1.2.0-alpha.5 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index eb15d51..c2da94a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@rc-component/steps", - "version": "1.2.0-alpha.4", + "version": "1.2.0-alpha.5", "description": "steps ui component for react", "keywords": [ "react",