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:
MadCcc 2023-09-26 13:42:43 +08:00 committed by GitHub
parent ef7c500a8e
commit 29be72bc38
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 53 additions and 119 deletions

View File

@ -84,7 +84,7 @@ exports[`Tour Primary 1`] = `
</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;"
>
<svg
@ -157,7 +157,7 @@ exports[`Tour Primary 1`] = `
</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;"
/>
</div>
@ -307,7 +307,7 @@ exports[`Tour controlled current 1`] = `
</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;"
>
<svg
@ -339,7 +339,7 @@ exports[`Tour controlled current 1`] = `
</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;"
/>
</div>
@ -696,7 +696,7 @@ exports[`Tour step support Primary 1`] = `
</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;"
>
<svg
@ -769,7 +769,7 @@ exports[`Tour step support Primary 1`] = `
</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;"
/>
</div>

View File

@ -529,4 +529,38 @@ describe('Tour', () => {
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');
});
});

View File

@ -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');
});
});

View File

@ -1,4 +1,4 @@
import React, { useContext } from 'react';
import React, { useContext, useMemo } from 'react';
import RCTour from '@rc-component/tour';
import classNames from 'classnames';
@ -10,15 +10,12 @@ import type { TourProps, TourStepProps } from './interface';
import TourPanel from './panelRender';
import PurePanel from './PurePanel';
import useStyle from './style';
import useMergedType from './useMergedType';
const Tour: React.FC<TourProps> & { _InternalPanelDoNotUseOrYouWillBeFired: typeof PurePanel } = (
props,
) => {
const {
prefixCls: customizePrefixCls,
current,
defaultCurrent,
type,
rootClassName,
indicatorsRender,
@ -30,12 +27,16 @@ const Tour: React.FC<TourProps> & { _InternalPanelDoNotUseOrYouWillBeFired: type
const [wrapSSR, hashId] = useStyle(prefixCls);
const [, token] = useToken();
const { currentMergedType, updateInnerCurrent } = useMergedType({
defaultType: type,
steps,
current,
defaultCurrent,
});
const mergedSteps = useMemo(
() =>
steps?.map((step) => ({
...step,
className: classNames(step.className, {
[`${prefixCls}-primary`]: (step.type ?? type) === 'primary',
}),
})),
[steps, type],
);
const builtinPlacements = getPlacements({
arrowPointAtCenter: true,
@ -47,7 +48,6 @@ const Tour: React.FC<TourProps> & { _InternalPanelDoNotUseOrYouWillBeFired: type
const customClassName = classNames(
{
[`${prefixCls}-primary`]: currentMergedType === 'primary',
[`${prefixCls}-rtl`]: direction === 'rtl',
},
hashId,
@ -63,23 +63,15 @@ const Tour: React.FC<TourProps> & { _InternalPanelDoNotUseOrYouWillBeFired: type
/>
);
const onStepChange = (stepCurrent: number) => {
updateInnerCurrent(stepCurrent);
props.onChange?.(stepCurrent);
};
return wrapSSR(
<RCTour
{...restProps}
rootClassName={customClassName}
prefixCls={prefixCls}
current={current}
defaultCurrent={defaultCurrent}
animated
renderPanel={mergedRenderPanel}
builtinPlacements={builtinPlacements}
onChange={onStepChange}
steps={steps}
steps={mergedSteps}
/>,
);
};

View File

@ -43,7 +43,6 @@ const TourPanel: React.FC<TourPanelProps> = ({
nextButtonProps,
prevButtonProps,
type: stepType,
className,
closeIcon: stepCloseIcon,
} = stepProps;
@ -120,7 +119,7 @@ const TourPanel: React.FC<TourPanelProps> = ({
const [contextLocale] = useLocale('Tour', defaultLocale.Tour);
return (
<div className={classNames(className, `${prefixCls}-content`)}>
<div className={`${prefixCls}-content`}>
<div className={`${prefixCls}-inner`}>
{closable && mergedDisplayCloseIcon}
{coverNode}

View File

@ -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;