From 3b411f359c8eda64df2a59c89e750a1585d0b389 Mon Sep 17 00:00:00 2001 From: danranvm Date: Mon, 6 Jun 2022 17:06:22 +0800 Subject: [PATCH] feat(cdk:drag-drop): add useDraggable and CdkDraggable --- package.json | 2 +- packages/cdk/drag-drop/demo/Basic.md | 14 +++ packages/cdk/drag-drop/demo/Basic.vue | 36 +++++++ packages/cdk/drag-drop/docs/Design.en.md | 3 + packages/cdk/drag-drop/docs/Design.zh.md | 3 + packages/cdk/drag-drop/docs/Index.en.md | 29 ++++++ packages/cdk/drag-drop/docs/Index.zh.md | 61 ++++++++++++ packages/cdk/drag-drop/index.ts | 22 +++++ .../cdk/drag-drop/src/draggable/Draggable.tsx | 64 ++++++++++++ packages/cdk/drag-drop/src/draggable/types.ts | 27 +++++ .../drag-drop/src/draggable/useDraggable.ts | 99 +++++++++++++++++++ packages/cdk/index.ts | 3 +- packages/cdk/resize/demo/Function.vue | 2 +- packages/cdk/resize/docs/Index.zh.md | 3 +- packages/cdk/resize/src/ResizeObserver.tsx | 15 ++- packages/cdk/resize/src/types.ts | 3 +- packages/cdk/resize/src/useResizeObserver.ts | 8 +- packages/cdk/types.d.ts | 4 +- packages/cdk/utils/index.ts | 1 + packages/cdk/utils/src/composable.ts | 15 ++- packages/cdk/utils/src/convert.ts | 7 +- packages/cdk/utils/src/dom.ts | 41 ++++---- packages/cdk/utils/src/useEventListener.ts | 51 ++++++++++ .../pro/table/src/contents/LayoutToolTree.tsx | 3 +- scripts/gulp/site/utils.ts | 12 ++- 25 files changed, 479 insertions(+), 49 deletions(-) create mode 100644 packages/cdk/drag-drop/demo/Basic.md create mode 100644 packages/cdk/drag-drop/demo/Basic.vue create mode 100644 packages/cdk/drag-drop/docs/Design.en.md create mode 100644 packages/cdk/drag-drop/docs/Design.zh.md create mode 100644 packages/cdk/drag-drop/docs/Index.en.md create mode 100644 packages/cdk/drag-drop/docs/Index.zh.md create mode 100644 packages/cdk/drag-drop/index.ts create mode 100644 packages/cdk/drag-drop/src/draggable/Draggable.tsx create mode 100644 packages/cdk/drag-drop/src/draggable/types.ts create mode 100644 packages/cdk/drag-drop/src/draggable/useDraggable.ts create mode 100644 packages/cdk/utils/src/useEventListener.ts diff --git a/package.json b/package.json index 9650499cc..07c3be7a8 100644 --- a/package.json +++ b/package.json @@ -111,7 +111,7 @@ "less-plugin-clean-css": "^1.5.1", "less-plugin-npm-import": "^2.1.0", "lint-staged": "^12.4.0", - "lodash": "^4.17.21", + "lodash-es": "^4.17.0", "markdownlint-cli": "^0.30.0", "marked": "^4.0.14", "npm-run-all": "^4.1.5", diff --git a/packages/cdk/drag-drop/demo/Basic.md b/packages/cdk/drag-drop/demo/Basic.md new file mode 100644 index 000000000..0ddf241aa --- /dev/null +++ b/packages/cdk/drag-drop/demo/Basic.md @@ -0,0 +1,14 @@ +--- +order: 0 +title: + zh: 基本使用 + en: Basic usage +--- + +## zh + +最简单的用法。 + +## en + +The simplest usage. diff --git a/packages/cdk/drag-drop/demo/Basic.vue b/packages/cdk/drag-drop/demo/Basic.vue new file mode 100644 index 000000000..f490ec869 --- /dev/null +++ b/packages/cdk/drag-drop/demo/Basic.vue @@ -0,0 +1,36 @@ + + + + + diff --git a/packages/cdk/drag-drop/docs/Design.en.md b/packages/cdk/drag-drop/docs/Design.en.md new file mode 100644 index 000000000..d1e713d5e --- /dev/null +++ b/packages/cdk/drag-drop/docs/Design.en.md @@ -0,0 +1,3 @@ +## Description + +## Usage scenarios diff --git a/packages/cdk/drag-drop/docs/Design.zh.md b/packages/cdk/drag-drop/docs/Design.zh.md new file mode 100644 index 000000000..933801767 --- /dev/null +++ b/packages/cdk/drag-drop/docs/Design.zh.md @@ -0,0 +1,3 @@ +## 组件定义 + +## 使用场景 diff --git a/packages/cdk/drag-drop/docs/Index.en.md b/packages/cdk/drag-drop/docs/Index.en.md new file mode 100644 index 000000000..3884ddfa0 --- /dev/null +++ b/packages/cdk/drag-drop/docs/Index.en.md @@ -0,0 +1,29 @@ +--- +category: cdk +type: +order: 0 +title: DragDrop +subtitle: +--- + +## API + +### IxDragDrop + +#### DragDropProps + +| Name | Description | Type | Default | Global Config | Remark | +| --- | --- | --- | --- | --- | --- | +| - | - | - | - | ✅ | - | + +#### DragDropSlots + +| Name | Description | Parameter Type | Remark | +| --- | --- | --- | --- | +| - | - | - | - | + +#### DragDropMethods + +| Name | Description | Parameter Type | Remark | +| --- | --- | --- | --- | +| - | - | - | - | diff --git a/packages/cdk/drag-drop/docs/Index.zh.md b/packages/cdk/drag-drop/docs/Index.zh.md new file mode 100644 index 000000000..5aff45f2d --- /dev/null +++ b/packages/cdk/drag-drop/docs/Index.zh.md @@ -0,0 +1,61 @@ +--- +category: cdk +type: +order: 0 +title: DragDrop +subtitle: 拖拽 +--- + +## API + +### useDraggable + +```ts +/** + * 使一个元素可以被拖拽 + * + * @param target 目标元素,可以是一个 Ref 或 组件实例 + * @param options 拖拽的配置 + * @returns 返回一个用于停止监听的函数, 和当前的拖拽状态 + */ +export function useDraggable( + target: MaybeElementRef, + options: DraggableOptions, +): { + position: ComputedRef + isDragging: ComputedRef + stop: () => void +} + +export interface DragPosition { + // 元素当前的 left 位置 + left: number + // 元素当前的 top 位置 + top: number + // 元素被拖拽后水平偏移量 + offsetX: number + // 元素被拖拽后垂直偏移量 + offsetY: number +} + +export type DraggableEvent = (position: DragPosition, evt: PointerEvent) => void + +export interface DraggableOptions { + onStart?: DraggableEvent + onMove?: DraggableEvent + onEnd?: DraggableEvent +} + +``` + +### CdkDraggable + +#### DraggableProps + +| 名称 | 说明 | 类型 | 默认值 | 全局配置 | 备注 | +| --- | --- | --- | --- | --- | --- | +| `disabled` | 是否禁用 | `boolean` | - | - | - | +| `is` | 拖拽的元素或者组件 | `string | Component` | `'div'` | - | - | +| `onStart` | 拖拽开始事件 | - | `DraggableEvent` | - | - | +| `onMove` | 拖拽过程中事件 | - | `DraggableEvent` | - | - | +| `onEnd` | 拖拽结束事件 | - | `DraggableEvent` | - | - | diff --git a/packages/cdk/drag-drop/index.ts b/packages/cdk/drag-drop/index.ts new file mode 100644 index 000000000..55586168a --- /dev/null +++ b/packages/cdk/drag-drop/index.ts @@ -0,0 +1,22 @@ +/** + * @license + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://github.com/IDuxFE/idux/blob/main/LICENSE + */ + +export * from './src/draggable/useDraggable' + +import type { DraggableComponent } from './src/draggable/types' + +import Draggable from './src/draggable/Draggable' + +const CdkDraggable = Draggable as unknown as DraggableComponent + +export { CdkDraggable } + +export type { + DraggableInstance, + DraggableComponent, + DraggablePublicProps as DraggableProps, +} from './src/draggable/types' diff --git a/packages/cdk/drag-drop/src/draggable/Draggable.tsx b/packages/cdk/drag-drop/src/draggable/Draggable.tsx new file mode 100644 index 000000000..e0478f502 --- /dev/null +++ b/packages/cdk/drag-drop/src/draggable/Draggable.tsx @@ -0,0 +1,64 @@ +/** + * @license + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://github.com/IDuxFE/idux/blob/main/LICENSE + */ + +import { defineComponent, h, normalizeClass, onBeforeUnmount, ref, shallowRef, watch } from 'vue' + +import { callEmit } from '@idux/cdk/utils' + +import { draggableProps } from './types' +import { type DragPosition, useDraggable } from './useDraggable' + +export default defineComponent({ + name: 'CdkDraggable', + props: draggableProps, + setup(props, { slots }) { + const elementRef = ref() + const onStart = (position: DragPosition, evt: PointerEvent) => callEmit(props.onStart, position, evt) + const onMove = (position: DragPosition, evt: PointerEvent) => callEmit(props.onMove, position, evt) + const onEnd = (position: DragPosition, evt: PointerEvent) => callEmit(props.onEnd, position, evt) + + const draggableResult = shallowRef() + + const cleanup = () => { + if (draggableResult.value) { + draggableResult.value.stop() + draggableResult.value = undefined + } + } + + watch( + [() => props.disabled], + ([disabled]) => { + cleanup() + if (!disabled) { + draggableResult.value = useDraggable(elementRef, { onStart, onMove, onEnd }) + } + }, + { + immediate: true, + flush: 'post', + }, + ) + + onBeforeUnmount(cleanup) + + return () => { + if (!draggableResult.value) { + return null + } + const tag = props.is as string + const { isDragging, position } = draggableResult.value + const classes = normalizeClass({ + 'cdk-draggable': true, + 'cdk-dragging': isDragging.value, + }) + const { left, top } = position.value + const style = `left:${left}px;top:${top}px;` + return h(tag, { ref: elementRef, class: classes, style }, slots) + } + }, +}) diff --git a/packages/cdk/drag-drop/src/draggable/types.ts b/packages/cdk/drag-drop/src/draggable/types.ts new file mode 100644 index 000000000..3f8b626c6 --- /dev/null +++ b/packages/cdk/drag-drop/src/draggable/types.ts @@ -0,0 +1,27 @@ +/** + * @license + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://github.com/IDuxFE/idux/blob/main/LICENSE + */ + +/* eslint-disable @typescript-eslint/no-explicit-any */ + +import type { DraggableEvent } from './useDraggable' +import type { ExtractInnerPropTypes, ExtractPublicPropTypes, MaybeArray } from '@idux/cdk/utils' +import type { Component, DefineComponent, HTMLAttributes, PropType } from 'vue' + +export const draggableProps = { + disabled: { type: Boolean, default: false }, + is: { type: [String, Object] as PropType, default: 'div' }, + onStart: [Function, Array] as PropType>, + onMove: [Function, Array] as PropType>, + onEnd: [Function, Array] as PropType>, +} as const + +export type DraggableProps = ExtractInnerPropTypes +export type DraggablePublicProps = ExtractPublicPropTypes +export type DraggableComponent = DefineComponent< + Omit & DraggablePublicProps +> +export type DraggableInstance = InstanceType> diff --git a/packages/cdk/drag-drop/src/draggable/useDraggable.ts b/packages/cdk/drag-drop/src/draggable/useDraggable.ts new file mode 100644 index 000000000..ab2db76a9 --- /dev/null +++ b/packages/cdk/drag-drop/src/draggable/useDraggable.ts @@ -0,0 +1,99 @@ +/** + * @license + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://github.com/IDuxFE/idux/blob/main/LICENSE + */ + +import { type ComputedRef, computed, ref, toRaw } from 'vue' + +import { type MaybeElementRef, convertElement, useEventListener } from '@idux/cdk/utils' + +export interface DragPosition { + left: number + top: number + offsetX: number + offsetY: number +} + +export type DraggableEvent = (position: DragPosition, evt: PointerEvent) => void + +export interface DraggableOptions { + onStart?: DraggableEvent + onMove?: DraggableEvent + onEnd?: DraggableEvent +} + +export function useDraggable( + target: MaybeElementRef, + options: DraggableOptions, +): { + position: ComputedRef + isDragging: ComputedRef + stop: () => void +} { + const startPosition = ref<{ left: number; top: number; pageX: number; pageY: number }>() + const currPosition = ref({} as DragPosition) + + const onStart = (evt: PointerEvent) => { + const element = convertElement(target) + if (evt.target !== element) { + return + } + + const { pageX, pageY } = evt + const { left, top } = element!.getBoundingClientRect() + + startPosition.value = { left, top, pageX, pageY } + + const position = { left, top, offsetX: 0, offsetY: 0 } + + options.onStart?.(position, evt) + } + + const onMove = (evt: PointerEvent) => { + if (!startPosition.value) { + return + } + + const { left, top, pageX, pageY } = startPosition.value + const offsetX = evt.pageX - pageX + const offsetY = evt.pageY - pageY + + const position = { + left: evt.pageX - pageX + left, + top: evt.pageY - pageY + top, + offsetX, + offsetY, + } + currPosition.value = position + + options.onMove?.(position, evt) + } + + const onEnd = (evt: PointerEvent) => { + if (!startPosition.value) { + return + } + + startPosition.value = undefined + + options.onEnd?.(toRaw(currPosition.value), evt) + } + + const { stop: stopPointerdown } = useEventListener(target, 'pointerdown', onStart, true) + const { stop: stopPointermove } = useEventListener(document, 'pointermove', onMove, true) + const { stop: stopPointerup } = useEventListener(document, 'pointerup', onEnd, true) + + const stop = () => { + stopPointerdown() + stopPointermove() + stopPointerup() + } + + return { + isDragging: computed(() => !!startPosition.value), + position: computed(() => currPosition.value), + stop, + } +} diff --git a/packages/cdk/index.ts b/packages/cdk/index.ts index 41a518ce6..7ee2e908b 100644 --- a/packages/cdk/index.ts +++ b/packages/cdk/index.ts @@ -8,12 +8,13 @@ import type { App, Directive } from 'vue' import { clickOutside } from '@idux/cdk/click-outside' +import { CdkDraggable } from '@idux/cdk/drag-drop' import { CdkPortal } from '@idux/cdk/portal' import { CdkResizeObserver } from '@idux/cdk/resize' import { CdkVirtualScroll } from '@idux/cdk/scroll' import { version } from '@idux/cdk/version' -const components = [CdkPortal, CdkResizeObserver, CdkVirtualScroll] +const components = [CdkPortal, CdkDraggable, CdkResizeObserver, CdkVirtualScroll] const directives: Record = { clickOutside, diff --git a/packages/cdk/resize/demo/Function.vue b/packages/cdk/resize/demo/Function.vue index a950bedbc..3e8e6167d 100644 --- a/packages/cdk/resize/demo/Function.vue +++ b/packages/cdk/resize/demo/Function.vue @@ -7,7 +7,7 @@ import { onBeforeUnmount, onMounted, ref } from 'vue' import { offResize, onResize } from '@idux/cdk/resize' import { convertElement } from '@idux/cdk/utils' -import { TextareaInstance } from '@idux/components' +import { TextareaInstance } from '@idux/components/textarea' const textareaRef = ref() const text = ref('') diff --git a/packages/cdk/resize/docs/Index.zh.md b/packages/cdk/resize/docs/Index.zh.md index a7463fad8..c64b74578 100644 --- a/packages/cdk/resize/docs/Index.zh.md +++ b/packages/cdk/resize/docs/Index.zh.md @@ -6,7 +6,7 @@ title: Resize subtitle: 调整尺寸 --- -对 `[ResizeObserver](https://developer.mozilla.org/zh-CN/docs/Web/API/ResizeObserver)` 的进一步封装。 +对 [ResizeObserver](https://developer.mozilla.org/zh-CN/docs/Web/API/ResizeObserver) 的进一步封装。 ## API @@ -35,6 +35,7 @@ export function useResizeObserver( | 名称 | 说明 | 类型 | 默认值 | 全局配置 | 备注 | | --- | --- | --- | --- | --- | --- | | `disabled` | 是否禁用 | `boolean` | - | - | - | +| `is` | 被观测的元素或者组件 | `string | Component` | `'div'` | - | - | | `options` | 传递给 `ResizeObserver` 的参数 | - | `ResizeObserverOptions` | - | 参见 [MDN:ResizeObserver](https://developer.mozilla.org/zh-CN/docs/Web/API/ResizeObserver/observe) | | `onResize` | 当元素尺寸改变时的回调 | - | `(entry: ResizeObserverEntry) => void` | - | - | diff --git a/packages/cdk/resize/src/ResizeObserver.tsx b/packages/cdk/resize/src/ResizeObserver.tsx index fb82d74af..0c13a491c 100644 --- a/packages/cdk/resize/src/ResizeObserver.tsx +++ b/packages/cdk/resize/src/ResizeObserver.tsx @@ -5,9 +5,9 @@ * found in the LICENSE file at https://github.com/IDuxFE/idux/blob/main/LICENSE */ -import { cloneVNode, defineComponent, onBeforeUnmount, ref, watch } from 'vue' +import { defineComponent, h, onBeforeUnmount, ref, watch } from 'vue' -import { Logger, callEmit, getFirstValidNode } from '@idux/cdk/utils' +import { callEmit } from '@idux/cdk/utils' import { resizeObserverProps } from './types' import { useResizeObserver } from './useResizeObserver' @@ -20,6 +20,7 @@ export default defineComponent({ const handlerResize = (evt: ResizeObserverEntry) => callEmit(props.onResize, evt) let stopHandler: (() => void) | undefined + const cleanup = () => { if (stopHandler) { stopHandler() @@ -32,7 +33,7 @@ export default defineComponent({ ([disabled, options, onResize]) => { cleanup() if (!disabled && onResize) { - stopHandler = useResizeObserver(elementRef, handlerResize, options) + stopHandler = useResizeObserver(elementRef, handlerResize, options).stop } }, { @@ -44,12 +45,8 @@ export default defineComponent({ onBeforeUnmount(cleanup) return () => { - const targetNode = getFirstValidNode(slots.default?.()) - if (!targetNode) { - __DEV__ && Logger.warn('cdk/resize', 'Child must is single rooted node') - return null - } - return cloneVNode(targetNode, { ref: elementRef }, true) + const tag = props.is as string + return h(tag, { ref: elementRef, class: 'cdk-resize-observer' }, slots) } }, }) diff --git a/packages/cdk/resize/src/types.ts b/packages/cdk/resize/src/types.ts index 53c13c4e5..56ba71393 100644 --- a/packages/cdk/resize/src/types.ts +++ b/packages/cdk/resize/src/types.ts @@ -9,10 +9,11 @@ import type { ResizeListener } from './utils' import type { ExtractInnerPropTypes, ExtractPublicPropTypes, MaybeArray } from '@idux/cdk/utils' -import type { DefineComponent, HTMLAttributes, PropType } from 'vue' +import type { Component, DefineComponent, HTMLAttributes, PropType } from 'vue' export const resizeObserverProps = { disabled: { type: Boolean, default: false }, + is: { type: [String, Object] as PropType, default: 'div' }, options: { type: Object as PropType, default: undefined }, onResize: [Function, Array] as PropType>, } as const diff --git a/packages/cdk/resize/src/useResizeObserver.ts b/packages/cdk/resize/src/useResizeObserver.ts index 86dd11249..9c06fac68 100644 --- a/packages/cdk/resize/src/useResizeObserver.ts +++ b/packages/cdk/resize/src/useResizeObserver.ts @@ -15,7 +15,7 @@ export function useResizeObserver( target: MaybeElementRef, listener: ResizeListener, options?: ResizeObserverOptions, -): () => void { +): { stop: () => void } { const stopWatch = watch( () => convertElement(target), (currElement, prevElement) => { @@ -30,12 +30,12 @@ export function useResizeObserver( { immediate: true, flush: 'post' }, ) - const dispose = () => { + const stop = () => { offResize(convertElement(target), listener) stopWatch() } - onScopeDispose(dispose) + onScopeDispose(stop) - return dispose + return { stop } } diff --git a/packages/cdk/types.d.ts b/packages/cdk/types.d.ts index 8797fd6c6..8fe8e7f81 100644 --- a/packages/cdk/types.d.ts +++ b/packages/cdk/types.d.ts @@ -5,12 +5,14 @@ * found in the LICENSE file at https://github.com/IDuxFE/idux/blob/main/LICENSE */ -import type { ResizeObserverComponent } from './resize' +import type { DraggableComponent } from '@idux/cdk/drag-drop' import type { PortalComponent } from '@idux/cdk/portal' +import type { ResizeObserverComponent } from '@idux/cdk/resize' import type { VirtualScrollComponent } from '@idux/cdk/scroll' declare module 'vue' { export interface GlobalComponents { + CdkDraggable: DraggableComponent CdkPortal: PortalComponent CdkResizeObserver: ResizeObserverComponent CdkVirtualScroll: VirtualScrollComponent diff --git a/packages/cdk/utils/index.ts b/packages/cdk/utils/index.ts index 32ac905c1..4b31faa51 100644 --- a/packages/cdk/utils/index.ts +++ b/packages/cdk/utils/index.ts @@ -15,4 +15,5 @@ export * from './src/offset' export * from './src/props' export * from './src/typeof' export * from './src/uniqueId' +export * from './src/useEventListener' export * from './src/vNode' diff --git a/packages/cdk/utils/src/composable.ts b/packages/cdk/utils/src/composable.ts index 5a4ccbce2..1884e8267 100644 --- a/packages/cdk/utils/src/composable.ts +++ b/packages/cdk/utils/src/composable.ts @@ -5,9 +5,18 @@ * found in the LICENSE file at https://github.com/IDuxFE/idux/blob/main/LICENSE */ -import type { ComputedRef, EffectScope, Ref } from 'vue' - -import { computed, effectScope, onScopeDispose, ref, shallowRef, toRaw, watch } from 'vue' +import { + type ComputedRef, + type EffectScope, + type Ref, + computed, + effectScope, + onScopeDispose, + ref, + shallowRef, + toRaw, + watch, +} from 'vue' import { isFunction } from 'lodash-es' diff --git a/packages/cdk/utils/src/convert.ts b/packages/cdk/utils/src/convert.ts index 506f50864..393f56c0d 100644 --- a/packages/cdk/utils/src/convert.ts +++ b/packages/cdk/utils/src/convert.ts @@ -5,9 +5,7 @@ * found in the LICENSE file at https://github.com/IDuxFE/idux/blob/main/LICENSE */ -import type { ComponentPublicInstance, Ref } from 'vue' - -import { unref } from 'vue' +import { type ComponentPublicInstance, type Ref, unref } from 'vue' import { isNil } from 'lodash-es' @@ -39,8 +37,9 @@ export function convertCssPixel(value: unknown): string { return typeof value === 'string' ? value : `${value}px` } +export type MaybeRef = T | Ref export type MaybeElement = ComponentPublicInstance | HTMLElement | null | undefined -export type MaybeElementRef = Ref | T +export type MaybeElementRef = MaybeRef export function convertElement( elementOrInstance: MaybeElementRef, diff --git a/packages/cdk/utils/src/dom.ts b/packages/cdk/utils/src/dom.ts index eeebccd3b..0bb7ce04d 100644 --- a/packages/cdk/utils/src/dom.ts +++ b/packages/cdk/utils/src/dom.ts @@ -9,22 +9,22 @@ import { isString } from 'lodash-es' -type ElType = HTMLElement | Document | Window +export type EventTarget = HTMLElement | Document | Window | null | undefined export function on( - el: ElType | undefined, + el: EventTarget, type: K | undefined, listener: ((this: HTMLElement, ev: HTMLElementEventMap[K]) => any) | undefined, options?: boolean | AddEventListenerOptions, ): void export function on( - el: ElType | undefined, + el: EventTarget, type: string | undefined, listener: EventListenerOrEventListenerObject | undefined, options?: boolean | AddEventListenerOptions, ): void export function on( - el: ElType | undefined, + el: EventTarget, type: string | undefined, listener: EventListenerOrEventListenerObject | undefined, options?: boolean | AddEventListenerOptions, @@ -35,19 +35,19 @@ export function on( } export function off( - el: ElType | undefined, + el: EventTarget, type: K | undefined, listener: ((this: HTMLElement, ev: HTMLElementEventMap[K]) => any) | undefined, options?: boolean | EventListenerOptions, ): void export function off( - el: ElType | undefined, + el: EventTarget, type: string | undefined, listener: EventListenerOrEventListenerObject | undefined, options?: boolean | EventListenerOptions, ): void export function off( - el: ElType | undefined, + el: EventTarget, type: string | undefined, listener: EventListenerOrEventListenerObject | undefined, options?: boolean | EventListenerOptions, @@ -137,19 +137,18 @@ export function isVisibleElement(element: HTMLElement | SVGElement | undefined): return isStyleVisible(element) && isAttributeVisible(element) } -export function getMouseClientXY(ev: MouseEvent | TouchEvent): { clientX: number; clientY: number } { - let clientX: number - let clientY: number - if (ev.type.startsWith('touch')) { - clientY = (ev as TouchEvent).touches[0].clientY - clientX = (ev as TouchEvent).touches[0].clientX - } else { - clientY = (ev as MouseEvent).clientY - clientX = (ev as MouseEvent).clientX - } +/** + * Investigate if an event is a `TouchEvent`. + */ +export function isTouchEvent(evt: MouseEvent | TouchEvent): evt is TouchEvent { + return evt.type.startsWith('touch') +} - return { - clientX, - clientY, - } +export function getMouseEvent(evt: MouseEvent | TouchEvent): MouseEvent | Touch { + return isTouchEvent(evt) ? evt.touches[0] || evt.changedTouches[0] : evt +} + +export function getMouseClientXY(evt: MouseEvent | TouchEvent): { clientX: number; clientY: number } { + const { clientX, clientY } = getMouseEvent(evt) + return { clientX, clientY } } diff --git a/packages/cdk/utils/src/useEventListener.ts b/packages/cdk/utils/src/useEventListener.ts new file mode 100644 index 000000000..32e03c5c0 --- /dev/null +++ b/packages/cdk/utils/src/useEventListener.ts @@ -0,0 +1,51 @@ +/** + * @license + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://github.com/IDuxFE/idux/blob/main/LICENSE + */ + +import { type ComponentPublicInstance, onScopeDispose, watch } from 'vue' + +import { MaybeElementRef, MaybeRef, convertElement } from './convert' +import { off, on } from './dom' + +export type EventListenerTarget = MaybeRef + +export function useEventListener( + target: EventListenerTarget, + type: K | undefined, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + listener: ((this: HTMLElement, ev: HTMLElementEventMap[K]) => any) | undefined, + options?: boolean | AddEventListenerOptions, +): { stop: () => void } +export function useEventListener( + target: EventListenerTarget, + type: string | undefined, + listener: EventListenerOrEventListenerObject | undefined, + options?: boolean | AddEventListenerOptions, +): { stop: () => void } +export function useEventListener( + target: EventListenerTarget, + type: string | undefined, + listener: EventListenerOrEventListenerObject | undefined, + options?: boolean | AddEventListenerOptions, +): { stop: () => void } { + const stopWatch = watch( + () => convertElement(target as unknown as MaybeElementRef), + (currElement, prevElement) => { + off(prevElement, type, listener, options) + on(currElement, type, listener, options) + }, + { immediate: true, flush: 'post' }, + ) + + const stop = () => { + off(convertElement(target as unknown as MaybeElementRef), type, listener, options) + stopWatch() + } + + onScopeDispose(stop) + + return { stop } +} diff --git a/packages/pro/table/src/contents/LayoutToolTree.tsx b/packages/pro/table/src/contents/LayoutToolTree.tsx index b1f583a57..25a11b146 100644 --- a/packages/pro/table/src/contents/LayoutToolTree.tsx +++ b/packages/pro/table/src/contents/LayoutToolTree.tsx @@ -9,7 +9,8 @@ import { computed } from '@vue/reactivity' import { type PropType, defineComponent, inject } from 'vue' import { type VKey } from '@idux/cdk/utils' -import { IxDivider, IxIcon } from '@idux/components' +import { IxDivider } from '@idux/components/divider' +import { IxIcon } from '@idux/components/icon' import { IxTree, type TreeDragDropOptions, type TreeProps } from '@idux/components/tree' import { useKey } from '@idux/components/utils' diff --git a/scripts/gulp/site/utils.ts b/scripts/gulp/site/utils.ts index 241b23b85..4c2938d5d 100644 --- a/scripts/gulp/site/utils.ts +++ b/scripts/gulp/site/utils.ts @@ -4,6 +4,7 @@ import { join } from 'path' import { readFileSync, readdirSync, statSync, writeFileSync } from 'fs-extra' // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore +// eslint-disable-next-line import/no-unresolved import { kebabCase, lowerFirst } from 'lodash' import { loadFront } from 'yaml-front-matter' @@ -34,7 +35,16 @@ export function initSite(): void { }) const filterPackageName = ['site'] - const filterComponentName = ['node_modules', 'config', 'style', 'locales', 'version', 'utils', '_private'] + const filterComponentName = [ + '_private', + 'config', + // 'drag-drop', // 暂时不对外提供 + 'locales', + 'node_modules', + 'style', + 'utils', + 'version', + ] readdirSync(packageRoot).forEach(packageName => { if (filterPackageName.includes(packageName)) { return