mirror of
https://github.com/ant-design/ant-design.git
synced 2025-06-11 19:42:54 +08:00
fix: Tour step.type
should work (#45086)
* fix: Tour step.type should work * chore: code clean * chore: update memo deps * chore: code clean
This commit is contained in:
parent
ef7c500a8e
commit
29be72bc38
@ -84,7 +84,7 @@ exports[`Tour Primary 1`] = `
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
class="ant-tour-mask ant-tour-primary"
|
class="ant-tour-mask"
|
||||||
style="position: fixed; left: 0px; right: 0px; top: 0px; bottom: 0px; z-index: 1001; pointer-events: none;"
|
style="position: fixed; left: 0px; right: 0px; top: 0px; bottom: 0px; z-index: 1001; pointer-events: none;"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
@ -157,7 +157,7 @@ exports[`Tour Primary 1`] = `
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
class="ant-tour-primary ant-tour-target-placeholder"
|
class="ant-tour-target-placeholder"
|
||||||
style="left: -6px; top: -6px; width: 12px; height: 12px; position: fixed; pointer-events: none;"
|
style="left: -6px; top: -6px; width: 12px; height: 12px; position: fixed; pointer-events: none;"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -307,7 +307,7 @@ exports[`Tour controlled current 1`] = `
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
class="ant-tour-mask ant-tour-primary"
|
class="ant-tour-mask"
|
||||||
style="position: fixed; left: 0px; right: 0px; top: 0px; bottom: 0px; z-index: 1001; pointer-events: none;"
|
style="position: fixed; left: 0px; right: 0px; top: 0px; bottom: 0px; z-index: 1001; pointer-events: none;"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
@ -339,7 +339,7 @@ exports[`Tour controlled current 1`] = `
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
class="ant-tour-primary ant-tour-target-placeholder"
|
class="ant-tour-target-placeholder"
|
||||||
style="left: 50%; top: 50%; width: 1px; height: 1px; position: fixed; pointer-events: none;"
|
style="left: 50%; top: 50%; width: 1px; height: 1px; position: fixed; pointer-events: none;"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -696,7 +696,7 @@ exports[`Tour step support Primary 1`] = `
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
class="ant-tour-mask ant-tour-primary"
|
class="ant-tour-mask"
|
||||||
style="position: fixed; left: 0px; right: 0px; top: 0px; bottom: 0px; z-index: 1001; pointer-events: none;"
|
style="position: fixed; left: 0px; right: 0px; top: 0px; bottom: 0px; z-index: 1001; pointer-events: none;"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
@ -769,7 +769,7 @@ exports[`Tour step support Primary 1`] = `
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
class="ant-tour-primary ant-tour-target-placeholder"
|
class="ant-tour-target-placeholder"
|
||||||
style="left: -6px; top: -6px; width: 12px; height: 12px; position: fixed; pointer-events: none;"
|
style="left: -6px; top: -6px; width: 12px; height: 12px; position: fixed; pointer-events: none;"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -529,4 +529,38 @@ describe('Tour', () => {
|
|||||||
|
|
||||||
resetIndex();
|
resetIndex();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('first step should be primary', () => {
|
||||||
|
const App: React.FC = () => {
|
||||||
|
const coverBtnRef = useRef<HTMLButtonElement>(null);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<button ref={coverBtnRef} type="button">
|
||||||
|
target
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<Tour
|
||||||
|
steps={[
|
||||||
|
{
|
||||||
|
title: '',
|
||||||
|
description: '',
|
||||||
|
target: () => coverBtnRef.current!,
|
||||||
|
type: 'primary',
|
||||||
|
className: 'should-be-primary',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '',
|
||||||
|
target: () => coverBtnRef.current!,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
render(<App />);
|
||||||
|
fireEvent.click(screen.getByRole('button', { name: 'target' }));
|
||||||
|
expect(document.querySelector('.should-be-primary')).toBeTruthy();
|
||||||
|
expect(document.querySelector('.should-be-primary')).toHaveClass('ant-tour-primary');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,60 +0,0 @@
|
|||||||
import { act, renderHook } from '../../../tests/utils';
|
|
||||||
import useMergedType from '../useMergedType';
|
|
||||||
|
|
||||||
describe('useMergedType', () => {
|
|
||||||
it('returns the merged type', () => {
|
|
||||||
const { result } = renderHook(() =>
|
|
||||||
useMergedType({
|
|
||||||
defaultType: 'default',
|
|
||||||
steps: [{ type: 'primary', title: 'Step 1' }],
|
|
||||||
current: 0,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
expect(result.current?.currentMergedType).toBe('primary');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns the default type', () => {
|
|
||||||
const { result } = renderHook(() =>
|
|
||||||
useMergedType({
|
|
||||||
defaultType: 'default',
|
|
||||||
steps: [],
|
|
||||||
current: 0,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
expect(result.current?.currentMergedType).toBe('default');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns the default type when index is invalid', () => {
|
|
||||||
const { result } = renderHook(() =>
|
|
||||||
useMergedType({
|
|
||||||
defaultType: 'default',
|
|
||||||
steps: [],
|
|
||||||
current: 0,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
expect(result.current?.currentMergedType).toBe('default');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns the default type when list is null', () => {
|
|
||||||
const { result } = renderHook(() =>
|
|
||||||
useMergedType({
|
|
||||||
defaultType: 'default',
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
expect(result.current?.currentMergedType).toBe('default');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns type of new step after onChange from rc-tour', () => {
|
|
||||||
const { result } = renderHook(() =>
|
|
||||||
useMergedType({
|
|
||||||
defaultType: 'default',
|
|
||||||
steps: [{ title: 'Step 1' }, { type: 'primary', title: 'Step 1' }],
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
act(() => {
|
|
||||||
result.current?.updateInnerCurrent?.(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(result.current?.currentMergedType).toBe('primary');
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useContext } from 'react';
|
import React, { useContext, useMemo } from 'react';
|
||||||
import RCTour from '@rc-component/tour';
|
import RCTour from '@rc-component/tour';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
@ -10,15 +10,12 @@ import type { TourProps, TourStepProps } from './interface';
|
|||||||
import TourPanel from './panelRender';
|
import TourPanel from './panelRender';
|
||||||
import PurePanel from './PurePanel';
|
import PurePanel from './PurePanel';
|
||||||
import useStyle from './style';
|
import useStyle from './style';
|
||||||
import useMergedType from './useMergedType';
|
|
||||||
|
|
||||||
const Tour: React.FC<TourProps> & { _InternalPanelDoNotUseOrYouWillBeFired: typeof PurePanel } = (
|
const Tour: React.FC<TourProps> & { _InternalPanelDoNotUseOrYouWillBeFired: typeof PurePanel } = (
|
||||||
props,
|
props,
|
||||||
) => {
|
) => {
|
||||||
const {
|
const {
|
||||||
prefixCls: customizePrefixCls,
|
prefixCls: customizePrefixCls,
|
||||||
current,
|
|
||||||
defaultCurrent,
|
|
||||||
type,
|
type,
|
||||||
rootClassName,
|
rootClassName,
|
||||||
indicatorsRender,
|
indicatorsRender,
|
||||||
@ -30,12 +27,16 @@ const Tour: React.FC<TourProps> & { _InternalPanelDoNotUseOrYouWillBeFired: type
|
|||||||
const [wrapSSR, hashId] = useStyle(prefixCls);
|
const [wrapSSR, hashId] = useStyle(prefixCls);
|
||||||
const [, token] = useToken();
|
const [, token] = useToken();
|
||||||
|
|
||||||
const { currentMergedType, updateInnerCurrent } = useMergedType({
|
const mergedSteps = useMemo(
|
||||||
defaultType: type,
|
() =>
|
||||||
steps,
|
steps?.map((step) => ({
|
||||||
current,
|
...step,
|
||||||
defaultCurrent,
|
className: classNames(step.className, {
|
||||||
});
|
[`${prefixCls}-primary`]: (step.type ?? type) === 'primary',
|
||||||
|
}),
|
||||||
|
})),
|
||||||
|
[steps, type],
|
||||||
|
);
|
||||||
|
|
||||||
const builtinPlacements = getPlacements({
|
const builtinPlacements = getPlacements({
|
||||||
arrowPointAtCenter: true,
|
arrowPointAtCenter: true,
|
||||||
@ -47,7 +48,6 @@ const Tour: React.FC<TourProps> & { _InternalPanelDoNotUseOrYouWillBeFired: type
|
|||||||
|
|
||||||
const customClassName = classNames(
|
const customClassName = classNames(
|
||||||
{
|
{
|
||||||
[`${prefixCls}-primary`]: currentMergedType === 'primary',
|
|
||||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||||
},
|
},
|
||||||
hashId,
|
hashId,
|
||||||
@ -63,23 +63,15 @@ const Tour: React.FC<TourProps> & { _InternalPanelDoNotUseOrYouWillBeFired: type
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
const onStepChange = (stepCurrent: number) => {
|
|
||||||
updateInnerCurrent(stepCurrent);
|
|
||||||
props.onChange?.(stepCurrent);
|
|
||||||
};
|
|
||||||
|
|
||||||
return wrapSSR(
|
return wrapSSR(
|
||||||
<RCTour
|
<RCTour
|
||||||
{...restProps}
|
{...restProps}
|
||||||
rootClassName={customClassName}
|
rootClassName={customClassName}
|
||||||
prefixCls={prefixCls}
|
prefixCls={prefixCls}
|
||||||
current={current}
|
|
||||||
defaultCurrent={defaultCurrent}
|
|
||||||
animated
|
animated
|
||||||
renderPanel={mergedRenderPanel}
|
renderPanel={mergedRenderPanel}
|
||||||
builtinPlacements={builtinPlacements}
|
builtinPlacements={builtinPlacements}
|
||||||
onChange={onStepChange}
|
steps={mergedSteps}
|
||||||
steps={steps}
|
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -43,7 +43,6 @@ const TourPanel: React.FC<TourPanelProps> = ({
|
|||||||
nextButtonProps,
|
nextButtonProps,
|
||||||
prevButtonProps,
|
prevButtonProps,
|
||||||
type: stepType,
|
type: stepType,
|
||||||
className,
|
|
||||||
closeIcon: stepCloseIcon,
|
closeIcon: stepCloseIcon,
|
||||||
} = stepProps;
|
} = stepProps;
|
||||||
|
|
||||||
@ -120,7 +119,7 @@ const TourPanel: React.FC<TourPanelProps> = ({
|
|||||||
const [contextLocale] = useLocale('Tour', defaultLocale.Tour);
|
const [contextLocale] = useLocale('Tour', defaultLocale.Tour);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classNames(className, `${prefixCls}-content`)}>
|
<div className={`${prefixCls}-content`}>
|
||||||
<div className={`${prefixCls}-inner`}>
|
<div className={`${prefixCls}-inner`}>
|
||||||
{closable && mergedDisplayCloseIcon}
|
{closable && mergedDisplayCloseIcon}
|
||||||
{coverNode}
|
{coverNode}
|
||||||
|
@ -1,31 +0,0 @@
|
|||||||
import useMergedState from 'rc-util/lib/hooks/useMergedState';
|
|
||||||
import { useLayoutEffect } from 'react';
|
|
||||||
import type { TourProps } from './interface';
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
defaultType?: string;
|
|
||||||
steps?: TourProps['steps'];
|
|
||||||
current?: number;
|
|
||||||
defaultCurrent?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* returns the merged type of a step or the default type.
|
|
||||||
*/
|
|
||||||
const useMergedType = ({ defaultType, steps = [], current, defaultCurrent }: Props) => {
|
|
||||||
const [innerCurrent, updateInnerCurrent] = useMergedState<number | undefined>(defaultCurrent, {
|
|
||||||
value: current,
|
|
||||||
});
|
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
|
||||||
if (current === undefined) return;
|
|
||||||
updateInnerCurrent(current);
|
|
||||||
}, [current]);
|
|
||||||
|
|
||||||
const innerType = typeof innerCurrent === 'number' ? steps[innerCurrent]?.type : defaultType;
|
|
||||||
const currentMergedType = innerType ?? defaultType;
|
|
||||||
|
|
||||||
return { currentMergedType, updateInnerCurrent };
|
|
||||||
};
|
|
||||||
|
|
||||||
export default useMergedType;
|
|
Loading…
Reference in New Issue
Block a user