@veltra/desktop 1.7.1 → 1.7.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -22,7 +22,7 @@ function useFeatures(options) {
22
22
  }),
23
23
  dynamicFeatures: computed(() => {
24
24
  const { features } = props;
25
- if (!Array.isArray(features) && typeof features === "object") return Object.entries(features).filter(([_, value]) => {
25
+ if (!Array.isArray(features) && typeof features === "object") return Object.entries(features).filter(([, value]) => {
26
26
  return typeof value === "function";
27
27
  }).reduce((acc, [key, value]) => {
28
28
  acc[key] = value;
@@ -1 +1 @@
1
- {"version":3,"file":"use-features.js","names":[],"sources":["../../../src/components/batch-edit/use-features.ts"],"sourcesContent":["import { computed } from 'vue'\n\nimport type { BatchEditFeature, BatchEditProps, TableRow } from '../../types'\n\ninterface Options {\n props: BatchEditProps\n}\nexport function useFeatures(options: Options) {\n const { props } = options\n const staticFeatures = computed(() => {\n const { features } = props\n\n if (Array.isArray(features)) {\n return new Set(features)\n }\n\n const defaultFeatures = new Set<BatchEditFeature>(['create', 'delete', 'update', 'createChild'])\n\n if (!features) {\n return defaultFeatures\n }\n\n // 函数与 false 的特性视为关闭;显式 true 视为开启(即便不在默认集合内)\n Object.entries(features).forEach(([key, value]) => {\n const k = key as BatchEditFeature\n if (typeof value === 'function' || value === false) {\n defaultFeatures.delete(k)\n } else if (value === true) {\n defaultFeatures.add(k)\n }\n })\n return defaultFeatures\n })\n\n const dynamicFeatures = computed<\n Record<BatchEditFeature, ((row?: TableRow) => boolean) | undefined>\n >(() => {\n const { features } = props\n if (!Array.isArray(features) && typeof features === 'object') {\n const ret = Object.entries(features)\n .filter(([_, value]) => {\n return typeof value === 'function'\n })\n .reduce(\n (acc, [key, value]) => {\n acc[key] = value\n return acc\n },\n {} as Record<BatchEditFeature, (row?: TableRow) => boolean>\n )\n return ret\n }\n\n return {} as Record<BatchEditFeature, ((row?: TableRow) => boolean) | undefined>\n })\n\n return { staticFeatures, dynamicFeatures }\n}\n"],"mappings":";;AAOA,SAAgB,YAAY,SAAkB;CAC5C,MAAM,EAAE,UAAU;CAgDlB,OAAO;EAAE,gBA/Cc,eAAe;GACpC,MAAM,EAAE,aAAa;GAErB,IAAI,MAAM,QAAQ,QAAQ,GACxB,OAAO,IAAI,IAAI,QAAQ;GAGzB,MAAM,kCAAkB,IAAI,IAAsB;IAAC;IAAU;IAAU;IAAU;GAAa,CAAC;GAE/F,IAAI,CAAC,UACH,OAAO;GAIT,OAAO,QAAQ,QAAQ,CAAC,CAAC,SAAS,CAAC,KAAK,WAAW;IACjD,MAAM,IAAI;IACV,IAAI,OAAO,UAAU,cAAc,UAAU,OAC3C,gBAAgB,OAAO,CAAC;SACnB,IAAI,UAAU,MACnB,gBAAgB,IAAI,CAAC;GAEzB,CAAC;GACD,OAAO;EACT,CAwBsB;EAAG,iBAtBD,eAEhB;GACN,MAAM,EAAE,aAAa;GACrB,IAAI,CAAC,MAAM,QAAQ,QAAQ,KAAK,OAAO,aAAa,UAYlD,OAXY,OAAO,QAAQ,QAAQ,CAAC,CACjC,QAAQ,CAAC,GAAG,WAAW;IACtB,OAAO,OAAO,UAAU;GAC1B,CAAC,CAAC,CACD,QACE,KAAK,CAAC,KAAK,WAAW;IACrB,IAAI,OAAO;IACX,OAAO;GACT,GACA,CAAC,CAEI;GAGX,OAAO,CAAC;EACV,CAEuC;CAAE;AAC3C"}
1
+ {"version":3,"file":"use-features.js","names":[],"sources":["../../../src/components/batch-edit/use-features.ts"],"sourcesContent":["import { computed } from 'vue'\n\nimport type { BatchEditFeature, BatchEditProps, TableRow } from '../../types'\n\ninterface Options {\n props: BatchEditProps\n}\nexport function useFeatures(options: Options) {\n const { props } = options\n const staticFeatures = computed(() => {\n const { features } = props\n\n if (Array.isArray(features)) {\n return new Set(features)\n }\n\n const defaultFeatures = new Set<BatchEditFeature>(['create', 'delete', 'update', 'createChild'])\n\n if (!features) {\n return defaultFeatures\n }\n\n // 函数与 false 的特性视为关闭;显式 true 视为开启(即便不在默认集合内)\n Object.entries(features).forEach(([key, value]) => {\n const k = key as BatchEditFeature\n if (typeof value === 'function' || value === false) {\n defaultFeatures.delete(k)\n } else if (value === true) {\n defaultFeatures.add(k)\n }\n })\n return defaultFeatures\n })\n\n const dynamicFeatures = computed<\n Record<BatchEditFeature, ((row?: TableRow) => boolean) | undefined>\n >(() => {\n const { features } = props\n if (!Array.isArray(features) && typeof features === 'object') {\n const ret = Object.entries(features)\n .filter(([, value]) => {\n return typeof value === 'function'\n })\n .reduce(\n (acc, [key, value]) => {\n acc[key] = value\n return acc\n },\n {} as Record<BatchEditFeature, (row?: TableRow) => boolean>\n )\n return ret\n }\n\n return {} as Record<BatchEditFeature, ((row?: TableRow) => boolean) | undefined>\n })\n\n return { staticFeatures, dynamicFeatures }\n}\n"],"mappings":";;AAOA,SAAgB,YAAY,SAAkB;CAC5C,MAAM,EAAE,UAAU;CAgDlB,OAAO;EAAE,gBA/Cc,eAAe;GACpC,MAAM,EAAE,aAAa;GAErB,IAAI,MAAM,QAAQ,QAAQ,GACxB,OAAO,IAAI,IAAI,QAAQ;GAGzB,MAAM,kCAAkB,IAAI,IAAsB;IAAC;IAAU;IAAU;IAAU;GAAa,CAAC;GAE/F,IAAI,CAAC,UACH,OAAO;GAIT,OAAO,QAAQ,QAAQ,CAAC,CAAC,SAAS,CAAC,KAAK,WAAW;IACjD,MAAM,IAAI;IACV,IAAI,OAAO,UAAU,cAAc,UAAU,OAC3C,gBAAgB,OAAO,CAAC;SACnB,IAAI,UAAU,MACnB,gBAAgB,IAAI,CAAC;GAEzB,CAAC;GACD,OAAO;EACT,CAwBsB;EAAG,iBAtBD,eAEhB;GACN,MAAM,EAAE,aAAa;GACrB,IAAI,CAAC,MAAM,QAAQ,QAAQ,KAAK,OAAO,aAAa,UAYlD,OAXY,OAAO,QAAQ,QAAQ,CAAC,CACjC,QAAQ,GAAG,WAAW;IACrB,OAAO,OAAO,UAAU;GAC1B,CAAC,CAAC,CACD,QACE,KAAK,CAAC,KAAK,WAAW;IACrB,IAAI,OAAO;IACX,OAAO;GACT,GACA,CAAC,CAEI;GAGX,OAAO,CAAC;EACV,CAEuC;CAAE;AAC3C"}
@@ -1,5 +1,5 @@
1
1
  import { computed, nextTick } from "vue";
2
- import { last, o } from "@cat-kit/core";
2
+ import { copy, last, o } from "@cat-kit/core";
3
3
  //#region src/components/batch-edit/use-handlers.ts
4
4
  /** 按索引路径在原始数据树中定位节点(等价于历史 Forest.visit 路径访问) */
5
5
  function visitDataByIndexPath(roots, indexPath, childrenKey) {
@@ -24,7 +24,7 @@ function useHandlers(options) {
24
24
  return typeof props.tree === "string" ? props.tree : "children";
25
25
  });
26
26
  function getInsertData() {
27
- return o(props.model ?? {}).copy();
27
+ return copy(props.model ?? {});
28
28
  }
29
29
  /**
30
30
  * 插入数据
@@ -1 +1 @@
1
- {"version":3,"file":"use-handlers.js","names":[],"sources":["../../../src/components/batch-edit/use-handlers.ts"],"sourcesContent":["import { last, o } from '@cat-kit/core'\nimport { computed, nextTick, type ShallowRef } from 'vue'\n\nimport type {\n TableRow,\n BatchEditEmits,\n BatchEditProps,\n BatchEditStates,\n FormExposed\n} from '../../types'\n\n/** 按索引路径在原始数据树中定位节点(等价于历史 Forest.visit 路径访问) */\nfunction visitDataByIndexPath<T extends Record<string, unknown>>(\n roots: T[],\n indexPath: number[],\n childrenKey: string\n): T | undefined {\n if (!indexPath.length) return undefined\n let currentList: T[] | undefined = roots\n let node: T | undefined\n for (let i = 0; i < indexPath.length; i++) {\n const idx = indexPath[i]!\n if (!currentList) return undefined\n node = currentList[idx]\n if (node === undefined) return undefined\n if (i < indexPath.length - 1) {\n const next = node[childrenKey]\n currentList = Array.isArray(next) ? (next as T[]) : undefined\n }\n }\n return node\n}\n\ninterface Options {\n props: BatchEditProps\n emit: BatchEditEmits\n state: BatchEditStates\n formRef: ShallowRef<FormExposed | null>\n resetState: () => void\n}\n\nexport interface EditReturned {\n handleSave: () => Promise<void>\n handleClose: () => void\n handleCreate: () => void\n handleDelete: (row: TableRow) => Promise<void>\n handleInsertToNext: (row: TableRow) => void\n handleInsertToPrev: (row: TableRow) => void\n handleInsertChild: (row: TableRow) => void\n}\n\nexport function useHandlers(options: Options): EditReturned {\n const { props, emit, state, resetState, formRef } = options\n\n const childrenKey = computed(() => {\n return typeof props.tree === 'string' ? props.tree : 'children'\n })\n\n function getInsertData(): Record<string, any> {\n return o(props.model ?? {}).copy()\n }\n\n /**\n * 插入数据\n * @param item 数据\n */\n function insert(item: Record<string, any>) {\n const data = [...(props.data ?? [])]\n\n const parent = visitDataByIndexPath(data ?? [], state.indexPath.slice(0, -1), childrenKey.value)\n\n if (parent) {\n const children = parent[childrenKey.value]\n if (!children) {\n parent[childrenKey.value] = [item]\n } else {\n children.splice(last(state.indexPath), 0, item)\n }\n } else {\n data.splice(last(state.indexPath), 0, item)\n }\n\n emit('update:data', data)\n\n return item\n }\n\n /**\n * 点击新增按钮\n */\n function handleCreate() {\n const { data } = props\n\n resetState()\n\n nextTick(() => {\n state.formActionType = 'create'\n state.formVisible = true\n state.depth = 1\n state.indexPath = [data?.length ?? 0]\n emit('create')\n })\n }\n\n function handleInsertToPrev(row: TableRow) {\n resetState()\n state.formActionType = 'create'\n state.formVisible = true\n state.parentRow = row.parent\n state.depth = row.depth\n state.indexPath = [...row.indexes]\n emit('create-prev', row)\n }\n\n function handleInsertToNext(row: TableRow) {\n resetState()\n state.formActionType = 'create'\n state.formVisible = true\n state.parentRow = row.parent\n state.depth = row.depth\n state.indexPath = [...row.indexes.slice(0, -1), row.index + 1]\n emit('create-next', row)\n }\n\n function handleInsertChild(row: TableRow) {\n resetState()\n state.formActionType = 'createChild'\n state.formVisible = true\n state.parentRow = row\n state.depth = row.depth + 1\n row.expanded = true\n state.indexPath = [...row.indexes, row.children?.length ?? 0]\n emit('create-child', row)\n }\n\n function runWithLoading<Arg extends any[]>(fn: (...args: Arg) => Promise<void> | void) {\n return async (...args: Arg) => {\n state.loading = true\n if (state.row) {\n state.row.operating = true\n }\n try {\n await fn.apply(null, args)\n } catch (error) {\n console.error(error)\n }\n state.loading = false\n if (state.row) {\n state.row.operating = false\n }\n }\n }\n\n /** 保存 */\n const handleSave = runWithLoading(async () => {\n const { model, saveMethod } = props\n const valid = await formRef.value?.validate()\n if (!model || !valid) return\n\n let item = getInsertData()\n\n // 新增\n if (state.formActionType === 'create' || state.formActionType === 'createChild') {\n await props.beforeCreate?.(item, state.parentRow?.data)\n if (saveMethod) {\n const result = await saveMethod(item, state.formActionType, state.parentRow?.data)\n if (result) {\n item = result\n }\n }\n insert(item)\n\n // 推进插入点,便于连续新增;并重置表单到初始默认值\n const next = last(state.indexPath) + 1\n state.indexPath = [...state.indexPath.slice(0, -1), next]\n formRef.value?.reset()\n return\n }\n\n // 普通模式下的编辑\n if (saveMethod) {\n const result = await saveMethod(item, state.formActionType, state.parentRow?.data)\n if (result) {\n item = result\n }\n }\n\n const { row } = state\n row &&\n Object.keys(item).forEach((key) => {\n o(row.data).set(key, o(item).get(key))\n })\n })\n\n const handleDelete = runWithLoading(async (row: TableRow) => {\n const { deleteMethod } = props\n\n if (deleteMethod) {\n const result = await deleteMethod([row.data])\n if (result === false) {\n return\n }\n }\n\n const data = [...(props.data ?? [])]\n\n const parent = visitDataByIndexPath(data, row.indexes.slice(0, -1), childrenKey.value)\n\n if (parent) {\n const children = parent[childrenKey.value]\n if (children) {\n children.splice(row.index, 1)\n } else {\n console.error('行路径不正确')\n }\n } else {\n data.splice(row.index, 1)\n }\n\n if (state.row === row) {\n resetState()\n }\n\n emit('update:data', data)\n })\n\n function handleClose() {\n resetState()\n }\n\n return {\n handleDelete,\n handleInsertChild,\n handleInsertToNext,\n handleInsertToPrev,\n handleCreate,\n handleClose,\n handleSave\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"use-handlers.js","names":[],"sources":["../../../src/components/batch-edit/use-handlers.ts"],"sourcesContent":["import { copy, last, o } from '@cat-kit/core'\nimport { computed, nextTick, type ShallowRef } from 'vue'\n\nimport type {\n TableRow,\n BatchEditEmits,\n BatchEditProps,\n BatchEditStates,\n FormExposed\n} from '../../types'\n\n/** 按索引路径在原始数据树中定位节点(等价于历史 Forest.visit 路径访问) */\nfunction visitDataByIndexPath<T extends Record<string, unknown>>(\n roots: T[],\n indexPath: number[],\n childrenKey: string\n): T | undefined {\n if (!indexPath.length) return undefined\n let currentList: T[] | undefined = roots\n let node: T | undefined\n for (let i = 0; i < indexPath.length; i++) {\n const idx = indexPath[i]!\n if (!currentList) return undefined\n node = currentList[idx]\n if (node === undefined) return undefined\n if (i < indexPath.length - 1) {\n const next = node[childrenKey]\n currentList = Array.isArray(next) ? (next as T[]) : undefined\n }\n }\n return node\n}\n\ninterface Options {\n props: BatchEditProps\n emit: BatchEditEmits\n state: BatchEditStates\n formRef: ShallowRef<FormExposed | null>\n resetState: () => void\n}\n\nexport interface EditReturned {\n handleSave: () => Promise<void>\n handleClose: () => void\n handleCreate: () => void\n handleDelete: (row: TableRow) => Promise<void>\n handleInsertToNext: (row: TableRow) => void\n handleInsertToPrev: (row: TableRow) => void\n handleInsertChild: (row: TableRow) => void\n}\n\nexport function useHandlers(options: Options): EditReturned {\n const { props, emit, state, resetState, formRef } = options\n\n const childrenKey = computed(() => {\n return typeof props.tree === 'string' ? props.tree : 'children'\n })\n\n function getInsertData(): Record<string, any> {\n return copy(props.model ?? {})\n }\n\n /**\n * 插入数据\n * @param item 数据\n */\n function insert(item: Record<string, any>) {\n const data = [...(props.data ?? [])]\n\n const parent = visitDataByIndexPath(data ?? [], state.indexPath.slice(0, -1), childrenKey.value)\n\n if (parent) {\n const children = parent[childrenKey.value]\n if (!children) {\n parent[childrenKey.value] = [item]\n } else {\n children.splice(last(state.indexPath), 0, item)\n }\n } else {\n data.splice(last(state.indexPath), 0, item)\n }\n\n emit('update:data', data)\n\n return item\n }\n\n /**\n * 点击新增按钮\n */\n function handleCreate() {\n const { data } = props\n\n resetState()\n\n nextTick(() => {\n state.formActionType = 'create'\n state.formVisible = true\n state.depth = 1\n state.indexPath = [data?.length ?? 0]\n emit('create')\n })\n }\n\n function handleInsertToPrev(row: TableRow) {\n resetState()\n state.formActionType = 'create'\n state.formVisible = true\n state.parentRow = row.parent\n state.depth = row.depth\n state.indexPath = [...row.indexes]\n emit('create-prev', row)\n }\n\n function handleInsertToNext(row: TableRow) {\n resetState()\n state.formActionType = 'create'\n state.formVisible = true\n state.parentRow = row.parent\n state.depth = row.depth\n state.indexPath = [...row.indexes.slice(0, -1), row.index + 1]\n emit('create-next', row)\n }\n\n function handleInsertChild(row: TableRow) {\n resetState()\n state.formActionType = 'createChild'\n state.formVisible = true\n state.parentRow = row\n state.depth = row.depth + 1\n row.expanded = true\n state.indexPath = [...row.indexes, row.children?.length ?? 0]\n emit('create-child', row)\n }\n\n function runWithLoading<Arg extends any[]>(fn: (...args: Arg) => Promise<void> | void) {\n return async (...args: Arg) => {\n state.loading = true\n if (state.row) {\n state.row.operating = true\n }\n try {\n await fn.apply(null, args)\n } catch (error) {\n console.error(error)\n }\n state.loading = false\n if (state.row) {\n state.row.operating = false\n }\n }\n }\n\n /** 保存 */\n const handleSave = runWithLoading(async () => {\n const { model, saveMethod } = props\n const valid = await formRef.value?.validate()\n if (!model || !valid) return\n\n let item = getInsertData()\n\n // 新增\n if (state.formActionType === 'create' || state.formActionType === 'createChild') {\n await props.beforeCreate?.(item, state.parentRow?.data)\n if (saveMethod) {\n const result = await saveMethod(item, state.formActionType, state.parentRow?.data)\n if (result) {\n item = result\n }\n }\n insert(item)\n\n // 推进插入点,便于连续新增;并重置表单到初始默认值\n const next = last(state.indexPath) + 1\n state.indexPath = [...state.indexPath.slice(0, -1), next]\n formRef.value?.reset()\n return\n }\n\n // 普通模式下的编辑\n if (saveMethod) {\n const result = await saveMethod(item, state.formActionType, state.parentRow?.data)\n if (result) {\n item = result\n }\n }\n\n const { row } = state\n row &&\n Object.keys(item).forEach((key) => {\n o(row.data).set(key, o(item).get(key))\n })\n })\n\n const handleDelete = runWithLoading(async (row: TableRow) => {\n const { deleteMethod } = props\n\n if (deleteMethod) {\n const result = await deleteMethod([row.data])\n if (result === false) {\n return\n }\n }\n\n const data = [...(props.data ?? [])]\n\n const parent = visitDataByIndexPath(data, row.indexes.slice(0, -1), childrenKey.value)\n\n if (parent) {\n const children = parent[childrenKey.value]\n if (children) {\n children.splice(row.index, 1)\n } else {\n console.error('行路径不正确')\n }\n } else {\n data.splice(row.index, 1)\n }\n\n if (state.row === row) {\n resetState()\n }\n\n emit('update:data', data)\n })\n\n function handleClose() {\n resetState()\n }\n\n return {\n handleDelete,\n handleInsertChild,\n handleInsertToNext,\n handleInsertToPrev,\n handleCreate,\n handleClose,\n handleSave\n }\n}\n"],"mappings":"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"}
@@ -14,10 +14,10 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
14
14
  const props = __props;
15
15
  const emits = __emit;
16
16
  const classList = computed(() => {
17
- return [cls.b, bem.is("checked", props.checked)];
17
+ return [cls.b, bem.is("checked", props.modelValue ?? props.checked)];
18
18
  });
19
19
  const handleChange = () => {
20
- emits("update:modelValue", props.checked);
20
+ emits("update:modelValue", !(props.modelValue ?? props.checked));
21
21
  };
22
22
  return (_ctx, _cache) => {
23
23
  return openBlock(), createElementBlock("div", {
@@ -1 +1 @@
1
- {"version":3,"file":"check-tag.js","names":[],"sources":["../../../src/components/check-tag/check-tag.vue"],"sourcesContent":["<template>\n <div :class=\"classList\" @click=\"handleChange\">\n <slot />\n </div>\n</template>\n\n<script lang=\"ts\" setup>\nimport { bem } from '@veltra/utils'\nimport { computed } from 'vue'\n\nimport type { CheckTagEmits, CheckTagProps } from '../../types'\n\ndefineOptions({ name: 'UCheckTag' })\n\nconst cls = bem('check-tag')\n\nconst props = withDefaults(defineProps<CheckTagProps>(), {})\n\nconst emits = defineEmits<CheckTagEmits>()\n\nconst classList = computed(() => {\n return [cls.b, bem.is('checked', props.checked)]\n})\n\nconst handleChange = () => {\n emits('update:modelValue', props.checked)\n}\n</script>\n"],"mappings":";;;;;;;;;;;;EAcA,MAAM,MAAM,IAAI,WAAW;EAE3B,MAAM,QAAQ;EAEd,MAAM,QAAQ;EAEd,MAAM,YAAY,eAAe;GAC/B,OAAO,CAAC,IAAI,GAAG,IAAI,GAAG,WAAW,MAAM,OAAO,CAAC;EACjD,CAAC;EAED,MAAM,qBAAqB;GACzB,MAAM,qBAAqB,MAAM,OAAO;EAC1C;;GAzBE,OAAA,UAAA,GAAA,mBAEM,OAAA;IAFA,OAAK,eAAE,UAAA,KAAS;IAAG,SAAO;GAC9B,GAAA,CAAA,WAAQ,KAAA,QAAA,SAAA,CAAA,GAAA,CAAA"}
1
+ {"version":3,"file":"check-tag.js","names":[],"sources":["../../../src/components/check-tag/check-tag.vue"],"sourcesContent":["<template>\n <div :class=\"classList\" @click=\"handleChange\">\n <slot />\n </div>\n</template>\n\n<script lang=\"ts\" setup>\nimport { bem } from '@veltra/utils'\nimport { computed } from 'vue'\n\nimport type { CheckTagEmits, CheckTagProps } from '../../types'\n\ndefineOptions({ name: 'UCheckTag' })\n\nconst cls = bem('check-tag')\n\nconst props = withDefaults(defineProps<CheckTagProps>(), {})\n\nconst emits = defineEmits<CheckTagEmits>()\n\nconst classList = computed(() => {\n return [cls.b, bem.is('checked', props.modelValue ?? props.checked)]\n})\n\nconst handleChange = () => {\n emits('update:modelValue', !(props.modelValue ?? props.checked))\n}\n</script>\n"],"mappings":";;;;;;;;;;;;EAcA,MAAM,MAAM,IAAI,WAAW;EAE3B,MAAM,QAAQ;EAEd,MAAM,QAAQ;EAEd,MAAM,YAAY,eAAe;GAC/B,OAAO,CAAC,IAAI,GAAG,IAAI,GAAG,WAAW,MAAM,cAAc,MAAM,OAAO,CAAC;EACrE,CAAC;EAED,MAAM,qBAAqB;GACzB,MAAM,qBAAqB,EAAE,MAAM,cAAc,MAAM,QAAQ;EACjE;;GAzBE,OAAA,UAAA,GAAA,mBAEM,OAAA;IAFA,OAAK,eAAE,UAAA,KAAS;IAAG,SAAO;GAC9B,GAAA,CAAA,WAAQ,KAAA,QAAA,SAAA,CAAA,GAAA,CAAA"}
@@ -1,17 +1,6 @@
1
1
  import { nextTick, watch } from "vue";
2
- import { o } from "@cat-kit/core";
2
+ import { copy, o } from "@cat-kit/core";
3
3
  //#region src/components/form/use-form-fields.ts
4
- /** 深拷贝 model,保留 undefined 等 o().copy() 会丢弃的值 */
5
- function snapshotModel(model) {
6
- const result = {};
7
- for (const key of Object.keys(model)) {
8
- const value = model[key];
9
- if (Array.isArray(value)) result[key] = value.map((item) => item !== null && typeof item === "object" ? snapshotModel(item) : item);
10
- else if (value !== null && typeof value === "object") result[key] = snapshotModel(value);
11
- else result[key] = value;
12
- }
13
- return result;
14
- }
15
4
  /** 按快照逐字段写回 model,支持 undefined 与嵌套对象 */
16
5
  function applySnapshot(target, source) {
17
6
  for (const key of Object.keys(source)) {
@@ -22,7 +11,7 @@ function applySnapshot(target, source) {
22
11
  continue;
23
12
  }
24
13
  if (Array.isArray(sourceValue)) {
25
- o(target).set(key, sourceValue.map((item) => item !== null && typeof item === "object" ? snapshotModel(item) : item));
14
+ o(target).set(key, copy(sourceValue));
26
15
  continue;
27
16
  }
28
17
  o(target).set(key, sourceValue);
@@ -45,7 +34,7 @@ function useFormFields(options) {
45
34
  return willValidate;
46
35
  }
47
36
  watch(() => props.model, (model) => {
48
- initialSnapshot = model ? snapshotModel(model) : void 0;
37
+ initialSnapshot = model ? copy(model) : void 0;
49
38
  }, {
50
39
  immediate: true,
51
40
  deep: false
@@ -1 +1 @@
1
- {"version":3,"file":"use-form-fields.js","names":[],"sources":["../../../src/components/form/use-form-fields.ts"],"sourcesContent":["import { o } from '@cat-kit/core'\nimport type { FormFieldItem } from '@veltra/utils'\nimport { nextTick, watch } from 'vue'\n\nimport type { FormProps } from '../../types/form'\n\ninterface Options {\n props: FormProps\n}\n\n/** 深拷贝 model,保留 undefined 等 o().copy() 会丢弃的值 */\nfunction snapshotModel(model: Record<string, any>): Record<string, any> {\n const result: Record<string, any> = {}\n\n for (const key of Object.keys(model)) {\n const value = model[key]\n if (Array.isArray(value)) {\n result[key] = value.map((item) =>\n item !== null && typeof item === 'object' ? snapshotModel(item) : item\n )\n } else if (value !== null && typeof value === 'object') {\n result[key] = snapshotModel(value)\n } else {\n result[key] = value\n }\n }\n\n return result\n}\n\n/** 按快照逐字段写回 model,支持 undefined 与嵌套对象 */\nfunction applySnapshot(target: Record<string, any>, source: Record<string, any>) {\n for (const key of Object.keys(source)) {\n const sourceValue = source[key]\n const targetValue = target[key]\n\n if (\n sourceValue !== null &&\n typeof sourceValue === 'object' &&\n !Array.isArray(sourceValue) &&\n targetValue !== null &&\n typeof targetValue === 'object' &&\n !Array.isArray(targetValue)\n ) {\n applySnapshot(targetValue, sourceValue)\n continue\n }\n\n if (Array.isArray(sourceValue)) {\n o(target).set(\n key,\n sourceValue.map((item) =>\n item !== null && typeof item === 'object' ? snapshotModel(item) : item\n )\n )\n continue\n }\n\n o(target).set(key, sourceValue)\n }\n}\n\nexport function useFormFields(options: Options) {\n const { props } = options\n const fields: Record<string, FormFieldItem> = {}\n\n let willValidate = true\n\n /** model 初始快照,供 reset 恢复 */\n let initialSnapshot: Record<string, any> | undefined\n\n function runWithoutChangeValidate(fn: () => void) {\n willValidate = false\n fn()\n nextTick(() => {\n willValidate = true\n })\n }\n\n function shouldValidate() {\n return willValidate\n }\n\n watch(\n () => props.model,\n (model) => {\n initialSnapshot = model ? snapshotModel(model) : undefined\n },\n { immediate: true, deep: false }\n )\n\n function registerField(field: string, item: FormFieldItem) {\n fields[field] = item\n }\n\n function unregisterField(field: string) {\n delete fields[field]\n }\n\n function clearValidate() {\n Object.values(fields).forEach((item) => item.clearValidate?.())\n }\n\n async function validate(keys?: string[]) {\n let validList: boolean[]\n if (keys) {\n validList = await Promise.all(\n keys.map((key) => fields[key]?.validate() ?? Promise.resolve(true))\n )\n } else {\n validList = await Promise.all(Object.values(fields).map((field) => field.validate()))\n }\n return validList.every((valid) => valid)\n }\n\n function reset() {\n if (!props.model || !initialSnapshot) return\n\n runWithoutChangeValidate(() => {\n applySnapshot(props.model!, initialSnapshot!)\n Object.values(fields).forEach((item) => item.clearValidate?.())\n })\n }\n\n return { fields, registerField, validate, unregisterField, clearValidate, reset, shouldValidate }\n}\n"],"mappings":";;;;AAWA,SAAS,cAAc,OAAiD;CACtE,MAAM,SAA8B,CAAC;CAErC,KAAK,MAAM,OAAO,OAAO,KAAK,KAAK,GAAG;EACpC,MAAM,QAAQ,MAAM;EACpB,IAAI,MAAM,QAAQ,KAAK,GACrB,OAAO,OAAO,MAAM,KAAK,SACvB,SAAS,QAAQ,OAAO,SAAS,WAAW,cAAc,IAAI,IAAI,IACpE;OACK,IAAI,UAAU,QAAQ,OAAO,UAAU,UAC5C,OAAO,OAAO,cAAc,KAAK;OAEjC,OAAO,OAAO;CAElB;CAEA,OAAO;AACT;;AAGA,SAAS,cAAc,QAA6B,QAA6B;CAC/E,KAAK,MAAM,OAAO,OAAO,KAAK,MAAM,GAAG;EACrC,MAAM,cAAc,OAAO;EAC3B,MAAM,cAAc,OAAO;EAE3B,IACE,gBAAgB,QAChB,OAAO,gBAAgB,YACvB,CAAC,MAAM,QAAQ,WAAW,KAC1B,gBAAgB,QAChB,OAAO,gBAAgB,YACvB,CAAC,MAAM,QAAQ,WAAW,GAC1B;GACA,cAAc,aAAa,WAAW;GACtC;EACF;EAEA,IAAI,MAAM,QAAQ,WAAW,GAAG;GAC9B,EAAE,MAAM,CAAC,CAAC,IACR,KACA,YAAY,KAAK,SACf,SAAS,QAAQ,OAAO,SAAS,WAAW,cAAc,IAAI,IAAI,IACpE,CACF;GACA;EACF;EAEA,EAAE,MAAM,CAAC,CAAC,IAAI,KAAK,WAAW;CAChC;AACF;AAEA,SAAgB,cAAc,SAAkB;CAC9C,MAAM,EAAE,UAAU;CAClB,MAAM,SAAwC,CAAC;CAE/C,IAAI,eAAe;;CAGnB,IAAI;CAEJ,SAAS,yBAAyB,IAAgB;EAChD,eAAe;EACf,GAAG;EACH,eAAe;GACb,eAAe;EACjB,CAAC;CACH;CAEA,SAAS,iBAAiB;EACxB,OAAO;CACT;CAEA,YACQ,MAAM,QACX,UAAU;EACT,kBAAkB,QAAQ,cAAc,KAAK,IAAI,KAAA;CACnD,GACA;EAAE,WAAW;EAAM,MAAM;CAAM,CACjC;CAEA,SAAS,cAAc,OAAe,MAAqB;EACzD,OAAO,SAAS;CAClB;CAEA,SAAS,gBAAgB,OAAe;EACtC,OAAO,OAAO;CAChB;CAEA,SAAS,gBAAgB;EACvB,OAAO,OAAO,MAAM,CAAC,CAAC,SAAS,SAAS,KAAK,gBAAgB,CAAC;CAChE;CAEA,eAAe,SAAS,MAAiB;EACvC,IAAI;EACJ,IAAI,MACF,YAAY,MAAM,QAAQ,IACxB,KAAK,KAAK,QAAQ,OAAO,IAAI,EAAE,SAAS,KAAK,QAAQ,QAAQ,IAAI,CAAC,CACpE;OAEA,YAAY,MAAM,QAAQ,IAAI,OAAO,OAAO,MAAM,CAAC,CAAC,KAAK,UAAU,MAAM,SAAS,CAAC,CAAC;EAEtF,OAAO,UAAU,OAAO,UAAU,KAAK;CACzC;CAEA,SAAS,QAAQ;EACf,IAAI,CAAC,MAAM,SAAS,CAAC,iBAAiB;EAEtC,+BAA+B;GAC7B,cAAc,MAAM,OAAQ,eAAgB;GAC5C,OAAO,OAAO,MAAM,CAAC,CAAC,SAAS,SAAS,KAAK,gBAAgB,CAAC;EAChE,CAAC;CACH;CAEA,OAAO;EAAE;EAAQ;EAAe;EAAU;EAAiB;EAAe;EAAO;CAAe;AAClG"}
1
+ {"version":3,"file":"use-form-fields.js","names":[],"sources":["../../../src/components/form/use-form-fields.ts"],"sourcesContent":["import { copy, o } from '@cat-kit/core'\nimport type { FormFieldItem } from '@veltra/utils'\nimport { nextTick, watch } from 'vue'\n\nimport type { FormProps } from '../../types/form'\n\ninterface Options {\n props: FormProps\n}\n\n/** 按快照逐字段写回 model,支持 undefined 与嵌套对象 */\nfunction applySnapshot(target: Record<string, any>, source: Record<string, any>) {\n for (const key of Object.keys(source)) {\n const sourceValue = source[key]\n const targetValue = target[key]\n\n if (\n sourceValue !== null &&\n typeof sourceValue === 'object' &&\n !Array.isArray(sourceValue) &&\n targetValue !== null &&\n typeof targetValue === 'object' &&\n !Array.isArray(targetValue)\n ) {\n applySnapshot(targetValue, sourceValue)\n continue\n }\n\n if (Array.isArray(sourceValue)) {\n o(target).set(key, copy(sourceValue))\n continue\n }\n\n o(target).set(key, sourceValue)\n }\n}\n\nexport function useFormFields(options: Options) {\n const { props } = options\n const fields: Record<string, FormFieldItem> = {}\n\n let willValidate = true\n\n /** model 初始快照,供 reset 恢复 */\n let initialSnapshot: Record<string, any> | undefined\n\n function runWithoutChangeValidate(fn: () => void) {\n willValidate = false\n fn()\n nextTick(() => {\n willValidate = true\n })\n }\n\n function shouldValidate() {\n return willValidate\n }\n\n watch(\n () => props.model,\n (model) => {\n initialSnapshot = model ? copy(model) : undefined\n },\n { immediate: true, deep: false }\n )\n\n function registerField(field: string, item: FormFieldItem) {\n fields[field] = item\n }\n\n function unregisterField(field: string) {\n delete fields[field]\n }\n\n function clearValidate() {\n Object.values(fields).forEach((item) => item.clearValidate?.())\n }\n\n async function validate(keys?: string[]) {\n let validList: boolean[]\n if (keys) {\n validList = await Promise.all(\n keys.map((key) => fields[key]?.validate() ?? Promise.resolve(true))\n )\n } else {\n validList = await Promise.all(Object.values(fields).map((field) => field.validate()))\n }\n return validList.every((valid) => valid)\n }\n\n function reset() {\n if (!props.model || !initialSnapshot) return\n\n runWithoutChangeValidate(() => {\n applySnapshot(props.model!, initialSnapshot!)\n Object.values(fields).forEach((item) => item.clearValidate?.())\n })\n }\n\n return { fields, registerField, validate, unregisterField, clearValidate, reset, shouldValidate }\n}\n"],"mappings":";;;;AAWA,SAAS,cAAc,QAA6B,QAA6B;CAC/E,KAAK,MAAM,OAAO,OAAO,KAAK,MAAM,GAAG;EACrC,MAAM,cAAc,OAAO;EAC3B,MAAM,cAAc,OAAO;EAE3B,IACE,gBAAgB,QAChB,OAAO,gBAAgB,YACvB,CAAC,MAAM,QAAQ,WAAW,KAC1B,gBAAgB,QAChB,OAAO,gBAAgB,YACvB,CAAC,MAAM,QAAQ,WAAW,GAC1B;GACA,cAAc,aAAa,WAAW;GACtC;EACF;EAEA,IAAI,MAAM,QAAQ,WAAW,GAAG;GAC9B,EAAE,MAAM,CAAC,CAAC,IAAI,KAAK,KAAK,WAAW,CAAC;GACpC;EACF;EAEA,EAAE,MAAM,CAAC,CAAC,IAAI,KAAK,WAAW;CAChC;AACF;AAEA,SAAgB,cAAc,SAAkB;CAC9C,MAAM,EAAE,UAAU;CAClB,MAAM,SAAwC,CAAC;CAE/C,IAAI,eAAe;;CAGnB,IAAI;CAEJ,SAAS,yBAAyB,IAAgB;EAChD,eAAe;EACf,GAAG;EACH,eAAe;GACb,eAAe;EACjB,CAAC;CACH;CAEA,SAAS,iBAAiB;EACxB,OAAO;CACT;CAEA,YACQ,MAAM,QACX,UAAU;EACT,kBAAkB,QAAQ,KAAK,KAAK,IAAI,KAAA;CAC1C,GACA;EAAE,WAAW;EAAM,MAAM;CAAM,CACjC;CAEA,SAAS,cAAc,OAAe,MAAqB;EACzD,OAAO,SAAS;CAClB;CAEA,SAAS,gBAAgB,OAAe;EACtC,OAAO,OAAO;CAChB;CAEA,SAAS,gBAAgB;EACvB,OAAO,OAAO,MAAM,CAAC,CAAC,SAAS,SAAS,KAAK,gBAAgB,CAAC;CAChE;CAEA,eAAe,SAAS,MAAiB;EACvC,IAAI;EACJ,IAAI,MACF,YAAY,MAAM,QAAQ,IACxB,KAAK,KAAK,QAAQ,OAAO,IAAI,EAAE,SAAS,KAAK,QAAQ,QAAQ,IAAI,CAAC,CACpE;OAEA,YAAY,MAAM,QAAQ,IAAI,OAAO,OAAO,MAAM,CAAC,CAAC,KAAK,UAAU,MAAM,SAAS,CAAC,CAAC;EAEtF,OAAO,UAAU,OAAO,UAAU,KAAK;CACzC;CAEA,SAAS,QAAQ;EACf,IAAI,CAAC,MAAM,SAAS,CAAC,iBAAiB;EAEtC,+BAA+B;GAC7B,cAAc,MAAM,OAAQ,eAAgB;GAC5C,OAAO,OAAO,MAAM,CAAC,CAAC,SAAS,SAAS,KAAK,gBAAgB,CAAC;EAChE,CAAC;CACH;CAEA,OAAO;EAAE;EAAQ;EAAe;EAAU;EAAiB;EAAe;EAAO;CAAe;AAClG"}
@@ -55,6 +55,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
55
55
  childrenKey: {},
56
56
  data: {},
57
57
  disabledNode: {},
58
+ checkOnClickNode: { type: Boolean },
58
59
  checkStrictly: { type: Boolean },
59
60
  slots: {},
60
61
  scrollToView: { type: Boolean }
@@ -1 +1 @@
1
- {"version":3,"file":"multi-tree-select.js","names":["$attrs"],"sources":["../../../src/components/multi-tree-select/multi-tree-select.vue"],"sourcesContent":["<template>\n <u-dropdown\n v-if=\"!readonly\"\n v-bind=\"$attrs\"\n :class=\"[cls.b, cls.m(size), bem.is('disabled', disabled), bem.is('focus', dropdownVisible)]\"\n trigger=\"click\"\n :content-class=\"[cls.e('panel'), cls.em('panel', size), contentClass]\"\n :content-style=\"contentStyle\"\n :disabled=\"disabled\"\n @mouseenter=\"hovered = true\"\n @mouseleave=\"hovered = false\"\n ref=\"dropdownRef\"\n :min-width=\"minWidth\"\n :width=\"width\"\n @update:visible=\"handleDropdownVisible\"\n >\n <template #trigger>\n <!-- 默认展示 -->\n <span :class=\"cls.e('placeholder')\" v-if=\"!filterable && !tags.length\">\n {{ placeholder }}\n </span>\n\n <!-- 选择的数据项 -->\n <div v-if=\"tags.length || filterable\" :class=\"cls.e('tags')\">\n <u-tag\n v-for=\"(tag, index) in visibleTags\"\n :key=\"tag[valueKey]\"\n :closable=\"!disabled\"\n @close=\"handleRemove(index)\"\n >\n {{ tag[labelKey] }}\n </u-tag>\n <u-tag v-if=\"hiddenCount > 0\">+{{ hiddenCount }}</u-tag>\n\n <!-- 内嵌查询输入框:承载过滤 -->\n <input\n v-if=\"filterable\"\n ref=\"inputRef\"\n :class=\"cls.e('input')\"\n v-model=\"qs\"\n :placeholder=\"tags.length ? '' : placeholder\"\n :disabled=\"disabled\"\n @click.stop=\"handleInputClick\"\n @focus=\"handleInputFocus\"\n />\n </div>\n <!-- 清空 icon -->\n <transition name=\"zoom-in\" mode=\"out-in\">\n <u-icon v-if=\"showClear\" :class=\"cls.e('clear')\" @click.stop=\"handleClear\">\n <Close />\n </u-icon>\n\n <!-- 下拉 icon -->\n <u-icon :class=\"cls.e(`arrow`)\" v-else-if=\"!readonly\">\n <ArrowDown />\n </u-icon>\n </transition>\n </template>\n <template #content>\n <div :class=\"[cls.e('content-header'), cls.m(size)]\">\n <!-- 全选 -->\n <u-checkbox\n :model-value=\"allChecked\"\n :indeterminate=\"indeterminate\"\n @update:model-value=\"handleCheckAll\"\n >\n 全选\n </u-checkbox>\n\n <u-button size=\"small\" text type=\"primary\" @click=\"handleToggleExpandAll\">\n {{ allExpanded ? '收起全部' : '展开全部' }}\n </u-button>\n </div>\n <!-- 菜单列表 -->\n <u-tree\n v-bind=\"treeProps\"\n v-model:checked=\"model\"\n @update:checked=\"handleCheck\"\n ref=\"treeRef\"\n :class=\"cls.e('content-tree')\"\n checkable\n :data=\"data\"\n :slots=\"slots\"\n scroll-to-view\n ></u-tree>\n </template>\n </u-dropdown>\n\n <div v-else-if=\"model.length\" :class=\"[cls.m(size), cls.e('readonly-tags')]\">\n <div :class=\"cls.e('tags')\">\n <u-tag v-for=\"option of tags\" :key=\"option[valueKey]\">\n {{ option[labelKey] }}\n </u-tag>\n </div>\n </div>\n\n <template v-else>\n {{ FORM_EMPTY_CONTENT }}\n </template>\n</template>\n\n<script lang=\"ts\" setup>\nimport { dfs, o } from '@cat-kit/core'\nimport { useFormFallbackProps } from '@veltra/compositions'\nimport { ArrowDown, Close } from '@veltra/icons/normal'\nimport { bem, fieldKey, FORM_EMPTY_CONTENT } from '@veltra/utils'\nimport { injectFormContext } from '@veltra/utils'\nimport { computed, nextTick, shallowRef, useTemplateRef, watch } from 'vue'\n\nimport type { MultiTreeSelectProps, MultiTreeSelectEmits, TreeExposed } from '../../types'\nimport type { DropdownExposed } from '../../types'\nimport { UButton } from '../button'\nimport { UCheckbox } from '../checkbox'\nimport { UDropdown } from '../dropdown'\nimport { UIcon } from '../icon'\nimport { UTag } from '../tag'\nimport { UTree } from '../tree'\nimport type { TreeSlotsScope } from '../tree/di'\n\ndefineOptions({ name: 'UMultiTreeSelect', inheritAttrs: false })\n\nconst cls = bem('multi-tree-select')\n\nconst props = withDefaults(defineProps<MultiTreeSelectProps>(), {\n labelKey: 'label',\n valueKey: 'value',\n placeholder: '请选择',\n expandAll: false,\n clearable: true,\n disabled: undefined,\n readonly: undefined,\n filterable: false,\n visibilityLimit: 3,\n minWidth: '280px'\n})\n\nconst labelKey = computed(() => fieldKey(props.labelKey, 'label'))\nconst valueKey = computed(() => fieldKey(props.valueKey, 'value'))\n\nconst treeProps = computed(() => {\n return o(props as Record<string, any>).omit([\n 'tips',\n 'field',\n 'placeholder',\n 'disabled',\n 'label',\n 'readonly',\n 'modelValue',\n 'contentClass',\n 'contentStyle',\n 'minWidth',\n 'width'\n ])\n})\n\nconst emit = defineEmits<MultiTreeSelectEmits>()\n\nconst slots = defineSlots<{ default?: (props: TreeSlotsScope) => any }>()\n\n/**过滤 */\nconst qs = shallowRef('')\nwatch(qs, (qs) => {\n treeRef.value?.filter(qs)\n})\n\nconst model = defineModel<(string | number)[]>({ default: () => [] })\n\nconst hovered = shallowRef(false)\n\nconst tags = shallowRef<Record<string, any>[]>([])\n\nconst { formProps } = injectFormContext()\n\nconst { size, disabled, readonly } = useFormFallbackProps([formProps ?? {}, props])\n\nconst showClear = computed(() => {\n return props.clearable && model.value?.length && hovered.value && !disabled.value\n})\n\nconst treeRef = shallowRef<TreeExposed>()\n\nconst dropdownRef = shallowRef<DropdownExposed>()\n\nlet changedByEvent = false\n\nfunction markEvent() {\n changedByEvent = true\n nextTick(() => {\n changedByEvent = false\n })\n}\n\n/**是否全选 */\nconst allChecked = computed(() => {\n return model.value?.length === treeRef.value?.forest.size\n})\n\n/**部分 */\nconst indeterminate = computed(() => {\n return model.value.length! > 0 && !allChecked.value\n})\n\n/** 全选*/\nconst handleCheckAll = (checked: boolean) => {\n treeRef.value?.checkAll(checked)\n\n dropdownRef.value?.updateDropdown()\n}\n\n/**选中 */\nconst handleCheck = (checked: (string | number)[], checkedData: Record<string, any>[]) => {\n markEvent()\n tags.value = checkedData\n emit('change', checkedData!)\n\n dropdownRef.value?.updateDropdown()\n}\n\n/**删除 */\nconst handleRemove = (index: number) => {\n markEvent()\n tags.value = tags.value.filter((_, i) => i !== index)\n model.value = model.value.filter((_, i) => i !== index)\n emit('change', tags.value)\n}\n\n/**清空 */\nconst handleClear = () => {\n markEvent()\n tags.value = []\n model.value = []\n emit('clear')\n}\n\nconst keyDicts = shallowRef(new Map<string | number, Record<string, any>>())\n\nwatch(\n () => props.data,\n (data) => {\n if (!data?.length) {\n keyDicts.value = new Map()\n } else {\n const newDict = new Map()\n data.forEach((item) => {\n dfs(\n item,\n (v) => {\n newDict.set(v[valueKey.value], v)\n },\n props.childrenKey\n )\n })\n keyDicts.value = newDict\n }\n },\n { immediate: true }\n)\n\nwatch(\n [keyDicts, model],\n ([keyDicts, model]) => {\n if (changedByEvent) return\n\n if (!keyDicts.size || !model?.length) {\n tags.value = []\n return\n }\n\n tags.value = model.filter((v) => keyDicts.has(v)).map((v) => keyDicts.get(v)!)\n },\n { immediate: true }\n)\n\nconst allExpanded = shallowRef(props.expandAll)\nfunction handleToggleExpandAll() {\n allExpanded.value = !allExpanded.value\n allExpanded.value ? treeRef.value?.expandAll() : treeRef.value?.collapseAll()\n}\n\nwatch(treeRef, (treeRef) => {\n if (!treeRef) {\n allExpanded.value = props.expandAll\n }\n})\n\nconst limit = () => {\n let { visibilityLimit } = props\n\n if (visibilityLimit < 0) {\n visibilityLimit = 0\n }\n if (disabled.value || readonly.value) {\n visibilityLimit = model.value?.length ?? 0\n }\n return visibilityLimit\n}\n\nconst visibleTags = computed(() => {\n if (tags.value.length > limit()) {\n return tags.value.slice(0, limit())\n }\n return tags.value\n})\n\nconst hiddenCount = computed(() => {\n if (tags.value.length > limit()) {\n return tags.value.length - limit()\n }\n return 0\n})\n\nconst dropdownVisible = shallowRef(false)\n\nconst inputRef = useTemplateRef<HTMLInputElement>('inputRef')\n\nconst handleDropdownVisible = (visible: boolean) => {\n dropdownVisible.value = visible\n if (!visible) {\n qs.value = ''\n }\n}\n\n/**\n * 拦截输入区域的点击(@click.stop):阻止 dropdown 的 trigger 开合切换,\n * 保持面板展开以不中断输入。\n */\nconst handleInputClick = () => {\n if (!dropdownVisible.value) dropdownRef.value?.open()\n}\n\nconst handleInputFocus = () => {\n if (!dropdownVisible.value) dropdownRef.value?.open()\n}\n</script>\n"],"mappings":"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"}
1
+ {"version":3,"file":"multi-tree-select.js","names":["$attrs"],"sources":["../../../src/components/multi-tree-select/multi-tree-select.vue"],"sourcesContent":["<template>\n <u-dropdown\n v-if=\"!readonly\"\n v-bind=\"$attrs\"\n :class=\"[cls.b, cls.m(size), bem.is('disabled', disabled), bem.is('focus', dropdownVisible)]\"\n trigger=\"click\"\n :content-class=\"[cls.e('panel'), cls.em('panel', size), contentClass]\"\n :content-style=\"contentStyle\"\n :disabled=\"disabled\"\n @mouseenter=\"hovered = true\"\n @mouseleave=\"hovered = false\"\n ref=\"dropdownRef\"\n :min-width=\"minWidth\"\n :width=\"width\"\n @update:visible=\"handleDropdownVisible\"\n >\n <template #trigger>\n <!-- 默认展示 -->\n <span :class=\"cls.e('placeholder')\" v-if=\"!filterable && !tags.length\">\n {{ placeholder }}\n </span>\n\n <!-- 选择的数据项 -->\n <div v-if=\"tags.length || filterable\" :class=\"cls.e('tags')\">\n <u-tag\n v-for=\"(tag, index) in visibleTags\"\n :key=\"tag[valueKey]\"\n :closable=\"!disabled\"\n @close=\"handleRemove(index)\"\n >\n {{ tag[labelKey] }}\n </u-tag>\n <u-tag v-if=\"hiddenCount > 0\">+{{ hiddenCount }}</u-tag>\n\n <!-- 内嵌查询输入框:承载过滤 -->\n <input\n v-if=\"filterable\"\n ref=\"inputRef\"\n :class=\"cls.e('input')\"\n v-model=\"qs\"\n :placeholder=\"tags.length ? '' : placeholder\"\n :disabled=\"disabled\"\n @click.stop=\"handleInputClick\"\n @focus=\"handleInputFocus\"\n />\n </div>\n <!-- 清空 icon -->\n <transition name=\"zoom-in\" mode=\"out-in\">\n <u-icon v-if=\"showClear\" :class=\"cls.e('clear')\" @click.stop=\"handleClear\">\n <Close />\n </u-icon>\n\n <!-- 下拉 icon -->\n <u-icon :class=\"cls.e(`arrow`)\" v-else-if=\"!readonly\">\n <ArrowDown />\n </u-icon>\n </transition>\n </template>\n <template #content>\n <div :class=\"[cls.e('content-header'), cls.m(size)]\">\n <!-- 全选 -->\n <u-checkbox\n :model-value=\"allChecked\"\n :indeterminate=\"indeterminate\"\n @update:model-value=\"handleCheckAll\"\n >\n 全选\n </u-checkbox>\n\n <u-button size=\"small\" text type=\"primary\" @click=\"handleToggleExpandAll\">\n {{ allExpanded ? '收起全部' : '展开全部' }}\n </u-button>\n </div>\n <!-- 菜单列表 -->\n <u-tree\n v-bind=\"treeProps\"\n v-model:checked=\"model\"\n @update:checked=\"handleCheck\"\n ref=\"treeRef\"\n :class=\"cls.e('content-tree')\"\n checkable\n :data=\"data\"\n :slots=\"slots\"\n scroll-to-view\n ></u-tree>\n </template>\n </u-dropdown>\n\n <div v-else-if=\"model.length\" :class=\"[cls.m(size), cls.e('readonly-tags')]\">\n <div :class=\"cls.e('tags')\">\n <u-tag v-for=\"option of tags\" :key=\"option[valueKey]\">\n {{ option[labelKey] }}\n </u-tag>\n </div>\n </div>\n\n <template v-else>\n {{ FORM_EMPTY_CONTENT }}\n </template>\n</template>\n\n<script lang=\"ts\" setup>\nimport { dfs, o } from '@cat-kit/core'\nimport { useFormFallbackProps } from '@veltra/compositions'\nimport { ArrowDown, Close } from '@veltra/icons/normal'\nimport { bem, fieldKey, FORM_EMPTY_CONTENT } from '@veltra/utils'\nimport { injectFormContext } from '@veltra/utils'\nimport { computed, nextTick, shallowRef, useTemplateRef, watch } from 'vue'\n\nimport type { MultiTreeSelectProps, MultiTreeSelectEmits, TreeExposed } from '../../types'\nimport type { DropdownExposed } from '../../types'\nimport { UButton } from '../button'\nimport { UCheckbox } from '../checkbox'\nimport { UDropdown } from '../dropdown'\nimport { UIcon } from '../icon'\nimport { UTag } from '../tag'\nimport { UTree } from '../tree'\nimport type { TreeSlotsScope } from '../tree/di'\n\ndefineOptions({ name: 'UMultiTreeSelect', inheritAttrs: false })\n\nconst cls = bem('multi-tree-select')\n\nconst props = withDefaults(defineProps<MultiTreeSelectProps>(), {\n labelKey: 'label',\n valueKey: 'value',\n placeholder: '请选择',\n expandAll: false,\n clearable: true,\n disabled: undefined,\n readonly: undefined,\n filterable: false,\n visibilityLimit: 3,\n minWidth: '280px'\n})\n\nconst labelKey = computed(() => fieldKey(props.labelKey, 'label'))\nconst valueKey = computed(() => fieldKey(props.valueKey, 'value'))\n\nconst treeProps = computed(() => {\n return o(props as Record<string, any>).omit([\n 'tips',\n 'field',\n 'placeholder',\n 'disabled',\n 'label',\n 'readonly',\n 'modelValue',\n 'contentClass',\n 'contentStyle',\n 'minWidth',\n 'width'\n ])\n})\n\nconst emit = defineEmits<MultiTreeSelectEmits>()\n\nconst slots = defineSlots<{ default?: (props: TreeSlotsScope) => any }>()\n\n/**过滤 */\nconst qs = shallowRef('')\nwatch(qs, (qs) => {\n treeRef.value?.filter(qs)\n})\n\nconst model = defineModel<(string | number)[]>({ default: () => [] })\n\nconst hovered = shallowRef(false)\n\nconst tags = shallowRef<Record<string, any>[]>([])\n\nconst { formProps } = injectFormContext()\n\nconst { size, disabled, readonly } = useFormFallbackProps([formProps ?? {}, props])\n\nconst showClear = computed(() => {\n return props.clearable && model.value?.length && hovered.value && !disabled.value\n})\n\nconst treeRef = shallowRef<TreeExposed>()\n\nconst dropdownRef = shallowRef<DropdownExposed>()\n\nlet changedByEvent = false\n\nfunction markEvent() {\n changedByEvent = true\n nextTick(() => {\n changedByEvent = false\n })\n}\n\n/**是否全选 */\nconst allChecked = computed(() => {\n return model.value?.length === treeRef.value?.forest.size\n})\n\n/**部分 */\nconst indeterminate = computed(() => {\n return model.value.length! > 0 && !allChecked.value\n})\n\n/** 全选*/\nconst handleCheckAll = (checked: boolean) => {\n treeRef.value?.checkAll(checked)\n\n dropdownRef.value?.updateDropdown()\n}\n\n/**选中 */\nconst handleCheck = (checked: (string | number)[], checkedData: Record<string, any>[]) => {\n markEvent()\n tags.value = checkedData\n emit('change', checkedData!)\n\n dropdownRef.value?.updateDropdown()\n}\n\n/**删除 */\nconst handleRemove = (index: number) => {\n markEvent()\n tags.value = tags.value.filter((_, i) => i !== index)\n model.value = model.value.filter((_, i) => i !== index)\n emit('change', tags.value)\n}\n\n/**清空 */\nconst handleClear = () => {\n markEvent()\n tags.value = []\n model.value = []\n emit('clear')\n}\n\nconst keyDicts = shallowRef(new Map<string | number, Record<string, any>>())\n\nwatch(\n () => props.data,\n (data) => {\n if (!data?.length) {\n keyDicts.value = new Map()\n } else {\n const newDict = new Map()\n data.forEach((item) => {\n dfs(\n item,\n (v) => {\n newDict.set(v[valueKey.value], v)\n },\n props.childrenKey\n )\n })\n keyDicts.value = newDict\n }\n },\n { immediate: true }\n)\n\nwatch(\n [keyDicts, model],\n ([keyDicts, model]) => {\n if (changedByEvent) return\n\n if (!keyDicts.size || !model?.length) {\n tags.value = []\n return\n }\n\n tags.value = model.filter((v) => keyDicts.has(v)).map((v) => keyDicts.get(v)!)\n },\n { immediate: true }\n)\n\nconst allExpanded = shallowRef(props.expandAll)\nfunction handleToggleExpandAll() {\n allExpanded.value = !allExpanded.value\n allExpanded.value ? treeRef.value?.expandAll() : treeRef.value?.collapseAll()\n}\n\nwatch(treeRef, (treeRef) => {\n if (!treeRef) {\n allExpanded.value = props.expandAll\n }\n})\n\nconst limit = () => {\n let { visibilityLimit } = props\n\n if (visibilityLimit < 0) {\n visibilityLimit = 0\n }\n if (disabled.value || readonly.value) {\n visibilityLimit = model.value?.length ?? 0\n }\n return visibilityLimit\n}\n\nconst visibleTags = computed(() => {\n if (tags.value.length > limit()) {\n return tags.value.slice(0, limit())\n }\n return tags.value\n})\n\nconst hiddenCount = computed(() => {\n if (tags.value.length > limit()) {\n return tags.value.length - limit()\n }\n return 0\n})\n\nconst dropdownVisible = shallowRef(false)\n\nconst inputRef = useTemplateRef<HTMLInputElement>('inputRef')\n\nconst handleDropdownVisible = (visible: boolean) => {\n dropdownVisible.value = visible\n if (!visible) {\n qs.value = ''\n }\n}\n\n/**\n * 拦截输入区域的点击(@click.stop):阻止 dropdown 的 trigger 开合切换,\n * 保持面板展开以不中断输入。\n */\nconst handleInputClick = () => {\n if (!dropdownVisible.value) dropdownRef.value?.open()\n}\n\nconst handleInputFocus = () => {\n if (!dropdownVisible.value) dropdownRef.value?.open()\n}\n</script>\n"],"mappings":"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"}
@@ -69,7 +69,7 @@ function useCheck(options) {
69
69
  () => props.rowKey,
70
70
  () => props.checkable,
71
71
  rows
72
- ], ([checked, rowKey, checkable, rows], [_, __, ___, oRows]) => {
72
+ ], ([checked, rowKey, checkable, rows], [, , , oRows]) => {
73
73
  if (changedByEvent || !checkable || !rowKey) return;
74
74
  changedByModel = true;
75
75
  rows !== oRows && setDicts();
@@ -92,7 +92,7 @@ function useCheck(options) {
92
92
  () => props.rowKey,
93
93
  () => props.selectable,
94
94
  rows
95
- ], ([selected, rowKey, selectable, rows], [_, __, ___, oRows]) => {
95
+ ], ([selected, rowKey, selectable, rows], [, , , oRows]) => {
96
96
  if (changedByEvent || !selectable || !rowKey) return;
97
97
  changedByModel = true;
98
98
  rows !== oRows && setDicts();
@@ -1 +1 @@
1
- {"version":3,"file":"use-check.js","names":["UCheckbox"],"sources":["../../../src/components/table/use-check.ts"],"sourcesContent":["import { dfs, o, type Forest } from '@cat-kit/core'\nimport type { BEM } from '@veltra/utils'\nimport {\n computed,\n createTextVNode,\n createVNode,\n nextTick,\n shallowRef,\n toRaw,\n triggerRef,\n watch,\n type ComputedRef,\n type ShallowRef\n} from 'vue'\n\nimport type { TableRow, TableColumn, TableEmits, TableProps, ComponentSize } from '../../types'\nimport { UCheckbox } from '../checkbox'\n\ninterface Options {\n rows: ShallowRef<TableRow[] | undefined>\n rowForest: ShallowRef<Forest<Record<string, unknown>, any> | undefined>\n props: TableProps\n emit: TableEmits<any>\n size: ComputedRef<ComponentSize>\n cls: BEM<'table'>\n}\n\ninterface UseCheckReturned {\n checkedRows: ShallowRef<Set<TableRow>>\n clearChecked: () => void\n clearSelected: () => void\n createCheckColumn: () => TableColumn\n createSelectColumn: () => TableColumn\n}\n\nexport function useCheck(options: Options): UseCheckReturned {\n const { rows, rowForest, props, emit, size, cls } = options\n\n const checkedRows = shallowRef(new Set<TableRow>())\n const selectedRow = shallowRef<TableRow>()\n\n /** 触发checkedRows的更新 */\n function triggerCheckedRows() {\n triggerRef(checkedRows)\n }\n\n function clearChecked() {\n checkedRows.value.forEach((row) => {\n row.checked = false\n })\n checkedRows.value.clear()\n triggerCheckedRows()\n }\n\n function clearSelected() {\n if (selectedRow.value) {\n selectedRow.value.checked = false\n selectedRow.value = undefined\n }\n }\n\n watch([() => props.checkable, () => props.selectable, () => rows.value], () => {\n clearChecked()\n clearSelected()\n })\n\n watch(selectedRow, (selectedRow) => {\n if (changedByModel) return\n changedByEvent = true\n emit('update:selected', selectedRow?.data ? toRaw(selectedRow.data) : undefined)\n nextTick(() => {\n changedByEvent = false\n })\n })\n\n let changedByEvent = false\n let changedByModel = false\n watch(checkedRows, (checkedRows) => {\n if (changedByModel) return\n changedByEvent = true\n emit(\n 'update:checked',\n Array.from(checkedRows).map((row) => toRaw(row.data))\n )\n nextTick(() => {\n changedByEvent = false\n })\n })\n\n let dicts: Map<string | number, TableRow> | undefined = undefined\n\n // 设置uid -> row 字典,以便于数据重复使用\n function setDicts() {\n if (dicts || !rows.value || !props.rowKey) return\n\n let mapEntries: [string | number, TableRow][] = []\n let i = 0\n while (i < rows.value.length) {\n const row = rows.value[i]!\n\n mapEntries.push([row.uid, row])\n i++\n }\n dicts = new Map(mapEntries)\n }\n\n watch(rows, () => {\n dicts = undefined\n })\n\n watch(\n [() => props.checked, () => props.rowKey, () => props.checkable, rows],\n ([checked, rowKey, checkable, rows], [_, __, ___, oRows]) => {\n if (changedByEvent || !checkable || !rowKey) return\n\n changedByModel = true\n\n // 如果没有字典,先建立字典\n rows !== oRows && setDicts()\n\n clearChecked()\n\n checked?.forEach((item) => {\n const uid = o(item).get(rowKey)\n if (uid === undefined || uid === null) return\n const row = dicts?.get(uid as string | number)\n if (!row) return\n\n row.checked = true\n checkedRows.value.add(row)\n })\n triggerCheckedRows()\n\n nextTick(() => {\n changedByModel = false\n })\n },\n { immediate: true }\n )\n\n watch(\n [() => props.selected, () => props.rowKey, () => props.selectable, rows],\n ([selected, rowKey, selectable, rows], [_, __, ___, oRows]) => {\n if (changedByEvent || !selectable || !rowKey) return\n\n changedByModel = true\n\n // 如果没有字典,先建立字典(懒建立)\n rows !== oRows && setDicts()\n\n if (selected) {\n const uid = o(selected).get(rowKey)\n const row =\n uid === undefined || uid === null ? undefined : dicts?.get(uid as string | number)\n if (row) {\n row.checked = true\n selectedRow.value = row\n }\n } else {\n clearSelected()\n }\n\n nextTick(() => {\n changedByModel = false\n })\n },\n { immediate: true }\n )\n\n const allChecked = computed(() => {\n const rowSize = props.tree ? rowForest.value?.size : rows.value?.length\n return !!rowSize && rowSize === checkedRows.value.size\n })\n\n function handleCheckAllTree(check: boolean) {\n if (check) {\n rowForest.value?.dfs((row) => {\n row.checked = true\n checkedRows.value.add(row)\n })\n } else {\n rowForest.value?.dfs((row) => {\n row.checked = false\n })\n checkedRows.value.clear()\n }\n triggerCheckedRows()\n }\n\n function handleCheckAllRows(check: boolean) {\n if (check) {\n rows.value?.forEach((row) => {\n row.checked = true\n checkedRows.value.add(row)\n })\n } else {\n rows.value?.forEach((row) => {\n row.checked = false\n })\n checkedRows.value.clear()\n }\n triggerCheckedRows()\n }\n\n function handleCheckAll(check: boolean) {\n if (props.tree) {\n handleCheckAllTree(check as boolean)\n } else {\n handleCheckAllRows(check as boolean)\n }\n }\n\n function handleCheckRow(row: TableRow, check: boolean) {\n const cb = check\n ? (row: TableRow) => checkedRows.value.add(row)\n : (row: TableRow) => checkedRows.value.delete(row)\n\n const childrenKey = typeof props.tree === 'string' ? props.tree : 'children'\n dfs(\n row as unknown as Record<string, unknown>,\n (node) => {\n const r = node as unknown as TableRow\n r.checked = check\n cb(r)\n },\n childrenKey\n )\n\n triggerCheckedRows()\n }\n\n const getCheckboxColumnWidth = () => {\n return size.value === 'large' ? 80 : 60\n }\n\n const checkboxClass = cls.e('checkbox')\n const checkboxClick = (e: Event) => e.stopPropagation()\n\n function createCheckColumn(): TableColumn {\n const width = getCheckboxColumnWidth()\n return {\n key: '__is_check_column__',\n name: '',\n width,\n minWidth: width,\n align: 'center',\n fixed: 'left',\n resizable: false,\n nameRender() {\n const checkboxNode = createVNode(UCheckbox, {\n modelValue: allChecked.value,\n 'onUpdate:modelValue': handleCheckAll\n })\n if (!props.tree) {\n return checkboxNode\n }\n\n // const expandNode = createVNode('i', {\n // text: true,\n // class: cls.e('expand-space')\n // })\n return [checkboxNode]\n },\n render(ctx) {\n const { row } = ctx\n\n // @ts-ignore\n return createVNode(UCheckbox, {\n class: checkboxClass,\n modelValue: row.checked,\n 'onUpdate:modelValue': (val: boolean) => {\n handleCheckRow(row, val)\n },\n onClick: checkboxClick\n })\n }\n }\n }\n\n function handleSelect(row: TableRow, check: boolean) {\n row.checked = check\n if (check) {\n if (selectedRow.value) {\n selectedRow.value.checked = false\n }\n selectedRow.value = row\n } else {\n selectedRow.value = undefined\n }\n }\n\n function createSelectColumn(): TableColumn {\n const width = getCheckboxColumnWidth()\n return {\n key: '__is_select_column__',\n name: '单选',\n minWidth: width,\n resizable: false,\n width,\n align: 'center',\n fixed: 'left',\n nameRender(_ctx) {\n if (!props.tree) {\n return '单选'\n }\n\n // const expandNode = createVNode('i', {\n // text: true,\n // class: cls.e('expand-space')\n // })\n return [createTextVNode('单选')]\n },\n\n render({ row }) {\n // @ts-ignore\n return createVNode(UCheckbox, {\n class: checkboxClass,\n modelValue: row.checked,\n 'onUpdate:modelValue': (val: boolean) => {\n handleSelect(row, val)\n },\n onClick: checkboxClick\n })\n }\n }\n }\n\n return { checkedRows, createCheckColumn, createSelectColumn, clearChecked, clearSelected }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"use-check.js","names":["UCheckbox"],"sources":["../../../src/components/table/use-check.ts"],"sourcesContent":["import { dfs, o, type Forest } from '@cat-kit/core'\nimport type { BEM } from '@veltra/utils'\nimport {\n computed,\n createTextVNode,\n createVNode,\n nextTick,\n shallowRef,\n toRaw,\n triggerRef,\n watch,\n type ComputedRef,\n type ShallowRef\n} from 'vue'\n\nimport type { TableRow, TableColumn, TableEmits, TableProps, ComponentSize } from '../../types'\nimport { UCheckbox } from '../checkbox'\n\ninterface Options {\n rows: ShallowRef<TableRow[] | undefined>\n rowForest: ShallowRef<Forest<Record<string, unknown>, any> | undefined>\n props: TableProps\n emit: TableEmits<any>\n size: ComputedRef<ComponentSize>\n cls: BEM<'table'>\n}\n\ninterface UseCheckReturned {\n checkedRows: ShallowRef<Set<TableRow>>\n clearChecked: () => void\n clearSelected: () => void\n createCheckColumn: () => TableColumn\n createSelectColumn: () => TableColumn\n}\n\nexport function useCheck(options: Options): UseCheckReturned {\n const { rows, rowForest, props, emit, size, cls } = options\n\n const checkedRows = shallowRef(new Set<TableRow>())\n const selectedRow = shallowRef<TableRow>()\n\n /** 触发checkedRows的更新 */\n function triggerCheckedRows() {\n triggerRef(checkedRows)\n }\n\n function clearChecked() {\n checkedRows.value.forEach((row) => {\n row.checked = false\n })\n checkedRows.value.clear()\n triggerCheckedRows()\n }\n\n function clearSelected() {\n if (selectedRow.value) {\n selectedRow.value.checked = false\n selectedRow.value = undefined\n }\n }\n\n watch([() => props.checkable, () => props.selectable, () => rows.value], () => {\n clearChecked()\n clearSelected()\n })\n\n watch(selectedRow, (selectedRow) => {\n if (changedByModel) return\n changedByEvent = true\n emit('update:selected', selectedRow?.data ? toRaw(selectedRow.data) : undefined)\n nextTick(() => {\n changedByEvent = false\n })\n })\n\n let changedByEvent = false\n let changedByModel = false\n watch(checkedRows, (checkedRows) => {\n if (changedByModel) return\n changedByEvent = true\n emit(\n 'update:checked',\n Array.from(checkedRows).map((row) => toRaw(row.data))\n )\n nextTick(() => {\n changedByEvent = false\n })\n })\n\n let dicts: Map<string | number, TableRow> | undefined = undefined\n\n // 设置uid -> row 字典,以便于数据重复使用\n function setDicts() {\n if (dicts || !rows.value || !props.rowKey) return\n\n let mapEntries: [string | number, TableRow][] = []\n let i = 0\n while (i < rows.value.length) {\n const row = rows.value[i]!\n\n mapEntries.push([row.uid, row])\n i++\n }\n dicts = new Map(mapEntries)\n }\n\n watch(rows, () => {\n dicts = undefined\n })\n\n watch(\n [() => props.checked, () => props.rowKey, () => props.checkable, rows],\n ([checked, rowKey, checkable, rows], [, , , oRows]) => {\n if (changedByEvent || !checkable || !rowKey) return\n\n changedByModel = true\n\n // 如果没有字典,先建立字典\n rows !== oRows && setDicts()\n\n clearChecked()\n\n checked?.forEach((item) => {\n const uid = o(item).get(rowKey)\n if (uid === undefined || uid === null) return\n const row = dicts?.get(uid as string | number)\n if (!row) return\n\n row.checked = true\n checkedRows.value.add(row)\n })\n triggerCheckedRows()\n\n nextTick(() => {\n changedByModel = false\n })\n },\n { immediate: true }\n )\n\n watch(\n [() => props.selected, () => props.rowKey, () => props.selectable, rows],\n ([selected, rowKey, selectable, rows], [, , , oRows]) => {\n if (changedByEvent || !selectable || !rowKey) return\n\n changedByModel = true\n\n // 如果没有字典,先建立字典(懒建立)\n rows !== oRows && setDicts()\n\n if (selected) {\n const uid = o(selected).get(rowKey)\n const row =\n uid === undefined || uid === null ? undefined : dicts?.get(uid as string | number)\n if (row) {\n row.checked = true\n selectedRow.value = row\n }\n } else {\n clearSelected()\n }\n\n nextTick(() => {\n changedByModel = false\n })\n },\n { immediate: true }\n )\n\n const allChecked = computed(() => {\n const rowSize = props.tree ? rowForest.value?.size : rows.value?.length\n return !!rowSize && rowSize === checkedRows.value.size\n })\n\n function handleCheckAllTree(check: boolean) {\n if (check) {\n rowForest.value?.dfs((row) => {\n row.checked = true\n checkedRows.value.add(row)\n })\n } else {\n rowForest.value?.dfs((row) => {\n row.checked = false\n })\n checkedRows.value.clear()\n }\n triggerCheckedRows()\n }\n\n function handleCheckAllRows(check: boolean) {\n if (check) {\n rows.value?.forEach((row) => {\n row.checked = true\n checkedRows.value.add(row)\n })\n } else {\n rows.value?.forEach((row) => {\n row.checked = false\n })\n checkedRows.value.clear()\n }\n triggerCheckedRows()\n }\n\n function handleCheckAll(check: boolean) {\n if (props.tree) {\n handleCheckAllTree(check as boolean)\n } else {\n handleCheckAllRows(check as boolean)\n }\n }\n\n function handleCheckRow(row: TableRow, check: boolean) {\n const cb = check\n ? (row: TableRow) => checkedRows.value.add(row)\n : (row: TableRow) => checkedRows.value.delete(row)\n\n const childrenKey = typeof props.tree === 'string' ? props.tree : 'children'\n dfs(\n row as unknown as Record<string, unknown>,\n (node) => {\n const r = node as unknown as TableRow\n r.checked = check\n cb(r)\n },\n childrenKey\n )\n\n triggerCheckedRows()\n }\n\n const getCheckboxColumnWidth = () => {\n return size.value === 'large' ? 80 : 60\n }\n\n const checkboxClass = cls.e('checkbox')\n const checkboxClick = (e: Event) => e.stopPropagation()\n\n function createCheckColumn(): TableColumn {\n const width = getCheckboxColumnWidth()\n return {\n key: '__is_check_column__',\n name: '',\n width,\n minWidth: width,\n align: 'center',\n fixed: 'left',\n resizable: false,\n nameRender() {\n const checkboxNode = createVNode(UCheckbox, {\n modelValue: allChecked.value,\n 'onUpdate:modelValue': handleCheckAll\n })\n if (!props.tree) {\n return checkboxNode\n }\n\n // const expandNode = createVNode('i', {\n // text: true,\n // class: cls.e('expand-space')\n // })\n return [checkboxNode]\n },\n render(ctx) {\n const { row } = ctx\n\n // @ts-ignore\n return createVNode(UCheckbox, {\n class: checkboxClass,\n modelValue: row.checked,\n 'onUpdate:modelValue': (val: boolean) => {\n handleCheckRow(row, val)\n },\n onClick: checkboxClick\n })\n }\n }\n }\n\n function handleSelect(row: TableRow, check: boolean) {\n row.checked = check\n if (check) {\n if (selectedRow.value) {\n selectedRow.value.checked = false\n }\n selectedRow.value = row\n } else {\n selectedRow.value = undefined\n }\n }\n\n function createSelectColumn(): TableColumn {\n const width = getCheckboxColumnWidth()\n return {\n key: '__is_select_column__',\n name: '单选',\n minWidth: width,\n resizable: false,\n width,\n align: 'center',\n fixed: 'left',\n nameRender(_ctx) {\n if (!props.tree) {\n return '单选'\n }\n\n // const expandNode = createVNode('i', {\n // text: true,\n // class: cls.e('expand-space')\n // })\n return [createTextVNode('单选')]\n },\n\n render({ row }) {\n // @ts-ignore\n return createVNode(UCheckbox, {\n class: checkboxClass,\n modelValue: row.checked,\n 'onUpdate:modelValue': (val: boolean) => {\n handleSelect(row, val)\n },\n onClick: checkboxClick\n })\n }\n }\n }\n\n return { checkedRows, createCheckColumn, createSelectColumn, clearChecked, clearSelected }\n}\n"],"mappings":"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"}
@@ -36,7 +36,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
36
36
  treeEmit("node-click", node);
37
37
  treeProps.selectable && handleSelect(node);
38
38
  treeProps.expandOnClickNode && toggleExpand();
39
- treeProps.checkable && !node.disabled && !treeProps.expandOnClickNode && toggleCheck(node, !node.checked, e.ctrlKey);
39
+ treeProps.checkable && treeProps.checkOnClickNode && !node.disabled && !treeProps.expandOnClickNode && toggleCheck(node, !node.checked, e.ctrlKey);
40
40
  }
41
41
  return (_ctx, _cache) => {
42
42
  return openBlock(), createElementBlock("div", {
@@ -89,7 +89,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
89
89
  ])) : createCommentVNode("v-if", true), createVNode(unref(NodeRender), { content: unref(getTreeSlotsNode)({
90
90
  node: __props.node,
91
91
  data: __props.node.data
92
- }) }, null, 8, ["content"])], 34)), [[unref(vRipple), (unref(treeProps).checkable || unref(treeProps).selectable) && !__props.node.disabled ? unref(cls).e("ripple") : false]])
92
+ }) }, null, 8, ["content"])], 34)), [[unref(vRipple), (unref(treeProps).selectable || unref(treeProps).checkable && unref(treeProps).checkOnClickNode) && !__props.node.disabled ? unref(cls).e("ripple") : false]])
93
93
  ], 2);
94
94
  };
95
95
  }
@@ -1 +1 @@
1
- {"version":3,"file":"tree-node.js","names":[],"sources":["../../../src/components/tree/tree-node.vue"],"sourcesContent":["<template>\n <div\n :class=\"[cls.e('node'), bem.is('expanded', node.expanded), bem.is('disabled', node.disabled)]\"\n :ref=\"measureRef\"\n >\n <span v-for=\"i in node.depth\" :key=\"i\" :class=\"cls.e('indent')\" aria-hidden=\"true\"></span>\n\n <u-icon v-if=\"!node.isLeaf\" :class=\"cls.e('expand-icon')\" @click.stop=\"toggleExpand\">\n <ArrowRight />\n </u-icon>\n <u-icon v-else :class=\"cls.e('leaf-icon')\" aria-hidden=\"true\">\n <Dot />\n </u-icon>\n\n <div\n :class=\"cls.e('node-content')\"\n @click=\"handleClick\"\n @contextmenu=\"treeEmit('node-contextmenu', $event, node)\"\n v-ripple=\"\n (treeProps.checkable || treeProps.selectable) && !node.disabled ? cls.e('ripple') : false\n \"\n >\n <u-checkbox\n v-if=\"treeProps.checkable\"\n :class=\"cls.e('checkbox')\"\n :model-value=\"node.checked\"\n :indeterminate=\"node.indeterminate\"\n :disabled=\"node.disabled\"\n @change=\"handleChange\"\n @click.stop\n />\n\n <u-node-render :content=\"getTreeSlotsNode({ node, data: node.data })\" />\n </div>\n </div>\n</template>\n\n<script lang=\"ts\" setup>\nimport { vRipple } from '@veltra/directives'\nimport { ArrowRight, Dot } from '@veltra/icons/normal'\nimport { bem } from '@veltra/utils'\nimport { inject } from 'vue'\n\nimport type { TreeNodeProps } from '../../types'\nimport UCheckbox from '../checkbox/checkbox.vue'\nimport { UIcon } from '../icon'\nimport { UNodeRender } from '../node-render'\nimport { TreeDIKey } from './di'\n\ndefineOptions({ name: 'UTreeNode' })\n\nconst props = defineProps<TreeNodeProps>()\n\nconst { treeProps, treeEmit, cls, getTreeSlotsNode, getFlattedNodes, toggleCheck, handleSelect } =\n inject(TreeDIKey)!\n\nfunction measureRef(el: unknown) {\n if (typeof props.index !== 'number' || !props.measureElement) return\n props.measureElement(props.index, el as Element | null)\n}\n\nfunction toggleExpand() {\n const { node } = props\n node.expanded = !node.expanded\n getFlattedNodes()\n\n treeEmit('expand', node)\n}\n\nfunction handleChange(checked: boolean, e: MouseEvent) {\n toggleCheck(props.node, checked, e.ctrlKey)\n}\n\nfunction handleClick(e: MouseEvent) {\n const { node } = props\n treeEmit('node-click', node)\n\n treeProps.selectable && handleSelect(node)\n treeProps.expandOnClickNode && toggleExpand()\n treeProps.checkable &&\n !node.disabled &&\n !treeProps.expandOnClickNode &&\n toggleCheck(node, !node.checked, e.ctrlKey)\n}\n</script>\n"],"mappings":"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"}
1
+ {"version":3,"file":"tree-node.js","names":[],"sources":["../../../src/components/tree/tree-node.vue"],"sourcesContent":["<template>\n <div\n :class=\"[cls.e('node'), bem.is('expanded', node.expanded), bem.is('disabled', node.disabled)]\"\n :ref=\"measureRef\"\n >\n <span v-for=\"i in node.depth\" :key=\"i\" :class=\"cls.e('indent')\" aria-hidden=\"true\"></span>\n\n <u-icon v-if=\"!node.isLeaf\" :class=\"cls.e('expand-icon')\" @click.stop=\"toggleExpand\">\n <ArrowRight />\n </u-icon>\n <u-icon v-else :class=\"cls.e('leaf-icon')\" aria-hidden=\"true\">\n <Dot />\n </u-icon>\n\n <div\n :class=\"cls.e('node-content')\"\n @click=\"handleClick\"\n @contextmenu=\"treeEmit('node-contextmenu', $event, node)\"\n v-ripple=\"\n (treeProps.selectable || (treeProps.checkable && treeProps.checkOnClickNode)) &&\n !node.disabled\n ? cls.e('ripple')\n : false\n \"\n >\n <u-checkbox\n v-if=\"treeProps.checkable\"\n :class=\"cls.e('checkbox')\"\n :model-value=\"node.checked\"\n :indeterminate=\"node.indeterminate\"\n :disabled=\"node.disabled\"\n @change=\"handleChange\"\n @click.stop\n />\n\n <u-node-render :content=\"getTreeSlotsNode({ node, data: node.data })\" />\n </div>\n </div>\n</template>\n\n<script lang=\"ts\" setup>\nimport { vRipple } from '@veltra/directives'\nimport { ArrowRight, Dot } from '@veltra/icons/normal'\nimport { bem } from '@veltra/utils'\nimport { inject } from 'vue'\n\nimport type { TreeNodeProps } from '../../types'\nimport UCheckbox from '../checkbox/checkbox.vue'\nimport { UIcon } from '../icon'\nimport { UNodeRender } from '../node-render'\nimport { TreeDIKey } from './di'\n\ndefineOptions({ name: 'UTreeNode' })\n\nconst props = defineProps<TreeNodeProps>()\n\nconst { treeProps, treeEmit, cls, getTreeSlotsNode, getFlattedNodes, toggleCheck, handleSelect } =\n inject(TreeDIKey)!\n\nfunction measureRef(el: unknown) {\n if (typeof props.index !== 'number' || !props.measureElement) return\n props.measureElement(props.index, el as Element | null)\n}\n\nfunction toggleExpand() {\n const { node } = props\n node.expanded = !node.expanded\n getFlattedNodes()\n\n treeEmit('expand', node)\n}\n\nfunction handleChange(checked: boolean, e: MouseEvent) {\n toggleCheck(props.node, checked, e.ctrlKey)\n}\n\nfunction handleClick(e: MouseEvent) {\n const { node } = props\n treeEmit('node-click', node)\n\n treeProps.selectable && handleSelect(node)\n treeProps.expandOnClickNode && toggleExpand()\n treeProps.checkable &&\n treeProps.checkOnClickNode &&\n !node.disabled &&\n !treeProps.expandOnClickNode &&\n toggleCheck(node, !node.checked, e.ctrlKey)\n}\n</script>\n"],"mappings":";;;;;;;;;;;;;;;;;;EAsDA,MAAM,QAAQ;EAEd,MAAM,EAAE,WAAW,UAAU,KAAK,kBAAkB,iBAAiB,aAAa,iBAChF,OAAO,SAAS;EAElB,SAAS,WAAW,IAAa;GAC/B,IAAI,OAAO,MAAM,UAAU,YAAY,CAAC,MAAM,gBAAgB;GAC9D,MAAM,eAAe,MAAM,OAAO,EAAoB;EACxD;EAEA,SAAS,eAAe;GACtB,MAAM,EAAE,SAAS;GACjB,KAAK,WAAW,CAAC,KAAK;GACtB,gBAAgB;GAEhB,SAAS,UAAU,IAAI;EACzB;EAEA,SAAS,aAAa,SAAkB,GAAe;GACrD,YAAY,MAAM,MAAM,SAAS,EAAE,OAAO;EAC5C;EAEA,SAAS,YAAY,GAAe;GAClC,MAAM,EAAE,SAAS;GACjB,SAAS,cAAc,IAAI;GAE3B,UAAU,cAAc,aAAa,IAAI;GACzC,UAAU,qBAAqB,aAAa;GAC5C,UAAU,aACR,UAAU,oBACV,CAAC,KAAK,YACN,CAAC,UAAU,qBACX,YAAY,MAAM,CAAC,KAAK,SAAS,EAAE,OAAO;EAC9C;;GAtFE,OAAA,UAAA,GAAA,mBAoCM,OAAA;IAnCH,OAAK,eAAA;KAAG,MAAA,GAAA,CAAG,CAAC,EAAC,MAAA;KAAU,MAAA,GAAA,CAAG,CAAC,GAAE,YAAa,QAAA,KAAK,QAAQ;KAAG,MAAA,GAAA,CAAG,CAAC,GAAE,YAAa,QAAA,KAAK,QAAQ;IAAA,CAAA;IAC1F,KAAK;;KAEN,UAAA,IAAA,GAAA,mBAA0F,UAAA,MAAA,WAAxE,QAAA,KAAK,QAAV,MAAC;KAAd,OAAA,UAAA,GAAA,mBAA0F,QAAA;MAA3D,KAAK;MAAI,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,QAAA,CAAA;MAAY,eAAY;;;IAE7D,CAAA,QAAA,KAAK,UAApB,UAAA,GAAA,YAES,MAAA,WAAA,GAAA;;KAFoB,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,aAAA,CAAA;KAAkB,SAAK,cAAO,cAAY,CAAA,MAAA,CAAA;;KACjF,SAAA,cAAc,CAAd,YAAc,MAAA,UAAA,CAAA,CAAA,CAAA;;IAEhB,GAAA,GAAA,CAAA,OAAA,CAAA,MAAA,UAAA,GAAA,YAES,MAAA,WAAA,GAAA;;KAFO,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,WAAA,CAAA;KAAe,eAAY;;KACrD,SAAA,cAAO,CAAP,YAAO,MAAA,GAAA,CAAA,CAAA,CAAA;;;IAGT,gBAAA,UAAA,GAAA,mBAsBM,OAAA;KArBH,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,cAAA,CAAA;KACZ,SAAO;KACP,eAAW,OAAA,OAAA,OAAA,MAAA,WAAE,MAAA,QAAA,CAAQ,CAAA,oBAAqB,QAAQ,QAAA,IAAI;IAS/C,GAAA,CAAA,MAAA,SAAA,CAAS,CAAC,aADlB,UAAA,GAAA,YAQE,aAAA;;KANC,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,UAAA,CAAA;KACZ,eAAa,QAAA,KAAK;KAClB,eAAe,QAAA,KAAK;KACpB,UAAU,QAAA,KAAK;KACf,UAAQ;KACR,SAAK,OAAA,OAAA,OAAA,KAAA,oBAAN,CAAA,GAAW,CAAA,MAAA,CAAA;;;;;;IAGb,CAAA,KAAA,mBAAA,QAAA,IAAA,GAAA,YAAwE,MAAA,UAAA,GAAA,EAAxD,SAAS,MAAA,gBAAA,CAAgB,CAAA;KAAA,MAAG,QAAA;KAAI,MAAQ,QAAA,KAAK;IAAI,CAAA,EAAA,GAAA,MAAA,GAAA,CAAA,SAAA,CAAA,CAAA,GAAA,EAjB7C,IAAA,CAAA,CAAA,MAAA,OAAA,IAAA,MAAA,SAAA,CAAS,CAAC,cAAe,MAAA,SAAA,CAAS,CAAC,aAAa,MAAA,SAAA,CAAS,CAAC,qBAA+B,CAAA,QAAA,KAAK,WAAqB,MAAA,GAAA,CAAG,CAAC,EAAC,QAAA,IAAA,KAAA,CAAA,CAAA"}
@@ -25,6 +25,10 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
25
25
  data: { default: () => [] },
26
26
  disabledNode: {},
27
27
  checkable: { type: Boolean },
28
+ checkOnClickNode: {
29
+ type: Boolean,
30
+ default: true
31
+ },
28
32
  selectable: { type: Boolean },
29
33
  checkStrictly: {
30
34
  type: Boolean,
@@ -1 +1 @@
1
- {"version":3,"file":"tree.js","names":[],"sources":["../../../src/components/tree/tree.vue"],"sourcesContent":["<template>\n <u-scroll\n :class=\"className\"\n ref=\"scrollRef\"\n :content-class=\"[cls.e('wrap'), bem.is('virtual', virtualEnabled)]\"\n >\n <template v-if=\"virtualEnabled\">\n <UTreeNode\n v-for=\"{ node, key, offset, index } of virtualNodes\"\n :node=\"node\"\n :key=\"key\"\n :class=\"bem.is('selected', node.data === selectedData)\"\n :index=\"index\"\n :measure-element=\"measureElement\"\n :style=\"{ transform: `translateY(${offset}px)` }\"\n />\n </template>\n <template v-else>\n <UTreeNode\n v-for=\"node of nodes\"\n :node=\"node\"\n :key=\"node.key\"\n :class=\"bem.is('selected', node.data === selectedData)\"\n />\n </template>\n\n <div :class=\"cls.e('empty')\" v-if=\"!nodes.length\">\n <UEmpty />\n </div>\n </u-scroll>\n</template>\n\n<script lang=\"ts\" setup>\nimport { useFormFallbackProps, useVirtualizer } from '@veltra/compositions'\nimport { bem, nextFrame, scrollIntoContainerView } from '@veltra/utils'\nimport { injectFormContext } from '@veltra/utils'\nimport { computed, provide, shallowRef, useSlots, watch, watchEffect, type VNode } from 'vue'\n\nimport type { TreeProps, TreeEmit, _TreeExposed } from '../../types'\nimport type { ScrollExposed } from '../../types'\nimport { UEmpty } from '../empty'\nimport { UScroll } from '../scroll'\nimport { TreeDIKey, type TreeConText, type TreeSlotsScope } from './di'\nimport UTreeNode from './tree-node.vue'\nimport { useCheck } from './use-check'\nimport { useFilter } from './use-filter'\nimport { useSelect } from './use-select'\nimport { useTreeNodes } from './use-tree-nodes'\n\ndefineOptions({ name: 'UTree' })\n\nconst props = withDefaults(defineProps<TreeProps>(), {\n labelKey: 'label',\n valueKey: 'value',\n childrenKey: 'children',\n expandOnClickNode: false,\n checkStrictly: false,\n data: () => []\n})\n\nconst emit = defineEmits<TreeEmit>()\n\nconst cls = bem('tree')\n\nconst { formProps } = injectFormContext()\n\nconst { size } = useFormFallbackProps([formProps ?? {}, props], { size: 'default' })\n\nconst scrollRef = shallowRef<ScrollExposed>()\n\nconst className = computed(() => {\n return [\n cls.b,\n cls.m(size.value),\n bem.is('selectable', props.selectable),\n bem.is('checkable', props.checkable)\n ]\n})\n\ndefineSlots<{ default: (props: TreeSlotsScope) => any }>()\n\nconst slots = useSlots()\n\nfunction getTreeSlotsNode(ctx: TreeSlotsScope): VNode[] | string | undefined {\n return (props.slots?.default ?? slots.default)?.(ctx) ?? ctx.node.label\n}\n\nconst { nodes, forest, getFlattedNodes, nodeDict } = useTreeNodes({ props })\n\nwatch(\n [() => props.selectable, () => props.checkable, forest],\n ([s, c]) => {\n // 如果选择或勾选,则不更新节点\n if (s || c) return\n getFlattedNodes()\n },\n { immediate: true }\n)\n\nconst { filter } = useFilter({ forest, getFlattedNodes })\n\nconst { handleSelect, selectedData } = useSelect({ props, emit, nodeDict, getFlattedNodes })\n\nconst { checkedData, toggleCheck } = useCheck({ props, emit, nodeDict, getFlattedNodes })\n\nconst estimateSize = (): number => {\n // 基于 style.scss 中节点稳态高度推算的默认值;\n // 实际高度仍由 `measureElement` 通过 ResizeObserver 回填覆盖。\n switch (size.value) {\n case 'small':\n return 32\n case 'large':\n return 44\n default:\n return 36\n }\n}\n\n// 80 阈值内化为消费者侧语义;低于此值时不启用虚拟化。\nconst virtualEnabled = computed(() => nodes.value.length > 80)\n\nconst { virtualizer, items } = useVirtualizer({\n count: computed(() => nodes.value.length),\n scrollEl: () => scrollRef.value?.containerRef ?? null,\n // 仅在虚拟化启用时把内容容器的 height 撑开到 totalSize;\n // 关闭时传 null,hook 会清除此前写入的内联 height,回到 CSS 默认。\n contentEl: () => (virtualEnabled.value ? (scrollRef.value?.contentRef ?? null) : null),\n estimateSize,\n gap: 2,\n // 以节点稳定 key 作为虚拟项身份,展开 / 收起 / 过滤引起的 nodes 数组变更\n // 保留未移动节点的真实测量值,避免再次滚动首屏抖动。\n getItemKey: (i) => nodes.value[i]?.key ?? i\n})\n\n// 身份稳定性已由底层 `getItemKey` 保证;直接以 `node.key` 作为 Vue 层 key。\n// `item.index` 仅作为 nodes / snapshot 竞态边缘的 fallback。\nconst virtualNodes = computed(() => {\n const _nodes = nodes.value\n return items.value.map((item) => {\n const node = _nodes[item.index]!\n return { node, key: node?.key ?? item.index, offset: item.start, index: item.index }\n })\n})\n\nconst measureElement: (index: number, el: Element | null) => void = (index, el) =>\n virtualizer.measureElement(index, el)\n\nfunction scrollTo(index: number): void {\n virtualizer.scrollToIndex(index, { align: 'center' })\n}\n\nfunction scrollIntoView() {\n const { selectable, checkable, scrollToView } = props\n if (!scrollToView || (!selectable && !checkable) || !nodes.value) return\n let index = -1\n\n if (selectable) {\n if (!selectedData.value) return\n index = nodes.value.findIndex((node) => node.data === selectedData.value)\n } else if (checkable) {\n if (!checkedData.size) return\n index = nodes.value.findIndex((node) => checkedData.has(node.data))\n }\n\n if (virtualEnabled.value) {\n scrollTo(index)\n } else {\n const { contentRef, containerRef } = scrollRef.value ?? {}\n const el = contentRef?.children[index]\n el && scrollIntoContainerView(el as HTMLElement, containerRef ?? null)\n }\n}\n\nwatchEffect(() => {\n nextFrame(() => {\n scrollIntoView()\n })\n})\n\nprovide(TreeDIKey, {\n cls,\n selectedData,\n checkedData,\n getFlattedNodes,\n getTreeSlotsNode,\n treeEmit: emit as TreeEmit,\n treeProps: props as TreeProps,\n toggleCheck: toggleCheck as TreeConText['toggleCheck'],\n handleSelect: handleSelect as TreeConText['handleSelect']\n})\n\ndefineExpose<_TreeExposed>({\n filter,\n forest,\n nodes,\n checkNode: toggleCheck,\n selectNode: handleSelect,\n checkAll(check: boolean) {\n forest.value.roots.forEach((node) => {\n toggleCheck(node, check)\n })\n },\n getSelected() {\n return selectedData\n },\n getChecked() {\n return Array.from(checkedData)\n },\n scrollTo,\n\n expandAll() {\n forest.value.dfs((node) => {\n node.expanded = true\n })\n getFlattedNodes()\n },\n collapseAll() {\n forest.value.dfs((node) => {\n node.expanded = false\n })\n getFlattedNodes()\n }\n})\n</script>\n"],"mappings":"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"}
1
+ {"version":3,"file":"tree.js","names":[],"sources":["../../../src/components/tree/tree.vue"],"sourcesContent":["<template>\n <u-scroll\n :class=\"className\"\n ref=\"scrollRef\"\n :content-class=\"[cls.e('wrap'), bem.is('virtual', virtualEnabled)]\"\n >\n <template v-if=\"virtualEnabled\">\n <UTreeNode\n v-for=\"{ node, key, offset, index } of virtualNodes\"\n :node=\"node\"\n :key=\"key\"\n :class=\"bem.is('selected', node.data === selectedData)\"\n :index=\"index\"\n :measure-element=\"measureElement\"\n :style=\"{ transform: `translateY(${offset}px)` }\"\n />\n </template>\n <template v-else>\n <UTreeNode\n v-for=\"node of nodes\"\n :node=\"node\"\n :key=\"node.key\"\n :class=\"bem.is('selected', node.data === selectedData)\"\n />\n </template>\n\n <div :class=\"cls.e('empty')\" v-if=\"!nodes.length\">\n <UEmpty />\n </div>\n </u-scroll>\n</template>\n\n<script lang=\"ts\" setup>\nimport { useFormFallbackProps, useVirtualizer } from '@veltra/compositions'\nimport { bem, nextFrame, scrollIntoContainerView } from '@veltra/utils'\nimport { injectFormContext } from '@veltra/utils'\nimport { computed, provide, shallowRef, useSlots, watch, watchEffect, type VNode } from 'vue'\n\nimport type { TreeProps, TreeEmit, _TreeExposed } from '../../types'\nimport type { ScrollExposed } from '../../types'\nimport { UEmpty } from '../empty'\nimport { UScroll } from '../scroll'\nimport { TreeDIKey, type TreeConText, type TreeSlotsScope } from './di'\nimport UTreeNode from './tree-node.vue'\nimport { useCheck } from './use-check'\nimport { useFilter } from './use-filter'\nimport { useSelect } from './use-select'\nimport { useTreeNodes } from './use-tree-nodes'\n\ndefineOptions({ name: 'UTree' })\n\nconst props = withDefaults(defineProps<TreeProps>(), {\n labelKey: 'label',\n valueKey: 'value',\n childrenKey: 'children',\n expandOnClickNode: false,\n checkOnClickNode: true,\n checkStrictly: false,\n data: () => []\n})\n\nconst emit = defineEmits<TreeEmit>()\n\nconst cls = bem('tree')\n\nconst { formProps } = injectFormContext()\n\nconst { size } = useFormFallbackProps([formProps ?? {}, props], { size: 'default' })\n\nconst scrollRef = shallowRef<ScrollExposed>()\n\nconst className = computed(() => {\n return [\n cls.b,\n cls.m(size.value),\n bem.is('selectable', props.selectable),\n bem.is('checkable', props.checkable)\n ]\n})\n\ndefineSlots<{ default: (props: TreeSlotsScope) => any }>()\n\nconst slots = useSlots()\n\nfunction getTreeSlotsNode(ctx: TreeSlotsScope): VNode[] | string | undefined {\n return (props.slots?.default ?? slots.default)?.(ctx) ?? ctx.node.label\n}\n\nconst { nodes, forest, getFlattedNodes, nodeDict } = useTreeNodes({ props })\n\nwatch(\n [() => props.selectable, () => props.checkable, forest],\n ([s, c]) => {\n // 如果选择或勾选,则不更新节点\n if (s || c) return\n getFlattedNodes()\n },\n { immediate: true }\n)\n\nconst { filter } = useFilter({ forest, getFlattedNodes })\n\nconst { handleSelect, selectedData } = useSelect({ props, emit, nodeDict, getFlattedNodes })\n\nconst { checkedData, toggleCheck } = useCheck({ props, emit, nodeDict, getFlattedNodes })\n\nconst estimateSize = (): number => {\n // 基于 style.scss 中节点稳态高度推算的默认值;\n // 实际高度仍由 `measureElement` 通过 ResizeObserver 回填覆盖。\n switch (size.value) {\n case 'small':\n return 32\n case 'large':\n return 44\n default:\n return 36\n }\n}\n\n// 80 阈值内化为消费者侧语义;低于此值时不启用虚拟化。\nconst virtualEnabled = computed(() => nodes.value.length > 80)\n\nconst { virtualizer, items } = useVirtualizer({\n count: computed(() => nodes.value.length),\n scrollEl: () => scrollRef.value?.containerRef ?? null,\n // 仅在虚拟化启用时把内容容器的 height 撑开到 totalSize;\n // 关闭时传 null,hook 会清除此前写入的内联 height,回到 CSS 默认。\n contentEl: () => (virtualEnabled.value ? (scrollRef.value?.contentRef ?? null) : null),\n estimateSize,\n gap: 2,\n // 以节点稳定 key 作为虚拟项身份,展开 / 收起 / 过滤引起的 nodes 数组变更\n // 保留未移动节点的真实测量值,避免再次滚动首屏抖动。\n getItemKey: (i) => nodes.value[i]?.key ?? i\n})\n\n// 身份稳定性已由底层 `getItemKey` 保证;直接以 `node.key` 作为 Vue 层 key。\n// `item.index` 仅作为 nodes / snapshot 竞态边缘的 fallback。\nconst virtualNodes = computed(() => {\n const _nodes = nodes.value\n return items.value.map((item) => {\n const node = _nodes[item.index]!\n return { node, key: node?.key ?? item.index, offset: item.start, index: item.index }\n })\n})\n\nconst measureElement: (index: number, el: Element | null) => void = (index, el) =>\n virtualizer.measureElement(index, el)\n\nfunction scrollTo(index: number): void {\n virtualizer.scrollToIndex(index, { align: 'center' })\n}\n\nfunction scrollIntoView() {\n const { selectable, checkable, scrollToView } = props\n if (!scrollToView || (!selectable && !checkable) || !nodes.value) return\n let index = -1\n\n if (selectable) {\n if (!selectedData.value) return\n index = nodes.value.findIndex((node) => node.data === selectedData.value)\n } else if (checkable) {\n if (!checkedData.size) return\n index = nodes.value.findIndex((node) => checkedData.has(node.data))\n }\n\n if (virtualEnabled.value) {\n scrollTo(index)\n } else {\n const { contentRef, containerRef } = scrollRef.value ?? {}\n const el = contentRef?.children[index]\n el && scrollIntoContainerView(el as HTMLElement, containerRef ?? null)\n }\n}\n\nwatchEffect(() => {\n nextFrame(() => {\n scrollIntoView()\n })\n})\n\nprovide(TreeDIKey, {\n cls,\n selectedData,\n checkedData,\n getFlattedNodes,\n getTreeSlotsNode,\n treeEmit: emit as TreeEmit,\n treeProps: props as TreeProps,\n toggleCheck: toggleCheck as TreeConText['toggleCheck'],\n handleSelect: handleSelect as TreeConText['handleSelect']\n})\n\ndefineExpose<_TreeExposed>({\n filter,\n forest,\n nodes,\n checkNode: toggleCheck,\n selectNode: handleSelect,\n checkAll(check: boolean) {\n forest.value.roots.forEach((node) => {\n toggleCheck(node, check)\n })\n },\n getSelected() {\n return selectedData\n },\n getChecked() {\n return Array.from(checkedData)\n },\n scrollTo,\n\n expandAll() {\n forest.value.dfs((node) => {\n node.expanded = true\n })\n getFlattedNodes()\n },\n collapseAll() {\n forest.value.dfs((node) => {\n node.expanded = false\n })\n getFlattedNodes()\n }\n})\n</script>\n"],"mappings":"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"}
@@ -51,6 +51,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
51
51
  childrenKey: {},
52
52
  data: {},
53
53
  disabledNode: {},
54
+ checkOnClickNode: { type: Boolean },
54
55
  checkStrictly: { type: Boolean },
55
56
  slots: {},
56
57
  scrollToView: { type: Boolean }
@@ -1 +1 @@
1
- {"version":3,"file":"tree-select.js","names":["$attrs","$slots"],"sources":["../../../src/components/tree-select/tree-select.vue"],"sourcesContent":["<template>\n <u-dropdown\n v-if=\"!readonly\"\n v-bind=\"$attrs\"\n :class=\"[cls.b, bem.is('disabled', disabled)]\"\n trigger=\"click\"\n :content-class=\"[cls.e('panel'), cls.em('panel', size), contentClass]\"\n :content-style=\"contentStyle\"\n ref=\"dropdownRef\"\n v-model:visible=\"dropdownVisible\"\n :min-width=\"minWidth\"\n :width=\"width\"\n :disabled=\"disabled\"\n @update:visible=\"handleDropdownVisible\"\n @mouseenter=\"hovered = true\"\n @mouseleave=\"hovered = false\"\n >\n <template #trigger>\n <u-input\n ref=\"inputRef\"\n :size=\"size\"\n :disabled=\"disabled\"\n :placeholder=\"inputPlaceholder\"\n :clearable=\"false\"\n :model-value=\"inputValue\"\n @update:model-value=\"handleQueryInput\"\n :native-readonly=\"!filterable || !querying\"\n @click.capture=\"handleTriggerClickCapture\"\n >\n <template #prefix v-if=\"$slots.prefix\">\n <slot name=\"prefix\" />\n </template>\n <template #suffix>\n <transition name=\"zoom-in\" mode=\"out-in\">\n <u-icon\n v-if=\"showClear\"\n :class=\"cls.e('clear')\"\n title=\"清除\"\n key=\"clear\"\n @click.stop=\"handleClear\"\n >\n <Close />\n </u-icon>\n <u-icon v-else :class=\"cls.e('arrow')\" key=\"arrow\"><ArrowDown /></u-icon>\n </transition>\n </template>\n </u-input>\n </template>\n <template #content>\n <!-- 菜单列表 -->\n\n <u-tree\n v-bind=\"treeProps\"\n :selected=\"model\"\n @update:selected=\"handleSelect\"\n ref=\"treeRef\"\n selectable\n :class=\"cls.e('content-tree')\"\n :slots=\"slots\"\n scroll-to-view\n />\n </template>\n </u-dropdown>\n\n <template v-else>\n {{ label || FORM_EMPTY_CONTENT }}\n </template>\n</template>\n\n<script lang=\"ts\" setup>\nimport { dfs, o } from '@cat-kit/core'\nimport { useFormFallbackProps, useUserAction } from '@veltra/compositions'\nimport { ArrowDown, Close } from '@veltra/icons/normal'\nimport { bem, fieldKey, FORM_EMPTY_CONTENT } from '@veltra/utils'\nimport { injectFormContext } from '@veltra/utils'\nimport { computed, nextTick, shallowRef, useTemplateRef, watch } from 'vue'\n\nimport type { TreeSelectProps, TreeSelectEmits, TreeExposed, InputExposed } from '../../types'\nimport { UDropdown } from '../dropdown'\nimport { UIcon } from '../icon'\nimport { UInput } from '../input'\nimport { UTree } from '../tree'\nimport type { TreeSlotsScope } from '../tree/di'\n\ndefineOptions({ name: 'UTreeSelect', inheritAttrs: false })\n\nconst props = withDefaults(defineProps<TreeSelectProps>(), {\n labelKey: 'label',\n valueKey: 'value',\n placeholder: '请选择',\n expandAll: false,\n clearable: true,\n disabled: undefined,\n readonly: undefined,\n filterable: false,\n minWidth: '280px'\n})\n\nconst emit = defineEmits<TreeSelectEmits>()\n\nconst slots = defineSlots<{\n /** 默认插槽 */\n default?: (props: TreeSlotsScope) => any\n /** 前缀插槽 */\n prefix?: () => any\n}>()\n\nconst treeProps = computed(() => {\n return o(props as Record<string, any>).omit([\n 'tips',\n 'field',\n 'placeholder',\n 'disabled',\n 'label',\n 'readonly',\n 'contentClass',\n 'contentStyle',\n 'minWidth',\n 'width'\n ])\n})\n\nconst cls = bem('tree-select')\n\nconst labelKey = computed(() => fieldKey(props.labelKey, 'label'))\nconst valueKey = computed(() => fieldKey(props.valueKey, 'value'))\n\n/**过滤 */\nconst qs = shallowRef('')\nwatch(qs, (qs) => {\n treeRef.value?.filter(qs)\n})\n\nconst model = defineModel<string | number>()\n\n/** 内部展示文案,仅由 data 推导;通过 update:text 单向通知父级 */\nconst label = shallowRef<string>()\n\nconst dropdownVisible = shallowRef(false)\n\n/**\n * 是否处于查询态:决定触发输入框显示查询串还是选中标签。\n * 与面板可见状态解耦 —— 选择后立即退出查询态,\n * 不等面板关闭动画结束(否则显示值会延迟一个动画时长才恢复)。\n */\nconst querying = shallowRef(false)\n\nconst inputRef = useTemplateRef<InputExposed>('inputRef')\n\n/** 更新内部文案;值变化时单向 emit update:text */\nfunction setLabel(next?: string) {\n if (label.value === next) return\n label.value = next\n emit('update:text', next)\n}\n\n/** 触发输入框的值:查询态下承载查询串,否则展示选中标签 */\nconst inputValue = computed(() => {\n if (props.filterable && querying.value) return qs.value\n return model.value || model.value === 0 ? label.value : undefined\n})\n\n/** 查询态下已选标签降级为占位提示 */\nconst inputPlaceholder = computed(() => {\n const display = model.value || model.value === 0 ? label.value : undefined\n if (props.filterable && querying.value && display) {\n return display\n }\n return props.placeholder\n})\n\nfunction handleQueryInput(value: string) {\n if (!props.filterable) return\n qs.value = value\n}\n\nconst hovered = shallowRef(false)\n\n/** 悬停且存在选中值时展示清除按钮(替代下拉箭头) */\nconst showClear = computed(() => {\n if (!props.clearable || disabled.value || !hovered.value) return false\n return !!(model.value || model.value === 0 ? label.value : undefined)\n})\n\n/**\n * 过滤模式下拦截输入区域的点击:\n * 阻止 dropdown 的 trigger 开合切换,保持面板展开以不中断输入。\n * 非输入区域(箭头、留白)放行,维持原开合行为。\n */\nfunction handleTriggerClickCapture(e: MouseEvent) {\n if (!props.filterable || disabled.value) return\n if (!(e.target instanceof HTMLInputElement)) return\n\n e.stopPropagation()\n if (!dropdownVisible.value) dropdownRef.value?.open()\n}\n\nwatch(dropdownVisible, (visible) => {\n if (visible && props.filterable) {\n // 面板展开后进入查询态并聚焦输入框,可以立即输入查询\n querying.value = true\n nextTick(() => inputRef.value?.el?.focus())\n } else if (!visible) {\n querying.value = false\n }\n})\n\nconst { formProps } = injectFormContext()\n\nconst { size, disabled, readonly } = useFormFallbackProps([formProps ?? {}, props])\n\nconst treeRef = shallowRef<TreeExposed>()\n\nconst dropdownRef = shallowRef<InstanceType<typeof UDropdown>>()\n\nconst { userAction, isUserActive } = useUserAction()\n\n/** 清空 */\nconst handleClear = userAction(() => {\n model.value = ''\n setLabel(undefined)\n emit('clear')\n emit('change', undefined)\n})\n\n/** 外部回显:按 data 查找 label(O(n));用户动作期内跳过 */\nwatch(\n [() => props.data, model],\n ([data, modelVal]) => {\n if (isUserActive()) return\n if (!data?.length || modelVal === undefined || modelVal === null || modelVal === '') {\n setLabel(undefined)\n return\n }\n\n let nextLabel: string | undefined\n const childrenKey = props.childrenKey ?? 'children'\n data.some((item) => {\n let founded = false\n dfs(\n item,\n (v) => {\n if (v[valueKey.value] === modelVal) {\n nextLabel = v[labelKey.value]\n founded = true\n return true\n }\n },\n childrenKey\n )\n\n return founded\n })\n setLabel(nextLabel)\n },\n { immediate: true }\n)\n\n/** 用户选择:O(1) 写入值与文案,跳过 data 回显查找 */\nconst handleSelect = userAction(\n (selected?: string | number, selectedData?: Record<string, any>) => {\n model.value = selected ?? ''\n\n if (selectedData) {\n setLabel(o(selectedData).get(labelKey.value))\n } else {\n setLabel(undefined)\n }\n\n emit('change', selectedData)\n // 立即退出查询态,输入框同步恢复显示选中标签\n querying.value = false\n qs.value = ''\n dropdownRef.value?.close()\n }\n)\nconst handleDropdownVisible = (visible: boolean) => {\n if (!visible) {\n qs.value = ''\n }\n}\n</script>\n"],"mappings":"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"}
1
+ {"version":3,"file":"tree-select.js","names":["$attrs","$slots"],"sources":["../../../src/components/tree-select/tree-select.vue"],"sourcesContent":["<template>\n <u-dropdown\n v-if=\"!readonly\"\n v-bind=\"$attrs\"\n :class=\"[cls.b, bem.is('disabled', disabled)]\"\n trigger=\"click\"\n :content-class=\"[cls.e('panel'), cls.em('panel', size), contentClass]\"\n :content-style=\"contentStyle\"\n ref=\"dropdownRef\"\n v-model:visible=\"dropdownVisible\"\n :min-width=\"minWidth\"\n :width=\"width\"\n :disabled=\"disabled\"\n @update:visible=\"handleDropdownVisible\"\n @mouseenter=\"hovered = true\"\n @mouseleave=\"hovered = false\"\n >\n <template #trigger>\n <u-input\n ref=\"inputRef\"\n :size=\"size\"\n :disabled=\"disabled\"\n :placeholder=\"inputPlaceholder\"\n :clearable=\"false\"\n :model-value=\"inputValue\"\n @update:model-value=\"handleQueryInput\"\n :native-readonly=\"!filterable || !querying\"\n @click.capture=\"handleTriggerClickCapture\"\n >\n <template #prefix v-if=\"$slots.prefix\">\n <slot name=\"prefix\" />\n </template>\n <template #suffix>\n <transition name=\"zoom-in\" mode=\"out-in\">\n <u-icon\n v-if=\"showClear\"\n :class=\"cls.e('clear')\"\n title=\"清除\"\n key=\"clear\"\n @click.stop=\"handleClear\"\n >\n <Close />\n </u-icon>\n <u-icon v-else :class=\"cls.e('arrow')\" key=\"arrow\"><ArrowDown /></u-icon>\n </transition>\n </template>\n </u-input>\n </template>\n <template #content>\n <!-- 菜单列表 -->\n\n <u-tree\n v-bind=\"treeProps\"\n :selected=\"model\"\n @update:selected=\"handleSelect\"\n ref=\"treeRef\"\n selectable\n :class=\"cls.e('content-tree')\"\n :slots=\"slots\"\n scroll-to-view\n />\n </template>\n </u-dropdown>\n\n <template v-else>\n {{ label || FORM_EMPTY_CONTENT }}\n </template>\n</template>\n\n<script lang=\"ts\" setup>\nimport { dfs, o } from '@cat-kit/core'\nimport { useFormFallbackProps, useUserAction } from '@veltra/compositions'\nimport { ArrowDown, Close } from '@veltra/icons/normal'\nimport { bem, fieldKey, FORM_EMPTY_CONTENT } from '@veltra/utils'\nimport { injectFormContext } from '@veltra/utils'\nimport { computed, nextTick, shallowRef, useTemplateRef, watch } from 'vue'\n\nimport type { TreeSelectProps, TreeSelectEmits, TreeExposed, InputExposed } from '../../types'\nimport { UDropdown } from '../dropdown'\nimport { UIcon } from '../icon'\nimport { UInput } from '../input'\nimport { UTree } from '../tree'\nimport type { TreeSlotsScope } from '../tree/di'\n\ndefineOptions({ name: 'UTreeSelect', inheritAttrs: false })\n\nconst props = withDefaults(defineProps<TreeSelectProps>(), {\n labelKey: 'label',\n valueKey: 'value',\n placeholder: '请选择',\n expandAll: false,\n clearable: true,\n disabled: undefined,\n readonly: undefined,\n filterable: false,\n minWidth: '280px'\n})\n\nconst emit = defineEmits<TreeSelectEmits>()\n\nconst slots = defineSlots<{\n /** 默认插槽 */\n default?: (props: TreeSlotsScope) => any\n /** 前缀插槽 */\n prefix?: () => any\n}>()\n\nconst treeProps = computed(() => {\n return o(props as Record<string, any>).omit([\n 'tips',\n 'field',\n 'placeholder',\n 'disabled',\n 'label',\n 'readonly',\n 'contentClass',\n 'contentStyle',\n 'minWidth',\n 'width'\n ])\n})\n\nconst cls = bem('tree-select')\n\nconst labelKey = computed(() => fieldKey(props.labelKey, 'label'))\nconst valueKey = computed(() => fieldKey(props.valueKey, 'value'))\n\n/**过滤 */\nconst qs = shallowRef('')\nwatch(qs, (qs) => {\n treeRef.value?.filter(qs)\n})\n\nconst model = defineModel<string | number>()\n\n/** 内部展示文案,仅由 data 推导;通过 update:text 单向通知父级 */\nconst label = shallowRef<string>()\n\nconst dropdownVisible = shallowRef(false)\n\n/**\n * 是否处于查询态:决定触发输入框显示查询串还是选中标签。\n * 与面板可见状态解耦 —— 选择后立即退出查询态,\n * 不等面板关闭动画结束(否则显示值会延迟一个动画时长才恢复)。\n */\nconst querying = shallowRef(false)\n\nconst inputRef = useTemplateRef<InputExposed>('inputRef')\n\n/** 更新内部文案;值变化时单向 emit update:text */\nfunction setLabel(next?: string) {\n if (label.value === next) return\n label.value = next\n emit('update:text', next)\n}\n\n/** 触发输入框的值:查询态下承载查询串,否则展示选中标签 */\nconst inputValue = computed(() => {\n if (props.filterable && querying.value) return qs.value\n return model.value || model.value === 0 ? label.value : undefined\n})\n\n/** 查询态下已选标签降级为占位提示 */\nconst inputPlaceholder = computed(() => {\n const display = model.value || model.value === 0 ? label.value : undefined\n if (props.filterable && querying.value && display) {\n return display\n }\n return props.placeholder\n})\n\nfunction handleQueryInput(value: string) {\n if (!props.filterable) return\n qs.value = value\n}\n\nconst hovered = shallowRef(false)\n\n/** 悬停且存在选中值时展示清除按钮(替代下拉箭头) */\nconst showClear = computed(() => {\n if (!props.clearable || disabled.value || !hovered.value) return false\n return !!(model.value || model.value === 0 ? label.value : undefined)\n})\n\n/**\n * 过滤模式下拦截输入区域的点击:\n * 阻止 dropdown 的 trigger 开合切换,保持面板展开以不中断输入。\n * 非输入区域(箭头、留白)放行,维持原开合行为。\n */\nfunction handleTriggerClickCapture(e: MouseEvent) {\n if (!props.filterable || disabled.value) return\n if (!(e.target instanceof HTMLInputElement)) return\n\n e.stopPropagation()\n if (!dropdownVisible.value) dropdownRef.value?.open()\n}\n\nwatch(dropdownVisible, (visible) => {\n if (visible && props.filterable) {\n // 面板展开后进入查询态并聚焦输入框,可以立即输入查询\n querying.value = true\n nextTick(() => inputRef.value?.el?.focus())\n } else if (!visible) {\n querying.value = false\n }\n})\n\nconst { formProps } = injectFormContext()\n\nconst { size, disabled, readonly } = useFormFallbackProps([formProps ?? {}, props])\n\nconst treeRef = shallowRef<TreeExposed>()\n\nconst dropdownRef = shallowRef<InstanceType<typeof UDropdown>>()\n\nconst { userAction, isUserActive } = useUserAction()\n\n/** 清空 */\nconst handleClear = userAction(() => {\n model.value = ''\n setLabel(undefined)\n emit('clear')\n emit('change', undefined)\n})\n\n/** 外部回显:按 data 查找 label(O(n));用户动作期内跳过 */\nwatch(\n [() => props.data, model],\n ([data, modelVal]) => {\n if (isUserActive()) return\n if (!data?.length || modelVal === undefined || modelVal === null || modelVal === '') {\n setLabel(undefined)\n return\n }\n\n let nextLabel: string | undefined\n const childrenKey = props.childrenKey ?? 'children'\n data.some((item) => {\n let founded = false\n dfs(\n item,\n (v) => {\n if (v[valueKey.value] === modelVal) {\n nextLabel = v[labelKey.value]\n founded = true\n return true\n }\n },\n childrenKey\n )\n\n return founded\n })\n setLabel(nextLabel)\n },\n { immediate: true }\n)\n\n/** 用户选择:O(1) 写入值与文案,跳过 data 回显查找 */\nconst handleSelect = userAction(\n (selected?: string | number, selectedData?: Record<string, any>) => {\n model.value = selected ?? ''\n\n if (selectedData) {\n setLabel(o(selectedData).get(labelKey.value))\n } else {\n setLabel(undefined)\n }\n\n emit('change', selectedData)\n // 立即退出查询态,输入框同步恢复显示选中标签\n querying.value = false\n qs.value = ''\n dropdownRef.value?.close()\n }\n)\nconst handleDropdownVisible = (visible: boolean) => {\n if (!visible) {\n qs.value = ''\n }\n}\n</script>\n"],"mappings":"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"}
@@ -40,6 +40,12 @@ interface TreeProps {
40
40
  disabledNode?: (item: Record<string, any>, node: TreeNode$1) => boolean;
41
41
  /** 可多选 */
42
42
  checkable?: boolean;
43
+ /**
44
+ * 点击节点时是否触发勾选。仅当 `checkable` 时生效;
45
+ * 设为 `false` 后只有点击 checkbox 才会勾选。
46
+ * @default true
47
+ */
48
+ checkOnClickNode?: boolean;
43
49
  /** 可单选 */
44
50
  selectable?: boolean;
45
51
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@veltra/desktop",
3
- "version": "1.7.1",
3
+ "version": "1.7.3",
4
4
  "homepage": "https://github.com/cabinet-fe/ultra-ui#readme",
5
5
  "bugs": {
6
6
  "url": "https://github.com/cabinet-fe/ultra-ui/issues"
@@ -78,15 +78,15 @@
78
78
  "@codemirror/view": "6.43.9"
79
79
  },
80
80
  "peerDependencies": {
81
- "@cat-kit/core": ">=1.1.8",
82
- "@cat-kit/fe": ">=1.1.8",
83
- "@veltra/compositions": "^1.7.1",
84
- "@veltra/directives": "^1.7.1",
81
+ "@cat-kit/core": ">=1.2.1",
82
+ "@cat-kit/fe": ">=1.2.1",
83
+ "@veltra/compositions": "^1.7.3",
84
+ "@veltra/directives": "^1.7.3",
85
85
  "@veltra/icons": "^1.5.0",
86
- "@veltra/sheet-core": "^2.5.2",
87
- "@veltra/styles": "^1.7.1",
88
- "@veltra/utils": "^1.7.1",
89
- "vue": ">=3.5.41"
86
+ "@veltra/sheet-core": "^2.5.3",
87
+ "@veltra/styles": "^1.7.3",
88
+ "@veltra/utils": "^1.7.3",
89
+ "vue": ">=3.5.42"
90
90
  },
91
91
  "peerDependenciesMeta": {
92
92
  "@veltra/sheet-core": {
@@ -38,7 +38,7 @@ export function useFeatures(options: Options) {
38
38
  const { features } = props
39
39
  if (!Array.isArray(features) && typeof features === 'object') {
40
40
  const ret = Object.entries(features)
41
- .filter(([_, value]) => {
41
+ .filter(([, value]) => {
42
42
  return typeof value === 'function'
43
43
  })
44
44
  .reduce(
@@ -1,4 +1,4 @@
1
- import { last, o } from '@cat-kit/core'
1
+ import { copy, last, o } from '@cat-kit/core'
2
2
  import { computed, nextTick, type ShallowRef } from 'vue'
3
3
 
4
4
  import type {
@@ -57,7 +57,7 @@ export function useHandlers(options: Options): EditReturned {
57
57
  })
58
58
 
59
59
  function getInsertData(): Record<string, any> {
60
- return o(props.model ?? {}).copy()
60
+ return copy(props.model ?? {})
61
61
  }
62
62
 
63
63
  /**
@@ -19,10 +19,10 @@ const props = withDefaults(defineProps<CheckTagProps>(), {})
19
19
  const emits = defineEmits<CheckTagEmits>()
20
20
 
21
21
  const classList = computed(() => {
22
- return [cls.b, bem.is('checked', props.checked)]
22
+ return [cls.b, bem.is('checked', props.modelValue ?? props.checked)]
23
23
  })
24
24
 
25
25
  const handleChange = () => {
26
- emits('update:modelValue', props.checked)
26
+ emits('update:modelValue', !(props.modelValue ?? props.checked))
27
27
  }
28
28
  </script>
@@ -1,4 +1,4 @@
1
- import { o } from '@cat-kit/core'
1
+ import { copy, o } from '@cat-kit/core'
2
2
  import type { FormFieldItem } from '@veltra/utils'
3
3
  import { nextTick, watch } from 'vue'
4
4
 
@@ -8,26 +8,6 @@ interface Options {
8
8
  props: FormProps
9
9
  }
10
10
 
11
- /** 深拷贝 model,保留 undefined 等 o().copy() 会丢弃的值 */
12
- function snapshotModel(model: Record<string, any>): Record<string, any> {
13
- const result: Record<string, any> = {}
14
-
15
- for (const key of Object.keys(model)) {
16
- const value = model[key]
17
- if (Array.isArray(value)) {
18
- result[key] = value.map((item) =>
19
- item !== null && typeof item === 'object' ? snapshotModel(item) : item
20
- )
21
- } else if (value !== null && typeof value === 'object') {
22
- result[key] = snapshotModel(value)
23
- } else {
24
- result[key] = value
25
- }
26
- }
27
-
28
- return result
29
- }
30
-
31
11
  /** 按快照逐字段写回 model,支持 undefined 与嵌套对象 */
32
12
  function applySnapshot(target: Record<string, any>, source: Record<string, any>) {
33
13
  for (const key of Object.keys(source)) {
@@ -47,12 +27,7 @@ function applySnapshot(target: Record<string, any>, source: Record<string, any>)
47
27
  }
48
28
 
49
29
  if (Array.isArray(sourceValue)) {
50
- o(target).set(
51
- key,
52
- sourceValue.map((item) =>
53
- item !== null && typeof item === 'object' ? snapshotModel(item) : item
54
- )
55
- )
30
+ o(target).set(key, copy(sourceValue))
56
31
  continue
57
32
  }
58
33
 
@@ -84,7 +59,7 @@ export function useFormFields(options: Options) {
84
59
  watch(
85
60
  () => props.model,
86
61
  (model) => {
87
- initialSnapshot = model ? snapshotModel(model) : undefined
62
+ initialSnapshot = model ? copy(model) : undefined
88
63
  },
89
64
  { immediate: true, deep: false }
90
65
  )
@@ -110,7 +110,7 @@ export function useCheck(options: Options): UseCheckReturned {
110
110
 
111
111
  watch(
112
112
  [() => props.checked, () => props.rowKey, () => props.checkable, rows],
113
- ([checked, rowKey, checkable, rows], [_, __, ___, oRows]) => {
113
+ ([checked, rowKey, checkable, rows], [, , , oRows]) => {
114
114
  if (changedByEvent || !checkable || !rowKey) return
115
115
 
116
116
  changedByModel = true
@@ -140,7 +140,7 @@ export function useCheck(options: Options): UseCheckReturned {
140
140
 
141
141
  watch(
142
142
  [() => props.selected, () => props.rowKey, () => props.selectable, rows],
143
- ([selected, rowKey, selectable, rows], [_, __, ___, oRows]) => {
143
+ ([selected, rowKey, selectable, rows], [, , , oRows]) => {
144
144
  if (changedByEvent || !selectable || !rowKey) return
145
145
 
146
146
  changedByModel = true
@@ -17,7 +17,10 @@
17
17
  @click="handleClick"
18
18
  @contextmenu="treeEmit('node-contextmenu', $event, node)"
19
19
  v-ripple="
20
- (treeProps.checkable || treeProps.selectable) && !node.disabled ? cls.e('ripple') : false
20
+ (treeProps.selectable || (treeProps.checkable && treeProps.checkOnClickNode)) &&
21
+ !node.disabled
22
+ ? cls.e('ripple')
23
+ : false
21
24
  "
22
25
  >
23
26
  <u-checkbox
@@ -78,6 +81,7 @@ function handleClick(e: MouseEvent) {
78
81
  treeProps.selectable && handleSelect(node)
79
82
  treeProps.expandOnClickNode && toggleExpand()
80
83
  treeProps.checkable &&
84
+ treeProps.checkOnClickNode &&
81
85
  !node.disabled &&
82
86
  !treeProps.expandOnClickNode &&
83
87
  toggleCheck(node, !node.checked, e.ctrlKey)
@@ -54,6 +54,7 @@ const props = withDefaults(defineProps<TreeProps>(), {
54
54
  valueKey: 'value',
55
55
  childrenKey: 'children',
56
56
  expandOnClickNode: false,
57
+ checkOnClickNode: true,
57
58
  checkStrictly: false,
58
59
  data: () => []
59
60
  })
package/src/types/tree.ts CHANGED
@@ -45,6 +45,12 @@ export interface TreeProps {
45
45
  disabledNode?: (item: Record<string, any>, node: TreeNode) => boolean
46
46
  /** 可多选 */
47
47
  checkable?: boolean
48
+ /**
49
+ * 点击节点时是否触发勾选。仅当 `checkable` 时生效;
50
+ * 设为 `false` 后只有点击 checkbox 才会勾选。
51
+ * @default true
52
+ */
53
+ checkOnClickNode?: boolean
48
54
  /** 可单选 */
49
55
  selectable?: boolean
50
56
  /**