添加cl-draggable组件

This commit is contained in:
icssoa
2025-07-27 22:27:53 +08:00
parent 0c4fc52b9a
commit 9a49963a91
10 changed files with 885 additions and 2 deletions

View File

@@ -3,6 +3,7 @@ import { useStore } from "@/cool";
// #ifdef H5 // #ifdef H5
import TouchEmulator from "hammer-touchemulator"; import TouchEmulator from "hammer-touchemulator";
// 模拟移动端调试的触摸事件
TouchEmulator(); TouchEmulator();
// #endif // #endif

View File

@@ -61,7 +61,9 @@ const list = computed<Item[]>(() => {
}); });
// 隐藏原生 tabBar // 隐藏原生 tabBar
// #ifndef MP
uni.hideTabBar(); uni.hideTabBar();
// #endif
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -2,6 +2,7 @@ import { computed, ref } from "vue";
import uniTheme from "@/theme.json"; import uniTheme from "@/theme.json";
import { router } from "../router"; import { router } from "../router";
import { ctx } from "../ctx"; import { ctx } from "../ctx";
import { isNull } from "../utils";
// 主题类型定义,仅支持 light 和 dark // 主题类型定义,仅支持 light 和 dark
type Theme = "light" | "dark"; type Theme = "light" | "dark";
@@ -46,7 +47,7 @@ export function getStyle(key: string): string | null {
* @returns 颜色值 * @returns 颜色值
*/ */
export const getColor = (name: string) => { export const getColor = (name: string) => {
if (ctx.color == null) { if (isNull(ctx.color)) {
return ""; return "";
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "cool-unix", "name": "cool-unix",
"version": "8.0.2", "version": "8.0.3",
"license": "MIT", "license": "MIT",
"scripts": { "scripts": {
"build-ui": "node ./uni_modules/cool-ui/scripts/generate-types.js", "build-ui": "node ./uni_modules/cool-ui/scripts/generate-types.js",

View File

@@ -285,6 +285,12 @@
"navigationBarTitleText": "Avatar 头像" "navigationBarTitleText": "Avatar 头像"
} }
}, },
{
"path": "data/draggable",
"style": {
"navigationBarTitleText": "Draggable 拖拽"
}
},
{ {
"path": "status/badge", "path": "status/badge",
"style": { "style": {

View File

@@ -0,0 +1,178 @@
<template>
<cl-page>
<view class="p-3 overflow-visible">
<demo-item label="纵向排列">
<cl-draggable v-model="list">
<template #item="{ item, index }">
<view
class="flex flex-row items-center p-3 bg-surface-100 rounded-lg mb-2"
:class="{
'!bg-surface-300': (item as UTSJSONObject).disabled
}"
>
<cl-text>{{ (item as UTSJSONObject).label }}</cl-text>
</view>
</template>
</cl-draggable>
</demo-item>
<demo-item label="结合列表使用">
<cl-list border>
<cl-draggable v-model="list2">
<template #item="{ item, index, dragging, dragIndex }">
<cl-list-item
icon="chat-thread-line"
:label="(item as UTSJSONObject).label"
arrow
:pt="{
inner: {
className:
dragging && dragIndex == index ? '!bg-surface-100' : ''
}
}"
></cl-list-item>
</template>
</cl-draggable>
</cl-list>
</demo-item>
<demo-item label="横向排列">
<cl-draggable v-model="list3" :columns="4">
<template #item="{ item, index }">
<view
class="flex flex-row items-center justify-center p-3 bg-surface-100 rounded-lg m-1"
:class="{
'!bg-surface-300': (item as UTSJSONObject).disabled
}"
>
<cl-text>{{ (item as UTSJSONObject).label }}</cl-text>
</view>
</template>
</cl-draggable>
</demo-item>
<demo-item label="结合图片使用">
<cl-draggable v-model="list4" :columns="4">
<template #item="{ item, index }">
<view class="p-[2px]">
<cl-image
:src="(item as UTSJSONObject).url"
mode="widthFix"
:pt="{
className: '!w-full'
}"
preview
></cl-image>
</view>
</template>
</cl-draggable>
</demo-item>
</view>
</cl-page>
</template>
<script lang="ts" setup>
import DemoItem from "../components/item.uvue";
import { ref } from "vue";
const list = ref<UTSJSONObject[]>([
{
label: "明月几时有,把酒问青天"
},
{
label: "不知天上宫阙,今夕是何年",
disabled: true
},
{
label: "我欲乘风归去,又恐琼楼玉宇"
},
{
label: "高处不胜寒,起舞弄清影"
},
{
label: "何似在人间"
}
]);
const list2 = ref<UTSJSONObject[]>([
{
label: "明月几时有,把酒问青天"
},
{
label: "不知天上宫阙,今夕是何年"
},
{
label: "我欲乘风归去,又恐琼楼玉宇"
},
{
label: "高处不胜寒,起舞弄清影"
},
{
label: "何似在人间"
}
]);
const list3 = ref<UTSJSONObject[]>([
{
label: "项目1"
},
{
label: "项目2"
},
{
label: "项目3"
},
{
label: "项目4"
},
{
label: "项目5"
},
{
label: "项目6"
},
{
label: "项目7"
},
{
label: "项目8",
disabled: true
},
{
label: "项目9"
},
{
label: "项目10"
},
{
label: "项目11"
},
{
label: "项目12"
}
]);
const list4 = ref<UTSJSONObject[]>([
{
url: "https://unix.cool-js.com/images/demo/1.jpg"
},
{
url: "https://unix.cool-js.com/images/demo/2.jpg"
},
{
url: "https://unix.cool-js.com/images/demo/3.jpg"
},
{
url: "https://unix.cool-js.com/images/demo/4.jpg"
},
{
url: "https://unix.cool-js.com/images/demo/5.jpg"
},
{
url: "https://unix.cool-js.com/images/demo/6.jpg"
},
{
url: "https://unix.cool-js.com/images/demo/7.jpg"
}
]);
</script>

View File

@@ -271,6 +271,11 @@ const data = computed<Item[]>(() => {
label: t("时间轴"), label: t("时间轴"),
icon: "timeline-view", icon: "timeline-view",
path: "/pages/demo/data/timeline" path: "/pages/demo/data/timeline"
},
{
label: t("拖拽"),
icon: "drag-move-line",
path: "/pages/demo/data/draggable"
} }
] ]
}, },

