@veltra/desktop 1.7.19 → 1.8.1
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.
- package/dist/components/batch-edit/batch-edit-form.js +40 -26
- package/dist/components/batch-edit/batch-edit-form.js.map +1 -1
- package/dist/components/batch-edit/use-handlers.js +3 -3
- package/dist/components/batch-edit/use-handlers.js.map +1 -1
- package/dist/components/batch-edit/use-shortcut-key.js +4 -2
- package/dist/components/batch-edit/use-shortcut-key.js.map +1 -1
- package/dist/components/card/style2.css +0 -2
- package/dist/components/condition-editor/condition-editor.js +8 -2
- package/dist/components/condition-editor/condition-editor.js.map +1 -1
- package/dist/components/dropdown/dropdown.js +5 -3
- package/dist/components/dropdown/dropdown.js.map +1 -1
- package/dist/components/expression-editor/components/path-preview.js +3 -6
- package/dist/components/expression-editor/components/path-preview.js.map +1 -1
- package/dist/components/expression-editor/components/variable-picker.js +49 -12
- package/dist/components/expression-editor/components/variable-picker.js.map +1 -1
- package/dist/components/expression-editor/core/editor.js +42 -0
- package/dist/components/expression-editor/core/editor.js.map +1 -1
- package/dist/components/expression-editor/expression-editor.js +68 -22
- package/dist/components/expression-editor/expression-editor.js.map +1 -1
- package/dist/components/expression-editor/style2.css +135 -73
- package/dist/components/form/form.js.map +1 -1
- package/dist/components/form/form.vue_vue_type_script_setup_true_lang.js +0 -1
- package/dist/components/form/form.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/form/style2.css +8 -3
- package/dist/components/form-item/style2.css +14 -0
- package/dist/components/index.d.ts +27 -26
- package/dist/components/index.js +54 -52
- package/dist/components/index.js.map +1 -1
- package/dist/components/kanban/di.js +7 -0
- package/dist/components/kanban/di.js.map +1 -0
- package/dist/components/kanban/kanban-column.js +67 -0
- package/dist/components/kanban/kanban-column.js.map +1 -0
- package/dist/components/kanban/kanban.js +89 -0
- package/dist/components/kanban/kanban.js.map +1 -0
- package/dist/components/kanban/style.d.ts +1 -0
- package/dist/components/kanban/style.js +1 -0
- package/dist/components/kanban/style2.css +128 -0
- package/dist/components/multi-select/multi-select.js +16 -12
- package/dist/components/multi-select/multi-select.js.map +1 -1
- package/dist/components/multi-select/style2.css +7 -0
- package/dist/components/multi-tree-select/multi-tree-select.js +82 -56
- package/dist/components/multi-tree-select/multi-tree-select.js.map +1 -1
- package/dist/components/multi-tree-select/style2.css +7 -0
- package/dist/components/rich-text-editor/image-node.js +154 -0
- package/dist/components/rich-text-editor/image-node.js.map +1 -0
- package/dist/components/rich-text-editor/rich-text-editor.js +80 -22
- package/dist/components/rich-text-editor/rich-text-editor.js.map +1 -1
- package/dist/components/rich-text-editor/style2.css +6 -0
- package/dist/components/rich-text-editor/toolbar.js +22 -2
- package/dist/components/rich-text-editor/toolbar.js.map +1 -1
- package/dist/components/select/select.js +7 -3
- package/dist/components/select/select.js.map +1 -1
- package/dist/components/select/style2.css +7 -0
- package/dist/components/select/use-options.js +14 -3
- package/dist/components/select/use-options.js.map +1 -1
- package/dist/components/tree-select/style2.css +7 -0
- package/dist/components/tree-select/tree-select.js +49 -17
- package/dist/components/tree-select/tree-select.js.map +1 -1
- package/dist/index.d.ts +48 -46
- package/dist/index.js +47 -46
- package/dist/types/dropdown.d.ts +10 -0
- package/dist/types/index.d.ts +3 -2
- package/dist/types/kanban.d.ts +69 -0
- package/dist/types/multi-tree-select.d.ts +7 -1
- package/dist/types/rich-text-editor.d.ts +13 -2
- package/dist/types/tree-select.d.ts +7 -1
- package/package.json +1 -1
- package/src/components/batch-edit/__test__/batch-edit.test.ts +112 -1
- package/src/components/batch-edit/batch-edit-form.vue +21 -2
- package/src/components/batch-edit/use-handlers.ts +6 -5
- package/src/components/batch-edit/use-shortcut-key.ts +5 -2
- package/src/components/card/style.scss +0 -2
- package/src/components/condition-editor/__test__/condition-editor.test.ts +61 -0
- package/src/components/condition-editor/condition-editor.vue +6 -1
- package/src/components/dropdown/dropdown.vue +9 -4
- package/src/components/expression-editor/__test__/editor.test.ts +66 -0
- package/src/components/expression-editor/__test__/expression-editor.test.ts +124 -0
- package/src/components/expression-editor/components/path-preview.vue +1 -2
- package/src/components/expression-editor/components/variable-picker.vue +54 -13
- package/src/components/expression-editor/core/editor.ts +61 -0
- package/src/components/expression-editor/expression-editor.vue +58 -20
- package/src/components/expression-editor/style.scss +160 -76
- package/src/components/form/form.vue +0 -1
- package/src/components/form/style.scss +11 -4
- package/src/components/form-item/style.scss +16 -1
- package/src/components/index.ts +2 -0
- package/src/components/kanban/__test__/kanban.test.ts +212 -0
- package/src/components/kanban/di.ts +19 -0
- package/src/components/kanban/index.ts +1 -0
- package/src/components/kanban/kanban-column.vue +77 -0
- package/src/components/kanban/kanban.vue +81 -0
- package/src/components/kanban/style.scss +124 -0
- package/src/components/kanban/style.ts +1 -0
- package/src/components/multi-select/multi-select.vue +11 -2
- package/src/components/multi-select/style.scss +6 -0
- package/src/components/multi-tree-select/multi-tree-select.vue +58 -9
- package/src/components/multi-tree-select/style.scss +6 -0
- package/src/components/rich-text-editor/image-node.ts +193 -0
- package/src/components/rich-text-editor/rich-text-editor.vue +131 -29
- package/src/components/rich-text-editor/style.scss +7 -0
- package/src/components/rich-text-editor/toolbar.vue +21 -1
- package/src/components/select/__test__/select.test.ts +78 -0
- package/src/components/select/select.vue +13 -3
- package/src/components/select/style.scss +6 -0
- package/src/components/select/use-options.ts +25 -4
- package/src/components/tree-select/__test__/tree-select.test.ts +116 -0
- package/src/components/tree-select/style.scss +6 -0
- package/src/components/tree-select/tree-select.vue +63 -13
- package/src/types/dropdown.ts +10 -0
- package/src/types/index.ts +1 -0
- package/src/types/kanban.ts +63 -0
- package/src/types/multi-tree-select.ts +12 -1
- package/src/types/rich-text-editor.ts +14 -1
- package/src/types/tree-select.ts +12 -1
|
@@ -51,6 +51,11 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
51
51
|
if (props.quickEdit && state.formActionType === "update") return false;
|
|
52
52
|
return creatable.value || updatable.value || creatableChild.value;
|
|
53
53
|
});
|
|
54
|
+
/** 弹框模式新增类操作显示「保存并继续」:保存后重置表单继续录入,不关闭弹框 */
|
|
55
|
+
const showSaveContinueBtn = computed(() => {
|
|
56
|
+
if (props.formMode !== "dialog") return false;
|
|
57
|
+
return creatable.value || creatableChild.value;
|
|
58
|
+
});
|
|
54
59
|
const headerInfo = computed(() => FORM_ACTION_HEADER_MAP[state.formActionType]);
|
|
55
60
|
/** 头部图标色调修饰类:样式中 createChild 对应的修饰类为 is-child */
|
|
56
61
|
const iconToneCls = computed(() => {
|
|
@@ -118,36 +123,45 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
118
123
|
_: 3
|
|
119
124
|
}, 8, ["class"]),
|
|
120
125
|
createElementVNode("footer", { class: normalizeClass(unref(cls).e("form-footer")) }, [createElementVNode("span", { class: normalizeClass(unref(cls).e("form-hint")) }, [unref(props).readonly ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createTextVNode(" 只读模式 ")], 64)) : createCommentVNode("v-if", true), createElementVNode("span", { class: normalizeClass({ [unref(bem).is("concealed")]: !shortcutActive.value }) }, [
|
|
121
|
-
!(unref(state).formActionType === "update" && unref(props).quickEdit) ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createVNode(unref(_sfc_main$4), null, {
|
|
122
|
-
default: withCtx(() => [..._cache[
|
|
126
|
+
unref(props).formMode === "panel" && !(unref(state).formActionType === "update" && unref(props).quickEdit) ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createVNode(unref(_sfc_main$4), null, {
|
|
127
|
+
default: withCtx(() => [..._cache[2] || (_cache[2] = [createTextVNode("Ctrl + S", -1)])]),
|
|
123
128
|
_: 1
|
|
124
|
-
}), _cache[
|
|
129
|
+
}), _cache[3] || (_cache[3] = createTextVNode(" 保存 · ", -1))], 64)) : createCommentVNode("v-if", true),
|
|
125
130
|
createVNode(unref(_sfc_main$4), null, {
|
|
126
|
-
default: withCtx(() => [..._cache[
|
|
131
|
+
default: withCtx(() => [..._cache[4] || (_cache[4] = [createTextVNode("Esc", -1)])]),
|
|
127
132
|
_: 1
|
|
128
133
|
}),
|
|
129
|
-
_cache[
|
|
130
|
-
], 2)], 2), createElementVNode("div", { class: normalizeClass(unref(cls).e("form-actions")) }, [
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
"
|
|
150
|
-
|
|
134
|
+
_cache[5] || (_cache[5] = createTextVNode(" 关闭 ", -1))
|
|
135
|
+
], 2)], 2), createElementVNode("div", { class: normalizeClass(unref(cls).e("form-actions")) }, [
|
|
136
|
+
createVNode(unref(_sfc_main$3), {
|
|
137
|
+
size: "small",
|
|
138
|
+
text: "",
|
|
139
|
+
loading: unref(state).loading,
|
|
140
|
+
onClick: unref(handleClose)
|
|
141
|
+
}, {
|
|
142
|
+
default: withCtx(() => [..._cache[6] || (_cache[6] = [createTextVNode(" 取消 ", -1)])]),
|
|
143
|
+
_: 1
|
|
144
|
+
}, 8, ["loading", "onClick"]),
|
|
145
|
+
showSaveContinueBtn.value ? (openBlock(), createBlock(unref(_sfc_main$3), {
|
|
146
|
+
key: 0,
|
|
147
|
+
size: "small",
|
|
148
|
+
title: "保存并继续",
|
|
149
|
+
loading: unref(state).loading,
|
|
150
|
+
onClick: _cache[0] || (_cache[0] = ($event) => unref(handleSave)(true))
|
|
151
|
+
}, {
|
|
152
|
+
default: withCtx(() => [..._cache[7] || (_cache[7] = [createTextVNode(" 保存并继续 ", -1)])]),
|
|
153
|
+
_: 1
|
|
154
|
+
}, 8, ["loading"])) : createCommentVNode("v-if", true),
|
|
155
|
+
showSaveBtn.value ? (openBlock(), createBlock(unref(_sfc_main$3), {
|
|
156
|
+
key: 1,
|
|
157
|
+
type: "primary",
|
|
158
|
+
size: "small",
|
|
159
|
+
title: "保存",
|
|
160
|
+
icon: unref(Save),
|
|
161
|
+
loading: unref(state).loading,
|
|
162
|
+
onClick: _cache[1] || (_cache[1] = ($event) => unref(handleSave)())
|
|
163
|
+
}, null, 8, ["icon", "loading"])) : createCommentVNode("v-if", true)
|
|
164
|
+
], 2)], 2)
|
|
151
165
|
], 2)), [[vShow, unref(state).formVisible]]) : createCommentVNode("v-if", true)], 2112);
|
|
152
166
|
};
|
|
153
167
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"batch-edit-form.js","names":[],"sources":["../../../src/components/batch-edit/batch-edit-form.vue"],"sourcesContent":["<template>\n <!-- 面板模式:表单常驻挂载(快照只在挂载时对传入的 model 拍一次),仅用 v-show 控制显隐;\n 弹框模式:表单随弹框挂载 / 卸载,model 初始快照由 use-edit-state 维护 -->\n <aside\n :class=\"[cls.e('form'), bem.is('dialog', props.formMode === 'dialog')]\"\n v-if=\"!!props.model\"\n v-show=\"state.formVisible\"\n >\n <header :class=\"cls.e('form-header')\">\n <span :class=\"[cls.e('form-icon'), iconToneCls]\">\n <u-icon>\n <component :is=\"headerInfo.icon\" />\n </u-icon>\n </span>\n <div :class=\"cls.e('form-title')\">\n <h3 :class=\"cls.e('form-title-text')\">{{ headerInfo.title }}</h3>\n </div>\n <u-button\n :class=\"cls.e('form-close')\"\n :icon=\"Close\"\n text\n circle\n size=\"small\"\n title=\"关闭\"\n @click=\"handleClose\"\n />\n </header>\n\n <u-scroll always :class=\"cls.e('form-body')\">\n <transition name=\"fade\" appear mode=\"out-in\">\n <u-form\n ref=\"formComponentRef\"\n :model=\"props.model\"\n :readonly=\"props.readonly\"\n :label-width=\"props.labelWidth\"\n @field:update=\"handleFieldUpdate\"\n >\n <slot\n v-bind=\"{\n row: state.row,\n parentRow: state.parentRow,\n formActionType: state.formActionType,\n depth: state.depth,\n indexes: state.indexPath,\n index: state.row?.index\n }\"\n />\n </u-form>\n </transition>\n </u-scroll>\n\n <footer :class=\"cls.e('form-footer')\">\n <span :class=\"cls.e('form-hint')\">\n <template v-if=\"props.readonly\"> 只读模式 </template>\n\n <span :class=\"{ [bem.is('concealed')]: !shortcutActive }\">\n <template v-if=\"!(state.formActionType === 'update' && props.quickEdit)\">\n <u-kbd>Ctrl + S</u-kbd> 保存 ·\n </template>\n <u-kbd>Esc</u-kbd> 关闭\n </span>\n </span>\n\n <div :class=\"cls.e('form-actions')\">\n <u-button size=\"small\" text :loading=\"state.loading\" @click=\"handleClose\"> 取消 </u-button>\n <u-button\n v-if=\"showSaveBtn\"\n type=\"primary\"\n size=\"small\"\n title=\"保存\"\n :icon=\"Save\"\n :loading=\"state.loading\"\n @click=\"handleSave\"\n />\n </div>\n </footer>\n </aside>\n</template>\n\n<script lang=\"ts\" setup>\nimport { o } from '@cat-kit/core'\nimport { Close, Save } from '@veltra/icons/normal'\nimport { bem } from '@veltra/utils'\nimport { computed, inject, shallowRef, toRef } from 'vue'\n\nimport type { _FormExposed, FormExposed } from '../../types/form'\nimport { UButton } from '../button'\nimport { UForm } from '../form'\nimport { UIcon } from '../icon'\nimport { UKbd } from '../kbd'\nimport { UScroll } from '../scroll'\nimport { BatchEditDIKey } from './di'\nimport { FORM_ACTION_HEADER_MAP } from './form-action-header'\nimport { useDialogEffect } from './use-dialog-effect'\n\ndefineOptions({ name: 'UBatchEditForm' })\n\nconst batchEditCtx = inject(BatchEditDIKey)!\n\nconst { cls, props, state, handleClose, handleSave, staticFeatures, dynamicFeatures, syncing } =\n batchEditCtx\n\nconst focused = toRef(batchEditCtx, 'focused')\n\n// 弹框模式下,弹框自身关闭(遮罩点击 / 右上角关闭)时同步走 handleClose,不保存\nuseDialogEffect({ closeForm: handleClose })\n\n/** 快捷键提示是否可见:面板模式随聚焦显隐;弹框模式弹框打开期间快捷键始终可用 */\nconst shortcutActive = computed(() => {\n return props.formMode === 'dialog' ? state.formVisible : focused.value\n})\n\nconst formComponentRef = shallowRef<FormExposed>()\n\ndefineExpose<_FormExposed>({\n el: toRef(() => formComponentRef.value?.el),\n validate: () => formComponentRef.value?.validate() ?? Promise.resolve(true),\n clearValidate: () => formComponentRef.value?.clearValidate(),\n reset: () => formComponentRef.value?.reset()\n})\n\nfunction handleFieldUpdate(field: string, value: any) {\n // 编程方式重置/回显期间不写回行数据,避免默认值污染源数据\n if (syncing.value) return\n\n if (state.row && props.quickEdit) {\n o(state.row.data).set(field, value)\n }\n}\n\nconst creatable = computed(() => {\n if (state.formActionType !== 'create') return false\n return staticFeatures.value.has('create') || dynamicFeatures.value.create?.(state.row)\n})\n\nconst creatableChild = computed(() => {\n if (state.formActionType !== 'createChild') return false\n return (\n staticFeatures.value.has('createChild') || dynamicFeatures.value.createChild?.(state.parentRow)\n )\n})\n\nconst updatable = computed(() => {\n if (state.formActionType !== 'update') return false\n return staticFeatures.value.has('update') || dynamicFeatures.value.update?.(state.row)\n})\n\nconst showSaveBtn = computed(() => {\n if (props.readonly) return false\n if (props.quickEdit && state.formActionType === 'update') return false\n return creatable.value || updatable.value || creatableChild.value\n})\n\nconst headerInfo = computed(() => FORM_ACTION_HEADER_MAP[state.formActionType])\n\n/** 头部图标色调修饰类:样式中 createChild 对应的修饰类为 is-child */\nconst iconToneCls = computed(() => {\n const type = state.formActionType\n return bem.is(type === 'createChild' ? 'child' : type)\n})\n</script>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"batch-edit-form.js","names":[],"sources":["../../../src/components/batch-edit/batch-edit-form.vue"],"sourcesContent":["<template>\n <!-- 面板模式:表单常驻挂载(快照只在挂载时对传入的 model 拍一次),仅用 v-show 控制显隐;\n 弹框模式:表单随弹框挂载 / 卸载,model 初始快照由 use-edit-state 维护 -->\n <aside\n :class=\"[cls.e('form'), bem.is('dialog', props.formMode === 'dialog')]\"\n v-if=\"!!props.model\"\n v-show=\"state.formVisible\"\n >\n <header :class=\"cls.e('form-header')\">\n <span :class=\"[cls.e('form-icon'), iconToneCls]\">\n <u-icon>\n <component :is=\"headerInfo.icon\" />\n </u-icon>\n </span>\n <div :class=\"cls.e('form-title')\">\n <h3 :class=\"cls.e('form-title-text')\">{{ headerInfo.title }}</h3>\n </div>\n <u-button\n :class=\"cls.e('form-close')\"\n :icon=\"Close\"\n text\n circle\n size=\"small\"\n title=\"关闭\"\n @click=\"handleClose\"\n />\n </header>\n\n <u-scroll always :class=\"cls.e('form-body')\">\n <transition name=\"fade\" appear mode=\"out-in\">\n <u-form\n ref=\"formComponentRef\"\n :model=\"props.model\"\n :readonly=\"props.readonly\"\n :label-width=\"props.labelWidth\"\n @field:update=\"handleFieldUpdate\"\n >\n <slot\n v-bind=\"{\n row: state.row,\n parentRow: state.parentRow,\n formActionType: state.formActionType,\n depth: state.depth,\n indexes: state.indexPath,\n index: state.row?.index\n }\"\n />\n </u-form>\n </transition>\n </u-scroll>\n\n <footer :class=\"cls.e('form-footer')\">\n <span :class=\"cls.e('form-hint')\">\n <template v-if=\"props.readonly\"> 只读模式 </template>\n\n <span :class=\"{ [bem.is('concealed')]: !shortcutActive }\">\n <template\n v-if=\"\n props.formMode === 'panel' && !(state.formActionType === 'update' && props.quickEdit)\n \"\n >\n <u-kbd>Ctrl + S</u-kbd> 保存 ·\n </template>\n <u-kbd>Esc</u-kbd> 关闭\n </span>\n </span>\n\n <div :class=\"cls.e('form-actions')\">\n <u-button size=\"small\" text :loading=\"state.loading\" @click=\"handleClose\"> 取消 </u-button>\n <u-button\n v-if=\"showSaveContinueBtn\"\n size=\"small\"\n title=\"保存并继续\"\n :loading=\"state.loading\"\n @click=\"handleSave(true)\"\n >\n 保存并继续\n </u-button>\n <u-button\n v-if=\"showSaveBtn\"\n type=\"primary\"\n size=\"small\"\n title=\"保存\"\n :icon=\"Save\"\n :loading=\"state.loading\"\n @click=\"handleSave()\"\n />\n </div>\n </footer>\n </aside>\n</template>\n\n<script lang=\"ts\" setup>\nimport { o } from '@cat-kit/core'\nimport { Close, Save } from '@veltra/icons/normal'\nimport { bem } from '@veltra/utils'\nimport { computed, inject, shallowRef, toRef } from 'vue'\n\nimport type { _FormExposed, FormExposed } from '../../types/form'\nimport { UButton } from '../button'\nimport { UForm } from '../form'\nimport { UIcon } from '../icon'\nimport { UKbd } from '../kbd'\nimport { UScroll } from '../scroll'\nimport { BatchEditDIKey } from './di'\nimport { FORM_ACTION_HEADER_MAP } from './form-action-header'\nimport { useDialogEffect } from './use-dialog-effect'\n\ndefineOptions({ name: 'UBatchEditForm' })\n\nconst batchEditCtx = inject(BatchEditDIKey)!\n\nconst { cls, props, state, handleClose, handleSave, staticFeatures, dynamicFeatures, syncing } =\n batchEditCtx\n\nconst focused = toRef(batchEditCtx, 'focused')\n\n// 弹框模式下,弹框自身关闭(遮罩点击 / 右上角关闭)时同步走 handleClose,不保存\nuseDialogEffect({ closeForm: handleClose })\n\n/** 快捷键提示是否可见:面板模式随聚焦显隐;弹框模式弹框打开期间快捷键始终可用 */\nconst shortcutActive = computed(() => {\n return props.formMode === 'dialog' ? state.formVisible : focused.value\n})\n\nconst formComponentRef = shallowRef<FormExposed>()\n\ndefineExpose<_FormExposed>({\n el: toRef(() => formComponentRef.value?.el),\n validate: () => formComponentRef.value?.validate() ?? Promise.resolve(true),\n clearValidate: () => formComponentRef.value?.clearValidate(),\n reset: () => formComponentRef.value?.reset()\n})\n\nfunction handleFieldUpdate(field: string, value: any) {\n // 编程方式重置/回显期间不写回行数据,避免默认值污染源数据\n if (syncing.value) return\n\n if (state.row && props.quickEdit) {\n o(state.row.data).set(field, value)\n }\n}\n\nconst creatable = computed(() => {\n if (state.formActionType !== 'create') return false\n return staticFeatures.value.has('create') || dynamicFeatures.value.create?.(state.row)\n})\n\nconst creatableChild = computed(() => {\n if (state.formActionType !== 'createChild') return false\n return (\n staticFeatures.value.has('createChild') || dynamicFeatures.value.createChild?.(state.parentRow)\n )\n})\n\nconst updatable = computed(() => {\n if (state.formActionType !== 'update') return false\n return staticFeatures.value.has('update') || dynamicFeatures.value.update?.(state.row)\n})\n\nconst showSaveBtn = computed(() => {\n if (props.readonly) return false\n if (props.quickEdit && state.formActionType === 'update') return false\n return creatable.value || updatable.value || creatableChild.value\n})\n\n/** 弹框模式新增类操作显示「保存并继续」:保存后重置表单继续录入,不关闭弹框 */\nconst showSaveContinueBtn = computed(() => {\n if (props.formMode !== 'dialog') return false\n return creatable.value || creatableChild.value\n})\n\nconst headerInfo = computed(() => FORM_ACTION_HEADER_MAP[state.formActionType])\n\n/** 头部图标色调修饰类:样式中 createChild 对应的修饰类为 is-child */\nconst iconToneCls = computed(() => {\n const type = state.formActionType\n return bem.is(type === 'createChild' ? 'child' : type)\n})\n</script>\n"],"mappings":"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"}
|
|
@@ -97,8 +97,8 @@ function useHandlers(options) {
|
|
|
97
97
|
if (state.row) state.row.operating = false;
|
|
98
98
|
};
|
|
99
99
|
}
|
|
100
|
-
/**
|
|
101
|
-
const handleSave = runWithLoading(async () => {
|
|
100
|
+
/** 保存;keepOpen 为 true 时(「保存并继续」)新增保存后不关闭表单 */
|
|
101
|
+
const handleSave = runWithLoading(async (keepOpen = false) => {
|
|
102
102
|
const { model, saveMethod } = props;
|
|
103
103
|
const valid = await formRef.value?.validate();
|
|
104
104
|
if (!model || !valid) return;
|
|
@@ -110,7 +110,7 @@ function useHandlers(options) {
|
|
|
110
110
|
if (result) item = result;
|
|
111
111
|
}
|
|
112
112
|
insert(item);
|
|
113
|
-
if (props.formMode === "dialog") {
|
|
113
|
+
if (props.formMode === "dialog" && !keepOpen) {
|
|
114
114
|
resetState();
|
|
115
115
|
return;
|
|
116
116
|
}
|
|
@@ -1 +1 @@
|
|
|
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 // 重入保护:进行中(快捷键/按钮并发触发)直接忽略\n if (state.loading) return\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 /**
|
|
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 /** @param keepOpen 新增类操作保存后不关闭表单(弹框模式「保存并继续」) */\n handleSave: (keepOpen?: boolean) => 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 // 重入保护:进行中(快捷键/按钮并发触发)直接忽略\n if (state.loading) return\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 /** 保存;keepOpen 为 true 时(「保存并继续」)新增保存后不关闭表单 */\n const handleSave = runWithLoading(async (keepOpen = false) => {\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 if (props.formMode === 'dialog' && !keepOpen) {\n resetState()\n return\n }\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 if (props.formMode === 'dialog') {\n resetState()\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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"}
|
|
@@ -24,15 +24,17 @@ function useShortcutKey(options) {
|
|
|
24
24
|
/**
|
|
25
25
|
* 键盘快捷键:
|
|
26
26
|
* - Esc 关闭表单
|
|
27
|
-
* - ⌘/Ctrl + S
|
|
27
|
+
* - ⌘/Ctrl + S 保存(仅面板模式;快速编辑模式下编辑行时除外)
|
|
28
28
|
*
|
|
29
29
|
* 面板模式仅组件获焦时生效;弹框模式表单被 teleport 到 body,
|
|
30
|
-
*
|
|
30
|
+
* 组件聚焦状态覆盖不到,改为弹框打开期间生效。
|
|
31
|
+
* 弹框模式不支持 ⌘/Ctrl + S 保存,保存只能走底部按钮
|
|
31
32
|
*/
|
|
32
33
|
function handleKeydown(e) {
|
|
33
34
|
if (!(props.formMode === "dialog" ? state.formVisible : focused.value)) return;
|
|
34
35
|
if (props.readonly && e.key !== "Escape") return;
|
|
35
36
|
if (e.key === "Escape") return runEscape(e);
|
|
37
|
+
if (props.formMode === "dialog") return;
|
|
36
38
|
if (!(e.metaKey || e.ctrlKey)) return;
|
|
37
39
|
if (e.key.toLowerCase() === "s") return runSave(e);
|
|
38
40
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-shortcut-key.js","names":[],"sources":["../../../src/components/batch-edit/use-shortcut-key.ts"],"sourcesContent":["import { shallowRef } from 'vue'\n\nimport type { BatchEditProps, BatchEditStates } from '../../types'\n\ninterface Options {\n props: BatchEditProps\n onSave: () => void\n onClose: () => void\n state: BatchEditStates\n}\nexport function useShortcutKey(options: Options) {\n const { props, onClose, onSave, state } = options\n const focused = shallowRef(false)\n\n function handleFocusIn() {\n focused.value = true\n }\n\n function handleFocusOut(e: FocusEvent) {\n const root = e.currentTarget as HTMLElement\n if (!root.contains(e.relatedTarget as Node | null)) {\n focused.value = false\n }\n }\n\n function runEscape(e: KeyboardEvent) {\n if (!state.formVisible) return\n e.preventDefault()\n e.stopPropagation()\n onClose()\n }\n\n function runSave(e: KeyboardEvent) {\n if (!state.formVisible) return\n if (props.quickEdit && state.formActionType === 'update') return\n e.preventDefault()\n onSave()\n }\n\n /**\n * 键盘快捷键:\n * - Esc 关闭表单\n * - ⌘/Ctrl + S
|
|
1
|
+
{"version":3,"file":"use-shortcut-key.js","names":[],"sources":["../../../src/components/batch-edit/use-shortcut-key.ts"],"sourcesContent":["import { shallowRef } from 'vue'\n\nimport type { BatchEditProps, BatchEditStates } from '../../types'\n\ninterface Options {\n props: BatchEditProps\n onSave: () => void\n onClose: () => void\n state: BatchEditStates\n}\nexport function useShortcutKey(options: Options) {\n const { props, onClose, onSave, state } = options\n const focused = shallowRef(false)\n\n function handleFocusIn() {\n focused.value = true\n }\n\n function handleFocusOut(e: FocusEvent) {\n const root = e.currentTarget as HTMLElement\n if (!root.contains(e.relatedTarget as Node | null)) {\n focused.value = false\n }\n }\n\n function runEscape(e: KeyboardEvent) {\n if (!state.formVisible) return\n e.preventDefault()\n e.stopPropagation()\n onClose()\n }\n\n function runSave(e: KeyboardEvent) {\n if (!state.formVisible) return\n if (props.quickEdit && state.formActionType === 'update') return\n e.preventDefault()\n onSave()\n }\n\n /**\n * 键盘快捷键:\n * - Esc 关闭表单\n * - ⌘/Ctrl + S 保存(仅面板模式;快速编辑模式下编辑行时除外)\n *\n * 面板模式仅组件获焦时生效;弹框模式表单被 teleport 到 body,\n * 组件聚焦状态覆盖不到,改为弹框打开期间生效。\n * 弹框模式不支持 ⌘/Ctrl + S 保存,保存只能走底部按钮\n */\n function handleKeydown(e: KeyboardEvent) {\n const active = props.formMode === 'dialog' ? state.formVisible : focused.value\n if (!active) return\n if (props.readonly && e.key !== 'Escape') return\n\n if (e.key === 'Escape') return runEscape(e)\n\n if (props.formMode === 'dialog') return\n\n const meta = e.metaKey || e.ctrlKey\n if (!meta) return\n\n const key = e.key.toLowerCase()\n\n if (key === 's') return runSave(e)\n }\n\n return { focused, handleFocusIn, handleFocusOut, handleKeydown }\n}\n"],"mappings":";;AAUA,SAAgB,eAAe,SAAkB;CAC/C,MAAM,EAAE,OAAO,SAAS,QAAQ,UAAU;CAC1C,MAAM,UAAU,WAAW,KAAK;CAEhC,SAAS,gBAAgB;EACvB,QAAQ,QAAQ;CAClB;CAEA,SAAS,eAAe,GAAe;EAErC,IAAI,CADS,EAAE,cACL,SAAS,EAAE,aAA4B,GAC/C,QAAQ,QAAQ;CAEpB;CAEA,SAAS,UAAU,GAAkB;EACnC,IAAI,CAAC,MAAM,aAAa;EACxB,EAAE,eAAe;EACjB,EAAE,gBAAgB;EAClB,QAAQ;CACV;CAEA,SAAS,QAAQ,GAAkB;EACjC,IAAI,CAAC,MAAM,aAAa;EACxB,IAAI,MAAM,aAAa,MAAM,mBAAmB,UAAU;EAC1D,EAAE,eAAe;EACjB,OAAO;CACT;;;;;;;;;;CAWA,SAAS,cAAc,GAAkB;EAEvC,IAAI,EADW,MAAM,aAAa,WAAW,MAAM,cAAc,QAAQ,QAC5D;EACb,IAAI,MAAM,YAAY,EAAE,QAAQ,UAAU;EAE1C,IAAI,EAAE,QAAQ,UAAU,OAAO,UAAU,CAAC;EAE1C,IAAI,MAAM,aAAa,UAAU;EAGjC,IAAI,EADS,EAAE,WAAW,EAAE,UACjB;EAIX,IAFY,EAAE,IAAI,YAEZ,MAAM,KAAK,OAAO,QAAQ,CAAC;CACnC;CAEA,OAAO;EAAE;EAAS;EAAe;EAAgB;CAAc;AACjE"}
|
|
@@ -18,14 +18,12 @@
|
|
|
18
18
|
.u-card {
|
|
19
19
|
border-radius: var(--u-card-radius, var(--u-radius-large));
|
|
20
20
|
background-color: var(--u-bg-color-top);
|
|
21
|
-
border: var(--u-border-muted);
|
|
22
21
|
box-shadow: var(--u-shadow-sm);
|
|
23
22
|
backdrop-filter: var(--u-bg-filter);
|
|
24
23
|
-webkit-backdrop-filter: var(--u-bg-filter);
|
|
25
24
|
overflow: hidden;
|
|
26
25
|
}
|
|
27
26
|
.u-card.is-integrate {
|
|
28
|
-
border: none;
|
|
29
27
|
box-shadow: none;
|
|
30
28
|
--u-card-header-bg: transparent;
|
|
31
29
|
--u-card-action-bg: transparent;
|
|
@@ -13,8 +13,14 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
13
13
|
fields: { default: () => [] },
|
|
14
14
|
variables: {},
|
|
15
15
|
size: {},
|
|
16
|
-
disabled: {
|
|
17
|
-
|
|
16
|
+
disabled: {
|
|
17
|
+
type: Boolean,
|
|
18
|
+
default: void 0
|
|
19
|
+
},
|
|
20
|
+
readonly: {
|
|
21
|
+
type: Boolean,
|
|
22
|
+
default: void 0
|
|
23
|
+
}
|
|
18
24
|
},
|
|
19
25
|
emits: ["update:modelValue"],
|
|
20
26
|
setup(__props, { emit: __emit }) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"condition-editor.js","names":[],"sources":["../../../src/components/condition-editor/condition-editor.vue"],"sourcesContent":["<template>\n <div :class=\"className\" @keydown=\"onKeydown\">\n <ConditionGroup\n :group=\"rootGroup\"\n :fields=\"props.fields\"\n :size=\"size\"\n :disabled=\"disabled\"\n :readonly=\"readonly\"\n @update:group=\"onGroupUpdate\"\n @mention=\"onMention\"\n />\n\n <VariablePicker\n ref=\"pickerRef\"\n :visible=\"pickerVisible\"\n :trigger-dom=\"pickerTriggerDom\"\n :variables=\"props.variables\"\n :filter=\"pickerFilter\"\n :selectable-levels=\"'leaf'\"\n @select=\"onPickerSelect\"\n @dismiss=\"onPickerDismiss\"\n @update:visible=\"onPickerVisibleChange\"\n />\n </div>\n</template>\n\n<script lang=\"ts\" setup>\nimport { useFormFallbackProps } from '@veltra/compositions'\nimport { bem, injectFormContext } from '@veltra/utils'\nimport { computed, shallowRef, useTemplateRef, watch } from 'vue'\n\nimport type { ConditionEditorProps, ConditionExpression } from '../../types'\nimport VariablePicker from '../expression-editor/components/variable-picker.vue'\nimport ConditionGroup from './components/condition-group.vue'\nimport type { MentionPayload } from './components/condition-row.vue'\nimport { createEmptyGroup } from './core/evaluator'\n\ndefineOptions({ name: 'UConditionEditor' })\n\nconst props = withDefaults(defineProps<ConditionEditorProps>(), {
|
|
1
|
+
{"version":3,"file":"condition-editor.js","names":[],"sources":["../../../src/components/condition-editor/condition-editor.vue"],"sourcesContent":["<template>\n <div :class=\"className\" @keydown=\"onKeydown\">\n <ConditionGroup\n :group=\"rootGroup\"\n :fields=\"props.fields\"\n :size=\"size\"\n :disabled=\"disabled\"\n :readonly=\"readonly\"\n @update:group=\"onGroupUpdate\"\n @mention=\"onMention\"\n />\n\n <VariablePicker\n ref=\"pickerRef\"\n :visible=\"pickerVisible\"\n :trigger-dom=\"pickerTriggerDom\"\n :variables=\"props.variables\"\n :filter=\"pickerFilter\"\n :selectable-levels=\"'leaf'\"\n @select=\"onPickerSelect\"\n @dismiss=\"onPickerDismiss\"\n @update:visible=\"onPickerVisibleChange\"\n />\n </div>\n</template>\n\n<script lang=\"ts\" setup>\nimport { useFormFallbackProps } from '@veltra/compositions'\nimport { bem, injectFormContext } from '@veltra/utils'\nimport { computed, shallowRef, useTemplateRef, watch } from 'vue'\n\nimport type { ConditionEditorProps, ConditionExpression } from '../../types'\nimport VariablePicker from '../expression-editor/components/variable-picker.vue'\nimport ConditionGroup from './components/condition-group.vue'\nimport type { MentionPayload } from './components/condition-row.vue'\nimport { createEmptyGroup } from './core/evaluator'\n\ndefineOptions({ name: 'UConditionEditor' })\n\nconst props = withDefaults(defineProps<ConditionEditorProps>(), {\n fields: () => [],\n // Boolean prop 缺省会被 Vue 归一成 false,挡住 UForm 下发的 disabled / readonly,须显式留 undefined\n disabled: undefined,\n readonly: undefined\n})\n\nconst emit = defineEmits<{ (e: 'update:modelValue', value: ConditionExpression): void }>()\n\nconst cls = bem('condition-editor')\nconst { formProps } = injectFormContext()\nconst { size, disabled, readonly } = useFormFallbackProps([formProps ?? {}, props])\n\nconst className = computed(() => [\n cls.b,\n cls.m(size.value),\n bem.is('disabled', disabled.value),\n bem.is('readonly', readonly.value)\n])\n\nconst rootGroup = shallowRef<ConditionExpression>(\n props.modelValue ? clone(props.modelValue) : createEmptyGroup()\n)\n\nfunction clone<T>(v: T): T {\n return JSON.parse(JSON.stringify(v)) as T\n}\n\nfunction onGroupUpdate(group: ConditionExpression) {\n rootGroup.value = group\n emit('update:modelValue', clone(group))\n}\n\nwatch(\n () => props.modelValue,\n (v) => {\n if (!v) {\n rootGroup.value = createEmptyGroup()\n return\n }\n if (JSON.stringify(v) === JSON.stringify(rootGroup.value)) return\n rootGroup.value = clone(v)\n }\n)\n\n// ── VariablePicker ──\n\nconst pickerRef = useTemplateRef<{ handleKeydown: (e: KeyboardEvent) => boolean }>('pickerRef')\nconst pickerVisible = shallowRef(false)\nconst pickerTriggerDom = shallowRef<HTMLElement | undefined>(undefined)\nconst pickerFilter = shallowRef('')\nconst mentionTarget = shallowRef<MentionPayload | null>(null)\n\nfunction onMention(payload: MentionPayload) {\n if (disabled.value || readonly.value) return\n mentionTarget.value = payload\n pickerTriggerDom.value = payload.triggerDom\n pickerFilter.value = ''\n pickerVisible.value = true\n}\n\nfunction onPickerSelect(item: { label: string; value: string }) {\n mentionTarget.value?.setValue({ kind: 'variable', name: item.value })\n pickerVisible.value = false\n mentionTarget.value = null\n}\n\nfunction onPickerDismiss() {\n pickerVisible.value = false\n mentionTarget.value = null\n}\n\nfunction onPickerVisibleChange(v: boolean) {\n if (!v) {\n pickerVisible.value = false\n mentionTarget.value = null\n }\n}\n\nfunction onKeydown(e: KeyboardEvent) {\n if (disabled.value || readonly.value) return\n if (pickerVisible.value) {\n const handled = pickerRef.value?.handleKeydown(e)\n if (handled) {\n e.preventDefault()\n }\n }\n}\n</script>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;EAuCA,MAAM,QAAQ;EAOd,MAAM,OAAO;EAEb,MAAM,MAAM,IAAI,kBAAkB;EAClC,MAAM,EAAE,cAAc,kBAAkB;EACxC,MAAM,EAAE,MAAM,UAAU,aAAa,qBAAqB,CAAC,aAAa,CAAC,GAAG,KAAK,CAAC;EAElF,MAAM,YAAY,eAAe;GAC/B,IAAI;GACJ,IAAI,EAAE,KAAK,KAAK;GAChB,IAAI,GAAG,YAAY,SAAS,KAAK;GACjC,IAAI,GAAG,YAAY,SAAS,KAAK;EACnC,CAAC;EAED,MAAM,YAAY,WAChB,MAAM,aAAa,MAAM,MAAM,UAAU,IAAI,iBAAiB,CAChE;EAEA,SAAS,MAAS,GAAS;GACzB,OAAO,KAAK,MAAM,KAAK,UAAU,CAAC,CAAC;EACrC;EAEA,SAAS,cAAc,OAA4B;GACjD,UAAU,QAAQ;GAClB,KAAK,qBAAqB,MAAM,KAAK,CAAC;EACxC;EAEA,YACQ,MAAM,aACX,MAAM;GACL,IAAI,CAAC,GAAG;IACN,UAAU,QAAQ,iBAAiB;IACnC;GACF;GACA,IAAI,KAAK,UAAU,CAAC,MAAM,KAAK,UAAU,UAAU,KAAK,GAAG;GAC3D,UAAU,QAAQ,MAAM,CAAC;EAC3B,CACF;EAIA,MAAM,YAAY,eAAiE,WAAW;EAC9F,MAAM,gBAAgB,WAAW,KAAK;EACtC,MAAM,mBAAmB,WAAoC,KAAA,CAAS;EACtE,MAAM,eAAe,WAAW,EAAE;EAClC,MAAM,gBAAgB,WAAkC,IAAI;EAE5D,SAAS,UAAU,SAAyB;GAC1C,IAAI,SAAS,SAAS,SAAS,OAAO;GACtC,cAAc,QAAQ;GACtB,iBAAiB,QAAQ,QAAQ;GACjC,aAAa,QAAQ;GACrB,cAAc,QAAQ;EACxB;EAEA,SAAS,eAAe,MAAwC;GAC9D,cAAc,OAAO,SAAS;IAAE,MAAM;IAAY,MAAM,KAAK;GAAM,CAAC;GACpE,cAAc,QAAQ;GACtB,cAAc,QAAQ;EACxB;EAEA,SAAS,kBAAkB;GACzB,cAAc,QAAQ;GACtB,cAAc,QAAQ;EACxB;EAEA,SAAS,sBAAsB,GAAY;GACzC,IAAI,CAAC,GAAG;IACN,cAAc,QAAQ;IACtB,cAAc,QAAQ;GACxB;EACF;EAEA,SAAS,UAAU,GAAkB;GACnC,IAAI,SAAS,SAAS,SAAS,OAAO;GACtC,IAAI,cAAc,OACA;QAAA,UAAU,OAAO,cAAc,CAAC,GAE9C,EAAE,eAAe;GAAA;EAGvB;;GA7HE,OAAA,UAAA,GAAA,mBAsBM,OAAA;IAtBA,OAAK,eAAE,UAAA,KAAS;IAAY;GAChC,GAAA,CAAA,YAQE,aAAA;IAPC,OAAO,UAAA;IACP,QAAQ,MAAM;IACd,MAAM,MAAA,IAAA;IACN,UAAU,MAAA,QAAA;IACV,UAAU,MAAA,QAAA;IACV,kBAAc;IACL;;;;;;;GAGZ,CAAA,GAAA,YAUE,aAAA;IATI,SAAA;IAAJ,KAAI;IACH,SAAS,cAAA;IACT,eAAa,iBAAA;IACb,WAAW,MAAM;IACjB,QAAQ,aAAA;IACR,qBAAmB;IACnB,UAAQ;IACR,WAAS;IACT,oBAAgB"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import NodeRender from "../node-render/node-render.js";
|
|
2
2
|
import { useNest } from "../tip/use-nest.js";
|
|
3
|
-
import { Fragment, Teleport, cloneVNode, computed, createBlock, createCommentVNode, createElementBlock, createVNode, defineComponent, normalizeClass, normalizeStyle, openBlock, renderSlot, resolveDynamicComponent, shallowRef, unref, useAttrs, useSlots, useTemplateRef, withCtx, withDirectives } from "vue";
|
|
3
|
+
import { Fragment, Teleport, cloneVNode, computed, createBlock, createCommentVNode, createElementBlock, createVNode, defineComponent, normalizeClass, normalizeStyle, openBlock, renderSlot, resolveDynamicComponent, shallowRef, toRef, unref, useAttrs, useSlots, useTemplateRef, withCtx, withDirectives } from "vue";
|
|
4
4
|
import { useModel as useModel$1, usePop, useTransition } from "@veltra/compositions";
|
|
5
5
|
import { bem, extractNormalVNodes, setStyles, zIndex } from "@veltra/utils";
|
|
6
6
|
import { vClickOutside } from "@veltra/directives";
|
|
@@ -11,6 +11,8 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
11
11
|
__name: "dropdown",
|
|
12
12
|
props: {
|
|
13
13
|
trigger: { default: "hover" },
|
|
14
|
+
direction: { default: "bottom" },
|
|
15
|
+
alignment: { default: "start" },
|
|
14
16
|
width: {},
|
|
15
17
|
minWidth: {},
|
|
16
18
|
contentTag: { default: "div" },
|
|
@@ -86,8 +88,8 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
86
88
|
const { update, popperContainerId } = usePop({
|
|
87
89
|
triggerRef: triggerDom,
|
|
88
90
|
contentRef,
|
|
89
|
-
direction:
|
|
90
|
-
alignment:
|
|
91
|
+
direction: toRef(() => props.direction),
|
|
92
|
+
alignment: toRef(() => props.alignment),
|
|
91
93
|
onPop(position) {
|
|
92
94
|
transitionName.value = position.placement.includes("top") ? "slide-up" : "slide-down";
|
|
93
95
|
transition.enter();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dropdown.js","names":[],"sources":["../../../src/components/dropdown/dropdown.vue"],"sourcesContent":["<template>\n <UNodeRender :content=\"renderTriggerNode()\" ref=\"trigger\" />\n\n <Teleport :to=\"`#${popperContainerId}`\">\n <component\n v-if=\"dropdownVisible\"\n ref=\"contentRef\"\n :is=\"contentTag\"\n :class=\"dropdownContentClass\"\n :style=\"[{ zIndex: zIndex() }, contentStyle]\"\n @mouseenter=\"eventsHandlers.onMouseenter\"\n @mouseleave=\"eventsHandlers.onMouseleave\"\n @keydown=\"emit('keydown', $event)\"\n v-click-outside=\"trigger === 'click' ? handleClickOutside : undefined\"\n >\n <slot name=\"content\" />\n </component>\n </Teleport>\n</template>\n\n<script lang=\"ts\" setup>\nimport { useModel, usePop, useTransition } from '@veltra/compositions'\nimport { vClickOutside } from '@veltra/directives'\nimport { bem, extractNormalVNodes, setStyles, zIndex } from '@veltra/utils'\nimport { shallowRef, computed, createVNode, cloneVNode, useTemplateRef, useAttrs } from 'vue'\n\nimport type { DropdownProps, DropdownExposed, DropdownEmits } from '../../types'\nimport { UNodeRender } from '../node-render'\nimport { useNest } from '../tip/use-nest'\n\ndefineOptions({ name: 'UDropdown', inheritAttrs: false })\n\nconst props = withDefaults(defineProps<DropdownProps>(), {
|
|
1
|
+
{"version":3,"file":"dropdown.js","names":[],"sources":["../../../src/components/dropdown/dropdown.vue"],"sourcesContent":["<template>\n <UNodeRender :content=\"renderTriggerNode()\" ref=\"trigger\" />\n\n <Teleport :to=\"`#${popperContainerId}`\">\n <component\n v-if=\"dropdownVisible\"\n ref=\"contentRef\"\n :is=\"contentTag\"\n :class=\"dropdownContentClass\"\n :style=\"[{ zIndex: zIndex() }, contentStyle]\"\n @mouseenter=\"eventsHandlers.onMouseenter\"\n @mouseleave=\"eventsHandlers.onMouseleave\"\n @keydown=\"emit('keydown', $event)\"\n v-click-outside=\"trigger === 'click' ? handleClickOutside : undefined\"\n >\n <slot name=\"content\" />\n </component>\n </Teleport>\n</template>\n\n<script lang=\"ts\" setup>\nimport { useModel, usePop, useTransition } from '@veltra/compositions'\nimport { vClickOutside } from '@veltra/directives'\nimport { bem, extractNormalVNodes, setStyles, zIndex } from '@veltra/utils'\nimport { shallowRef, computed, createVNode, cloneVNode, useTemplateRef, useAttrs, toRef } from 'vue'\n\nimport type { DropdownProps, DropdownExposed, DropdownEmits } from '../../types'\nimport { UNodeRender } from '../node-render'\nimport { useNest } from '../tip/use-nest'\n\ndefineOptions({ name: 'UDropdown', inheritAttrs: false })\n\nconst props = withDefaults(defineProps<DropdownProps>(), {\n trigger: 'hover',\n direction: 'bottom',\n alignment: 'start',\n contentTag: 'div'\n})\n\nconst emit = defineEmits<DropdownEmits>()\n\nconst slots = defineSlots<{\n /** 内容 */\n content?: () => any\n /** 触发器 */\n trigger?: () => any\n}>()\n\nconst cls = bem('dropdown')\n\nconst dropdownContentClass = computed(() => {\n let fixed = [cls.e('content')]\n const className = props.contentClass\n if (!className) return fixed\n if (!Array.isArray(className)) {\n return [...fixed, className]\n }\n return [...fixed, ...className]\n})\n\nconst triggerRef = useTemplateRef('trigger')\nconst customTriggerRef = shallowRef<HTMLElement>()\nconst contentRef = shallowRef<HTMLElement>()\n\nconst triggerDom = computed(() => {\n return customTriggerRef.value || triggerRef.value?.$el\n})\n\n/**显示隐藏 */\nconst visible = useModel({ defaultValue: false, propName: 'visible', props, emit })\n\nconst dropdownVisible = useNest(visible)\n\nlet closeTimer: number | undefined\n\nconst attrs = useAttrs()\nfunction renderTriggerNode() {\n const slotsNode = slots.trigger?.()\n if (!slotsNode) return null\n const nodes = extractNormalVNodes(slotsNode)\n const props = { class: cls.b, ...attrs, ...eventsHandlers.value }\n if (nodes.length === 1) return cloneVNode(nodes[0]!, props)\n\n return createVNode('div', props, nodes)\n}\n\nfunction stopClose() {\n closeTimer !== undefined && clearTimeout(closeTimer)\n}\n\n/** 打开下拉框 */\nfunction open(config?: { trigger?: HTMLElement }) {\n stopClose()\n const { trigger } = config || {}\n if (trigger && trigger instanceof HTMLElement) {\n customTriggerRef.value = trigger\n }\n\n visible.value = true\n}\n\nfunction close() {\n if (props.trigger === 'hover') {\n // 给200毫秒重新浮动的缓冲时间\n closeTimer = setTimeout(() => {\n transition.leave()\n }, 200)\n } else {\n transition.leave()\n }\n}\n\n/** 点击外部 */\nfunction handleClickOutside(e: MouseEvent) {\n const { trigger } = props\n // 当下拉框为点击时触发时,点击触发元素时不关闭\n // 其他任何时候点击外部都关闭下拉器\n if (trigger === 'click' && triggerDom.value.contains(e.target as Node)) {\n return\n }\n close()\n}\n\nconst transitionName = shallowRef('slide-down')\n\nconst { update, popperContainerId } = usePop({\n triggerRef: triggerDom,\n contentRef,\n direction: toRef(() => props.direction),\n alignment: toRef(() => props.alignment),\n onPop(position) {\n transitionName.value = position.placement.includes('top') ? 'slide-up' : 'slide-down'\n\n transition.enter()\n },\n\n onTriggerPositionChange() {\n close()\n },\n\n onBeforeUpdate(triggerEl, contentEl) {\n setStyles(contentEl, {\n width: props.width ?? `${triggerEl.offsetWidth}px`,\n minWidth: props.minWidth\n })\n }\n})\n\nconst transition = useTransition('css', {\n name: transitionName,\n target: contentRef,\n afterLeave() {\n visible.value = false\n },\n\n leaveCanceled() {\n visible.value = false\n }\n})\n\nfunction triggerClick() {\n if (visible.value) {\n close()\n } else {\n open()\n }\n}\n\nconst eventsHandlers = computed(() => {\n const { trigger, disabled } = props\n\n const handlers: Record<string, Function> = {}\n if (disabled || trigger === 'custom') return handlers\n\n if (trigger === 'click') {\n handlers.onClick = triggerClick\n } else if (trigger === 'hover') {\n handlers.onMouseenter = open\n handlers.onMouseleave = close\n }\n\n return handlers\n})\n\ndefineExpose<DropdownExposed>({\n open,\n close,\n /**暴露出更新dropdown内容位置方法 适用与级联选择器组件 */\n updateDropdown: update\n})\n</script>\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Fragment,
|
|
1
|
+
import { Fragment, createElementBlock, createElementVNode, defineComponent, normalizeClass, normalizeStyle, openBlock, renderList, toDisplayString, unref } from "vue";
|
|
2
2
|
import { bem } from "@veltra/utils";
|
|
3
3
|
//#region src/components/expression-editor/components/path-preview.vue
|
|
4
4
|
const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
@@ -12,11 +12,8 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
12
12
|
return openBlock(), createElementBlock("li", {
|
|
13
13
|
key: `${i}-${node.value || node.label}`,
|
|
14
14
|
class: normalizeClass([unref(cls).e("path-tree-item"), unref(bem).is("active", i === __props.path.length - 1)]),
|
|
15
|
-
style: normalizeStyle({
|
|
16
|
-
}, [
|
|
17
|
-
key: 0,
|
|
18
|
-
class: normalizeClass(unref(cls).e("path-tree-branch"))
|
|
19
|
-
}, "└", 2)) : createCommentVNode("v-if", true), createElementVNode("span", { class: normalizeClass(unref(cls).e("path-tree-label")) }, toDisplayString(node.label), 3)], 6);
|
|
15
|
+
style: normalizeStyle({ "--depth": i })
|
|
16
|
+
}, [createElementVNode("span", { class: normalizeClass(unref(cls).e("path-tree-label")) }, toDisplayString(node.label), 3)], 6);
|
|
20
17
|
}), 128))], 2)], 2);
|
|
21
18
|
};
|
|
22
19
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"path-preview.js","names":[],"sources":["../../../../src/components/expression-editor/components/path-preview.vue"],"sourcesContent":["<template>\n <div :class=\"cls.e('path-preview')\">\n <div :class=\"cls.e('path-preview-title')\">变量路径</div>\n <ul :class=\"cls.e('path-tree')\">\n <li\n v-for=\"(node, i) in path\"\n :key=\"`${i}-${node.value || node.label}`\"\n :class=\"[cls.e('path-tree-item'), bem.is('active', i === path.length - 1)]\"\n :style=\"{
|
|
1
|
+
{"version":3,"file":"path-preview.js","names":[],"sources":["../../../../src/components/expression-editor/components/path-preview.vue"],"sourcesContent":["<template>\n <div :class=\"cls.e('path-preview')\">\n <div :class=\"cls.e('path-preview-title')\">变量路径</div>\n <ul :class=\"cls.e('path-tree')\">\n <li\n v-for=\"(node, i) in path\"\n :key=\"`${i}-${node.value || node.label}`\"\n :class=\"[cls.e('path-tree-item'), bem.is('active', i === path.length - 1)]\"\n :style=\"{ '--depth': i }\"\n >\n <span :class=\"cls.e('path-tree-label')\">{{ node.label }}</span>\n </li>\n </ul>\n </div>\n</template>\n\n<script lang=\"ts\" setup>\nimport { bem } from '@veltra/utils'\n\nimport type { VariableItem } from '../../../types'\n\ndefineOptions({ name: 'UExpressionPathPreview' })\n\ndefineProps<{ path: VariableItem[] }>()\n\nconst cls = bem('expression-editor')\n</script>\n"],"mappings":";;;;;;;;EAyBA,MAAM,MAAM,IAAI,mBAAmB;;GAxBjC,OAAA,UAAA,GAAA,mBAYM,OAAA,EAZA,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,cAAA,CAAA,EAAA,GAChB,CAAA,mBAAoD,OAAA,EAA9C,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,oBAAA,CAAA,EAAwB,GAAA,QAAI,CAAA,GAC9C,mBASK,MAAA,EATA,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,WAAA,CAAA,EAAA,GACf,EAAA,UAAA,IAAA,GAAA,mBAOK,UAAA,MAAA,WANiB,QAAA,OAAZ,MAAM,MAAC;IADjB,OAAA,UAAA,GAAA,mBAOK,MAAA;KALF,KAAG,GAAK,EAAC,GAAI,KAAK,SAAS,KAAK;KAChC,OAAK,eAAA,CAAG,MAAA,GAAA,CAAG,CAAC,EAAC,gBAAA,GAAoB,MAAA,GAAA,CAAG,CAAC,GAAE,UAAW,MAAM,QAAA,KAAK,SAAM,CAAA,CAAA,CAAA;KACnE,OAAK,eAAA,EAAA,WAAe,EAAC,CAAA;IAEtB,GAAA,CAAA,mBAA+D,QAAA,EAAxD,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,iBAAA,CAAA,EAAwB,GAAA,gBAAA,KAAK,KAAK,GAAA,CAAA,CAAA,GAAA,CAAA"}
|
|
@@ -3,7 +3,7 @@ import _sfc_main$2 from "../../empty/empty.js";
|
|
|
3
3
|
import _sfc_main$3 from "../../scroll/scroll.js";
|
|
4
4
|
import _sfc_main$4 from "../../tip/tip.js";
|
|
5
5
|
import _sfc_main$5 from "./path-preview.js";
|
|
6
|
-
import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createVNode, defineComponent, nextTick, normalizeClass, openBlock, ref, renderList, toDisplayString, unref, watch, withCtx, withModifiers } from "vue";
|
|
6
|
+
import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, nextTick, normalizeClass, openBlock, ref, renderList, toDisplayString, unref, useTemplateRef, watch, withCtx, withModifiers } from "vue";
|
|
7
7
|
import { bem } from "@veltra/utils";
|
|
8
8
|
import { ArrowRight } from "@veltra/icons/normal";
|
|
9
9
|
//#region src/components/expression-editor/components/variable-picker.vue
|
|
@@ -34,6 +34,8 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
34
34
|
const cls = bem("expression-editor");
|
|
35
35
|
const navPath = ref([]);
|
|
36
36
|
const activeIndex = ref(0);
|
|
37
|
+
const root = useTemplateRef("root");
|
|
38
|
+
const listScroll = useTemplateRef("listScroll");
|
|
37
39
|
const isFlat = computed(() => props.filter !== "");
|
|
38
40
|
function hasChildren(item) {
|
|
39
41
|
return !!item.children && item.children.length > 0;
|
|
@@ -107,12 +109,17 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
107
109
|
emit("select", item);
|
|
108
110
|
return;
|
|
109
111
|
}
|
|
110
|
-
|
|
111
|
-
activeIndex.value = 0;
|
|
112
|
+
expandInto(item);
|
|
112
113
|
return;
|
|
113
114
|
}
|
|
114
115
|
emit("select", item);
|
|
115
116
|
}
|
|
117
|
+
/** 进入 item 的下一级(点击展开图标 / leaf 模式点击分支项共用) */
|
|
118
|
+
function expandInto(item) {
|
|
119
|
+
if (!hasChildren(item)) return;
|
|
120
|
+
navPath.value = [...navPath.value, item];
|
|
121
|
+
activeIndex.value = 0;
|
|
122
|
+
}
|
|
116
123
|
function flattenSourceFor(it) {
|
|
117
124
|
const flat = it;
|
|
118
125
|
const out = {
|
|
@@ -134,10 +141,13 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
134
141
|
}
|
|
135
142
|
function scrollActiveIntoView() {
|
|
136
143
|
nextTick(() => {
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
144
|
+
const item = root.value?.querySelector(`[data-idx="${activeIndex.value}"]`);
|
|
145
|
+
const scroller = listScroll.value?.containerRef;
|
|
146
|
+
if (!(item instanceof HTMLElement) || !(scroller instanceof HTMLElement)) return;
|
|
147
|
+
const top = item.getBoundingClientRect().top - scroller.getBoundingClientRect().top + scroller.scrollTop;
|
|
148
|
+
const bottom = top + item.offsetHeight;
|
|
149
|
+
if (top < scroller.scrollTop) scroller.scrollTop = top;
|
|
150
|
+
else if (bottom > scroller.scrollTop + scroller.clientHeight) scroller.scrollTop = bottom - scroller.clientHeight;
|
|
141
151
|
});
|
|
142
152
|
}
|
|
143
153
|
function handleVisibleChange(v) {
|
|
@@ -185,8 +195,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
185
195
|
if (isFlat.value) return false;
|
|
186
196
|
const item = currentList.value[activeIndex.value];
|
|
187
197
|
if (item && hasChildren(item)) {
|
|
188
|
-
|
|
189
|
-
activeIndex.value = 0;
|
|
198
|
+
expandInto(item);
|
|
190
199
|
return true;
|
|
191
200
|
}
|
|
192
201
|
return false;
|
|
@@ -209,6 +218,8 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
209
218
|
"onUpdate:visible": _cache[2] || (_cache[2] = ($event) => handleVisibleChange($event))
|
|
210
219
|
}, {
|
|
211
220
|
content: withCtx(() => [createElementVNode("div", {
|
|
221
|
+
ref_key: "root",
|
|
222
|
+
ref: root,
|
|
212
223
|
class: normalizeClass(unref(cls).e("picker")),
|
|
213
224
|
onMousedown: _cache[1] || (_cache[1] = withModifiers(() => {}, ["prevent"]))
|
|
214
225
|
}, [
|
|
@@ -241,6 +252,8 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
241
252
|
key: 0,
|
|
242
253
|
class: normalizeClass(unref(cls).e("panel"))
|
|
243
254
|
}, [createVNode(unref(_sfc_main$3), {
|
|
255
|
+
ref_key: "listScroll",
|
|
256
|
+
ref: listScroll,
|
|
244
257
|
tag: "ul",
|
|
245
258
|
class: normalizeClass(unref(cls).e("panel-list")),
|
|
246
259
|
"content-class": unref(cls).e("panel-content")
|
|
@@ -254,11 +267,13 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
254
267
|
onMouseenter: ($event) => activeIndex.value = idx
|
|
255
268
|
}, [createElementVNode("span", { class: normalizeClass(unref(cls).e("item-label")) }, toDisplayString(item.label), 3), !isFlat.value && hasChildren(item) ? (openBlock(), createBlock(unref(_sfc_main$1), {
|
|
256
269
|
key: 0,
|
|
257
|
-
class: normalizeClass(unref(cls).e("item-expand"))
|
|
270
|
+
class: normalizeClass(unref(cls).e("item-expand")),
|
|
271
|
+
title: "展开下一级",
|
|
272
|
+
onClick: withModifiers(($event) => expandInto(item), ["stop"])
|
|
258
273
|
}, {
|
|
259
274
|
default: withCtx(() => [createVNode(unref(ArrowRight))]),
|
|
260
275
|
_: 1
|
|
261
|
-
}, 8, ["class"])) : createCommentVNode("v-if", true)], 42, _hoisted_2);
|
|
276
|
+
}, 8, ["class", "onClick"])) : createCommentVNode("v-if", true)], 42, _hoisted_2);
|
|
262
277
|
}), 128))]),
|
|
263
278
|
_: 1
|
|
264
279
|
}, 8, ["class", "content-class"])], 2)) : (openBlock(), createElementBlock("div", {
|
|
@@ -267,7 +282,29 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
267
282
|
}, [createVNode(unref(_sfc_main$2), { description: "暂无可用变量" })], 2)), isFlat.value && activePath.value.length > 0 ? (openBlock(), createBlock(_sfc_main$5, {
|
|
268
283
|
key: 2,
|
|
269
284
|
path: activePath.value
|
|
270
|
-
}, null, 8, ["path"])) : createCommentVNode("v-if", true)], 2)
|
|
285
|
+
}, null, 8, ["path"])) : createCommentVNode("v-if", true)], 2),
|
|
286
|
+
currentList.value.length > 0 ? (openBlock(), createElementBlock("div", {
|
|
287
|
+
key: 1,
|
|
288
|
+
class: normalizeClass(unref(cls).e("picker-hint"))
|
|
289
|
+
}, [isFlat.value ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
|
|
290
|
+
_cache[3] || (_cache[3] = createElementVNode("span", null, [
|
|
291
|
+
createElementVNode("kbd", null, "↑"),
|
|
292
|
+
createElementVNode("kbd", null, "↓"),
|
|
293
|
+
createTextVNode(" 选择")
|
|
294
|
+
], -1)),
|
|
295
|
+
_cache[4] || (_cache[4] = createElementVNode("span", null, [createElementVNode("kbd", null, "Enter"), createTextVNode(" 确认")], -1)),
|
|
296
|
+
_cache[5] || (_cache[5] = createElementVNode("span", null, [createElementVNode("kbd", null, "Esc"), createTextVNode(" 关闭")], -1))
|
|
297
|
+
], 64)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
|
|
298
|
+
_cache[6] || (_cache[6] = createElementVNode("span", null, [
|
|
299
|
+
createElementVNode("kbd", null, "↑"),
|
|
300
|
+
createElementVNode("kbd", null, "↓"),
|
|
301
|
+
createTextVNode(" 选择")
|
|
302
|
+
], -1)),
|
|
303
|
+
_cache[7] || (_cache[7] = createElementVNode("span", null, [createElementVNode("kbd", null, "→"), createTextVNode(" 展开")], -1)),
|
|
304
|
+
_cache[8] || (_cache[8] = createElementVNode("span", null, [createElementVNode("kbd", null, "←"), createTextVNode(" 返回")], -1)),
|
|
305
|
+
_cache[9] || (_cache[9] = createElementVNode("span", null, [createElementVNode("kbd", null, "Enter"), createTextVNode(" 确认")], -1)),
|
|
306
|
+
_cache[10] || (_cache[10] = createElementVNode("span", null, [createElementVNode("kbd", null, "Esc"), createTextVNode(" 关闭")], -1))
|
|
307
|
+
], 64))], 2)) : createCommentVNode("v-if", true)
|
|
271
308
|
], 34)]),
|
|
272
309
|
_: 1
|
|
273
310
|
}, 8, ["trigger-dom", "visible"]);
|