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 @@
+
+
+ Draggable dom!
+
+
+
+
+ CdkDraggable!
+
+
+
+
+
+
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