View File

@@ -0,0 +1,673 @@
<template>
<view
class="cl-draggable"
:class="[
{
'cl-draggable--grid': props.columns > 1
},
pt.className
]"
>
<view
v-for="(item, index) in list"
:key="getItemKey(item, index)"
class="cl-draggable__item"
:class="[
{
'cl-draggable__item--disabled': disabled
},
dragging && dragIndex == index ? `opacity-80 ${pt.ghost?.className}` : ''
]"
:style="getItemStyle(index)"
@touchstart="
(event: UniTouchEvent) => {
onTouchStart(event, index);
}
"
@touchmove.stop.prevent="onTouchMove"
@touchend="onTouchEnd"
>
<slot
name="item"
:item="item"
:index="index"
:dragging="dragging"
:dragIndex="dragIndex"
:insertIndex="insertIndex"
>
</slot>
</view>
</view>
</template>
<script lang="ts" setup>
import { computed, ref, getCurrentInstance, type PropType, watch } from "vue";
import { isNull, parsePt, uuid } from "@/cool";
import type { PassThroughProps } from "../../types";
defineOptions({
name: "cl-draggable"
});
defineSlots<{
item(props: {
item: UTSJSONObject;
index: number;
dragging: boolean;
dragIndex: number;
insertIndex: number;
}): any;
}>();
// 项目位置信息类型定义
type ItemPosition = {
top: number;
left: number;
width: number;
height: number;
};
// 位移偏移量类型定义
type TranslateOffset = {
x: number;
y: number;
};
const props = defineProps({
/** PassThrough 样式配置 */
pt: {
type: Object,
default: () => ({})
},
/** 数据数组,支持双向绑定 */
modelValue: {
type: Array as PropType<UTSJSONObject[]>,
default: () => []
},
/** 是否禁用拖拽功能 */
disabled: {
type: Boolean,
default: false
},
/** 动画持续时间(毫秒) */
animation: {
type: Number,
default: 150
},
/** 列数1为单列纵向布局>1为多列网格布局 */
columns: {
type: Number,
default: 1
}
});
const emit = defineEmits(["update:modelValue", "change", "start", "end"]);
const { proxy } = getCurrentInstance()!;
// 透传样式类型定义
type PassThrough = {
className?: string;
ghost?: PassThroughProps;
};
/** PassThrough 样式解析 */
const pt = computed(() => parsePt<PassThrough>(props.pt));
/** 数据列表 */
const list = ref<UTSJSONObject[]>([]);
/** 是否正在拖拽 */
const dragging = ref(false);
/** 当前拖拽元素的原始索引 */
const dragIndex = ref(-1);
/** 预期插入的目标索引 */
const insertIndex = ref(-1);
/** 触摸开始时的Y坐标 */
const startY = ref(0);
/** 触摸开始时的X坐标 */
const startX = ref(0);
/** Y轴偏移量 */
const offsetY = ref(0);
/** X轴偏移量 */
const offsetX = ref(0);
/** 当前拖拽的数据项 */
const dragItem = ref<UTSJSONObject>({});
/** 所有项目的位置信息缓存 */
const itemPositions = ref<ItemPosition[]>([]);
/** 是否处于放下动画状态 */
const dropping = ref(false);
/** 动态计算的项目高度 */
const itemHeight = ref(0);
/** 动态计算的项目宽度 */
const itemWidth = ref(0);
/** 是否已开始排序模拟(防止误触) */
const sortingStarted = ref(false);
/**
* 重置所有拖拽相关的状态
* 在拖拽结束后调用,确保组件回到初始状态
*/
function reset() {
dragging.value = false; // 拖拽状态
dropping.value = false; // 放下动画状态
dragIndex.value = -1; // 拖拽元素索引
insertIndex.value = -1; // 插入位置索引
offsetX.value = 0; // X轴偏移
offsetY.value = 0; // Y轴偏移
dragItem.value = {}; // 拖拽的数据项
itemPositions.value = []; // 位置信息缓存
itemHeight.value = 0; // 动态计算的高度
itemWidth.value = 0; // 动态计算的宽度
sortingStarted.value = false; // 排序模拟状态
}
/**
* 计算网格布局中元素的位移偏移
* @param index 当前元素索引
* @param dragIdx 拖拽元素索引
* @param insertIdx 插入位置索引
* @returns 包含 x 和 y 坐标偏移的对象
*/
function calculateGridOffset(index: number, dragIdx: number, insertIdx: number): TranslateOffset {
const cols = props.columns;
// 计算当前元素在网格中的行列位置
const currentRow = Math.floor(index / cols);
const currentCol = index % cols;
// 计算元素在拖拽后的新位置索引
let newIndex = index;
if (dragIdx < insertIdx) {
// 向后拖拽dragIdx+1 到 insertIdx 之间的元素需要向前移动一位
if (index > dragIdx && index <= insertIdx) {
newIndex = index - 1;
}
} else if (dragIdx > insertIdx) {
// 向前拖拽insertIdx 到 dragIdx-1 之间的元素需要向后移动一位
if (index >= insertIdx && index < dragIdx) {
newIndex = index + 1;
}
}
// 计算新位置的行列坐标
const newRow = Math.floor(newIndex / cols);
const newCol = newIndex % cols;
// 使用动态计算的网格尺寸
const cellWidth = itemWidth.value;
const cellHeight = itemHeight.value;
// 计算实际的像素位移
const offsetX = (newCol - currentCol) * cellWidth;
const offsetY = (newRow - currentRow) * cellHeight;
return { x: offsetX, y: offsetY };
}
/**
* 计算网格布局的插入位置
* @param dragCenterX 拖拽元素中心点X坐标
* @param dragCenterY 拖拽元素中心点Y坐标
* @returns 最佳插入位置索引
*/
function calculateGridInsertIndex(dragCenterX: number, dragCenterY: number): number {
if (itemPositions.value.length == 0) {
return dragIndex.value;
}
let closestIndex = dragIndex.value;
let minDistance = Infinity;
// 使用欧几里得距离找到最近的网格位置(包括原位置)
for (let i = 0; i < itemPositions.value.length; i++) {
const position = itemPositions.value[i];
// 计算到元素中心点的距离
const centerX = position.left + position.width / 2;
const centerY = position.top + position.height / 2;
// 使用欧几里得距离公式
const distance = Math.sqrt(
Math.pow(dragCenterX - centerX, 2) + Math.pow(dragCenterY - centerY, 2)
);
// 更新最近的位置
if (distance < minDistance) {
minDistance = distance;
closestIndex = i;
}
}
return closestIndex;
}
/**
* 计算单列布局的插入位置
* @param clientY Y坐标
* @returns 最佳插入位置索引
*/
function calculateSingleColumnInsertIndex(clientY: number): number {
let closestIndex = dragIndex.value;
let minDistance = Infinity;
// 遍历所有元素,找到距离最近的元素中心
for (let i = 0; i < itemPositions.value.length; i++) {
const position = itemPositions.value[i];
// 计算到元素中心点的距离
const itemCenter = position.top + position.height / 2;
const distance = Math.abs(clientY - itemCenter);
if (distance < minDistance) {
minDistance = distance;
closestIndex = i;
}
}
return closestIndex;
}
/**
* 计算拖拽元素的最佳插入位置
* @param clientPosition 在主轴上的坐标仅用于单列布局的Y轴坐标
* @returns 最佳插入位置的索引
*/
function calculateInsertIndex(clientPosition: number): number {
// 如果没有位置信息,保持原位置
if (itemPositions.value.length == 0) {
return dragIndex.value;
}
// 根据布局类型选择计算方式
if (props.columns > 1) {
// 多列网格布局计算拖拽元素的中心点坐标使用2D坐标计算最近位置
const dragPos = itemPositions.value[dragIndex.value];
const dragCenterX = dragPos.left + dragPos.width / 2 + offsetX.value;
const dragCenterY = dragPos.top + dragPos.height / 2 + offsetY.value;
return calculateGridInsertIndex(dragCenterX, dragCenterY);
} else {
// 单列布局基于Y轴距离计算最近的元素中心
return calculateSingleColumnInsertIndex(clientPosition);
}
}
/**
* 计算单列布局的位移偏移
* @param index 元素索引
* @param dragIdx 拖拽元素索引
* @param insertIdx 插入位置索引
* @returns 位移偏移对象
*/
function calculateSingleColumnOffset(
index: number,
dragIdx: number,
insertIdx: number
): TranslateOffset {
if (dragIdx < insertIdx) {
// 向下拖拽dragIdx+1 到 insertIdx 之间的元素向上移动
if (index > dragIdx && index <= insertIdx) {
return { x: 0, y: -itemHeight.value };
}
} else if (dragIdx > insertIdx) {
// 向上拖拽insertIdx 到 dragIdx-1 之间的元素向下移动
if (index >= insertIdx && index < dragIdx) {
return { x: 0, y: itemHeight.value };
}
}
return { x: 0, y: 0 };
}
/**
* 计算非拖拽元素的位移偏移量
* @param index 元素索引
* @returns 包含 x 和 y 坐标偏移的对象
*/
function getItemTranslateOffset(index: number): TranslateOffset {
// 只在满足所有条件时才计算位移:拖拽中、非放下状态、已开始排序
if (!dragging.value || dropping.value || !sortingStarted.value) {
return { x: 0, y: 0 };
}
const dragIdx = dragIndex.value;
const insertIdx = insertIndex.value;
// 跳过正在拖拽的元素(拖拽元素由位置控制)
if (index == dragIdx) {
return { x: 0, y: 0 };
}
// 没有位置变化时不需要位移(拖回原位置)
if (dragIdx == insertIdx) {
return { x: 0, y: 0 };
}
// 根据布局类型计算位移
if (props.columns > 1) {
// 多列网格布局使用2D位移计算
return calculateGridOffset(index, dragIdx, insertIdx);
} else {
// 单列布局:使用简单的纵向位移
return calculateSingleColumnOffset(index, dragIdx, insertIdx);
}
}
/**
* 计算项目的完整样式对象
* @param index 项目索引
* @returns 样式对象
*/
function getItemStyle(index: number) {
const style = {};
const isCurrent = dragIndex.value == index;
// 多列布局时设置等宽分布
if (props.columns > 1) {
const widthPercent = 100 / props.columns;
style["flex-basis"] = `${widthPercent}%`;
style["width"] = `${widthPercent}%`;
style["box-sizing"] = "border-box";
}
// 放下动画期间,只保留基础样式
if (dropping.value) {
return style;
}
// 为非拖拽元素添加过渡动画
if (props.animation > 0 && !isCurrent) {
style["transition-property"] = "transform";
style["transition-duration"] = `${props.animation}ms`;
style["transition-timing-function"] = "ease";
}
// 拖拽状态下的样式处理
if (dragging.value) {
if (isCurrent) {
// 拖拽元素:跟随移动
style["transform"] = `translate(${offsetX.value}px, ${offsetY.value}px)`;
style["z-index"] = "100";
} else {
// 其他元素:显示排序预览位移
const translateOffset = getItemTranslateOffset(index);
if (translateOffset.x != 0 || translateOffset.y != 0) {
style["transform"] = `translate(${translateOffset.x}px, ${translateOffset.y}px)`;
}
}
}
return style;
}
/**
* 获取所有项目的位置信息
*/
async function getItemPosition(): Promise<void> {
return new Promise((resolve) => {
uni.createSelectorQuery()
.in(proxy)
.select(".cl-draggable")
.boundingClientRect()
.exec((res) => {
const box = res[0] as NodeInfo;
itemWidth.value = (box.width ?? 0) / props.columns;
uni.createSelectorQuery()
.in(proxy)
.selectAll(".cl-draggable__item")
.boundingClientRect()
.exec((res) => {
const rects = res[0] as NodeInfo[];
const positions: ItemPosition[] = [];
for (let i = 0; i < rects.length; i++) {
const rect = rects[i];
if (i == 0) {
itemHeight.value = rect.height ?? 0;
}
positions.push({
top: rect.top ?? 0,
left: rect.left ?? 0,
width: itemWidth.value,
height: itemHeight.value
});
}
itemPositions.value = positions;
resolve();
});
});
});
}
/**
* 获取项目是否禁用
* @param index 项目索引
* @returns 是否禁用
*/
function getItemDisabled(index: number): boolean {
return !isNull(list.value[index]["disabled"]) && (list.value[index]["disabled"] as boolean);
}
/**
* 检查拖拽元素的中心点是否移动到其他元素区域
*/
function checkMovedToOtherElement(): boolean {
// 如果没有位置信息,默认未移出
if (itemPositions.value.length == 0) return false;
const dragIdx = dragIndex.value;
const dragPosition = itemPositions.value[dragIdx];
// 计算拖拽元素当前的中心点位置(考虑拖拽偏移)
const dragCenterX = dragPosition.left + dragPosition.width / 2 + offsetX.value;
const dragCenterY = dragPosition.top + dragPosition.height / 2 + offsetY.value;
// 根据布局类型采用不同的判断策略
if (props.columns > 1) {
// 多列网格布局:检查中心点是否与其他元素区域重叠
for (let i = 0; i < itemPositions.value.length; i++) {
if (i == dragIdx) continue;
const otherPosition = itemPositions.value[i];
const isOverlapping =
dragCenterX >= otherPosition.left &&
dragCenterX <= otherPosition.left + otherPosition.width &&
dragCenterY >= otherPosition.top &&
dragCenterY <= otherPosition.top + otherPosition.height;
if (isOverlapping) {
return true;
}
}
} else {
// 检查是否向上移动超过上一个元素的中线
if (dragIdx > 0) {
const prevPosition = itemPositions.value[dragIdx - 1];
const prevCenterY = prevPosition.top + prevPosition.height / 2;
if (dragCenterY <= prevCenterY) {
return true;
}
}
// 检查是否向下移动超过下一个元素的中线
if (dragIdx < itemPositions.value.length - 1) {
const nextPosition = itemPositions.value[dragIdx + 1];
const nextCenterY = nextPosition.top + nextPosition.height / 2;
if (dragCenterY >= nextCenterY) {
return true;
}
}
}
return false;
}
/**
* 触摸开始事件处理
* @param event 触摸事件对象
* @param index 触摸的项目索引
*/
async function onTouchStart(event: UniTouchEvent, index: number): Promise<void> {
// 检查是否禁用或索引无效
if (props.disabled) return;
if (getItemDisabled(index)) return;
if (index < 0 || index >= list.value.length) return;
const touch = event.touches[0];
// 初始化拖拽状态
dragging.value = true;
dragIndex.value = index;
insertIndex.value = index; // 初始插入位置为原位置
startX.value = touch.clientX;
startY.value = touch.clientY;
offsetX.value = 0;
offsetY.value = 0;
dragItem.value = list.value[index];
// 先获取所有项目的位置信息,为后续计算做准备
await getItemPosition();
// 触发开始事件
emit("start", index);
}
/**
* 触摸移动事件处理
* @param event 触摸事件对象
*/
function onTouchMove(event: TouchEvent): void {
if (!dragging.value) return;
const touch = event.touches[0];
// 更新拖拽偏移量
offsetX.value = touch.clientX - startX.value;
offsetY.value = touch.clientY - startY.value;
// 智能启动排序模拟:只有移出原元素区域才开始
if (!sortingStarted.value) {
if (checkMovedToOtherElement()) {
sortingStarted.value = true;
}
}
// 只有开始排序模拟后才计算插入位置
if (sortingStarted.value) {
// 计算拖拽元素当前的中心点坐标
const dragPos = itemPositions.value[dragIndex.value];
const dragCenterX = dragPos.left + dragPos.width / 2 + offsetX.value;
const dragCenterY = dragPos.top + dragPos.height / 2 + offsetY.value;
// 根据布局类型选择坐标轴网格布局使用X坐标单列布局使用Y坐标
const dragCenter = props.columns > 1 ? dragCenterX : dragCenterY;
// 计算最佳插入位置
const newIndex = calculateInsertIndex(dragCenter);
if (newIndex != insertIndex.value) {
insertIndex.value = newIndex;
}
}
// 阻止默认行为和事件冒泡
event.preventDefault();
}
/**
* 触摸结束事件处理
*/
function onTouchEnd(): void {
if (!dragging.value) return;
const oldIndex = dragIndex.value;
const newIndex = insertIndex.value;
// 如果位置发生变化,立即更新数组
if (oldIndex != newIndex && newIndex >= 0) {
const newList = [...list.value];
const item = newList.splice(oldIndex, 1)[0];
newList.splice(newIndex, 0, item);
list.value = newList;
// 触发变化事件
emit("update:modelValue", list.value);
emit("change", list.value);
}
// 开始放下动画
dropping.value = true;
dragging.value = false;
// 让拖拽元素回到自然位置(偏移归零)
offsetX.value = 0;
offsetY.value = 0;
// 等待放下动画完成后重置所有状态
setTimeout(() => {
emit("end", newIndex >= 0 ? newIndex : oldIndex);
reset();
}, 10);
}
/**
* 根据平台选择合适的key
* @param item 数据项
* @param index 索引
* @returns 合适的key
*/
function getItemKey(item: UTSJSONObject, index: number): string {
// #ifdef MP
// 小程序环境使用 index 作为 key避免数据错乱
return `${index}`;
// #endif
// #ifndef MP
// 其他平台使用 uid提供更好的性能
return item["uid"] as string;
// #endif
}
watch(
computed(() => props.modelValue),
(val: UTSJSONObject[]) => {
list.value = val.map((e) => {
return {
uid: e["uid"] ?? uuid(),
...e
};
});
},
{
immediate: true
}
);
</script>
<style lang="scss" scoped>
.cl-draggable {
@apply flex-col relative overflow-visible;
}
.cl-draggable--grid {
@apply flex-row flex-wrap;
}
.cl-draggable__item {
@apply relative;
}
.cl-draggable__item--dragging {
@apply opacity-80;
}
.cl-draggable__item--disabled {
@apply opacity-60;
}
</style>

