Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ exports[`Cascader should render option correctly when using defaultValue prop 1`
loop={false}
onIndexChange={[Function]}
slideSize={100}
stopPropagation={Array []}
stuckAtBoundary={false}
trackOffset={0}
>
Expand Down Expand Up @@ -473,6 +474,7 @@ exports[`Cascader when value change 1`] = `
loop={false}
onIndexChange={[Function]}
slideSize={100}
stopPropagation={Array []}
stuckAtBoundary={false}
trackOffset={0}
>
Expand Down
4 changes: 4 additions & 0 deletions packages/rc-ui-lib/src/swiper/PropsType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { BaseTypeProps } from '../utils';
type DirectionTypes = 'horizontal' | 'vertical';
type IndicatorColorTypes = 'primary' | 'white';

type PropagationEvent = "mousedown" | "mousemove" | "mouseup"

export type PageIndicatorProps = {
total: number;
current: number;
Expand Down Expand Up @@ -43,6 +45,8 @@ export interface SwiperProps extends BaseTypeProps {
stuckAtBoundary?: boolean;
/** 子元素 */
children?: React.ReactElement | React.ReactElement[];
/** 阻止事件冒泡 */
stopPropagation?: PropagationEvent[];
}

export interface SwiperInstance {
Expand Down
5 changes: 5 additions & 0 deletions packages/rc-ui-lib/src/swiper/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,11 @@ export default () => {
| stuckAtBoundary | 是否在边界两边卡住,避免出现空白,仅在非 `loop` 模式且 `slideSize` < 100 时生效 | _boolean_ | `false` |
| indicator | 自定义指示器 | _boolean \| (total, current) => ReactNode_ | - |
| indicatorProps | 指示器属性 | _IndicatorProps_ | - |
| stopPropagation | 阻止某些事件的冒泡[2.0.2] | _PropagationEvent[]_ | [] |

```ts
type PropagationEvent = 'mouseup' | 'mousemove' | 'mousedown';
```

### DirectionTypes 格式

Expand Down
44 changes: 42 additions & 2 deletions packages/rc-ui-lib/src/swiper/Swiper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,29 @@ import { devWarning } from '../utils/dev-log';
import { noop } from '../utils';
import { getRect } from '../hooks/get-rect';
import useMountedRef from '../hooks/use-mounted-ref';
import { mergeFuncProps } from '../utils/with-func-props';

function modulus(value: number, division: number) {
const remainder = value % division;
return remainder < 0 ? remainder + division : remainder;
}

const eventToPropRecord = {
mousedown: 'onMouseDown',
mousemove: 'onMouseMove',
mouseup: 'onMouseUp',
} as const;

let currentUid: undefined | {};

const Swiper = forwardRef<SwiperInstance, SwiperProps>((props, ref) => {
const { prefixCls, createNamespace } = useContext(ConfigProviderContext);
const [bem] = createNamespace('swiper', prefixCls);

const { loop: outerLoop, autoplay, direction, autoplayInterval } = props;

const [uid] = useState({});

const lock = useRef<boolean>(false);
const trackRef = useRef<HTMLDivElement>(null);
const [root, setRoot] = useState<HTMLDivElement>(null);
Expand Down Expand Up @@ -123,10 +134,24 @@ const Swiper = forwardRef<SwiperInstance, SwiperProps>((props, ref) => {
[count],
);

const dragCancelRef = useRef<(() => void) | null>(null);
function forceCancelDrag() {
dragCancelRef.current?.();
draggingRef.current = false;
}

const bind = useDrag(
(state) => {
if (lock.current) return;
dragCancelRef.current = state.cancel;
if (!state.intentional) return;
if (state.first && !currentUid) {
currentUid = uid;
}
if (currentUid !== uid) return;
currentUid = state.last ? undefined : uid;
const slidePixels = getSlidePixels();

if (lock.current) return;
if (!slidePixels) return;
const paramIndex = isVertical ? 1 : 0;
const offset = state.offset[paramIndex];
Expand Down Expand Up @@ -203,6 +228,7 @@ const Swiper = forwardRef<SwiperInstance, SwiperProps>((props, ref) => {
if (draggingRef.current) {
e.stopPropagation();
}
forceCancelDrag();
};

function swipeTo(index: number, immediate = false) {
Expand Down Expand Up @@ -260,6 +286,19 @@ const Swiper = forwardRef<SwiperInstance, SwiperProps>((props, ref) => {
devWarning('Swiper', '`Swiper` needs at least one child.');
}

const dragProps = { ...(props.allowTouchMove ? bind() : {}) };

const stopPropagationProps: Partial<Record<any, any>> = {};
props.stopPropagation.forEach(key => {
const prop = eventToPropRecord[key];
stopPropagationProps[prop] = function (e: Event) {
e.stopPropagation();
};
})


const mergedProps = mergeFuncProps(dragProps, stopPropagationProps);

return (
<div
ref={setRoot}
Expand All @@ -274,7 +313,7 @@ const Swiper = forwardRef<SwiperInstance, SwiperProps>((props, ref) => {
}),
)}
onClickCapture={onClickCapture}
{...(props.allowTouchMove ? bind() : {})}
{...mergedProps}
>
<div
className={classnames(
Expand Down Expand Up @@ -318,6 +357,7 @@ Swiper.defaultProps = {
slideSize: 100,
stuckAtBoundary: false,
trackOffset: 0,
stopPropagation: [],
};

Swiper.displayName = 'Swiper';
Expand Down
23 changes: 23 additions & 0 deletions packages/rc-ui-lib/src/swiper/__test__/index.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -303,4 +303,27 @@ describe('Swipe test with testing library', () => {

expect(container).toMatchSnapshot();
});

it('stop propagation should be work', async () => {
const onMouseDown = jest.fn();
const onMouseMove = jest.fn();
const onMouseUp = jest.fn();

const { container } = render(
<Swiper style={swipeStyle} stopPropagation={['mousedown', 'mousemove', 'mouseup']}>
<Swiper.Item>1</Swiper.Item>
<Swiper.Item>2</Swiper.Item>
<Swiper.Item>3</Swiper.Item>
</Swiper>,
);

const track = container.querySelector('.rc-swiper__track');
mockOffset(track);
await TestsEvent.triggerDrag(track, [-100, 0]);
await sleep(100);

expect(onMouseDown).not.toBeCalled();
expect(onMouseMove).not.toBeCalled();
expect(onMouseUp).not.toBeCalled();
});
});
29 changes: 29 additions & 0 deletions packages/rc-ui-lib/src/utils/with-func-props.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
type Merge<T, P> = {
[K in keyof T & keyof P]: P[K] | T[K];
};

export function mergeFuncProps<T extends Record<string, any>, P extends Record<string, any>>(
p1: T,
p2: P,
): Merge<T, P> {
const p1Keys = Object.keys(p1);
const p2Keys = Object.keys(p2);
const keys = new Set([...p1Keys, ...p2Keys]);
const res: any = {};

keys.forEach((key) => {
const p1Value = p1[key];
const p2Value = p2[key];

if (typeof p1Value === 'function' && typeof p2Value === 'function') {
res[key] = function (...args: any[]) {
p1Value(...args);
p2Value(...args);
};
} else {
res[key] = p1Value || p2Value;
}
});

return res;
}