|
@@ -23,6 +23,7 @@ const props = withDefaults(defineProps<TreeProps>(), {
|
|
|
defaultExpandedKeys: () => [],
|
|
|
defaultExpandedLevel: 0,
|
|
|
disabled: false,
|
|
|
+ disabledField: 'disabled',
|
|
|
expanded: () => [],
|
|
|
iconField: 'icon',
|
|
|
labelField: 'label',
|
|
@@ -101,16 +102,37 @@ function updateTreeValue() {
|
|
|
if (val === undefined) {
|
|
|
treeValue.value = undefined;
|
|
|
} else {
|
|
|
- treeValue.value = Array.isArray(val)
|
|
|
- ? val.map((v) => getItemByValue(v))
|
|
|
- : getItemByValue(val);
|
|
|
+ if (Array.isArray(val)) {
|
|
|
+ const filteredValues = val.filter((v) => {
|
|
|
+ const item = getItemByValue(v);
|
|
|
+ return item && !get(item, props.disabledField);
|
|
|
+ });
|
|
|
+ treeValue.value = filteredValues.map((v) => getItemByValue(v));
|
|
|
+
|
|
|
+ if (filteredValues.length !== val.length) {
|
|
|
+ modelValue.value = filteredValues;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ const item = getItemByValue(val);
|
|
|
+ if (item && !get(item, props.disabledField)) {
|
|
|
+ treeValue.value = item;
|
|
|
+ } else {
|
|
|
+ treeValue.value = undefined;
|
|
|
+ modelValue.value = undefined;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
function updateModelValue(val: Arrayable<Recordable<any>>) {
|
|
|
- modelValue.value = Array.isArray(val)
|
|
|
- ? val.map((v) => get(v, props.valueField))
|
|
|
- : get(val, props.valueField);
|
|
|
+ if (Array.isArray(val)) {
|
|
|
+ const filteredVal = val.filter((v) => !get(v, props.disabledField));
|
|
|
+ modelValue.value = filteredVal.map((v) => get(v, props.valueField));
|
|
|
+ } else {
|
|
|
+ if (val && !get(val, props.disabledField)) {
|
|
|
+ modelValue.value = get(val, props.valueField);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
function expandToLevel(level: number) {
|
|
@@ -149,10 +171,18 @@ function collapseAll() {
|
|
|
expanded.value = [];
|
|
|
}
|
|
|
|
|
|
+function isNodeDisabled(item: FlattenedItem<Recordable<any>>) {
|
|
|
+ return props.disabled || get(item.value, props.disabledField);
|
|
|
+}
|
|
|
+
|
|
|
function onToggle(item: FlattenedItem<Recordable<any>>) {
|
|
|
emits('expand', item);
|
|
|
}
|
|
|
function onSelect(item: FlattenedItem<Recordable<any>>, isSelected: boolean) {
|
|
|
+ if (isNodeDisabled(item)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
if (
|
|
|
!props.checkStrictly &&
|
|
|
props.multiple &&
|
|
@@ -224,28 +254,34 @@ defineExpose({
|
|
|
:class="
|
|
|
cn('cursor-pointer', getNodeClass?.(item), {
|
|
|
'data-[selected]:bg-accent': !multiple,
|
|
|
- 'cursor-not-allowed': disabled,
|
|
|
+ 'cursor-not-allowed': isNodeDisabled(item),
|
|
|
})
|
|
|
"
|
|
|
v-bind="
|
|
|
Object.assign(item.bind, {
|
|
|
- onfocus: disabled ? 'this.blur()' : undefined,
|
|
|
+ onfocus: isNodeDisabled(item) ? 'this.blur()' : undefined,
|
|
|
+ disabled: isNodeDisabled(item),
|
|
|
})
|
|
|
"
|
|
|
@select="
|
|
|
- (event) => {
|
|
|
+ (event: any) => {
|
|
|
+ if (isNodeDisabled(item)) {
|
|
|
+ event.preventDefault();
|
|
|
+ event.stopPropagation();
|
|
|
+ return;
|
|
|
+ }
|
|
|
if (event.detail.originalEvent.type === 'click') {
|
|
|
event.preventDefault();
|
|
|
}
|
|
|
- !disabled && onSelect(item, event.detail.isSelected);
|
|
|
+ onSelect(item, event.detail.isSelected);
|
|
|
}
|
|
|
"
|
|
|
@toggle="
|
|
|
- (event) => {
|
|
|
+ (event: any) => {
|
|
|
if (event.detail.originalEvent.type === 'click') {
|
|
|
event.preventDefault();
|
|
|
}
|
|
|
- !disabled && onToggle(item);
|
|
|
+ !isNodeDisabled(item) && onToggle(item);
|
|
|
}
|
|
|
"
|
|
|
class="tree-node focus:ring-grass8 my-0.5 flex items-center rounded px-2 py-1 outline-none focus:ring-2"
|
|
@@ -266,24 +302,32 @@ defineExpose({
|
|
|
</div>
|
|
|
<Checkbox
|
|
|
v-if="multiple"
|
|
|
- :checked="isSelected"
|
|
|
- :disabled="disabled"
|
|
|
- :indeterminate="isIndeterminate"
|
|
|
+ :checked="isSelected && !isNodeDisabled(item)"
|
|
|
+ :disabled="isNodeDisabled(item)"
|
|
|
+ :indeterminate="isIndeterminate && !isNodeDisabled(item)"
|
|
|
@click="
|
|
|
- () => {
|
|
|
- !disabled && handleSelect();
|
|
|
- // onSelect(item, !isSelected);
|
|
|
+ (event: MouseEvent) => {
|
|
|
+ if (isNodeDisabled(item)) {
|
|
|
+ event.preventDefault();
|
|
|
+ event.stopPropagation();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ handleSelect();
|
|
|
}
|
|
|
"
|
|
|
/>
|
|
|
<div
|
|
|
class="flex items-center gap-1 pl-2"
|
|
|
@click="
|
|
|
- (_event) => {
|
|
|
- // $event.stopPropagation();
|
|
|
- // $event.preventDefault();
|
|
|
- !disabled && handleSelect();
|
|
|
- // onSelect(item, !isSelected);
|
|
|
+ (event: MouseEvent) => {
|
|
|
+ if (isNodeDisabled(item)) {
|
|
|
+ event.preventDefault();
|
|
|
+ event.stopPropagation();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ event.stopPropagation();
|
|
|
+ event.preventDefault();
|
|
|
+ handleSelect();
|
|
|
}
|
|
|
"
|
|
|
>
|