View File

@@ -0,0 +1,15 @@
import type { PassThroughProps } from "../../types";
export type ClDraggablePassThrough = {
className?: string;
ghost?: PassThroughProps;
};
export type ClDraggableProps = {
className?: string;
pt?: ClDraggablePassThrough;
modelValue?: UTSJSONObject[];
disabled?: boolean;
animation?: number;
columns?: number;
};

View File

@@ -12,6 +12,7 @@ import type { ClCheckboxProps, ClCheckboxPassThrough } from "./components/cl-che
import type { ClColProps, ClColPassThrough } from "./components/cl-col/props"; import type { ClColProps, ClColPassThrough } from "./components/cl-col/props";
import type { ClCollapseProps, ClCollapsePassThrough } from "./components/cl-collapse/props"; import type { ClCollapseProps, ClCollapsePassThrough } from "./components/cl-collapse/props";
import type { ClCountdownProps, ClCountdownPassThrough } from "./components/cl-countdown/props"; import type { ClCountdownProps, ClCountdownPassThrough } from "./components/cl-countdown/props";
import type { ClDraggableProps, ClDraggablePassThrough } from "./components/cl-draggable/props";
import type { ClFloatViewProps } from "./components/cl-float-view/props"; import type { ClFloatViewProps } from "./components/cl-float-view/props";
import type { ClFooterProps, ClFooterPassThrough } from "./components/cl-footer/props"; import type { ClFooterProps, ClFooterPassThrough } from "./components/cl-footer/props";
import type { ClIconProps, ClIconPassThrough } from "./components/cl-icon/props"; import type { ClIconProps, ClIconPassThrough } from "./components/cl-icon/props";
@@ -77,6 +78,7 @@ declare module "vue" {
"cl-col": (typeof import('./components/cl-col/cl-col.uvue')['default']) & import('vue').DefineComponent<ClColProps>; "cl-col": (typeof import('./components/cl-col/cl-col.uvue')['default']) & import('vue').DefineComponent<ClColProps>;
"cl-collapse": (typeof import('./components/cl-collapse/cl-collapse.uvue')['default']) & import('vue').DefineComponent<ClCollapseProps>; "cl-collapse": (typeof import('./components/cl-collapse/cl-collapse.uvue')['default']) & import('vue').DefineComponent<ClCollapseProps>;
"cl-countdown": (typeof import('./components/cl-countdown/cl-countdown.uvue')['default']) & import('vue').DefineComponent<ClCountdownProps>; "cl-countdown": (typeof import('./components/cl-countdown/cl-countdown.uvue')['default']) & import('vue').DefineComponent<ClCountdownProps>;
"cl-draggable": (typeof import('./components/cl-draggable/cl-draggable.uvue')['default']) & import('vue').DefineComponent<ClDraggableProps>;
"cl-float-view": (typeof import('./components/cl-float-view/cl-float-view.uvue')['default']) & import('vue').DefineComponent<ClFloatViewProps>; "cl-float-view": (typeof import('./components/cl-float-view/cl-float-view.uvue')['default']) & import('vue').DefineComponent<ClFloatViewProps>;
"cl-footer": (typeof import('./components/cl-footer/cl-footer.uvue')['default']) & import('vue').DefineComponent<ClFooterProps>; "cl-footer": (typeof import('./components/cl-footer/cl-footer.uvue')['default']) & import('vue').DefineComponent<ClFooterProps>;
"cl-icon": (typeof import('./components/cl-icon/cl-icon.uvue')['default']) & import('vue').DefineComponent<ClIconProps>; "cl-icon": (typeof import('./components/cl-icon/cl-icon.uvue')['default']) & import('vue').DefineComponent<ClIconProps>;