@veltra/desktop 1.2.10 → 1.2.13
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/action/action-group.js.map +1 -1
- package/dist/components/action/action-group.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/components/action/action-group.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/action/action.js +2 -2
- package/dist/components/action/action.js.map +1 -1
- package/dist/components/auto-complete/auto-complete.js +4 -4
- package/dist/components/auto-complete/auto-complete.js.map +1 -1
- package/dist/components/auto-complete/use-keyboard.js.map +1 -1
- package/dist/components/badge/badge.js +2 -2
- package/dist/components/badge/badge.js.map +1 -1
- package/dist/components/batch-edit/batch-edit-form.js +2 -2
- package/dist/components/batch-edit/batch-edit-form.js.map +1 -1
- package/dist/components/batch-edit/batch-edit-list.js +2 -2
- package/dist/components/batch-edit/batch-edit-list.js.map +1 -1
- package/dist/components/batch-edit/batch-edit.js +2 -2
- package/dist/components/batch-edit/batch-edit.js.map +1 -1
- package/dist/components/batch-edit/use-edit-state.js.map +1 -1
- package/dist/components/batch-edit/use-features.js.map +1 -1
- package/dist/components/batch-edit/use-handlers.js.map +1 -1
- package/dist/components/breadcrumb/breadcrumb.js +2 -2
- package/dist/components/breadcrumb/breadcrumb.js.map +1 -1
- package/dist/components/button/button-group.js +2 -2
- package/dist/components/button/button-group.js.map +1 -1
- package/dist/components/button/button.js +2 -2
- package/dist/components/button/button.js.map +1 -1
- package/dist/components/calendar/calendar.js +3 -3
- package/dist/components/calendar/calendar.js.map +1 -1
- package/dist/components/calendar/utils.js.map +1 -1
- package/dist/components/card/card-action.js +2 -2
- package/dist/components/card/card-action.js.map +1 -1
- package/dist/components/card/card-content.js +2 -2
- package/dist/components/card/card-content.js.map +1 -1
- package/dist/components/card/card-cover.js +2 -2
- package/dist/components/card/card-cover.js.map +1 -1
- package/dist/components/card/card-header.js +2 -2
- package/dist/components/card/card-header.js.map +1 -1
- package/dist/components/card/card.js +2 -2
- package/dist/components/card/card.js.map +1 -1
- package/dist/components/cascade/cascade-panel-item.js +1 -1
- package/dist/components/cascade/cascade-panel-item.js.map +1 -1
- package/dist/components/cascade/cascade.js +7 -3
- package/dist/components/cascade/cascade.js.map +1 -1
- package/dist/components/cascade/cascade.vue.d.ts +8 -5
- package/dist/components/cascade/use-check.js +3 -1
- package/dist/components/cascade/use-check.js.map +1 -1
- package/dist/components/cascade/use-data-map.js.map +1 -1
- package/dist/components/cascade/use-select.js +30 -14
- package/dist/components/cascade/use-select.js.map +1 -1
- package/dist/components/check-tag/check-tag.js +2 -2
- package/dist/components/check-tag/check-tag.js.map +1 -1
- package/dist/components/checkbox/checkbox-button.js +4 -4
- package/dist/components/checkbox/checkbox-button.js.map +1 -1
- package/dist/components/checkbox/checkbox.js +4 -4
- package/dist/components/checkbox/checkbox.js.map +1 -1
- package/dist/components/checkbox-group/checkbox-group.js +4 -4
- package/dist/components/checkbox-group/checkbox-group.js.map +1 -1
- package/dist/components/code-editor/basic-setup.js +44 -0
- package/dist/components/code-editor/basic-setup.js.map +1 -0
- package/dist/components/code-editor/code-editor.js +5 -5
- package/dist/components/code-editor/code-editor.js.map +1 -1
- package/dist/components/collapse/collapse-item.js +2 -2
- package/dist/components/collapse/collapse-item.js.map +1 -1
- package/dist/components/collapse/collapse.js +2 -2
- package/dist/components/collapse/collapse.js.map +1 -1
- package/dist/components/condition-editor/components/condition-group.js +2 -2
- package/dist/components/condition-editor/components/condition-group.js.map +1 -1
- package/dist/components/condition-editor/components/condition-row.js +2 -2
- package/dist/components/condition-editor/components/condition-row.js.map +1 -1
- package/dist/components/condition-editor/condition-editor.js +2 -2
- package/dist/components/condition-editor/condition-editor.js.map +1 -1
- package/dist/components/condition-editor/core/evaluator.js.map +1 -1
- package/dist/components/contextmenu/contextmenu-item.js +2 -2
- package/dist/components/contextmenu/contextmenu-item.js.map +1 -1
- package/dist/components/contextmenu/contextmenu-panel.js +2 -2
- package/dist/components/contextmenu/contextmenu-panel.js.map +1 -1
- package/dist/components/contextmenu/contextmenu-sub.js +2 -2
- package/dist/components/contextmenu/contextmenu-sub.js.map +1 -1
- package/dist/components/contextmenu/contextmenu.js +2 -2
- package/dist/components/contextmenu/contextmenu.js.map +1 -1
- package/dist/components/date-panel/date-panel.js +2 -2
- package/dist/components/date-panel/date-panel.js.map +1 -1
- package/dist/components/date-panel/headers/day.js +2 -2
- package/dist/components/date-panel/headers/day.js.map +1 -1
- package/dist/components/date-panel/headers/month.js +2 -2
- package/dist/components/date-panel/headers/month.js.map +1 -1
- package/dist/components/date-panel/headers/year.js +2 -2
- package/dist/components/date-panel/headers/year.js.map +1 -1
- package/dist/components/date-panel/panels/day.js +2 -2
- package/dist/components/date-panel/panels/day.js.map +1 -1
- package/dist/components/date-panel/panels/month.js +2 -2
- package/dist/components/date-panel/panels/month.js.map +1 -1
- package/dist/components/date-panel/panels/year.js +2 -2
- package/dist/components/date-panel/panels/year.js.map +1 -1
- package/dist/components/date-panel/use-panel-date.js.map +1 -1
- package/dist/components/date-picker/date-picker.js +2 -2
- package/dist/components/date-picker/date-picker.js.map +1 -1
- package/dist/components/date-range-picker/date-range-picker.js +2 -2
- package/dist/components/date-range-picker/date-range-picker.js.map +1 -1
- package/dist/components/dialog/dialog.js +4 -4
- package/dist/components/dialog/dialog.js.map +1 -1
- package/dist/components/drawer/drawer.js +4 -4
- package/dist/components/drawer/drawer.js.map +1 -1
- package/dist/components/dropdown/dropdown.js +2 -2
- package/dist/components/dropdown/dropdown.js.map +1 -1
- package/dist/components/dual-nav/dual-nav-app.js +2 -2
- package/dist/components/dual-nav/dual-nav-app.js.map +1 -1
- package/dist/components/dual-nav/dual-nav.js +2 -2
- package/dist/components/dual-nav/dual-nav.js.map +1 -1
- package/dist/components/empty/empty.js +2 -2
- package/dist/components/empty/empty.js.map +1 -1
- package/dist/components/expression-editor/components/path-preview.js +2 -2
- package/dist/components/expression-editor/components/path-preview.js.map +1 -1
- package/dist/components/expression-editor/components/variable-picker.js +2 -2
- package/dist/components/expression-editor/components/variable-picker.js.map +1 -1
- package/dist/components/expression-editor/core/editor.js.map +1 -1
- package/dist/components/expression-editor/core/model.js.map +1 -1
- package/dist/components/expression-editor/expression-editor.js +2 -2
- package/dist/components/expression-editor/expression-editor.js.map +1 -1
- package/dist/components/file-picker/file-picker.js +2 -2
- package/dist/components/file-picker/file-picker.js.map +1 -1
- package/dist/components/file-picker/helper.js.map +1 -1
- package/dist/components/file-viewer/file-viewer.js +4 -4
- package/dist/components/file-viewer/file-viewer.js.map +1 -1
- package/dist/components/file-viewer/helper.js.map +1 -1
- package/dist/components/file-viewer/previewers/docx-previewer.js +2 -2
- package/dist/components/file-viewer/previewers/docx-previewer.js.map +1 -1
- package/dist/components/file-viewer/previewers/image-previewer.js +2 -2
- package/dist/components/file-viewer/previewers/image-previewer.js.map +1 -1
- package/dist/components/file-viewer/previewers/pdf-previewer.js +2 -2
- package/dist/components/file-viewer/previewers/pdf-previewer.js.map +1 -1
- package/dist/components/file-viewer/previewers/pdf-viewport-scroll.js +2 -2
- package/dist/components/file-viewer/previewers/pdf-viewport-scroll.js.map +1 -1
- package/dist/components/file-viewer/previewers/pdf-zoom-bridge.js +2 -2
- package/dist/components/file-viewer/previewers/pdf-zoom-bridge.js.map +1 -1
- package/dist/components/file-viewer/previewers/sheet-previewer.js +2 -2
- package/dist/components/file-viewer/previewers/sheet-previewer.js.map +1 -1
- package/dist/components/file-viewer/previewers/text-previewer.js +2 -2
- package/dist/components/file-viewer/previewers/text-previewer.js.map +1 -1
- package/dist/components/file-viewer/previewers/video-previewer.js +2 -2
- package/dist/components/file-viewer/previewers/video-previewer.js.map +1 -1
- package/dist/components/file-viewer/sheet-parser.js.map +1 -1
- package/dist/components/float-button/float-button.js +2 -2
- package/dist/components/float-button/float-button.js.map +1 -1
- package/dist/components/form/form.js.map +1 -1
- package/dist/components/form/form.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/form/form.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/form/use-form-fields.js.map +1 -1
- package/dist/components/form/use-node-interceptor.js +1 -1
- package/dist/components/form/use-node-interceptor.js.map +1 -1
- package/dist/components/form-item/form-item.js.map +1 -1
- package/dist/components/form-item/form-item.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/form-item/form-item.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/form-item/validate.js.map +1 -1
- package/dist/components/gantt-chart/gantt-chart.js +2 -2
- package/dist/components/gantt-chart/gantt-chart.js.map +1 -1
- package/dist/components/grid/breakpoint.js.map +1 -1
- package/dist/components/grid/grid-item.js +2 -2
- package/dist/components/grid/grid-item.js.map +1 -1
- package/dist/components/grid/grid.js +2 -2
- package/dist/components/grid/grid.js.map +1 -1
- package/dist/components/grid-input/grid-input.js +2 -2
- package/dist/components/grid-input/grid-input.js.map +1 -1
- package/dist/components/grid-input/grid-input.vue.d.ts +1 -1
- package/dist/components/group-input/group-input.js +2 -2
- package/dist/components/group-input/group-input.js.map +1 -1
- package/dist/components/icon/icon.js +2 -2
- package/dist/components/icon/icon.js.map +1 -1
- package/dist/components/input/input.js.map +1 -1
- package/dist/components/input/input.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/input/input.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/kbd/kbd.js +2 -2
- package/dist/components/kbd/kbd.js.map +1 -1
- package/dist/components/layout/layout-resizer.js +2 -2
- package/dist/components/layout/layout-resizer.js.map +1 -1
- package/dist/components/layout/layout.js +2 -2
- package/dist/components/layout/layout.js.map +1 -1
- package/dist/components/list/list-item.js +2 -2
- package/dist/components/list/list-item.js.map +1 -1
- package/dist/components/list/list.js +2 -2
- package/dist/components/list/list.js.map +1 -1
- package/dist/components/loading/directive.js.map +1 -1
- package/dist/components/loading/loading.js +2 -2
- package/dist/components/loading/loading.js.map +1 -1
- package/dist/components/message/message-box.js +2 -2
- package/dist/components/message/message-box.js.map +1 -1
- package/dist/components/message/message.js +2 -2
- package/dist/components/message/message.js.map +1 -1
- package/dist/components/message/message2.js.map +1 -1
- package/dist/components/message-confirm/message-confirm.js +2 -2
- package/dist/components/message-confirm/message-confirm.js.map +1 -1
- package/dist/components/multi-select/multi-select-option.js +2 -2
- package/dist/components/multi-select/multi-select-option.js.map +1 -1
- package/dist/components/multi-select/multi-select.js +4 -4
- package/dist/components/multi-select/multi-select.js.map +1 -1
- package/dist/components/multi-tree-select/multi-tree-select.js +4 -4
- package/dist/components/multi-tree-select/multi-tree-select.js.map +1 -1
- package/dist/components/multi-tree-select/multi-tree-select.vue.d.ts +1 -1
- package/dist/components/nav/nav-icon.js +2 -2
- package/dist/components/nav/nav-icon.js.map +1 -1
- package/dist/components/nav/nav-item-collapsed.js +2 -2
- package/dist/components/nav/nav-item-collapsed.js.map +1 -1
- package/dist/components/nav/nav-item.js +2 -2
- package/dist/components/nav/nav-item.js.map +1 -1
- package/dist/components/nav/nav-sub-collapsed.js +2 -2
- package/dist/components/nav/nav-sub-collapsed.js.map +1 -1
- package/dist/components/nav/nav-sub.js +2 -2
- package/dist/components/nav/nav-sub.js.map +1 -1
- package/dist/components/nav/nav.js +2 -2
- package/dist/components/nav/nav.js.map +1 -1
- package/dist/components/notification/index.js.map +1 -1
- package/dist/components/notification/notification.js +2 -2
- package/dist/components/notification/notification.js.map +1 -1
- package/dist/components/number/number.js +2 -2
- package/dist/components/number/number.js.map +1 -1
- package/dist/components/number-input/number-input.js +4 -4
- package/dist/components/number-input/number-input.js.map +1 -1
- package/dist/components/number-range-input/number-range-input.js +4 -4
- package/dist/components/number-range-input/number-range-input.js.map +1 -1
- package/dist/components/number-range-input/number-range-input.vue.d.ts +1 -1
- package/dist/components/paginator/paginator.js +4 -4
- package/dist/components/paginator/paginator.js.map +1 -1
- package/dist/components/palette/color-transform.js.map +1 -1
- package/dist/components/palette/palette-alpha.js +2 -2
- package/dist/components/palette/palette-alpha.js.map +1 -1
- package/dist/components/palette/palette-color-switch.js +1 -1
- package/dist/components/palette/palette-color-switch.js.map +1 -1
- package/dist/components/palette/palette-hue.js +2 -2
- package/dist/components/palette/palette-hue.js.map +1 -1
- package/dist/components/palette/palette-sv.js +2 -2
- package/dist/components/palette/palette-sv.js.map +1 -1
- package/dist/components/palette/palette.js +3 -3
- package/dist/components/palette/palette.js.map +1 -1
- package/dist/components/palette/use-hsv.js.map +1 -1
- package/dist/components/password-input/password-input.js +3 -3
- package/dist/components/password-input/password-input.js.map +1 -1
- package/dist/components/pop-confirm/pop-confirm.js +2 -2
- package/dist/components/pop-confirm/pop-confirm.js.map +1 -1
- package/dist/components/progress/progress.js +2 -2
- package/dist/components/progress/progress.js.map +1 -1
- package/dist/components/progress-nodes/progress-nodes.js +2 -2
- package/dist/components/progress-nodes/progress-nodes.js.map +1 -1
- package/dist/components/progress-nodes/progress-nodes.vue.d.ts +1 -1
- package/dist/components/radio/radio.js +4 -4
- package/dist/components/radio/radio.js.map +1 -1
- package/dist/components/radio-group/radio-group.js +4 -4
- package/dist/components/radio-group/radio-group.js.map +1 -1
- package/dist/components/rich-text-editor/rich-text-editor.js +2 -2
- package/dist/components/rich-text-editor/rich-text-editor.js.map +1 -1
- package/dist/components/rich-text-editor/toolbar.js +1 -1
- package/dist/components/rich-text-editor/toolbar.js.map +1 -1
- package/dist/components/scroll/scroll-bar.js +2 -2
- package/dist/components/scroll/scroll-bar.js.map +1 -1
- package/dist/components/scroll/scroll.js +2 -2
- package/dist/components/scroll/scroll.js.map +1 -1
- package/dist/components/select/select.js +4 -4
- package/dist/components/select/select.js.map +1 -1
- package/dist/components/select/use-keyboard.js.map +1 -1
- package/dist/components/select/use-options.js.map +1 -1
- package/dist/components/slider/slider-thumb.js +1 -1
- package/dist/components/slider/slider-thumb.js.map +1 -1
- package/dist/components/slider/slider.js +2 -2
- package/dist/components/slider/slider.js.map +1 -1
- package/dist/components/steps/steps.js +2 -2
- package/dist/components/steps/steps.js.map +1 -1
- package/dist/components/steps/steps.vue.d.ts +2 -2
- package/dist/components/switch/switch.js +4 -4
- package/dist/components/switch/switch.js.map +1 -1
- package/dist/components/table/table-body.js +2 -2
- package/dist/components/table/table-body.js.map +1 -1
- package/dist/components/table/table-cell.js +2 -2
- package/dist/components/table/table-cell.js.map +1 -1
- package/dist/components/table/table-foot.js +2 -2
- package/dist/components/table/table-foot.js.map +1 -1
- package/dist/components/table/table-head.js.map +1 -1
- package/dist/components/table/table-row.js.map +1 -1
- package/dist/components/table/table.js +2 -2
- package/dist/components/table/table.js.map +1 -1
- package/dist/components/table/use-check.js.map +1 -1
- package/dist/components/table/use-col-resize.js.map +1 -1
- package/dist/components/table/use-columns.js.map +1 -1
- package/dist/components/table/use-rows.js.map +1 -1
- package/dist/components/table/use-table.js.map +1 -1
- package/dist/components/table-editor/table-editor.js +2 -2
- package/dist/components/table-editor/table-editor.js.map +1 -1
- package/dist/components/tabs/tabs-horizontal.js +4 -4
- package/dist/components/tabs/tabs-horizontal.js.map +1 -1
- package/dist/components/tabs/tabs-horizontal.vue.d.ts +3 -3
- package/dist/components/tabs/tabs-vertical.js +4 -4
- package/dist/components/tabs/tabs-vertical.js.map +1 -1
- package/dist/components/tabs/tabs-vertical.vue.d.ts +2 -2
- package/dist/components/tabs/tabs.js +4 -4
- package/dist/components/tabs/tabs.js.map +1 -1
- package/dist/components/tabs/tabs.vue.d.ts +3 -3
- package/dist/components/tag/tag.js +2 -2
- package/dist/components/tag/tag.js.map +1 -1
- package/dist/components/text/text.js +2 -2
- package/dist/components/text/text.js.map +1 -1
- package/dist/components/textarea/textarea.js +4 -4
- package/dist/components/textarea/textarea.js.map +1 -1
- package/dist/components/theme/theme.js +1 -1
- package/dist/components/theme/theme.js.map +1 -1
- package/dist/components/tip/tip.js +2 -2
- package/dist/components/tip/tip.js.map +1 -1
- package/dist/components/tip/use-nest.js.map +1 -1
- package/dist/components/tree/tree-node.js +2 -2
- package/dist/components/tree/tree-node.js.map +1 -1
- package/dist/components/tree/tree-node2.js.map +1 -1
- package/dist/components/tree/tree.js +2 -2
- package/dist/components/tree/tree.js.map +1 -1
- package/dist/components/tree/tree.vue.d.ts +1 -1
- package/dist/components/tree/use-check.js.map +1 -1
- package/dist/components/tree-select/tree-select.js +7 -6
- package/dist/components/tree-select/tree-select.js.map +1 -1
- package/dist/components/tree-select/tree-select.vue.d.ts +5 -4
- package/dist/components/watermark/watermark.js +2 -2
- package/dist/components/watermark/watermark.js.map +1 -1
- package/dist/types/cascade.d.ts +10 -6
- package/dist/types/tree-select.d.ts +2 -1
- package/package.json +24 -23
- package/src/components/action/action-group.vue +2 -2
- package/src/components/action/action.vue +1 -1
- package/src/components/auto-complete/auto-complete.vue +1 -1
- package/src/components/badge/badge.vue +1 -1
- package/src/components/batch-edit/batch-edit-form.vue +1 -1
- package/src/components/batch-edit/batch-edit-list.vue +1 -1
- package/src/components/batch-edit/batch-edit.vue +1 -1
- package/src/components/breadcrumb/breadcrumb.vue +1 -1
- package/src/components/button/button-group.vue +1 -1
- package/src/components/button/button.vue +1 -1
- package/src/components/calendar/calendar.vue +1 -1
- package/src/components/card/card-action.vue +1 -1
- package/src/components/card/card-content.vue +1 -1
- package/src/components/card/card-cover.vue +1 -1
- package/src/components/card/card-header.vue +1 -1
- package/src/components/card/card.vue +1 -1
- package/src/components/cascade/cascade.vue +3 -2
- package/src/components/cascade/use-check.ts +3 -1
- package/src/components/cascade/use-select.ts +43 -29
- package/src/components/check-tag/check-tag.vue +1 -1
- package/src/components/checkbox/checkbox-button.vue +1 -1
- package/src/components/checkbox/checkbox.vue +1 -1
- package/src/components/checkbox-group/checkbox-group.vue +1 -1
- package/src/components/code-editor/basic-setup.ts +63 -0
- package/src/components/code-editor/code-editor.vue +3 -3
- package/src/components/collapse/collapse-item.vue +1 -1
- package/src/components/collapse/collapse.vue +1 -1
- package/src/components/condition-editor/components/condition-group.vue +1 -1
- package/src/components/condition-editor/components/condition-row.vue +1 -1
- package/src/components/condition-editor/condition-editor.vue +1 -1
- package/src/components/contextmenu/contextmenu-item.vue +1 -1
- package/src/components/contextmenu/contextmenu-panel.vue +1 -1
- package/src/components/contextmenu/contextmenu-sub.vue +1 -1
- package/src/components/contextmenu/contextmenu.vue +1 -1
- package/src/components/date-panel/date-panel.vue +1 -1
- package/src/components/date-panel/headers/day.vue +1 -1
- package/src/components/date-panel/headers/month.vue +1 -1
- package/src/components/date-panel/headers/year.vue +1 -1
- package/src/components/date-panel/panels/day.vue +1 -1
- package/src/components/date-panel/panels/month.vue +1 -1
- package/src/components/date-panel/panels/year.vue +1 -1
- package/src/components/date-picker/date-picker.vue +1 -1
- package/src/components/date-range-picker/date-range-picker.vue +1 -1
- package/src/components/dialog/dialog.vue +1 -1
- package/src/components/drawer/drawer.vue +1 -1
- package/src/components/dropdown/dropdown.vue +1 -1
- package/src/components/dual-nav/dual-nav-app.vue +1 -1
- package/src/components/dual-nav/dual-nav.vue +1 -1
- package/src/components/empty/empty.vue +1 -1
- package/src/components/expression-editor/components/path-preview.vue +1 -1
- package/src/components/expression-editor/components/variable-picker.vue +1 -1
- package/src/components/expression-editor/expression-editor.vue +1 -1
- package/src/components/file-picker/file-picker.vue +1 -1
- package/src/components/file-viewer/file-viewer.vue +1 -1
- package/src/components/file-viewer/previewers/docx-previewer.vue +1 -1
- package/src/components/file-viewer/previewers/image-previewer.vue +1 -1
- package/src/components/file-viewer/previewers/pdf-previewer.vue +1 -1
- package/src/components/file-viewer/previewers/pdf-viewport-scroll.vue +1 -1
- package/src/components/file-viewer/previewers/pdf-zoom-bridge.vue +1 -1
- package/src/components/file-viewer/previewers/sheet-previewer.vue +1 -1
- package/src/components/file-viewer/previewers/text-previewer.vue +1 -1
- package/src/components/file-viewer/previewers/video-previewer.vue +1 -1
- package/src/components/float-button/float-button.vue +1 -1
- package/src/components/form/form.vue +1 -1
- package/src/components/form/use-node-interceptor.ts +2 -1
- package/src/components/form-item/form-item.vue +1 -1
- package/src/components/gantt-chart/gantt-chart.vue +1 -1
- package/src/components/grid/grid-item.vue +1 -1
- package/src/components/grid/grid.vue +1 -1
- package/src/components/grid-input/grid-input.vue +1 -1
- package/src/components/group-input/group-input.vue +1 -1
- package/src/components/icon/icon.vue +1 -1
- package/src/components/input/input.vue +1 -1
- package/src/components/kbd/kbd.vue +1 -1
- package/src/components/layout/layout-resizer.vue +1 -1
- package/src/components/layout/layout.vue +1 -1
- package/src/components/list/list-item.vue +1 -1
- package/src/components/list/list.vue +1 -1
- package/src/components/loading/loading.vue +1 -1
- package/src/components/message/message-box.vue +1 -1
- package/src/components/message/message.vue +1 -1
- package/src/components/message-confirm/message-confirm.vue +1 -1
- package/src/components/multi-select/multi-select-option.vue +1 -1
- package/src/components/multi-select/multi-select.vue +1 -1
- package/src/components/multi-tree-select/multi-tree-select.vue +1 -1
- package/src/components/nav/nav-icon.vue +1 -1
- package/src/components/nav/nav-item-collapsed.vue +1 -1
- package/src/components/nav/nav-item.vue +1 -1
- package/src/components/nav/nav-sub-collapsed.vue +1 -1
- package/src/components/nav/nav-sub.vue +1 -1
- package/src/components/nav/nav.vue +1 -1
- package/src/components/notification/notification.vue +1 -1
- package/src/components/number/number.vue +1 -1
- package/src/components/number-input/number-input.vue +1 -1
- package/src/components/number-range-input/number-range-input.vue +1 -1
- package/src/components/paginator/paginator.vue +1 -1
- package/src/components/palette/palette-alpha.vue +1 -1
- package/src/components/palette/palette-hue.vue +1 -1
- package/src/components/palette/palette-sv.vue +1 -1
- package/src/components/palette/palette.vue +1 -1
- package/src/components/password-input/password-input.vue +1 -1
- package/src/components/pop-confirm/pop-confirm.vue +1 -1
- package/src/components/progress/progress.vue +1 -1
- package/src/components/progress-nodes/progress-nodes.vue +1 -1
- package/src/components/radio/radio.vue +1 -1
- package/src/components/radio-group/radio-group.vue +1 -1
- package/src/components/scroll/scroll-bar.vue +1 -1
- package/src/components/scroll/scroll.vue +1 -1
- package/src/components/select/select.vue +1 -1
- package/src/components/slider/slider.vue +1 -1
- package/src/components/steps/steps.vue +1 -1
- package/src/components/switch/switch.vue +1 -1
- package/src/components/table/table-body.vue +1 -1
- package/src/components/table/table-cell.vue +1 -1
- package/src/components/table/table-foot.vue +1 -1
- package/src/components/table/table.vue +1 -1
- package/src/components/table-editor/table-editor.vue +1 -1
- package/src/components/tabs/tabs-horizontal.vue +1 -1
- package/src/components/tabs/tabs-vertical.vue +1 -1
- package/src/components/tabs/tabs.vue +1 -1
- package/src/components/tag/tag.vue +1 -1
- package/src/components/text/text.vue +1 -1
- package/src/components/textarea/textarea.vue +1 -1
- package/src/components/tip/tip.vue +1 -1
- package/src/components/tree/tree-node.vue +1 -1
- package/src/components/tree/tree.vue +1 -1
- package/src/components/tree-select/tree-select.vue +3 -3
- package/src/components/watermark/watermark.vue +1 -1
- package/src/types/cascade.ts +10 -6
- package/src/types/tree-select.ts +2 -1
|
@@ -5,8 +5,8 @@ import { bem } from "@veltra/utils";
|
|
|
5
5
|
import { vRipple } from "@veltra/directives";
|
|
6
6
|
//#region src/components/dual-nav/dual-nav-app.vue
|
|
7
7
|
const _hoisted_1 = ["disabled"];
|
|
8
|
-
const _sfc_main =
|
|
9
|
-
name: "
|
|
8
|
+
const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
9
|
+
name: "UDualNavApp",
|
|
10
10
|
__name: "dual-nav-app",
|
|
11
11
|
props: {
|
|
12
12
|
app: {},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dual-nav-app.js","names":[],"sources":["../../../src/components/dual-nav/dual-nav-app.vue"],"sourcesContent":["<template>\n <u-tip v-model:visible=\"tipVisible\" direction=\"right\" hide-arrow :disabled=\"tipSuppressed\">\n <button\n type=\"button\"\n v-ripple=\"!app.disabled\"\n :class=\"[\n cls.e('app'),\n bem.is('active', active),\n bem.is('selected', selected),\n bem.is('disabled', app.disabled ?? false)\n ]\"\n :disabled=\"app.disabled\"\n @click=\"handleClick\"\n @mouseleave=\"handleMouseleave\"\n >\n <UNavIcon v-if=\"app.icon\" :icon=\"app.icon\" :class=\"cls.e('app-icon')\" />\n <span v-else :class=\"cls.e('app-fallback')\">{{ app.title[0] }}</span>\n </button>\n\n <template #content>\n <div :class=\"cls.e('app-tip')\">\n <div :class=\"cls.e('app-tip-title')\">{{ app.title }}</div>\n <p v-if=\"app.description\" :class=\"cls.e('app-tip-description')\">\n {{ app.description }}\n </p>\n </div>\n </template>\n </u-tip>\n</template>\n\n<script setup lang=\"ts\">\nimport { vRipple } from '@veltra/directives'\nimport { bem } from '@veltra/utils'\nimport { shallowRef } from 'vue'\n\nimport type { DualNavRootItem } from '../../types'\nimport UNavIcon from '../nav/nav-icon.vue'\nimport { UTip } from '../tip'\n\ndefineOptions({ name: '
|
|
1
|
+
{"version":3,"file":"dual-nav-app.js","names":[],"sources":["../../../src/components/dual-nav/dual-nav-app.vue"],"sourcesContent":["<template>\n <u-tip v-model:visible=\"tipVisible\" direction=\"right\" hide-arrow :disabled=\"tipSuppressed\">\n <button\n type=\"button\"\n v-ripple=\"!app.disabled\"\n :class=\"[\n cls.e('app'),\n bem.is('active', active),\n bem.is('selected', selected),\n bem.is('disabled', app.disabled ?? false)\n ]\"\n :disabled=\"app.disabled\"\n @click=\"handleClick\"\n @mouseleave=\"handleMouseleave\"\n >\n <UNavIcon v-if=\"app.icon\" :icon=\"app.icon\" :class=\"cls.e('app-icon')\" />\n <span v-else :class=\"cls.e('app-fallback')\">{{ app.title[0] }}</span>\n </button>\n\n <template #content>\n <div :class=\"cls.e('app-tip')\">\n <div :class=\"cls.e('app-tip-title')\">{{ app.title }}</div>\n <p v-if=\"app.description\" :class=\"cls.e('app-tip-description')\">\n {{ app.description }}\n </p>\n </div>\n </template>\n </u-tip>\n</template>\n\n<script setup lang=\"ts\">\nimport { vRipple } from '@veltra/directives'\nimport { bem } from '@veltra/utils'\nimport { shallowRef } from 'vue'\n\nimport type { DualNavRootItem } from '../../types'\nimport UNavIcon from '../nav/nav-icon.vue'\nimport { UTip } from '../tip'\n\ndefineOptions({ name: 'UDualNavApp' })\n\nconst cls = bem('dual-nav')\n\ndefineProps<{ app: DualNavRootItem; active: boolean; selected: boolean }>()\n\nconst emit = defineEmits<{ click: [] }>()\n\nconst tipVisible = shallowRef(false)\n/** 点击后暂时禁用 hover 弹出,移出触发区后恢复 */\nconst tipSuppressed = shallowRef(false)\n\nfunction handleClick() {\n tipSuppressed.value = true\n tipVisible.value = false\n emit('click')\n}\n\nfunction handleMouseleave() {\n tipSuppressed.value = false\n}\n</script>\n"],"mappings":";;;;;;;;;;;;;;;;;EAyCA,MAAM,MAAM,IAAI,UAAU;EAI1B,MAAM,OAAO;EAEb,MAAM,aAAa,WAAW,KAAK;;EAEnC,MAAM,gBAAgB,WAAW,KAAK;EAEtC,SAAS,cAAc;GACrB,cAAc,QAAQ;GACtB,WAAW,QAAQ;GACnB,KAAK,OAAO;EACd;EAEA,SAAS,mBAAmB;GAC1B,cAAc,QAAQ;EACxB;;uBA1DE,YA0BQ,MAAA,WAAA,GAAA;IA1BO,SAAS,WAAA;8DAAA,WAAU,QAAA;IAAE,WAAU;IAAQ,cAAA;IAAY,UAAU,cAAA;;IAkB/D,SAAO,cAMV,CALN,mBAKM,OAAA,EALA,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,SAAA,CAAA,EAAA,GAAA,CAChB,mBAA0D,OAAA,EAApD,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,eAAA,CAAA,EAAA,GAAA,gBAAsB,QAAA,IAAI,KAAK,GAAA,CAAA,GACxC,QAAA,IAAI,eAAA,UAAA,GAAb,mBAEI,KAAA;;KAFuB,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,qBAAA,CAAA;uBAClC,QAAA,IAAI,WAAW,GAAA,CAAA,KAAA,mBAAA,QAAA,IAAA,CAAA,GAAA,CAAA,CAAA,CAAA;2BANf,CAAA,gBAAA,UAAA,GAfT,mBAeS,UAAA;KAdP,MAAK;KAEJ,OAAK,eAAA;MAAY,MAAA,GAAA,CAAG,CAAC,EAAC,KAAA;MAAiB,MAAA,GAAA,CAAG,CAAC,GAAE,UAAW,QAAA,MAAM;MAAW,MAAA,GAAA,CAAG,CAAC,GAAE,YAAa,QAAA,QAAQ;MAAW,MAAA,GAAA,CAAG,CAAC,GAAE,YAAa,QAAA,IAAI,YAAQ,KAAA;;KAM9I,UAAU,QAAA,IAAI;KACd,SAAO;KACP,cAAY;QAEG,QAAA,IAAI,QAAA,UAAA,GAApB,YAAwE,aAAA;;KAA7C,MAAM,QAAA,IAAI;KAAO,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,UAAA,CAAA;oDACxD,mBAAqE,QAAA;;KAAvD,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,cAAA,CAAA;uBAAqB,QAAA,IAAI,MAAK,EAAA,GAAA,CAAA,EAAA,GAAA,IAAA,UAAA,IAAA,CAAA,CAAA,MAAA,OAAA,GAAA,CAZ7C,QAAA,IAAI,QAAQ,CAAA,CAAA,CAAA,CAAA"}
|
|
@@ -9,8 +9,8 @@ import { bem } from "@veltra/utils";
|
|
|
9
9
|
import { Folder, FolderOpened } from "@veltra/icons/normal";
|
|
10
10
|
//#region src/components/dual-nav/dual-nav.vue
|
|
11
11
|
const _hoisted_1 = ["aria-label"];
|
|
12
|
-
const _sfc_main =
|
|
13
|
-
name: "
|
|
12
|
+
const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
13
|
+
name: "UDualNav",
|
|
14
14
|
__name: "dual-nav",
|
|
15
15
|
props: {
|
|
16
16
|
currentPath: {},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dual-nav.js","names":[],"sources":["../../../src/components/dual-nav/dual-nav.vue"],"sourcesContent":["<template>\n <div :class=\"cls.b\">\n <div :class=\"cls.e('rail')\">\n <DualNavApp\n v-for=\"app in menus\"\n :key=\"app.path\"\n :app=\"app\"\n :active=\"isAppActive(app)\"\n :selected=\"isAppSelected(app)\"\n @click=\"handleAppClick(app)\"\n />\n </div>\n\n <!-- <div :class=\"cls.e('divider')\" aria-hidden=\"true\" /> -->\n\n <div :class=\"cls.e('panel')\">\n <template v-if=\"panelApp\">\n <div :class=\"cls.e('panel-header')\">\n <div :class=\"cls.e('panel-header-main')\">\n <h3 :class=\"cls.e('panel-title')\">{{ panelApp.title }}</h3>\n <p v-if=\"panelApp.description\" :class=\"cls.e('description')\">\n {{ panelApp.description }}\n </p>\n </div>\n\n <u-tip\n v-if=\"hasExpandableMenus\"\n :content=\"allExpanded ? '折叠全部' : '展开全部'\"\n hide-arrow\n >\n <button\n type=\"button\"\n :class=\"cls.e('toggle-expand')\"\n :aria-label=\"allExpanded ? '折叠全部' : '展开全部'\"\n @click=\"handleToggleExpandAll\"\n >\n <u-icon>\n <FolderOpened v-if=\"!allExpanded\" />\n <Folder v-else />\n </u-icon>\n </button>\n </u-tip>\n </div>\n\n <div :class=\"cls.e('panel-body')\">\n <UNav\n ref=\"navRef\"\n :menus=\"panelMenus\"\n :current-path=\"currentPath\"\n :collapsed=\"false\"\n @item-click=\"emit('item-click', $event)\"\n />\n </div>\n </template>\n </div>\n </div>\n</template>\n\n<script lang=\"ts\" setup>\nimport { Folder, FolderOpened } from '@veltra/icons/normal'\nimport { bem } from '@veltra/utils'\nimport { computed, ref, useTemplateRef, watch } from 'vue'\n\nimport type { DualNavEmits, DualNavProps, DualNavRootItem } from '../../types/dual-nav'\nimport type { NavExposed, NavItem } from '../../types/nav'\nimport { UIcon } from '../icon'\nimport { UNav } from '../nav'\nimport { collectNavBranchPaths } from '../nav/helper'\nimport { UTip } from '../tip'\nimport DualNavApp from './dual-nav-app.vue'\nimport { findFirstLeaf, findRootApp } from './helper'\n\ndefineOptions({ name: '
|
|
1
|
+
{"version":3,"file":"dual-nav.js","names":[],"sources":["../../../src/components/dual-nav/dual-nav.vue"],"sourcesContent":["<template>\n <div :class=\"cls.b\">\n <div :class=\"cls.e('rail')\">\n <DualNavApp\n v-for=\"app in menus\"\n :key=\"app.path\"\n :app=\"app\"\n :active=\"isAppActive(app)\"\n :selected=\"isAppSelected(app)\"\n @click=\"handleAppClick(app)\"\n />\n </div>\n\n <!-- <div :class=\"cls.e('divider')\" aria-hidden=\"true\" /> -->\n\n <div :class=\"cls.e('panel')\">\n <template v-if=\"panelApp\">\n <div :class=\"cls.e('panel-header')\">\n <div :class=\"cls.e('panel-header-main')\">\n <h3 :class=\"cls.e('panel-title')\">{{ panelApp.title }}</h3>\n <p v-if=\"panelApp.description\" :class=\"cls.e('description')\">\n {{ panelApp.description }}\n </p>\n </div>\n\n <u-tip\n v-if=\"hasExpandableMenus\"\n :content=\"allExpanded ? '折叠全部' : '展开全部'\"\n hide-arrow\n >\n <button\n type=\"button\"\n :class=\"cls.e('toggle-expand')\"\n :aria-label=\"allExpanded ? '折叠全部' : '展开全部'\"\n @click=\"handleToggleExpandAll\"\n >\n <u-icon>\n <FolderOpened v-if=\"!allExpanded\" />\n <Folder v-else />\n </u-icon>\n </button>\n </u-tip>\n </div>\n\n <div :class=\"cls.e('panel-body')\">\n <UNav\n ref=\"navRef\"\n :menus=\"panelMenus\"\n :current-path=\"currentPath\"\n :collapsed=\"false\"\n @item-click=\"emit('item-click', $event)\"\n />\n </div>\n </template>\n </div>\n </div>\n</template>\n\n<script lang=\"ts\" setup>\nimport { Folder, FolderOpened } from '@veltra/icons/normal'\nimport { bem } from '@veltra/utils'\nimport { computed, ref, useTemplateRef, watch } from 'vue'\n\nimport type { DualNavEmits, DualNavProps, DualNavRootItem } from '../../types/dual-nav'\nimport type { NavExposed, NavItem } from '../../types/nav'\nimport { UIcon } from '../icon'\nimport { UNav } from '../nav'\nimport { collectNavBranchPaths } from '../nav/helper'\nimport { UTip } from '../tip'\nimport DualNavApp from './dual-nav-app.vue'\nimport { findFirstLeaf, findRootApp } from './helper'\n\ndefineOptions({ name: 'UDualNav' })\n\nconst props = defineProps<DualNavProps>()\nconst emit = defineEmits<DualNavEmits>()\n\nconst cls = bem('dual-nav')\nconst navRef = useTemplateRef<NavExposed>('navRef')\n\n/** 右栏当前展示的应用(点击左轨或 currentPath 同步) */\nconst panelAppPath = ref<string>()\nconst allExpanded = ref(false)\n\nfunction syncPanelAppFromCurrentPath(currentPath?: string) {\n const rootApp = findRootApp(props.menus, currentPath)\n if (rootApp) {\n panelAppPath.value = rootApp.path\n return\n }\n\n if (!panelAppPath.value && props.menus?.length) {\n panelAppPath.value = props.menus[0]!.path\n }\n}\n\nwatch(\n () => [props.currentPath, props.menus] as const,\n ([currentPath]) => {\n syncPanelAppFromCurrentPath(currentPath)\n },\n { immediate: true }\n)\n\nconst panelApp = computed<DualNavRootItem | undefined>(() => {\n if (!panelAppPath.value || !props.menus?.length) return undefined\n return props.menus.find((app) => app.path === panelAppPath.value)\n})\n\n/** 右栏菜单:有子级时展示子级,单层时展示根项自身 */\nconst panelMenus = computed<NavItem[] | undefined>(() => {\n const app = panelApp.value\n if (!app) return undefined\n if (app.children?.length) return app.children\n return [app]\n})\n\nconst hasExpandableMenus = computed(() => {\n return collectNavBranchPaths(panelMenus.value).length > 0\n})\n\nwatch(panelAppPath, () => {\n allExpanded.value = false\n})\n\n/** 左轨高亮:currentPath 落在该应用下时为激活态 */\nfunction isAppActive(app: NavItem): boolean {\n return findRootApp(props.menus, props.currentPath)?.path === app.path\n}\n\n/** 左轨选中:已切换右栏但尚未导航到该应用下任一菜单时,使用 hover 风格 */\nfunction isAppSelected(app: NavItem): boolean {\n return panelAppPath.value === app.path && !isAppActive(app)\n}\n\nfunction handleAppClick(app: NavItem) {\n if (app.disabled) return\n\n panelAppPath.value = app.path\n\n emit('item-click', findFirstLeaf(app))\n}\n\nfunction handleToggleExpandAll() {\n if (allExpanded.value) {\n navRef.value?.collapseAll()\n allExpanded.value = false\n return\n }\n\n navRef.value?.expandAll()\n allExpanded.value = true\n}\n</script>\n"],"mappings":"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"}
|
|
@@ -3,8 +3,8 @@ import { createElementBlock, createElementVNode, createVNode, defineComponent, n
|
|
|
3
3
|
import { bem } from "@veltra/utils";
|
|
4
4
|
import { Empty } from "@veltra/icons/normal";
|
|
5
5
|
//#region src/components/empty/empty.vue
|
|
6
|
-
const _sfc_main =
|
|
7
|
-
name: "
|
|
6
|
+
const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
7
|
+
name: "UEmpty",
|
|
8
8
|
__name: "empty",
|
|
9
9
|
props: {
|
|
10
10
|
size: { default: 48 },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"empty.js","names":[],"sources":["../../../src/components/empty/empty.vue"],"sourcesContent":["<template>\n <span :class=\"cls.b\">\n <u-icon :size=\"size\"> <Empty /> </u-icon>\n <div>{{ text }}</div>\n </span>\n</template>\n\n<script lang=\"ts\" setup>\nimport { Empty } from '@veltra/icons/normal'\nimport { bem } from '@veltra/utils'\n\nimport type { EmptyProps } from '../../types'\nimport { UIcon } from '../icon'\n\ndefineOptions({ name: '
|
|
1
|
+
{"version":3,"file":"empty.js","names":[],"sources":["../../../src/components/empty/empty.vue"],"sourcesContent":["<template>\n <span :class=\"cls.b\">\n <u-icon :size=\"size\"> <Empty /> </u-icon>\n <div>{{ text }}</div>\n </span>\n</template>\n\n<script lang=\"ts\" setup>\nimport { Empty } from '@veltra/icons/normal'\nimport { bem } from '@veltra/utils'\n\nimport type { EmptyProps } from '../../types'\nimport { UIcon } from '../icon'\n\ndefineOptions({ name: 'UEmpty' })\n\nwithDefaults(defineProps<EmptyProps>(), { size: 48, text: '暂无数据' })\n\nconst cls = bem('empty')\n</script>\n"],"mappings":";;;;;;;;;;;;;EAkBA,MAAM,MAAM,IAAI,OAAO;;uBAjBrB,mBAGO,QAAA,EAHA,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,CAAC,EAAA,GAAA,CACjB,YAAyC,MAAA,WAAA,GAAA,EAAhC,MAAM,QAAA,KAAI,GAAA;2BAAY,CAAT,YAAS,MAAA,KAAA,CAAA,CAAA,CAAA;;oBAC/B,mBAAqB,OAAA,MAAA,gBAAb,QAAA,IAAI,GAAA,CAAA,CAAA,GAAA,CAAA"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Fragment, createCommentVNode, 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
|
-
const _sfc_main =
|
|
5
|
-
name: "
|
|
4
|
+
const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
5
|
+
name: "UExpressionPathPreview",
|
|
6
6
|
__name: "path-preview",
|
|
7
7
|
props: { path: {} },
|
|
8
8
|
setup(__props) {
|
|
@@ -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=\"{ paddingLeft: `${i * 14}px` }\"\n >\n <span v-if=\"i > 0\" :class=\"cls.e('path-tree-branch')\">└</span>\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: '
|
|
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=\"{ paddingLeft: `${i * 14}px` }\"\n >\n <span v-if=\"i > 0\" :class=\"cls.e('path-tree-branch')\">└</span>\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":";;;;;;;;EA0BA,MAAM,MAAM,IAAI,mBAAmB;;uBAzBjC,mBAaM,OAAA,EAbA,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,cAAA,CAAA,EAAA,GAAA,CAChB,mBAAoD,OAAA,EAA9C,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,oBAAA,CAAA,EAAA,GAAwB,QAAI,CAAA,GAC9C,mBAUK,MAAA,EAVA,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,WAAA,CAAA,EAAA,GAAA,EAAA,UAAA,IAAA,GACf,mBAQK,UAAA,MAAA,WAPiB,QAAA,OAAZ,MAAM,MAAC;wBADjB,mBAQK,MAAA;KANF,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,aAAA,GAAoB,IAAC,GAAA,IAAA,CAAA;QAEf,IAAC,KAAA,UAAA,GAAb,mBAA8D,QAAA;;KAA1C,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,kBAAA,CAAA;OAAsB,KAAC,CAAA,KAAA,mBAAA,QAAA,IAAA,GACvD,mBAA+D,QAAA,EAAxD,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,iBAAA,CAAA,EAAA,GAAA,gBAAwB,KAAK,KAAK,GAAA,CAAA,CAAA,GAAA,CAAA"}
|
|
@@ -13,8 +13,8 @@ const _hoisted_2 = [
|
|
|
13
13
|
"onClick",
|
|
14
14
|
"onMouseenter"
|
|
15
15
|
];
|
|
16
|
-
const _sfc_main =
|
|
17
|
-
name: "
|
|
16
|
+
const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
17
|
+
name: "UVariablePicker",
|
|
18
18
|
__name: "variable-picker",
|
|
19
19
|
props: {
|
|
20
20
|
visible: { type: Boolean },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"variable-picker.js","names":[],"sources":["../../../../src/components/expression-editor/components/variable-picker.vue"],"sourcesContent":["<template>\n <u-tip\n hide-arrow\n alignment=\"start\"\n direction=\"bottom\"\n trigger=\"click\"\n :trigger-dom=\"triggerDom\"\n :visible=\"visible\"\n @update:visible=\"handleVisibleChange($event)\"\n >\n <template #content>\n <div :class=\"cls.e('picker')\" @mousedown.prevent>\n <!-- 面包屑:仅逐级模式且非根级显示 -->\n <div v-if=\"!isFlat && navPath.length > 0\" :class=\"cls.e('breadcrumbs')\">\n <span :class=\"cls.e('breadcrumb-item')\">\n <span :class=\"cls.e('breadcrumb-link')\" @click=\"navigateTo(0)\">全部变量</span>\n <u-icon :class=\"cls.e('breadcrumb-separator')\">\n <ArrowRight />\n </u-icon>\n </span>\n <span\n v-for=\"(crumb, i) in navPath\"\n :key=\"`${i}-${crumb.value}`\"\n :class=\"cls.e('breadcrumb-item')\"\n >\n <span\n :class=\"[\n cls.e('breadcrumb-link'),\n { [cls.em('breadcrumb-link', 'active')]: i === navPath.length - 1 }\n ]\"\n @click=\"navigateTo(i + 1)\"\n >{{ crumb.label }}</span\n >\n <u-icon v-if=\"i < navPath.length - 1\" :class=\"cls.e('breadcrumb-separator')\">\n <ArrowRight />\n </u-icon>\n </span>\n </div>\n\n <div :class=\"cls.e('picker-body')\">\n <div :class=\"cls.e('panel')\" v-if=\"currentList.length > 0\">\n <u-scroll tag=\"ul\" :class=\"cls.e('panel-list')\" :content-class=\"cls.e('panel-content')\">\n <li\n v-for=\"(item, idx) in currentList\"\n :key=\"`${idx}-${item.value}`\"\n :data-idx=\"idx\"\n :class=\"getItemCls(item, idx)\"\n @click=\"handleItemClick(item, idx)\"\n @mouseenter=\"activeIndex = idx\"\n >\n <span :class=\"cls.e('item-label')\">{{ item.label }}</span>\n <u-icon v-if=\"!isFlat && hasChildren(item)\" :class=\"cls.e('item-expand')\">\n <ArrowRight />\n </u-icon>\n </li>\n </u-scroll>\n </div>\n <div v-else :class=\"cls.e('empty')\">\n <UEmpty description=\"暂无可用变量\" />\n </div>\n\n <PathPreview v-if=\"isFlat && activePath.length > 0\" :path=\"activePath\" />\n </div>\n </div>\n </template>\n </u-tip>\n</template>\n\n<script lang=\"ts\" setup>\nimport { ArrowRight } from '@veltra/icons/normal'\nimport { bem } from '@veltra/utils'\nimport { computed, nextTick, ref, watch } from 'vue'\n\nimport type { VariableItem } from '../../../types'\nimport { UEmpty } from '../../empty'\nimport { UIcon } from '../../icon'\nimport { UScroll } from '../../scroll'\nimport { UTip } from '../../tip'\nimport PathPreview from './path-preview.vue'\n\ndefineOptions({ name: 'VariablePicker' })\n\ninterface FlatItem extends VariableItem {\n /** 仅扁平模式使用:从根到当前节点的路径 */\n __path: VariableItem[]\n}\n\nconst props = defineProps<{\n visible: boolean\n triggerDom?: HTMLElement\n /** 顶层变量树 */\n variables?: VariableItem[]\n /** 来自编辑器 mention 状态的过滤字符串。空 = 逐级模式;非空 = 扁平模式。 */\n filter: string\n /** 是否允许选中分支节点 */\n selectableLevels: 'leaf' | 'any'\n}>()\n\nconst emit = defineEmits<{\n (e: 'select', item: VariableItem): void\n (e: 'update:visible', visible: boolean): void\n /** 用户主动取消(按 Esc)。编辑器据此把 mention 状态置为 dismissed。 */\n (e: 'dismiss'): void\n}>()\n\nconst cls = bem('expression-editor')\n\nconst navPath = ref<VariableItem[]>([])\nconst activeIndex = ref(0)\n\nconst isFlat = computed(() => props.filter !== '')\n\nfunction hasChildren(item: VariableItem): boolean {\n return !!item.children && item.children.length > 0\n}\n\nfunction isLeaf(item: VariableItem): boolean {\n return !hasChildren(item)\n}\n\n/** 当前层级展示的列表(来源依模式而定) */\nconst currentList = computed<VariableItem[]>(() => {\n const variables = props.variables ?? []\n if (isFlat.value) return flatList.value\n let level: VariableItem[] = variables\n for (const node of navPath.value) {\n const found = level.find((it) => it.value === node.value)\n if (!found || !found.children) break\n level = found.children\n }\n return level\n})\n\n/** 扁平模式下:根据 selectableLevels 拍平 + 过滤 */\nconst flatList = computed<FlatItem[]>(() => {\n const variables = props.variables ?? []\n const out: FlatItem[] = []\n const includeBranches = props.selectableLevels === 'any'\n function walk(items: VariableItem[], path: VariableItem[]) {\n for (const it of items) {\n const nextPath = [...path, it]\n if (isLeaf(it)) {\n out.push({ ...it, __path: nextPath })\n } else {\n if (includeBranches) out.push({ ...it, __path: nextPath })\n walk(it.children!, nextPath)\n }\n }\n }\n walk(variables, [])\n const q = props.filter.toLowerCase()\n return out.filter((it) => it.label.toLowerCase().includes(q))\n})\n\n/** 当前 active 项;扁平模式下用于驱动路径预览 */\nconst activePath = computed<VariableItem[]>(() => {\n if (!isFlat.value) return []\n const item = flatList.value[activeIndex.value] as FlatItem | undefined\n return item ? item.__path : []\n})\n\nfunction getItemCls(_item: VariableItem, idx: number) {\n return [cls.e('item'), bem.is('active', idx === activeIndex.value)]\n}\n\nfunction navigateTo(i: number) {\n // 0 = 全部变量;i 之后表示进入到 navPath[i-1]\n navPath.value = navPath.value.slice(0, i)\n activeIndex.value = 0\n}\n\nfunction handleItemClick(item: VariableItem, idx: number) {\n activeIndex.value = idx\n selectActive()\n}\n\nfunction selectActive() {\n const item = currentList.value[activeIndex.value]\n if (!item) return\n\n if (isFlat.value) {\n // 扁平模式始终是「选中并替换」\n emit('select', flattenSourceFor(item))\n return\n }\n\n // 逐级模式\n if (hasChildren(item)) {\n if (props.selectableLevels === 'any') {\n // Enter 在分支项上:选中分支本身\n emit('select', item)\n return\n }\n // 默认 'leaf':进入下一级\n navPath.value = [...navPath.value, item]\n activeIndex.value = 0\n return\n }\n emit('select', item)\n}\n\nfunction flattenSourceFor(it: VariableItem): VariableItem {\n const flat = it as FlatItem\n // 还原为「不带 __path 的纯 VariableItem」,避免泄漏内部字段\n const out: VariableItem = { value: flat.value, label: flat.label }\n if (flat.type) out.type = flat.type\n if (flat.children) out.children = flat.children\n return out\n}\n\nfunction moveActive(delta: -1 | 1) {\n const max = currentList.value.length - 1\n if (max < 0) return\n let next = activeIndex.value + delta\n if (next < 0) next = 0\n if (next > max) next = max\n activeIndex.value = next\n scrollActiveIntoView()\n}\n\nfunction scrollActiveIntoView() {\n void nextTick(() => {\n const list = document.querySelector(`.${cls.e('panel-list')}`)\n if (!list) return\n const item = list.querySelector(`[data-idx=\"${activeIndex.value}\"]`)\n if (item && 'scrollIntoView' in item) {\n ;(item as HTMLElement).scrollIntoView({ block: 'nearest' })\n }\n })\n}\n\nfunction handleVisibleChange(v: boolean) {\n emit('update:visible', v)\n if (!v) reset()\n}\n\nfunction reset() {\n navPath.value = []\n activeIndex.value = 0\n}\n\nwatch(\n () => props.visible,\n (v) => {\n if (!v) reset()\n else activeIndex.value = 0\n }\n)\n\nwatch(\n () => props.filter,\n () => {\n // 过滤词变化:重置 active;逐级 → 扁平时清空 navPath\n activeIndex.value = 0\n if (isFlat.value) navPath.value = []\n }\n)\n\n/**\n * 由父级 forward 进来的键盘事件。\n * 返回 true 表示已处理(外部应 preventDefault)。\n */\nfunction handleKeydown(e: KeyboardEvent): boolean {\n if (!props.visible) return false\n\n switch (e.key) {\n case 'Escape':\n emit('dismiss')\n emit('update:visible', false)\n reset()\n return true\n case 'ArrowDown':\n moveActive(1)\n return true\n case 'ArrowUp':\n moveActive(-1)\n return true\n case 'ArrowLeft':\n // 仅逐级模式:返回上一级;扁平模式下不拦截,让光标正常移动并触发 mention dismiss\n if (!isFlat.value && navPath.value.length > 0) {\n navPath.value = navPath.value.slice(0, -1)\n activeIndex.value = 0\n return true\n }\n return false\n case 'ArrowRight': {\n if (isFlat.value) return false\n const item = currentList.value[activeIndex.value]\n if (item && hasChildren(item)) {\n navPath.value = [...navPath.value, item]\n activeIndex.value = 0\n return true\n }\n return false\n }\n case 'Enter':\n selectActive()\n return true\n default:\n return false\n }\n}\n\ndefineExpose({ handleKeydown })\n</script>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"variable-picker.js","names":[],"sources":["../../../../src/components/expression-editor/components/variable-picker.vue"],"sourcesContent":["<template>\n <u-tip\n hide-arrow\n alignment=\"start\"\n direction=\"bottom\"\n trigger=\"click\"\n :trigger-dom=\"triggerDom\"\n :visible=\"visible\"\n @update:visible=\"handleVisibleChange($event)\"\n >\n <template #content>\n <div :class=\"cls.e('picker')\" @mousedown.prevent>\n <!-- 面包屑:仅逐级模式且非根级显示 -->\n <div v-if=\"!isFlat && navPath.length > 0\" :class=\"cls.e('breadcrumbs')\">\n <span :class=\"cls.e('breadcrumb-item')\">\n <span :class=\"cls.e('breadcrumb-link')\" @click=\"navigateTo(0)\">全部变量</span>\n <u-icon :class=\"cls.e('breadcrumb-separator')\">\n <ArrowRight />\n </u-icon>\n </span>\n <span\n v-for=\"(crumb, i) in navPath\"\n :key=\"`${i}-${crumb.value}`\"\n :class=\"cls.e('breadcrumb-item')\"\n >\n <span\n :class=\"[\n cls.e('breadcrumb-link'),\n { [cls.em('breadcrumb-link', 'active')]: i === navPath.length - 1 }\n ]\"\n @click=\"navigateTo(i + 1)\"\n >{{ crumb.label }}</span\n >\n <u-icon v-if=\"i < navPath.length - 1\" :class=\"cls.e('breadcrumb-separator')\">\n <ArrowRight />\n </u-icon>\n </span>\n </div>\n\n <div :class=\"cls.e('picker-body')\">\n <div :class=\"cls.e('panel')\" v-if=\"currentList.length > 0\">\n <u-scroll tag=\"ul\" :class=\"cls.e('panel-list')\" :content-class=\"cls.e('panel-content')\">\n <li\n v-for=\"(item, idx) in currentList\"\n :key=\"`${idx}-${item.value}`\"\n :data-idx=\"idx\"\n :class=\"getItemCls(item, idx)\"\n @click=\"handleItemClick(item, idx)\"\n @mouseenter=\"activeIndex = idx\"\n >\n <span :class=\"cls.e('item-label')\">{{ item.label }}</span>\n <u-icon v-if=\"!isFlat && hasChildren(item)\" :class=\"cls.e('item-expand')\">\n <ArrowRight />\n </u-icon>\n </li>\n </u-scroll>\n </div>\n <div v-else :class=\"cls.e('empty')\">\n <UEmpty description=\"暂无可用变量\" />\n </div>\n\n <PathPreview v-if=\"isFlat && activePath.length > 0\" :path=\"activePath\" />\n </div>\n </div>\n </template>\n </u-tip>\n</template>\n\n<script lang=\"ts\" setup>\nimport { ArrowRight } from '@veltra/icons/normal'\nimport { bem } from '@veltra/utils'\nimport { computed, nextTick, ref, watch } from 'vue'\n\nimport type { VariableItem } from '../../../types'\nimport { UEmpty } from '../../empty'\nimport { UIcon } from '../../icon'\nimport { UScroll } from '../../scroll'\nimport { UTip } from '../../tip'\nimport PathPreview from './path-preview.vue'\n\ndefineOptions({ name: 'UVariablePicker' })\n\ninterface FlatItem extends VariableItem {\n /** 仅扁平模式使用:从根到当前节点的路径 */\n __path: VariableItem[]\n}\n\nconst props = defineProps<{\n visible: boolean\n triggerDom?: HTMLElement\n /** 顶层变量树 */\n variables?: VariableItem[]\n /** 来自编辑器 mention 状态的过滤字符串。空 = 逐级模式;非空 = 扁平模式。 */\n filter: string\n /** 是否允许选中分支节点 */\n selectableLevels: 'leaf' | 'any'\n}>()\n\nconst emit = defineEmits<{\n (e: 'select', item: VariableItem): void\n (e: 'update:visible', visible: boolean): void\n /** 用户主动取消(按 Esc)。编辑器据此把 mention 状态置为 dismissed。 */\n (e: 'dismiss'): void\n}>()\n\nconst cls = bem('expression-editor')\n\nconst navPath = ref<VariableItem[]>([])\nconst activeIndex = ref(0)\n\nconst isFlat = computed(() => props.filter !== '')\n\nfunction hasChildren(item: VariableItem): boolean {\n return !!item.children && item.children.length > 0\n}\n\nfunction isLeaf(item: VariableItem): boolean {\n return !hasChildren(item)\n}\n\n/** 当前层级展示的列表(来源依模式而定) */\nconst currentList = computed<VariableItem[]>(() => {\n const variables = props.variables ?? []\n if (isFlat.value) return flatList.value\n let level: VariableItem[] = variables\n for (const node of navPath.value) {\n const found = level.find((it) => it.value === node.value)\n if (!found || !found.children) break\n level = found.children\n }\n return level\n})\n\n/** 扁平模式下:根据 selectableLevels 拍平 + 过滤 */\nconst flatList = computed<FlatItem[]>(() => {\n const variables = props.variables ?? []\n const out: FlatItem[] = []\n const includeBranches = props.selectableLevels === 'any'\n function walk(items: VariableItem[], path: VariableItem[]) {\n for (const it of items) {\n const nextPath = [...path, it]\n if (isLeaf(it)) {\n out.push({ ...it, __path: nextPath })\n } else {\n if (includeBranches) out.push({ ...it, __path: nextPath })\n walk(it.children!, nextPath)\n }\n }\n }\n walk(variables, [])\n const q = props.filter.toLowerCase()\n return out.filter((it) => it.label.toLowerCase().includes(q))\n})\n\n/** 当前 active 项;扁平模式下用于驱动路径预览 */\nconst activePath = computed<VariableItem[]>(() => {\n if (!isFlat.value) return []\n const item = flatList.value[activeIndex.value] as FlatItem | undefined\n return item ? item.__path : []\n})\n\nfunction getItemCls(_item: VariableItem, idx: number) {\n return [cls.e('item'), bem.is('active', idx === activeIndex.value)]\n}\n\nfunction navigateTo(i: number) {\n // 0 = 全部变量;i 之后表示进入到 navPath[i-1]\n navPath.value = navPath.value.slice(0, i)\n activeIndex.value = 0\n}\n\nfunction handleItemClick(item: VariableItem, idx: number) {\n activeIndex.value = idx\n selectActive()\n}\n\nfunction selectActive() {\n const item = currentList.value[activeIndex.value]\n if (!item) return\n\n if (isFlat.value) {\n // 扁平模式始终是「选中并替换」\n emit('select', flattenSourceFor(item))\n return\n }\n\n // 逐级模式\n if (hasChildren(item)) {\n if (props.selectableLevels === 'any') {\n // Enter 在分支项上:选中分支本身\n emit('select', item)\n return\n }\n // 默认 'leaf':进入下一级\n navPath.value = [...navPath.value, item]\n activeIndex.value = 0\n return\n }\n emit('select', item)\n}\n\nfunction flattenSourceFor(it: VariableItem): VariableItem {\n const flat = it as FlatItem\n // 还原为「不带 __path 的纯 VariableItem」,避免泄漏内部字段\n const out: VariableItem = { value: flat.value, label: flat.label }\n if (flat.type) out.type = flat.type\n if (flat.children) out.children = flat.children\n return out\n}\n\nfunction moveActive(delta: -1 | 1) {\n const max = currentList.value.length - 1\n if (max < 0) return\n let next = activeIndex.value + delta\n if (next < 0) next = 0\n if (next > max) next = max\n activeIndex.value = next\n scrollActiveIntoView()\n}\n\nfunction scrollActiveIntoView() {\n void nextTick(() => {\n const list = document.querySelector(`.${cls.e('panel-list')}`)\n if (!list) return\n const item = list.querySelector(`[data-idx=\"${activeIndex.value}\"]`)\n if (item && 'scrollIntoView' in item) {\n ;(item as HTMLElement).scrollIntoView({ block: 'nearest' })\n }\n })\n}\n\nfunction handleVisibleChange(v: boolean) {\n emit('update:visible', v)\n if (!v) reset()\n}\n\nfunction reset() {\n navPath.value = []\n activeIndex.value = 0\n}\n\nwatch(\n () => props.visible,\n (v) => {\n if (!v) reset()\n else activeIndex.value = 0\n }\n)\n\nwatch(\n () => props.filter,\n () => {\n // 过滤词变化:重置 active;逐级 → 扁平时清空 navPath\n activeIndex.value = 0\n if (isFlat.value) navPath.value = []\n }\n)\n\n/**\n * 由父级 forward 进来的键盘事件。\n * 返回 true 表示已处理(外部应 preventDefault)。\n */\nfunction handleKeydown(e: KeyboardEvent): boolean {\n if (!props.visible) return false\n\n switch (e.key) {\n case 'Escape':\n emit('dismiss')\n emit('update:visible', false)\n reset()\n return true\n case 'ArrowDown':\n moveActive(1)\n return true\n case 'ArrowUp':\n moveActive(-1)\n return true\n case 'ArrowLeft':\n // 仅逐级模式:返回上一级;扁平模式下不拦截,让光标正常移动并触发 mention dismiss\n if (!isFlat.value && navPath.value.length > 0) {\n navPath.value = navPath.value.slice(0, -1)\n activeIndex.value = 0\n return true\n }\n return false\n case 'ArrowRight': {\n if (isFlat.value) return false\n const item = currentList.value[activeIndex.value]\n if (item && hasChildren(item)) {\n navPath.value = [...navPath.value, item]\n activeIndex.value = 0\n return true\n }\n return false\n }\n case 'Enter':\n selectActive()\n return true\n default:\n return false\n }\n}\n\ndefineExpose({ handleKeydown })\n</script>\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"editor.js","names":[],"sources":["../../../../src/components/expression-editor/core/editor.ts"],"sourcesContent":["import type { BEM } from '@veltra/utils'\n\nimport type { VariableItem } from '../../../types'\nimport { createChip, isChipElement, readChipType, readChipValue } from './chip'\nimport { normalize, parse, serialize, type Doc, type Segment } from './model'\n\nconst TEXT_SEG_ATTR = 'data-seg'\nconst TEXT_SEG_VALUE = 'text'\n\nexport interface EditorVariableInfo {\n value: string\n label: string\n type?: string\n}\n\nexport interface EditorOptions {\n container: HTMLElement\n cls: BEM<'expression-editor'>\n initialDoc: Doc\n /**\n * 在 DOM → 模型反推、字符串 → 模型反序列化时为 chip 补齐 label / type。\n * 用 getter 形式以便外层 `variables` props 变化时拿到最新映射。\n */\n getVariableMap?: () => Map<string, VariableItem>\n /** 模型每次更新(包括用户键入文本)后回调 */\n onChange?: (doc: Doc) => void\n /** 选中区域 / 光标偏移变化时回调,offset 为序列化字符串中的位置;无选中或不在编辑器内时为 null */\n onSelectionChange?: (info: { offset: number | null }) => void\n /** 用户点击某个 chip 的主体(重选) */\n onChipReselect?: (info: { chipEl: HTMLElement; segIndex: number; chipOffset: number }) => void\n /** 用户点击某个 chip 的 ×(删除) */\n onChipRemove?: (info: { chipEl: HTMLElement; segIndex: number }) => void\n}\n\nexport interface EditorAPI {\n /** 当前模型 */\n getDoc(): Doc\n /** 完全替换模型(会重渲染 DOM) */\n setDoc(doc: Doc): void\n /** 序列化为字符串(modelValue 形态) */\n getValue(): string\n /** 反序列化字符串为模型并替换(可选传入 variableMap 以补齐 label/type) */\n setValue(value: string): void\n /** 当前光标偏移(无 selection 返回 null) */\n getCaretOffset(): number | null\n /** 把光标设置到指定偏移(不会修改模型) */\n setCaretOffset(offset: number): void\n /**\n * 用一个 var chip 替换 [start, end) 区间。\n * 调用方通常在 mention 选中时用:start = `@` 起点、end = 当前光标。\n */\n replaceRangeWithVar(start: number, end: number, variable: EditorVariableInfo): void\n /** 移除指定段下标对应的 var chip(必须是 var 段)。 */\n removeVarAt(segIndex: number): void\n /** 替换指定段下标对应的 var chip 为新变量(必须是 var 段)。 */\n replaceVarAt(segIndex: number, variable: EditorVariableInfo): void\n /** 卸载所有事件监听(不会销毁 container DOM) */\n dispose(): void\n /** 强制根据当前模型重渲染 DOM(光标位置尽量保留) */\n rerender(): void\n /** 容器引用(只读) */\n readonly container: HTMLElement\n}\n\nexport function createEditor(opts: EditorOptions): EditorAPI {\n let doc: Doc = normalize(opts.initialDoc)\n let composing = false\n\n function emitChange(next: Doc) {\n doc = next\n opts.onChange?.(doc)\n }\n\n function makeTextSpan(value: string): HTMLSpanElement {\n const span = document.createElement('span')\n span.setAttribute(TEXT_SEG_ATTR, TEXT_SEG_VALUE)\n span.textContent = value\n return span\n }\n\n function makeChipSpan(seg: Extract<Segment, { kind: 'var' }>): HTMLElement {\n return createChip(seg, {\n cls: opts.cls,\n onReselect: (chipEl) => {\n const { segIndex, chipOffset } = locateChip(chipEl)\n if (segIndex < 0) return\n opts.onChipReselect?.({ chipEl, segIndex, chipOffset })\n },\n onRemove: (chipEl) => {\n const { segIndex } = locateChip(chipEl)\n if (segIndex < 0) return\n opts.onChipRemove?.({ chipEl, segIndex })\n }\n })\n }\n\n function locateChip(chipEl: HTMLElement): { segIndex: number; chipOffset: number } {\n let chipOffset = 0\n let segIdx = -1\n let i = 0\n for (const child of Array.from(opts.container.childNodes)) {\n if (child === chipEl) {\n segIdx = i\n return { segIndex: segIdx, chipOffset }\n }\n chipOffset += childSerialLength(child)\n i++\n }\n return { segIndex: -1, chipOffset: -1 }\n }\n\n function childSerialLength(node: Node): number {\n if (isChipElement(node)) return readChipValue(node).length + 2\n return (node.textContent ?? '').length\n }\n\n /** 渲染 doc 到 container:每个 var 两侧都补一个 text span(即便空),保证光标可停靠。 */\n function render(targetCaret?: number) {\n const container = opts.container\n container.innerHTML = ''\n\n // 在边界与每两个 var 之间确保有 text span 占位\n const expanded: Segment[] = []\n let lastWasVar = false\n let first = true\n for (const seg of doc) {\n if (first) {\n if (seg.kind === 'var') expanded.push({ kind: 'text', value: '' })\n first = false\n } else if (lastWasVar && seg.kind === 'var') {\n expanded.push({ kind: 'text', value: '' })\n }\n expanded.push(seg)\n lastWasVar = seg.kind === 'var'\n }\n if (lastWasVar || expanded.length === 0) expanded.push({ kind: 'text', value: '' })\n\n for (const seg of expanded) {\n if (seg.kind === 'text') container.appendChild(makeTextSpan(seg.value))\n else container.appendChild(makeChipSpan(seg))\n }\n\n if (typeof targetCaret === 'number') setCaret(targetCaret)\n }\n\n /** 从 DOM 反推模型:宽容裸 text node、空 text span。 */\n function readDocFromDOM(): Doc {\n const segs: Segment[] = []\n for (const child of Array.from(opts.container.childNodes)) {\n if (isChipElement(child)) {\n const value = readChipValue(child)\n const domType = readChipType(child)\n const fallbackLabel =\n child.querySelector(`.${opts.cls.e('chip-label')}`)?.textContent ?? value\n // 优先从 variableMap 取最新 label / type,保持与外部数据源一致\n const fromMap = opts.getVariableMap?.().get(value)\n const finalType = fromMap?.type ?? domType\n const seg: Segment = finalType\n ? { kind: 'var', value, label: fromMap?.label ?? fallbackLabel, type: finalType }\n : { kind: 'var', value, label: fromMap?.label ?? fallbackLabel }\n segs.push(seg)\n } else {\n segs.push({ kind: 'text', value: child.textContent ?? '' })\n }\n }\n return normalize(segs)\n }\n\n /**\n * 计算光标在序列化字符串中的全局偏移。\n * 规则:\n * - 在 text span / 裸 text node 中:父级 / 节点之前的 segments 长度累加 + selection 内偏移\n * - 在 chip 边界:根据 selection 在 chip 节点之前 / 之后判断\n */\n function getCaretOffset(): number | null {\n const sel = document.getSelection()\n if (!sel || sel.rangeCount === 0) return null\n const range = sel.getRangeAt(0)\n if (!opts.container.contains(range.startContainer)) return null\n\n let offset = 0\n let found = false\n for (const child of Array.from(opts.container.childNodes)) {\n if (found) break\n if (isChipElement(child)) {\n if (range.startContainer === child) {\n // selection.startOffset 表示子节点索引:0 表示 chip 起始,>=1 表示 chip 之后\n if (range.startOffset === 0) return offset\n return offset + childSerialLength(child)\n }\n if (range.startContainer === opts.container && getChildIndex(child) === range.startOffset) {\n // 容器层 selection:偏移即子节点索引\n return offset\n }\n offset += childSerialLength(child)\n } else {\n // text span 或裸 text 节点\n if (\n range.startContainer === child ||\n (child.contains(range.startContainer) && child !== opts.container)\n ) {\n // 计算 selection 在该 child textContent 中的偏移\n const localOffset = computeTextOffsetWithin(\n child,\n range.startContainer,\n range.startOffset\n )\n return offset + localOffset\n }\n if (range.startContainer === opts.container && getChildIndex(child) === range.startOffset) {\n return offset\n }\n offset += childSerialLength(child)\n }\n }\n if (\n range.startContainer === opts.container &&\n range.startOffset === opts.container.childNodes.length\n ) {\n return offset\n }\n return null\n }\n\n function getChildIndex(node: Node): number {\n let i = 0\n let cur: Node | null = node.previousSibling\n while (cur) {\n i++\n cur = cur.previousSibling\n }\n return i\n }\n\n function computeTextOffsetWithin(root: Node, target: Node, targetOffset: number): number {\n if (root === target) return targetOffset\n let total = 0\n function walk(n: Node): boolean {\n if (n === target) {\n total += targetOffset\n return true\n }\n if (n.nodeType === 3) {\n total += (n as Text).data.length\n return false\n }\n for (const c of Array.from(n.childNodes)) {\n if (walk(c)) return true\n }\n return false\n }\n walk(root)\n return total\n }\n\n /** 把光标放到 offset 处,offset 大于文档长度时落到末尾。 */\n function setCaret(offset: number): void {\n const sel = document.getSelection()\n if (!sel) return\n\n let remain = offset\n const children = Array.from(opts.container.childNodes)\n for (let i = 0; i < children.length; i++) {\n const child = children[i]!\n const len = childSerialLength(child)\n if (isChipElement(child)) {\n if (remain <= 0) {\n // 光标定到 chip 之前 → 落到容器层 child 索引\n placeAt(opts.container, i)\n return\n }\n if (remain < len) {\n // 落在 chip 内部 → 视作 chip 之后\n placeAt(opts.container, i + 1)\n return\n }\n remain -= len\n } else {\n if (remain <= len) {\n // 落在该 text span 内\n placeWithinText(child, remain)\n return\n }\n remain -= len\n }\n }\n // 落到末尾\n if (children.length === 0) {\n placeAt(opts.container, 0)\n return\n }\n const last = children[children.length - 1]!\n if (isChipElement(last)) placeAt(opts.container, children.length)\n else placeWithinText(last, (last.textContent ?? '').length)\n }\n\n function placeAt(parent: Node, index: number) {\n const sel = document.getSelection()\n if (!sel) return\n const range = document.createRange()\n range.setStart(parent, index)\n range.collapse(true)\n sel.removeAllRanges()\n sel.addRange(range)\n }\n\n function placeWithinText(span: Node, offset: number): void {\n const sel = document.getSelection()\n if (!sel) return\n const target = firstTextDescendant(span)\n const range = document.createRange()\n if (target) {\n const max = target.data.length\n range.setStart(target, Math.min(offset, max))\n } else {\n // 空 span:让光标落到 span 内(child index 0)\n range.setStart(span, 0)\n }\n range.collapse(true)\n sel.removeAllRanges()\n sel.addRange(range)\n }\n\n function firstTextDescendant(root: Node): Text | null {\n if (root.nodeType === 3) return root as Text\n for (const c of Array.from(root.childNodes)) {\n const t = firstTextDescendant(c)\n if (t) return t\n }\n return null\n }\n\n /** input 后:从 DOM 反推 doc,并触发 onChange(如有变化)。 */\n function syncFromDOM(): void {\n if (composing) return\n const next = readDocFromDOM()\n if (!docEqual(next, doc)) emitChange(next)\n }\n\n function docEqual(a: Doc, b: Doc): boolean {\n if (a.length !== b.length) return false\n for (let i = 0; i < a.length; i++) {\n const x = a[i]!\n const y = b[i]!\n if (x.kind !== y.kind) return false\n if (x.kind === 'text' && y.kind === 'text' && x.value !== y.value) return false\n if (x.kind === 'var' && y.kind === 'var') {\n if (x.value !== y.value || x.label !== y.label || x.type !== y.type) return false\n }\n }\n return true\n }\n\n function onInput() {\n syncFromDOM()\n }\n function onCompositionStart() {\n composing = true\n }\n function onCompositionEnd() {\n composing = false\n syncFromDOM()\n }\n function onPaste(e: ClipboardEvent) {\n e.preventDefault()\n const text = e.clipboardData?.getData('text/plain') ?? ''\n if (!text) return\n insertPlainTextAtCaret(text)\n }\n function onSelectionChange() {\n if (composing) return\n if (!opts.onSelectionChange) return\n const sel = document.getSelection()\n if (!sel || sel.rangeCount === 0) {\n opts.onSelectionChange({ offset: null })\n return\n }\n const range = sel.getRangeAt(0)\n if (!opts.container.contains(range.startContainer)) {\n opts.onSelectionChange({ offset: null })\n return\n }\n opts.onSelectionChange({ offset: getCaretOffset() })\n }\n\n function insertPlainTextAtCaret(text: string) {\n const sel = document.getSelection()\n if (!sel || sel.rangeCount === 0) return\n const range = sel.getRangeAt(0)\n if (!opts.container.contains(range.startContainer)) return\n range.deleteContents()\n const node = document.createTextNode(text)\n range.insertNode(node)\n range.setStartAfter(node)\n range.collapse(true)\n sel.removeAllRanges()\n sel.addRange(range)\n syncFromDOM()\n }\n\n // 命令:替换区间为 var chip\n function replaceRangeWithVar(start: number, end: number, variable: EditorVariableInfo) {\n const a = Math.min(start, end)\n const b = Math.max(start, end)\n const left = sliceDoc(doc, 0, a)\n const right = sliceDoc(doc, b, totalLength(doc))\n const inserted: Segment = variable.type\n ? { kind: 'var', value: variable.value, label: variable.label, type: variable.type }\n : { kind: 'var', value: variable.value, label: variable.label }\n const next = normalize([...left, inserted, ...right])\n emitChange(next)\n render(a + variable.value.length + 2) // 光标定到 chip 之后\n }\n\n function removeVarAt(segIndex: number) {\n const target = doc[segIndex]\n if (!target || target.kind !== 'var') return\n const before = doc.slice(0, segIndex)\n const after = doc.slice(segIndex + 1)\n const caretOffset = sliceLength(before)\n const next = normalize([...before, ...after])\n emitChange(next)\n render(caretOffset)\n }\n\n function replaceVarAt(segIndex: number, variable: EditorVariableInfo) {\n const target = doc[segIndex]\n if (!target || target.kind !== 'var') return\n const next = doc.slice()\n const replaced: Segment = variable.type\n ? { kind: 'var', value: variable.value, label: variable.label, type: variable.type }\n : { kind: 'var', value: variable.value, label: variable.label }\n next[segIndex] = replaced\n const caretOffset = sliceLength(doc.slice(0, segIndex)) + variable.value.length + 2\n emitChange(normalize(next))\n render(caretOffset)\n }\n\n // 工具:基于序列化偏移的切片(不会切开 var)\n function sliceDoc(d: Doc, start: number, end: number): Doc {\n const out: Segment[] = []\n let pos = 0\n for (const seg of d) {\n const len = seg.kind === 'text' ? seg.value.length : seg.value.length + 2\n const segStart = pos\n const segEnd = pos + len\n if (segEnd <= start || segStart >= end) {\n pos += len\n continue\n }\n if (seg.kind === 'text') {\n const a = Math.max(0, start - segStart)\n const b = Math.min(len, end - segStart)\n const slice = seg.value.slice(a, b)\n if (slice) out.push({ kind: 'text', value: slice })\n } else {\n // var 是原子:只有当 [start, end) 完整覆盖该 var 时保留;否则抛弃\n if (start <= segStart && end >= segEnd) out.push(seg)\n }\n pos += len\n }\n return out\n }\n\n function sliceLength(d: Doc): number {\n let n = 0\n for (const s of d) n += s.kind === 'text' ? s.value.length : s.value.length + 2\n return n\n }\n\n function totalLength(d: Doc): number {\n return sliceLength(d)\n }\n\n // 绑定监听\n const container = opts.container\n container.addEventListener('input', onInput)\n container.addEventListener('compositionstart', onCompositionStart)\n container.addEventListener('compositionend', onCompositionEnd)\n container.addEventListener('paste', onPaste)\n document.addEventListener('selectionchange', onSelectionChange)\n\n // 初次渲染\n render()\n\n return {\n getDoc: () => doc,\n setDoc: (next) => {\n doc = normalize(next)\n render()\n opts.onChange?.(doc)\n },\n getValue: () => serialize(doc),\n setValue: (value) => {\n doc = parse(value, opts.getVariableMap?.())\n render()\n opts.onChange?.(doc)\n },\n getCaretOffset,\n setCaretOffset: setCaret,\n replaceRangeWithVar,\n removeVarAt,\n replaceVarAt,\n rerender: () => render(),\n dispose: () => {\n container.removeEventListener('input', onInput)\n container.removeEventListener('compositionstart', onCompositionStart)\n container.removeEventListener('compositionend', onCompositionEnd)\n container.removeEventListener('paste', onPaste)\n document.removeEventListener('selectionchange', onSelectionChange)\n },\n container\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"editor.js","names":[],"sources":["../../../../src/components/expression-editor/core/editor.ts"],"sourcesContent":["import type { BEM } from '@veltra/utils'\n\nimport type { VariableItem } from '../../../types'\nimport { createChip, isChipElement, readChipType, readChipValue } from './chip'\nimport { normalize, parse, serialize, type Doc, type Segment } from './model'\n\nconst TEXT_SEG_ATTR = 'data-seg'\nconst TEXT_SEG_VALUE = 'text'\n\nexport interface EditorVariableInfo {\n value: string\n label: string\n type?: string\n}\n\nexport interface EditorOptions {\n container: HTMLElement\n cls: BEM<'expression-editor'>\n initialDoc: Doc\n /**\n * 在 DOM → 模型反推、字符串 → 模型反序列化时为 chip 补齐 label / type。\n * 用 getter 形式以便外层 `variables` props 变化时拿到最新映射。\n */\n getVariableMap?: () => Map<string, VariableItem>\n /** 模型每次更新(包括用户键入文本)后回调 */\n onChange?: (doc: Doc) => void\n /** 选中区域 / 光标偏移变化时回调,offset 为序列化字符串中的位置;无选中或不在编辑器内时为 null */\n onSelectionChange?: (info: { offset: number | null }) => void\n /** 用户点击某个 chip 的主体(重选) */\n onChipReselect?: (info: { chipEl: HTMLElement; segIndex: number; chipOffset: number }) => void\n /** 用户点击某个 chip 的 ×(删除) */\n onChipRemove?: (info: { chipEl: HTMLElement; segIndex: number }) => void\n}\n\nexport interface EditorAPI {\n /** 当前模型 */\n getDoc(): Doc\n /** 完全替换模型(会重渲染 DOM) */\n setDoc(doc: Doc): void\n /** 序列化为字符串(modelValue 形态) */\n getValue(): string\n /** 反序列化字符串为模型并替换(可选传入 variableMap 以补齐 label/type) */\n setValue(value: string): void\n /** 当前光标偏移(无 selection 返回 null) */\n getCaretOffset(): number | null\n /** 把光标设置到指定偏移(不会修改模型) */\n setCaretOffset(offset: number): void\n /**\n * 用一个 var chip 替换 [start, end) 区间。\n * 调用方通常在 mention 选中时用:start = `@` 起点、end = 当前光标。\n */\n replaceRangeWithVar(start: number, end: number, variable: EditorVariableInfo): void\n /** 移除指定段下标对应的 var chip(必须是 var 段)。 */\n removeVarAt(segIndex: number): void\n /** 替换指定段下标对应的 var chip 为新变量(必须是 var 段)。 */\n replaceVarAt(segIndex: number, variable: EditorVariableInfo): void\n /** 卸载所有事件监听(不会销毁 container DOM) */\n dispose(): void\n /** 强制根据当前模型重渲染 DOM(光标位置尽量保留) */\n rerender(): void\n /** 容器引用(只读) */\n readonly container: HTMLElement\n}\n\nexport function createEditor(opts: EditorOptions): EditorAPI {\n let doc: Doc = normalize(opts.initialDoc)\n let composing = false\n\n function emitChange(next: Doc) {\n doc = next\n opts.onChange?.(doc)\n }\n\n function makeTextSpan(value: string): HTMLSpanElement {\n const span = document.createElement('span')\n span.setAttribute(TEXT_SEG_ATTR, TEXT_SEG_VALUE)\n span.textContent = value\n return span\n }\n\n function makeChipSpan(seg: Extract<Segment, { kind: 'var' }>): HTMLElement {\n return createChip(seg, {\n cls: opts.cls,\n onReselect: (chipEl) => {\n const { segIndex, chipOffset } = locateChip(chipEl)\n if (segIndex < 0) return\n opts.onChipReselect?.({ chipEl, segIndex, chipOffset })\n },\n onRemove: (chipEl) => {\n const { segIndex } = locateChip(chipEl)\n if (segIndex < 0) return\n opts.onChipRemove?.({ chipEl, segIndex })\n }\n })\n }\n\n function locateChip(chipEl: HTMLElement): { segIndex: number; chipOffset: number } {\n let chipOffset = 0\n let segIdx = -1\n let i = 0\n for (const child of Array.from(opts.container.childNodes)) {\n if (child === chipEl) {\n segIdx = i\n return { segIndex: segIdx, chipOffset }\n }\n chipOffset += childSerialLength(child)\n i++\n }\n return { segIndex: -1, chipOffset: -1 }\n }\n\n function childSerialLength(node: Node): number {\n if (isChipElement(node)) return readChipValue(node).length + 2\n return (node.textContent ?? '').length\n }\n\n /** 渲染 doc 到 container:每个 var 两侧都补一个 text span(即便空),保证光标可停靠。 */\n function render(targetCaret?: number) {\n const container = opts.container\n container.innerHTML = ''\n\n // 在边界与每两个 var 之间确保有 text span 占位\n const expanded: Segment[] = []\n let lastWasVar = false\n let first = true\n for (const seg of doc) {\n if (first) {\n if (seg.kind === 'var') expanded.push({ kind: 'text', value: '' })\n first = false\n } else if (lastWasVar && seg.kind === 'var') {\n expanded.push({ kind: 'text', value: '' })\n }\n expanded.push(seg)\n lastWasVar = seg.kind === 'var'\n }\n if (lastWasVar || expanded.length === 0) expanded.push({ kind: 'text', value: '' })\n\n for (const seg of expanded) {\n if (seg.kind === 'text') container.appendChild(makeTextSpan(seg.value))\n else container.appendChild(makeChipSpan(seg))\n }\n\n if (typeof targetCaret === 'number') setCaret(targetCaret)\n }\n\n /** 从 DOM 反推模型:宽容裸 text node、空 text span。 */\n function readDocFromDOM(): Doc {\n const segs: Segment[] = []\n for (const child of Array.from(opts.container.childNodes)) {\n if (isChipElement(child)) {\n const value = readChipValue(child)\n const domType = readChipType(child)\n const fallbackLabel =\n child.querySelector(`.${opts.cls.e('chip-label')}`)?.textContent ?? value\n // 优先从 variableMap 取最新 label / type,保持与外部数据源一致\n const fromMap = opts.getVariableMap?.().get(value)\n const finalType = fromMap?.type ?? domType\n const seg: Segment = finalType\n ? { kind: 'var', value, label: fromMap?.label ?? fallbackLabel, type: finalType }\n : { kind: 'var', value, label: fromMap?.label ?? fallbackLabel }\n segs.push(seg)\n } else {\n segs.push({ kind: 'text', value: child.textContent ?? '' })\n }\n }\n return normalize(segs)\n }\n\n /**\n * 计算光标在序列化字符串中的全局偏移。\n * 规则:\n * - 在 text span / 裸 text node 中:父级 / 节点之前的 segments 长度累加 + selection 内偏移\n * - 在 chip 边界:根据 selection 在 chip 节点之前 / 之后判断\n */\n function getCaretOffset(): number | null {\n const sel = document.getSelection()\n if (!sel || sel.rangeCount === 0) return null\n const range = sel.getRangeAt(0)\n if (!opts.container.contains(range.startContainer)) return null\n\n let offset = 0\n let found = false\n for (const child of Array.from(opts.container.childNodes)) {\n if (found) break\n if (isChipElement(child)) {\n if (range.startContainer === child) {\n // selection.startOffset 表示子节点索引:0 表示 chip 起始,>=1 表示 chip 之后\n if (range.startOffset === 0) return offset\n return offset + childSerialLength(child)\n }\n if (range.startContainer === opts.container && getChildIndex(child) === range.startOffset) {\n // 容器层 selection:偏移即子节点索引\n return offset\n }\n offset += childSerialLength(child)\n } else {\n // text span 或裸 text 节点\n if (\n range.startContainer === child ||\n (child.contains(range.startContainer) && child !== opts.container)\n ) {\n // 计算 selection 在该 child textContent 中的偏移\n const localOffset = computeTextOffsetWithin(\n child,\n range.startContainer,\n range.startOffset\n )\n return offset + localOffset\n }\n if (range.startContainer === opts.container && getChildIndex(child) === range.startOffset) {\n return offset\n }\n offset += childSerialLength(child)\n }\n }\n if (\n range.startContainer === opts.container &&\n range.startOffset === opts.container.childNodes.length\n ) {\n return offset\n }\n return null\n }\n\n function getChildIndex(node: Node): number {\n let i = 0\n let cur: Node | null = node.previousSibling\n while (cur) {\n i++\n cur = cur.previousSibling\n }\n return i\n }\n\n function computeTextOffsetWithin(root: Node, target: Node, targetOffset: number): number {\n if (root === target) return targetOffset\n let total = 0\n function walk(n: Node): boolean {\n if (n === target) {\n total += targetOffset\n return true\n }\n if (n.nodeType === 3) {\n total += (n as Text).data.length\n return false\n }\n for (const c of Array.from(n.childNodes)) {\n if (walk(c)) return true\n }\n return false\n }\n walk(root)\n return total\n }\n\n /** 把光标放到 offset 处,offset 大于文档长度时落到末尾。 */\n function setCaret(offset: number): void {\n const sel = document.getSelection()\n if (!sel) return\n\n let remain = offset\n const children = Array.from(opts.container.childNodes)\n for (let i = 0; i < children.length; i++) {\n const child = children[i]!\n const len = childSerialLength(child)\n if (isChipElement(child)) {\n if (remain <= 0) {\n // 光标定到 chip 之前 → 落到容器层 child 索引\n placeAt(opts.container, i)\n return\n }\n if (remain < len) {\n // 落在 chip 内部 → 视作 chip 之后\n placeAt(opts.container, i + 1)\n return\n }\n remain -= len\n } else {\n if (remain <= len) {\n // 落在该 text span 内\n placeWithinText(child, remain)\n return\n }\n remain -= len\n }\n }\n // 落到末尾\n if (children.length === 0) {\n placeAt(opts.container, 0)\n return\n }\n const last = children[children.length - 1]!\n if (isChipElement(last)) placeAt(opts.container, children.length)\n else placeWithinText(last, (last.textContent ?? '').length)\n }\n\n function placeAt(parent: Node, index: number) {\n const sel = document.getSelection()\n if (!sel) return\n const range = document.createRange()\n range.setStart(parent, index)\n range.collapse(true)\n sel.removeAllRanges()\n sel.addRange(range)\n }\n\n function placeWithinText(span: Node, offset: number): void {\n const sel = document.getSelection()\n if (!sel) return\n const target = firstTextDescendant(span)\n const range = document.createRange()\n if (target) {\n const max = target.data.length\n range.setStart(target, Math.min(offset, max))\n } else {\n // 空 span:让光标落到 span 内(child index 0)\n range.setStart(span, 0)\n }\n range.collapse(true)\n sel.removeAllRanges()\n sel.addRange(range)\n }\n\n function firstTextDescendant(root: Node): Text | null {\n if (root.nodeType === 3) return root as Text\n for (const c of Array.from(root.childNodes)) {\n const t = firstTextDescendant(c)\n if (t) return t\n }\n return null\n }\n\n /** input 后:从 DOM 反推 doc,并触发 onChange(如有变化)。 */\n function syncFromDOM(): void {\n if (composing) return\n const next = readDocFromDOM()\n if (!docEqual(next, doc)) emitChange(next)\n }\n\n function docEqual(a: Doc, b: Doc): boolean {\n if (a.length !== b.length) return false\n for (let i = 0; i < a.length; i++) {\n const x = a[i]!\n const y = b[i]!\n if (x.kind !== y.kind) return false\n if (x.kind === 'text' && y.kind === 'text' && x.value !== y.value) return false\n if (x.kind === 'var' && y.kind === 'var') {\n if (x.value !== y.value || x.label !== y.label || x.type !== y.type) return false\n }\n }\n return true\n }\n\n function onInput() {\n syncFromDOM()\n }\n function onCompositionStart() {\n composing = true\n }\n function onCompositionEnd() {\n composing = false\n syncFromDOM()\n }\n function onPaste(e: ClipboardEvent) {\n e.preventDefault()\n const text = e.clipboardData?.getData('text/plain') ?? ''\n if (!text) return\n insertPlainTextAtCaret(text)\n }\n function onSelectionChange() {\n if (composing) return\n if (!opts.onSelectionChange) return\n const sel = document.getSelection()\n if (!sel || sel.rangeCount === 0) {\n opts.onSelectionChange({ offset: null })\n return\n }\n const range = sel.getRangeAt(0)\n if (!opts.container.contains(range.startContainer)) {\n opts.onSelectionChange({ offset: null })\n return\n }\n opts.onSelectionChange({ offset: getCaretOffset() })\n }\n\n function insertPlainTextAtCaret(text: string) {\n const sel = document.getSelection()\n if (!sel || sel.rangeCount === 0) return\n const range = sel.getRangeAt(0)\n if (!opts.container.contains(range.startContainer)) return\n range.deleteContents()\n const node = document.createTextNode(text)\n range.insertNode(node)\n range.setStartAfter(node)\n range.collapse(true)\n sel.removeAllRanges()\n sel.addRange(range)\n syncFromDOM()\n }\n\n // 命令:替换区间为 var chip\n function replaceRangeWithVar(start: number, end: number, variable: EditorVariableInfo) {\n const a = Math.min(start, end)\n const b = Math.max(start, end)\n const left = sliceDoc(doc, 0, a)\n const right = sliceDoc(doc, b, totalLength(doc))\n const inserted: Segment = variable.type\n ? { kind: 'var', value: variable.value, label: variable.label, type: variable.type }\n : { kind: 'var', value: variable.value, label: variable.label }\n const next = normalize([...left, inserted, ...right])\n emitChange(next)\n render(a + variable.value.length + 2) // 光标定到 chip 之后\n }\n\n function removeVarAt(segIndex: number) {\n const target = doc[segIndex]\n if (!target || target.kind !== 'var') return\n const before = doc.slice(0, segIndex)\n const after = doc.slice(segIndex + 1)\n const caretOffset = sliceLength(before)\n const next = normalize([...before, ...after])\n emitChange(next)\n render(caretOffset)\n }\n\n function replaceVarAt(segIndex: number, variable: EditorVariableInfo) {\n const target = doc[segIndex]\n if (!target || target.kind !== 'var') return\n const next = doc.slice()\n const replaced: Segment = variable.type\n ? { kind: 'var', value: variable.value, label: variable.label, type: variable.type }\n : { kind: 'var', value: variable.value, label: variable.label }\n next[segIndex] = replaced\n const caretOffset = sliceLength(doc.slice(0, segIndex)) + variable.value.length + 2\n emitChange(normalize(next))\n render(caretOffset)\n }\n\n // 工具:基于序列化偏移的切片(不会切开 var)\n function sliceDoc(d: Doc, start: number, end: number): Doc {\n const out: Segment[] = []\n let pos = 0\n for (const seg of d) {\n const len = seg.kind === 'text' ? seg.value.length : seg.value.length + 2\n const segStart = pos\n const segEnd = pos + len\n if (segEnd <= start || segStart >= end) {\n pos += len\n continue\n }\n if (seg.kind === 'text') {\n const a = Math.max(0, start - segStart)\n const b = Math.min(len, end - segStart)\n const slice = seg.value.slice(a, b)\n if (slice) out.push({ kind: 'text', value: slice })\n } else {\n // var 是原子:只有当 [start, end) 完整覆盖该 var 时保留;否则抛弃\n if (start <= segStart && end >= segEnd) out.push(seg)\n }\n pos += len\n }\n return out\n }\n\n function sliceLength(d: Doc): number {\n let n = 0\n for (const s of d) n += s.kind === 'text' ? s.value.length : s.value.length + 2\n return n\n }\n\n function totalLength(d: Doc): number {\n return sliceLength(d)\n }\n\n // 绑定监听\n const container = opts.container\n container.addEventListener('input', onInput)\n container.addEventListener('compositionstart', onCompositionStart)\n container.addEventListener('compositionend', onCompositionEnd)\n container.addEventListener('paste', onPaste)\n document.addEventListener('selectionchange', onSelectionChange)\n\n // 初次渲染\n render()\n\n return {\n getDoc: () => doc,\n setDoc: (next) => {\n doc = normalize(next)\n render()\n opts.onChange?.(doc)\n },\n getValue: () => serialize(doc),\n setValue: (value) => {\n doc = parse(value, opts.getVariableMap?.())\n render()\n opts.onChange?.(doc)\n },\n getCaretOffset,\n setCaretOffset: setCaret,\n replaceRangeWithVar,\n removeVarAt,\n replaceVarAt,\n rerender: () => render(),\n dispose: () => {\n container.removeEventListener('input', onInput)\n container.removeEventListener('compositionstart', onCompositionStart)\n container.removeEventListener('compositionend', onCompositionEnd)\n container.removeEventListener('paste', onPaste)\n document.removeEventListener('selectionchange', onSelectionChange)\n },\n container\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model.js","names":[],"sources":["../../../../src/components/expression-editor/core/model.ts"],"sourcesContent":["import type { VariableItem } from '../../../types'\n\n/** 单个文档段:纯文本或变量 chip */\nexport type Segment =\n | { kind: 'text'; value: string }\n | { kind: 'var'; value: string; label: string; type?: string }\n\n/** 归一化的文档形态:相邻 text 段会合并、空 text 段不保留 */\nexport type Doc = Segment[]\n\nconst VARIABLE_PATTERN = /\\{([^}]+)\\}/g\n\n/**\n * 反序列化:将 modelValue 字符串解析为 Segment[]。\n * 沿用旧 parser.ts 的正则切分逻辑,保证 round-trip 与历史一致。\n */\nexport function parse(content: string, variableMap?: Map<string, VariableItem>): Doc {\n const segments: Segment[] = []\n if (!content) return segments\n\n let cursor = 0\n for (const match of content.matchAll(VARIABLE_PATTERN)) {\n const value = match[1]!\n const start = match.index!\n if (start > cursor) {\n segments.push({ kind: 'text', value: content.slice(cursor, start) })\n }\n const found = variableMap?.get(value)\n segments.push({\n kind: 'var',\n value,\n label: found?.label ?? value,\n ...(found?.type ? { type: found.type } : {})\n })\n cursor = start + match[0].length\n }\n if (cursor < content.length) {\n segments.push({ kind: 'text', value: content.slice(cursor) })\n }\n\n return normalize(segments)\n}\n\n/** 序列化:var 段输出 `{value}`,text 段直接拼接。 */\nexport function serialize(doc: Doc): string {\n let out = ''\n for (const seg of doc) {\n out += seg.kind === 'text' ? seg.value : `{${seg.value}}`\n }\n return out\n}\n\n/**\n * 归一化:合并相邻 text 段、丢弃空 text 段。\n * 注意:DOM 层另需保证 var 两侧有 text 占位(即便空),由 editor 渲染时补齐。\n */\nexport function normalize(doc: Doc): Doc {\n const out: Segment[] = []\n for (const seg of doc) {\n if (seg.kind === 'text') {\n if (!seg.value) continue\n const last = out[out.length - 1]\n if (last && last.kind === 'text') {\n out[out.length - 1] = { kind: 'text', value: last.value + seg.value }\n continue\n }\n }\n out.push(seg)\n }\n return out\n}\n\ninterface SplitResult {\n before: Doc\n after: Doc\n}\n\n/**\n * 在序列化后的字符串偏移上切分(不会切开 var)。\n * 若偏移落在 var 中间,向前对齐到 var 起点。\n */\nexport function splitAt(doc: Doc, globalOffset: number): SplitResult {\n const before: Doc = []\n const after: Doc = []\n let pos = 0\n let consumed = false\n\n for (const seg of doc) {\n const segLen = seg.kind === 'text' ? seg.value.length : seg.value.length + 2\n if (consumed) {\n after.push(seg)\n continue\n }\n if (globalOffset >= pos + segLen) {\n before.push(seg)\n pos += segLen\n continue\n }\n if (seg.kind === 'text') {\n const offset = globalOffset - pos\n if (offset > 0) before.push({ kind: 'text', value: seg.value.slice(0, offset) })\n if (offset < seg.value.length) after.push({ kind: 'text', value: seg.value.slice(offset) })\n } else {\n after.push(seg)\n }\n consumed = true\n }\n return { before, after }\n}\n"],"mappings":";AAUA,MAAM,mBAAmB;;;;;AAMzB,SAAgB,MAAM,SAAiB,aAA8C;CACnF,MAAM,WAAsB,CAAC;CAC7B,IAAI,CAAC,SAAS,OAAO;CAErB,IAAI,SAAS;CACb,KAAK,MAAM,SAAS,QAAQ,SAAS,gBAAgB,GAAG;EACtD,MAAM,QAAQ,MAAM;EACpB,MAAM,QAAQ,MAAM;EACpB,IAAI,QAAQ,QACV,SAAS,KAAK;GAAE,MAAM;GAAQ,OAAO,QAAQ,MAAM,QAAQ,KAAK;EAAE,CAAC;EAErE,MAAM,QAAQ,aAAa,IAAI,KAAK;EACpC,SAAS,KAAK;GACZ,MAAM;GACN;GACA,OAAO,OAAO,SAAS;GACvB,GAAI,OAAO,OAAO,EAAE,MAAM,MAAM,KAAK,IAAI,CAAC;EAC5C,CAAC;EACD,SAAS,QAAQ,MAAM,
|
|
1
|
+
{"version":3,"file":"model.js","names":[],"sources":["../../../../src/components/expression-editor/core/model.ts"],"sourcesContent":["import type { VariableItem } from '../../../types'\n\n/** 单个文档段:纯文本或变量 chip */\nexport type Segment =\n | { kind: 'text'; value: string }\n | { kind: 'var'; value: string; label: string; type?: string }\n\n/** 归一化的文档形态:相邻 text 段会合并、空 text 段不保留 */\nexport type Doc = Segment[]\n\nconst VARIABLE_PATTERN = /\\{([^}]+)\\}/g\n\n/**\n * 反序列化:将 modelValue 字符串解析为 Segment[]。\n * 沿用旧 parser.ts 的正则切分逻辑,保证 round-trip 与历史一致。\n */\nexport function parse(content: string, variableMap?: Map<string, VariableItem>): Doc {\n const segments: Segment[] = []\n if (!content) return segments\n\n let cursor = 0\n for (const match of content.matchAll(VARIABLE_PATTERN)) {\n const value = match[1]!\n const start = match.index!\n if (start > cursor) {\n segments.push({ kind: 'text', value: content.slice(cursor, start) })\n }\n const found = variableMap?.get(value)\n segments.push({\n kind: 'var',\n value,\n label: found?.label ?? value,\n ...(found?.type ? { type: found.type } : {})\n })\n cursor = start + match[0].length\n }\n if (cursor < content.length) {\n segments.push({ kind: 'text', value: content.slice(cursor) })\n }\n\n return normalize(segments)\n}\n\n/** 序列化:var 段输出 `{value}`,text 段直接拼接。 */\nexport function serialize(doc: Doc): string {\n let out = ''\n for (const seg of doc) {\n out += seg.kind === 'text' ? seg.value : `{${seg.value}}`\n }\n return out\n}\n\n/**\n * 归一化:合并相邻 text 段、丢弃空 text 段。\n * 注意:DOM 层另需保证 var 两侧有 text 占位(即便空),由 editor 渲染时补齐。\n */\nexport function normalize(doc: Doc): Doc {\n const out: Segment[] = []\n for (const seg of doc) {\n if (seg.kind === 'text') {\n if (!seg.value) continue\n const last = out[out.length - 1]\n if (last && last.kind === 'text') {\n out[out.length - 1] = { kind: 'text', value: last.value + seg.value }\n continue\n }\n }\n out.push(seg)\n }\n return out\n}\n\ninterface SplitResult {\n before: Doc\n after: Doc\n}\n\n/**\n * 在序列化后的字符串偏移上切分(不会切开 var)。\n * 若偏移落在 var 中间,向前对齐到 var 起点。\n */\nexport function splitAt(doc: Doc, globalOffset: number): SplitResult {\n const before: Doc = []\n const after: Doc = []\n let pos = 0\n let consumed = false\n\n for (const seg of doc) {\n const segLen = seg.kind === 'text' ? seg.value.length : seg.value.length + 2\n if (consumed) {\n after.push(seg)\n continue\n }\n if (globalOffset >= pos + segLen) {\n before.push(seg)\n pos += segLen\n continue\n }\n if (seg.kind === 'text') {\n const offset = globalOffset - pos\n if (offset > 0) before.push({ kind: 'text', value: seg.value.slice(0, offset) })\n if (offset < seg.value.length) after.push({ kind: 'text', value: seg.value.slice(offset) })\n } else {\n after.push(seg)\n }\n consumed = true\n }\n return { before, after }\n}\n"],"mappings":";AAUA,MAAM,mBAAmB;;;;;AAMzB,SAAgB,MAAM,SAAiB,aAA8C;CACnF,MAAM,WAAsB,CAAC;CAC7B,IAAI,CAAC,SAAS,OAAO;CAErB,IAAI,SAAS;CACb,KAAK,MAAM,SAAS,QAAQ,SAAS,gBAAgB,GAAG;EACtD,MAAM,QAAQ,MAAM;EACpB,MAAM,QAAQ,MAAM;EACpB,IAAI,QAAQ,QACV,SAAS,KAAK;GAAE,MAAM;GAAQ,OAAO,QAAQ,MAAM,QAAQ,KAAK;EAAE,CAAC;EAErE,MAAM,QAAQ,aAAa,IAAI,KAAK;EACpC,SAAS,KAAK;GACZ,MAAM;GACN;GACA,OAAO,OAAO,SAAS;GACvB,GAAI,OAAO,OAAO,EAAE,MAAM,MAAM,KAAK,IAAI,CAAC;EAC5C,CAAC;EACD,SAAS,QAAQ,MAAM,EAAE,CAAC;CAC5B;CACA,IAAI,SAAS,QAAQ,QACnB,SAAS,KAAK;EAAE,MAAM;EAAQ,OAAO,QAAQ,MAAM,MAAM;CAAE,CAAC;CAG9D,OAAO,UAAU,QAAQ;AAC3B;;AAGA,SAAgB,UAAU,KAAkB;CAC1C,IAAI,MAAM;CACV,KAAK,MAAM,OAAO,KAChB,OAAO,IAAI,SAAS,SAAS,IAAI,QAAQ,IAAI,IAAI,MAAM;CAEzD,OAAO;AACT;;;;;AAMA,SAAgB,UAAU,KAAe;CACvC,MAAM,MAAiB,CAAC;CACxB,KAAK,MAAM,OAAO,KAAK;EACrB,IAAI,IAAI,SAAS,QAAQ;GACvB,IAAI,CAAC,IAAI,OAAO;GAChB,MAAM,OAAO,IAAI,IAAI,SAAS;GAC9B,IAAI,QAAQ,KAAK,SAAS,QAAQ;IAChC,IAAI,IAAI,SAAS,KAAK;KAAE,MAAM;KAAQ,OAAO,KAAK,QAAQ,IAAI;IAAM;IACpE;GACF;EACF;EACA,IAAI,KAAK,GAAG;CACd;CACA,OAAO;AACT"}
|
|
@@ -12,8 +12,8 @@ const _hoisted_1 = [
|
|
|
12
12
|
"data-empty",
|
|
13
13
|
"data-placeholder"
|
|
14
14
|
];
|
|
15
|
-
const _sfc_main =
|
|
16
|
-
name: "
|
|
15
|
+
const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
16
|
+
name: "UExpressionEditor",
|
|
17
17
|
__name: "expression-editor",
|
|
18
18
|
props: {
|
|
19
19
|
modelValue: {},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"expression-editor.js","names":[],"sources":["../../../src/components/expression-editor/expression-editor.vue"],"sourcesContent":["<template>\n <div :class=\"className\">\n <div\n ref=\"container\"\n :class=\"cls.e('container')\"\n :contenteditable=\"!readonly && !disabled\"\n :data-empty=\"isEmpty || undefined\"\n :data-placeholder=\"props.placeholder\"\n @keydown=\"onKeydown\"\n @blur=\"onBlur\"\n ></div>\n\n <div v-if=\"showPlaceholder\" :class=\"cls.e('placeholder')\">\n {{ props.placeholder }}\n </div>\n\n <VariablePicker\n ref=\"pickerRef\"\n :visible=\"pickerVisible\"\n :trigger-dom=\"pickerTriggerDom\"\n :variables=\"props.variables\"\n :filter=\"pickerFilter\"\n :selectable-levels=\"props.selectableLevels ?? '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 } from '@veltra/utils'\nimport { injectFormContext } from '@veltra/utils'\nimport {\n computed,\n nextTick,\n onBeforeUnmount,\n onMounted,\n shallowRef,\n useTemplateRef,\n watch\n} from 'vue'\n\nimport type { ExpressionEditorProps, VariableItem } from '../../types'\nimport VariablePicker from './components/variable-picker.vue'\nimport { createEditor, type EditorAPI } from './core/editor'\nimport { createMention, type MentionAPI } from './core/mention'\nimport { parse, type Doc } from './core/model'\nimport { createVariableMap } from './di'\n\ndefineOptions({ name: 'ExpressionEditor' })\n\nconst props = withDefaults(defineProps<ExpressionEditorProps>(), {\n placeholder: '请输入表达式,输入 @ 可插入变量',\n selectableLevels: 'leaf'\n})\n\nconst emit = defineEmits<{ (e: 'update:modelValue', value: string): void }>()\n\nconst cls = bem('expression-editor')\nconst { formProps } = injectFormContext()\nconst { size, disabled, readonly } = useFormFallbackProps([formProps ?? {}, props])\n\nconst containerRef = useTemplateRef<HTMLDivElement>('container')\nconst pickerRef = useTemplateRef<{ handleKeydown: (e: KeyboardEvent) => boolean }>('pickerRef')\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 variableMap = computed(() => createVariableMap(props.variables))\n\nconst editorRef = shallowRef<EditorAPI | null>(null)\nconst mention: MentionAPI = createMention()\n\nconst currentDoc = shallowRef<Doc>([])\nconst isEmpty = computed(() => currentDoc.value.length === 0)\nconst showPlaceholder = computed(() => isEmpty.value && !disabled.value)\n\nconst pickerMode = shallowRef<'mention' | 'reselect' | null>(null)\nconst pickerTriggerDom = shallowRef<HTMLElement | undefined>(undefined)\nconst reselectingSegIdx = shallowRef<number | null>(null)\nconst pickerFilter = shallowRef('')\n\nconst pickerVisible = computed(() => pickerMode.value !== null)\n\nfunction syncMention() {\n const editor = editorRef.value\n if (!editor) return\n if (pickerMode.value === 'reselect') return\n const caret = editor.getCaretOffset()\n const state = mention.update(currentDoc.value, caret)\n if (state) {\n pickerMode.value = 'mention'\n pickerFilter.value = state.filter\n pickerTriggerDom.value = containerRef.value ?? undefined\n } else if (pickerMode.value === 'mention') {\n closePicker()\n }\n}\n\nfunction closePicker() {\n pickerMode.value = null\n reselectingSegIdx.value = null\n pickerFilter.value = ''\n}\n\nonMounted(() => {\n if (!containerRef.value) return\n const initialDoc = parse(props.modelValue ?? '', variableMap.value)\n currentDoc.value = initialDoc\n\n const editor = createEditor({\n container: containerRef.value,\n cls,\n initialDoc,\n getVariableMap: () => variableMap.value,\n onChange: (doc) => {\n currentDoc.value = doc\n const value = serializeFromDoc(doc)\n if (value !== (props.modelValue ?? '')) emit('update:modelValue', value)\n syncMention()\n },\n onSelectionChange: () => {\n syncMention()\n },\n onChipReselect: ({ chipEl, segIndex }) => {\n if (disabled.value || readonly.value) return\n mention.commit()\n pickerMode.value = 'reselect'\n pickerFilter.value = ''\n pickerTriggerDom.value = chipEl\n reselectingSegIdx.value = segIndex\n },\n onChipRemove: ({ segIndex }) => {\n if (disabled.value || readonly.value) return\n editor.removeVarAt(segIndex)\n }\n })\n editorRef.value = editor\n})\n\nonBeforeUnmount(() => {\n editorRef.value?.dispose()\n})\n\nfunction serializeFromDoc(doc: Doc): string {\n let s = ''\n for (const seg of doc) s += seg.kind === 'text' ? seg.value : `{${seg.value}}`\n return s\n}\n\nwatch(\n () => props.modelValue,\n (v) => {\n const editor = editorRef.value\n if (!editor) return\n if (v === editor.getValue()) return\n editor.setValue(v ?? '')\n }\n)\n\nwatch(variableMap, () => {\n // variables 变化:重渲染以刷新 chip label / type\n const editor = editorRef.value\n if (!editor) return\n editor.setValue(editor.getValue())\n})\n\nfunction onKeydown(e: KeyboardEvent) {\n if (disabled.value || readonly.value) return\n // mention / reselect 激活时,优先把箭头键 / Enter / Esc 转给 picker\n if (pickerMode.value !== null) {\n const handledByPicker = pickerRef.value?.handleKeydown(e)\n if (handledByPicker) {\n e.preventDefault()\n return\n }\n }\n\n if (pickerMode.value === 'mention') {\n // 这些键导致 mention 退出(保留 @filter 文本,光标继续移动)\n if (e.key === ' ' || e.key === 'ArrowLeft' || e.key === 'ArrowRight') {\n mention.dismiss()\n closePicker()\n }\n }\n}\n\nfunction onBlur() {\n if (pickerMode.value === 'mention') {\n mention.dismiss()\n // 下一帧再关闭,避免和 picker 内 click 冲突\n void nextTick(() => closePicker())\n }\n}\n\nfunction onPickerSelect(item: VariableItem) {\n const editor = editorRef.value\n if (!editor) return\n\n if (pickerMode.value === 'mention') {\n const state = mention.getState()\n if (!state) return\n const anchor = state.anchorOffset\n const caret = editor.getCaretOffset() ?? anchor + state.filter.length + 1\n editor.replaceRangeWithVar(anchor, caret, {\n value: item.value,\n label: item.label,\n ...(item.type ? { type: item.type } : {})\n })\n mention.commit()\n } else if (pickerMode.value === 'reselect') {\n const idx = reselectingSegIdx.value\n if (idx !== null) {\n editor.replaceVarAt(idx, {\n value: item.value,\n label: item.label,\n ...(item.type ? { type: item.type } : {})\n })\n }\n }\n closePicker()\n}\n\nfunction onPickerDismiss() {\n if (pickerMode.value === 'mention') mention.dismiss()\n closePicker()\n}\n\nfunction onPickerVisibleChange(v: boolean) {\n if (!v && pickerMode.value !== null) {\n if (pickerMode.value === 'mention') mention.dismiss()\n closePicker()\n }\n}\n</script>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"expression-editor.js","names":[],"sources":["../../../src/components/expression-editor/expression-editor.vue"],"sourcesContent":["<template>\n <div :class=\"className\">\n <div\n ref=\"container\"\n :class=\"cls.e('container')\"\n :contenteditable=\"!readonly && !disabled\"\n :data-empty=\"isEmpty || undefined\"\n :data-placeholder=\"props.placeholder\"\n @keydown=\"onKeydown\"\n @blur=\"onBlur\"\n ></div>\n\n <div v-if=\"showPlaceholder\" :class=\"cls.e('placeholder')\">\n {{ props.placeholder }}\n </div>\n\n <VariablePicker\n ref=\"pickerRef\"\n :visible=\"pickerVisible\"\n :trigger-dom=\"pickerTriggerDom\"\n :variables=\"props.variables\"\n :filter=\"pickerFilter\"\n :selectable-levels=\"props.selectableLevels ?? '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 } from '@veltra/utils'\nimport { injectFormContext } from '@veltra/utils'\nimport {\n computed,\n nextTick,\n onBeforeUnmount,\n onMounted,\n shallowRef,\n useTemplateRef,\n watch\n} from 'vue'\n\nimport type { ExpressionEditorProps, VariableItem } from '../../types'\nimport VariablePicker from './components/variable-picker.vue'\nimport { createEditor, type EditorAPI } from './core/editor'\nimport { createMention, type MentionAPI } from './core/mention'\nimport { parse, type Doc } from './core/model'\nimport { createVariableMap } from './di'\n\ndefineOptions({ name: 'UExpressionEditor' })\n\nconst props = withDefaults(defineProps<ExpressionEditorProps>(), {\n placeholder: '请输入表达式,输入 @ 可插入变量',\n selectableLevels: 'leaf'\n})\n\nconst emit = defineEmits<{ (e: 'update:modelValue', value: string): void }>()\n\nconst cls = bem('expression-editor')\nconst { formProps } = injectFormContext()\nconst { size, disabled, readonly } = useFormFallbackProps([formProps ?? {}, props])\n\nconst containerRef = useTemplateRef<HTMLDivElement>('container')\nconst pickerRef = useTemplateRef<{ handleKeydown: (e: KeyboardEvent) => boolean }>('pickerRef')\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 variableMap = computed(() => createVariableMap(props.variables))\n\nconst editorRef = shallowRef<EditorAPI | null>(null)\nconst mention: MentionAPI = createMention()\n\nconst currentDoc = shallowRef<Doc>([])\nconst isEmpty = computed(() => currentDoc.value.length === 0)\nconst showPlaceholder = computed(() => isEmpty.value && !disabled.value)\n\nconst pickerMode = shallowRef<'mention' | 'reselect' | null>(null)\nconst pickerTriggerDom = shallowRef<HTMLElement | undefined>(undefined)\nconst reselectingSegIdx = shallowRef<number | null>(null)\nconst pickerFilter = shallowRef('')\n\nconst pickerVisible = computed(() => pickerMode.value !== null)\n\nfunction syncMention() {\n const editor = editorRef.value\n if (!editor) return\n if (pickerMode.value === 'reselect') return\n const caret = editor.getCaretOffset()\n const state = mention.update(currentDoc.value, caret)\n if (state) {\n pickerMode.value = 'mention'\n pickerFilter.value = state.filter\n pickerTriggerDom.value = containerRef.value ?? undefined\n } else if (pickerMode.value === 'mention') {\n closePicker()\n }\n}\n\nfunction closePicker() {\n pickerMode.value = null\n reselectingSegIdx.value = null\n pickerFilter.value = ''\n}\n\nonMounted(() => {\n if (!containerRef.value) return\n const initialDoc = parse(props.modelValue ?? '', variableMap.value)\n currentDoc.value = initialDoc\n\n const editor = createEditor({\n container: containerRef.value,\n cls,\n initialDoc,\n getVariableMap: () => variableMap.value,\n onChange: (doc) => {\n currentDoc.value = doc\n const value = serializeFromDoc(doc)\n if (value !== (props.modelValue ?? '')) emit('update:modelValue', value)\n syncMention()\n },\n onSelectionChange: () => {\n syncMention()\n },\n onChipReselect: ({ chipEl, segIndex }) => {\n if (disabled.value || readonly.value) return\n mention.commit()\n pickerMode.value = 'reselect'\n pickerFilter.value = ''\n pickerTriggerDom.value = chipEl\n reselectingSegIdx.value = segIndex\n },\n onChipRemove: ({ segIndex }) => {\n if (disabled.value || readonly.value) return\n editor.removeVarAt(segIndex)\n }\n })\n editorRef.value = editor\n})\n\nonBeforeUnmount(() => {\n editorRef.value?.dispose()\n})\n\nfunction serializeFromDoc(doc: Doc): string {\n let s = ''\n for (const seg of doc) s += seg.kind === 'text' ? seg.value : `{${seg.value}}`\n return s\n}\n\nwatch(\n () => props.modelValue,\n (v) => {\n const editor = editorRef.value\n if (!editor) return\n if (v === editor.getValue()) return\n editor.setValue(v ?? '')\n }\n)\n\nwatch(variableMap, () => {\n // variables 变化:重渲染以刷新 chip label / type\n const editor = editorRef.value\n if (!editor) return\n editor.setValue(editor.getValue())\n})\n\nfunction onKeydown(e: KeyboardEvent) {\n if (disabled.value || readonly.value) return\n // mention / reselect 激活时,优先把箭头键 / Enter / Esc 转给 picker\n if (pickerMode.value !== null) {\n const handledByPicker = pickerRef.value?.handleKeydown(e)\n if (handledByPicker) {\n e.preventDefault()\n return\n }\n }\n\n if (pickerMode.value === 'mention') {\n // 这些键导致 mention 退出(保留 @filter 文本,光标继续移动)\n if (e.key === ' ' || e.key === 'ArrowLeft' || e.key === 'ArrowRight') {\n mention.dismiss()\n closePicker()\n }\n }\n}\n\nfunction onBlur() {\n if (pickerMode.value === 'mention') {\n mention.dismiss()\n // 下一帧再关闭,避免和 picker 内 click 冲突\n void nextTick(() => closePicker())\n }\n}\n\nfunction onPickerSelect(item: VariableItem) {\n const editor = editorRef.value\n if (!editor) return\n\n if (pickerMode.value === 'mention') {\n const state = mention.getState()\n if (!state) return\n const anchor = state.anchorOffset\n const caret = editor.getCaretOffset() ?? anchor + state.filter.length + 1\n editor.replaceRangeWithVar(anchor, caret, {\n value: item.value,\n label: item.label,\n ...(item.type ? { type: item.type } : {})\n })\n mention.commit()\n } else if (pickerMode.value === 'reselect') {\n const idx = reselectingSegIdx.value\n if (idx !== null) {\n editor.replaceVarAt(idx, {\n value: item.value,\n label: item.label,\n ...(item.type ? { type: item.type } : {})\n })\n }\n }\n closePicker()\n}\n\nfunction onPickerDismiss() {\n if (pickerMode.value === 'mention') mention.dismiss()\n closePicker()\n}\n\nfunction onPickerVisibleChange(v: boolean) {\n if (!v && pickerMode.value !== null) {\n if (pickerMode.value === 'mention') mention.dismiss()\n closePicker()\n }\n}\n</script>\n"],"mappings":"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"}
|
|
@@ -3,8 +3,8 @@ import { createBlock, createElementVNode, defineComponent, normalizeClass, openB
|
|
|
3
3
|
import { bem } from "@veltra/utils";
|
|
4
4
|
//#region src/components/file-picker/file-picker.vue
|
|
5
5
|
const _hoisted_1 = ["multiple", "accept"];
|
|
6
|
-
const _sfc_main =
|
|
7
|
-
name: "
|
|
6
|
+
const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
7
|
+
name: "UFilePicker",
|
|
8
8
|
__name: "file-picker",
|
|
9
9
|
props: {
|
|
10
10
|
tag: { default: "div" },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-picker.js","names":[],"sources":["../../../src/components/file-picker/file-picker.vue"],"sourcesContent":["<template>\n <component\n :is=\"tag\"\n :class=\"cls.b\"\n @click.stop=\"handleClickPicker\"\n @dragover.prevent=\"handleDragover\"\n @dragleave=\"handleDragLeave\"\n @drop.prevent=\"handleDrop\"\n >\n <input\n :multiple=\"multiple\"\n :class=\"cls.e('native')\"\n type=\"file\"\n :accept=\"accept\"\n hidden\n placeholder=\"选择文件\"\n ref=\"fileRef\"\n @change=\"handleChange\"\n capture=\"environment\"\n />\n <slot :is-dragover=\"isDragover\" />\n </component>\n</template>\n\n<script lang=\"ts\" setup>\nimport { bem } from '@veltra/utils'\nimport { shallowRef, ref } from 'vue'\n\nimport type { UploaderProps, UploaderEmits } from '../../types'\nimport { matchAccept } from './helper'\n\ndefineOptions({ name: '
|
|
1
|
+
{"version":3,"file":"file-picker.js","names":[],"sources":["../../../src/components/file-picker/file-picker.vue"],"sourcesContent":["<template>\n <component\n :is=\"tag\"\n :class=\"cls.b\"\n @click.stop=\"handleClickPicker\"\n @dragover.prevent=\"handleDragover\"\n @dragleave=\"handleDragLeave\"\n @drop.prevent=\"handleDrop\"\n >\n <input\n :multiple=\"multiple\"\n :class=\"cls.e('native')\"\n type=\"file\"\n :accept=\"accept\"\n hidden\n placeholder=\"选择文件\"\n ref=\"fileRef\"\n @change=\"handleChange\"\n capture=\"environment\"\n />\n <slot :is-dragover=\"isDragover\" />\n </component>\n</template>\n\n<script lang=\"ts\" setup>\nimport { bem } from '@veltra/utils'\nimport { shallowRef, ref } from 'vue'\n\nimport type { UploaderProps, UploaderEmits } from '../../types'\nimport { matchAccept } from './helper'\n\ndefineOptions({ name: 'UFilePicker' })\n\nconst props = withDefaults(defineProps<UploaderProps>(), { tag: 'div', multiple: false })\n\nconst emit = defineEmits<UploaderEmits>()\n\nconst cls = bem('file-picker')\n\nconst fileRef = shallowRef<HTMLInputElement>()\nconst isDragover = ref(false)\n\nconst processFiles = (files: File[]) => {\n const filteredFiles = files.filter((file) => matchAccept(file, props.accept))\n emit('pick', filteredFiles)\n}\n\nconst handleChange = (e: Event) => {\n const target = e.target as HTMLInputElement\n const files = Array.from(target.files || [])\n processFiles(files)\n target.value = ''\n}\n\nconst handleDragover = (e: DragEvent) => {\n if (props.disabled) return\n isDragover.value = true\n}\n\nconst handleDragLeave = (e: DragEvent) => {\n if (props.disabled) return\n const currentTarget = e.currentTarget as HTMLElement\n const relatedTarget = e.relatedTarget as HTMLElement | null\n\n if (currentTarget.contains(relatedTarget)) return\n isDragover.value = false\n}\n\nconst handleDrop = (e: DragEvent) => {\n if (props.disabled) return\n isDragover.value = false\n const files = Array.from(e.dataTransfer?.files || [])\n processFiles(files)\n}\n\nfunction handleClickPicker() {\n if (props.disabled) return\n fileRef.value?.click()\n}\n</script>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;EAiCA,MAAM,QAAQ;EAEd,MAAM,OAAO;EAEb,MAAM,MAAM,IAAI,aAAa;EAE7B,MAAM,UAAU,WAA6B;EAC7C,MAAM,aAAa,IAAI,KAAK;EAE5B,MAAM,gBAAgB,UAAkB;GAEtC,KAAK,QADiB,MAAM,QAAQ,SAAS,YAAY,MAAM,MAAM,MAAM,CAC9D,CAAa;EAC5B;EAEA,MAAM,gBAAgB,MAAa;GACjC,MAAM,SAAS,EAAE;GAEjB,aADc,MAAM,KAAK,OAAO,SAAS,CAAC,CAC7B,CAAK;GAClB,OAAO,QAAQ;EACjB;EAEA,MAAM,kBAAkB,MAAiB;GACvC,IAAI,MAAM,UAAU;GACpB,WAAW,QAAQ;EACrB;EAEA,MAAM,mBAAmB,MAAiB;GACxC,IAAI,MAAM,UAAU;GACpB,MAAM,gBAAgB,EAAE;GACxB,MAAM,gBAAgB,EAAE;GAExB,IAAI,cAAc,SAAS,aAAa,GAAG;GAC3C,WAAW,QAAQ;EACrB;EAEA,MAAM,cAAc,MAAiB;GACnC,IAAI,MAAM,UAAU;GACpB,WAAW,QAAQ;GAEnB,aADc,MAAM,KAAK,EAAE,cAAc,SAAS,CAAC,CACtC,CAAK;EACpB;EAEA,SAAS,oBAAoB;GAC3B,IAAI,MAAM,UAAU;GACpB,QAAQ,OAAO,MAAM;EACvB;;uBA7EE,YAoBY,wBAnBL,QAAA,GAAG,GAAA;IACP,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,CAAC;IACZ,SAAK,cAAO,mBAAiB,CAAA,MAAA,CAAA;IAC7B,YAAQ,cAAU,gBAAc,CAAA,SAAA,CAAA;IAChC,aAAW;IACX,QAAI,cAAU,YAAU,CAAA,SAAA,CAAA;;2BAYvB,CAVF,mBAUE,SAAA;KATC,UAAU,QAAA;KACV,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,QAAA,CAAA;KACb,MAAK;KACJ,QAAQ,QAAA;KACT,QAAA;KACA,aAAY;cACR;KAAJ,KAAI;KACH,UAAQ;KACT,SAAQ;8BAEV,WAAkC,KAAA,QAAA,WAAA,EAA3B,YAAa,WAAA,MAAU,CAAA,CAAA,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helper.js","names":[],"sources":["../../../src/components/file-picker/helper.ts"],"sourcesContent":["/**\n * 校验文件是否匹配 accept 字符串(支持 MIME 类型与通配符)。\n *\n * 支持的形式:\n * - `*` / `*\\/*`:接受所有文件\n * - `image/*`:MIME 类型组匹配\n * - `application/pdf`:精确 MIME 类型\n * - `.pdf` / `.docx`:扩展名匹配(不区分大小写)\n *\n * 多个值以逗号分隔,命中任一即视为匹配。\n */\nexport function matchAccept(file: File, accept?: string): boolean {\n if (!accept) return true\n\n const fileType = file.type.toLowerCase()\n const fileName = file.name.toLowerCase()\n const acceptList = accept\n .split(',')\n .map((item) => item.trim().toLowerCase())\n .filter(Boolean)\n\n if (!acceptList.length) return true\n\n return acceptList.some((item) => {\n if (item === '*' || item === '*/*') return true\n if (item.startsWith('.')) return fileName.endsWith(item)\n if (item.endsWith('/*')) {\n const group = item.slice(0, -2)\n return fileType.startsWith(`${group}/`)\n }\n return fileType === item\n })\n}\n"],"mappings":";;;;;;;;;;;;AAWA,SAAgB,YAAY,MAAY,QAA0B;CAChE,IAAI,CAAC,QAAQ,OAAO;CAEpB,MAAM,WAAW,KAAK,KAAK,YAAY;CACvC,MAAM,WAAW,KAAK,KAAK,YAAY;CACvC,MAAM,aAAa,OAChB,MAAM,GAAG,
|
|
1
|
+
{"version":3,"file":"helper.js","names":[],"sources":["../../../src/components/file-picker/helper.ts"],"sourcesContent":["/**\n * 校验文件是否匹配 accept 字符串(支持 MIME 类型与通配符)。\n *\n * 支持的形式:\n * - `*` / `*\\/*`:接受所有文件\n * - `image/*`:MIME 类型组匹配\n * - `application/pdf`:精确 MIME 类型\n * - `.pdf` / `.docx`:扩展名匹配(不区分大小写)\n *\n * 多个值以逗号分隔,命中任一即视为匹配。\n */\nexport function matchAccept(file: File, accept?: string): boolean {\n if (!accept) return true\n\n const fileType = file.type.toLowerCase()\n const fileName = file.name.toLowerCase()\n const acceptList = accept\n .split(',')\n .map((item) => item.trim().toLowerCase())\n .filter(Boolean)\n\n if (!acceptList.length) return true\n\n return acceptList.some((item) => {\n if (item === '*' || item === '*/*') return true\n if (item.startsWith('.')) return fileName.endsWith(item)\n if (item.endsWith('/*')) {\n const group = item.slice(0, -2)\n return fileType.startsWith(`${group}/`)\n }\n return fileType === item\n })\n}\n"],"mappings":";;;;;;;;;;;;AAWA,SAAgB,YAAY,MAAY,QAA0B;CAChE,IAAI,CAAC,QAAQ,OAAO;CAEpB,MAAM,WAAW,KAAK,KAAK,YAAY;CACvC,MAAM,WAAW,KAAK,KAAK,YAAY;CACvC,MAAM,aAAa,OAChB,MAAM,GAAG,CAAC,CACV,KAAK,SAAS,KAAK,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CACxC,OAAO,OAAO;CAEjB,IAAI,CAAC,WAAW,QAAQ,OAAO;CAE/B,OAAO,WAAW,MAAM,SAAS;EAC/B,IAAI,SAAS,OAAO,SAAS,OAAO,OAAO;EAC3C,IAAI,KAAK,WAAW,GAAG,GAAG,OAAO,SAAS,SAAS,IAAI;EACvD,IAAI,KAAK,SAAS,IAAI,GAAG;GACvB,MAAM,QAAQ,KAAK,MAAM,GAAG,EAAE;GAC9B,OAAO,SAAS,WAAW,GAAG,MAAM,EAAE;EACxC;EACA,OAAO,aAAa;CACtB,CAAC;AACH"}
|
|
@@ -20,11 +20,11 @@ const MIN_SCALE = .5;
|
|
|
20
20
|
const MAX_SCALE = 3;
|
|
21
21
|
/** 每次缩放固定增减 10% */
|
|
22
22
|
const SCALE_STEP = .1;
|
|
23
|
-
const _sfc_main =
|
|
24
|
-
name: "
|
|
23
|
+
const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
24
|
+
name: "UFileViewer",
|
|
25
25
|
inheritAttrs: false,
|
|
26
26
|
__name: "file-viewer",
|
|
27
|
-
props:
|
|
27
|
+
props: /*@__PURE__*/ mergeModels({
|
|
28
28
|
files: {},
|
|
29
29
|
modelValue: { default: void 0 },
|
|
30
30
|
sidebarWidth: {
|
|
@@ -61,7 +61,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
61
61
|
},
|
|
62
62
|
"openModifiers": {}
|
|
63
63
|
}),
|
|
64
|
-
emits:
|
|
64
|
+
emits: /*@__PURE__*/ mergeModels([
|
|
65
65
|
"update:modelValue",
|
|
66
66
|
"update:open",
|
|
67
67
|
"change",
|