UNPKG

@farris/ui-vue

Version:

Farris Vue, a Farris Design based Vue3 component library.

730 lines (729 loc) 19.8 kB
import { defineComponent as H, ref as m, watch as R, inject as q, computed as P, onMounted as W, createVNode as O, onUnmounted as z } from "vue"; import { debounce as G, cloneDeep as M } from "lodash-es"; import _ from "../button-edit/index.esm.js"; import { resolveAppearance as J, createPropsResolver as K } from "../dynamic-resolver/index.esm.js"; import Q from "../tree-view/index.esm.js"; import { FInputGroup as X } from "../input-group/index.esm.js"; import { withInstall as Y } from "../common/index.esm.js"; const Z = /* @__PURE__ */ new Map([ ["appearance", J] ]), ee = "https://json-schema.org/draft/2020-12/schema", te = "https://farris-design.gitee.io/combo-list.schema.json", ae = "combo-tree", le = "A Farris Input Component", ne = "object", ie = { id: { description: "The unique identifier for a combo list", type: "string" }, type: { description: "The type string of number combo list component", type: "string", default: "combo-tree" }, appearance: { description: "", type: "object", properties: { class: { type: "string" }, style: { type: "string" } }, default: {} }, binding: { description: "", type: "object", default: {} }, editable: { description: "", type: "boolean", default: !0 }, enableLinkLabel: { description: "", type: "boolean", default: !1 }, label: { description: "", type: "string", default: "" }, lableWidth: { description: "", type: "number" }, placeholder: { description: "", type: "string", default: "" }, valueField: { description: "", type: "string", default: "id" }, titleField: { description: "", type: "string", default: "name" }, textField: { description: "", type: "string", default: "name" }, data: { description: "", type: "array" }, readonly: { description: "", type: "boolean", default: !1 }, required: { description: "", type: "boolean", default: !1 }, tabindex: { description: "", type: "number", default: -1 }, textAlign: { description: "", type: "string", enum: [ "left", "middle", "right" ], default: "left" }, visible: { description: "", type: "boolean", default: !0 }, onBlur: { description: "", type: "string", default: "" }, onClickLinkLabel: { description: "", type: "string", default: "" }, formatter: { type: "object", default: null }, customRowStatus: { type: "object", default: null }, minPanelWidth: { description: "", type: "number", default: 160 }, idField: { description: "", type: "string", default: "id" }, multiSelect: { description: "", type: "boolean", default: !1 }, viewType: { description: "", type: "string", default: "text" }, searchFields: { description: "", type: "array", default: [] }, enableSearch: { description: "", type: "boolean", default: !1 }, displayFormatter: { type: "object", default: null }, enableClear: { description: "", type: "boolean", default: !0 } }, oe = [ "id", "type" ], ue = { $schema: ee, $id: te, title: ae, description: le, type: ne, properties: ie, required: oe }; function de(e, d, v) { return d; } var re = /* @__PURE__ */ ((e) => (e.Text = "text", e.Tag = "tag", e))(re || {}), ce = /* @__PURE__ */ ((e) => (e.top = "top", e.bottom = "bottom", e.auto = "auto", e))(ce || {}); const L = { /** * 组件标识 */ id: { type: String }, /** * 数据源, 同tree grid组件的data属性 * @default [] */ data: { type: Array, default: [] }, /** * 可选,展示文本 */ displayText: { type: String, default: "" }, /** * 是否禁用 * @default false */ disabled: { type: Boolean, default: !1 }, /** * 可选,下拉图标 默认为'<span class="f-icon f-icon-arrow-60-down"></span>' * @default '<span class="f-icon f-icon-arrow-chevron-down"></span>' */ dropDownIcon: { type: String, default: '<span class="f-icon f-icon-arrow-chevron-down"></span>' }, /** * 是否可编辑 * @default false */ editable: { type: Boolean, default: !1 }, /** * 可选,是否启用清空,单选且允许编辑下可用 * @default true */ enableClear: { type: Boolean, default: !0 }, /** * 可选,是否启用搜索 * @default false */ enableSearch: { type: Boolean, default: !1 }, /** * 可选,鼠标悬停时是否显示控件值 * @default true */ enableTitle: { type: Boolean, default: !0 }, /** * 自适应宽度 * @default false */ fitEditor: { type: Boolean, default: !1 }, /** * 可选,是否强制显示占位符 * @default false */ forcePlaceholder: { type: Boolean, default: !1 }, /** * 可选,清空值时隐藏面板 * @default true */ hidePanelOnClear: { type: Boolean, default: !0 }, /** * 可选,数据源id字段 * @default id */ idField: { type: String, default: "id" }, /** * 可选,字段映射 */ mapFields: { type: Object }, /** * 可选,下拉面板最大高度 * @default 350 */ maxHeight: { type: Number, default: 350 }, /** * 最大输入长度 */ maxLength: { type: Number }, /** * 可选,是否支持多选 * @default false */ multiSelect: { type: Boolean, default: !1 }, /** * 绑定值 */ modelValue: { type: String, default: "" }, /** * 占位符 */ placeholder: { type: String }, /** * 可选,下拉面板展示位置 默认为`auto` * @default Placement.auto */ placement: { type: String, default: "auto" /* auto */ }, /** * 是否只读 * @default false */ readonly: { type: Boolean, default: !1 }, /** * 可选,是否支持远端过滤 * @default false */ remoteSearch: { type: Boolean, default: !1 }, /** * 可选,多选时值分隔符 * @default , */ separator: { type: String, default: "," }, /** * tab index * @default -1 */ tabIndex: { type: Number, default: -1 }, /** * 可选,数据源显示字段 * @default name */ textField: { type: String, default: "name" }, /** * 可选,数据源的title * @default name */ titleField: { type: String, default: "name" }, /** * 可选,数据源值字段 * @default id */ valueField: { type: String, default: "id" }, /** * 可选,数据源的title * @default ViewType.Text */ viewType: { type: String, default: "text" /* Text */ }, /** * 作为内嵌编辑器被创建后默认获得焦点 */ focusOnCreated: { type: Boolean, default: !1 }, /** * 作为内嵌编辑器被创建后默认选中文本 */ selectOnCreated: { type: Boolean, default: !1 }, /** * 树表展示格式化函数 */ formatter: { type: Function, default: null }, /** * 显示文本格式化函数 */ displayFormatter: { type: Function, default: null }, editorParams: { type: Object }, repositoryToken: { type: Symbol, default: null }, /** * 自定义行状态 */ customRowStatus: { type: Object, default: null }, minPanelWidth: { type: Number, default: 160 }, /** * 查询字段集合 */ searchFields: { type: Array, default: ["name"] } }, se = K(L, ue, Z, de), fe = { data: { type: Array, default: [] }, enableSearch: { type: Boolean, default: !1 }, idField: { type: String, default: "id" }, multiSelect: { default: !1, type: Boolean }, selectedValues: { type: String, default: "" }, separator: { type: String, default: "," }, textField: { type: String, default: "name" }, titleField: { type: String, default: "name" }, width: { type: Number }, height: { type: Number, default: 350 }, valueField: { type: String, default: "id" }, formatter: { type: Function }, maxHeight: { type: Number, default: 350 }, repositoryToken: { type: Symbol, default: null }, editorParams: { type: Object }, customRowStatus: { type: Object, default: null }, searchHandler: { type: Function, default: () => { } } }, me = /* @__PURE__ */ H({ name: "FComboTreeContainer", props: fe, emits: ["selectionChange", "selectItem", "unSelectItem", "expandNode"], setup(e, d) { const v = m(e.data), y = m([]), T = m(e.separator), x = m(e.width), w = m(e.height), I = m(e.maxHeight), p = m(String(e.selectedValues).split(T.value)), b = m(), C = { customRowStatus: e.customRowStatus }; R(() => e.selectedValues, (t) => { p.value = String(t).split(T.value); }), R(() => e.data, (t) => { var g; v.value = t, (g = b.value) == null || g.updateDataSource(t); }); const a = { enableSelectRow: !0, multiSelect: e.multiSelect, showCheckbox: e.multiSelect, multiSelectMode: "OnCheckAndClick" }; let l = null; e.repositoryToken && (l = q(e.repositoryToken)); const u = P(() => [{ field: e.textField, title: "", dataType: "string", formatter: e.formatter }]), r = P(() => { const t = {}; return x.value !== void 0 && (t.width = `${x.value}px`), w.value !== void 0 && (t.height = `${w.value}px`), I.value !== void 0 && I.value > 0 && (t.maxHeight = `${I.value}px`, t.overflow = "auto"), v.value.length === 0 && (t.height = "200px"), t.position = "relative", t; }); function c(t = []) { t && t.length > 0 ? (y.value = [...t], p.value = y.value.map((g) => g[e.idField])) : (y.value = [], p.value = []), d.emit("selectionChange", y.value); } W(() => { l && l.getData(e.editorParams).then((t) => { v.value = t; }), p.value && b.value.activeRowById(p.value[0]); }); const h = (t) => { b.value.selectItemByIds(t); }; return d.expose({ treeInstance: b, checkItems: h }), () => O("div", { class: "f-combo-tree-container d-flex flex-column", style: r.value }, [e.enableSearch && O("div", { class: "p-2", style: "position: sticky;top:0;z-index: 2; background:white", onMousedown: (t) => t.stopPropagation() }, [O(X, { buttonContent: '<i class="f-icon f-icon-search"></i>', enableClear: !0, placeholder: "请输入搜索内容", onClear: () => d.emit("clearSearch"), onInput: (t, g) => e.searchHandler(g) }, null)]), O(Q, { ref: b, fit: !0, data: v.value, idField: e.idField, columns: u.value, "selection-values": p.value, onSelectionUpdate: c, columnOption: { fitColumns: !0, fitMode: "expand" }, rowOption: C, autoHeight: !0, selection: a, rowNumber: { enable: !1 }, onSelectItem: (t) => d.emit("selectItem", t.raw), onUnSelectItem: (t) => d.emit("unSelectItem", t.raw), onExpandNode: (t) => d.emit("expandNode", { node: t.row, treeRef: b.value }) }, null)]); } }); function ve(e) { const d = m(""), v = m(e.modelValue), y = m(e.data || []), T = m(e.editable); function x(a, l = []) { return a = a || [], a.reduce((u, r) => (r.id = r.id || r.data[e.idField], u.push(r), r.children && r.children.length && x(r.children, u), u), l); } function w(a) { const l = String(a).split(e.separator).map((h, t) => [h, t]), u = new Map(l), r = []; return x(y.value, r), r.filter((h) => { const t = h.data ? String(h.data[e.valueField]) : String(h[e.valueField]); return u.has(t); }).map((h) => h.data ? h.data : h).sort((h, t) => { const g = u.get(String(h[e.valueField])) || 0, B = u.get(String(t[e.valueField])) || 0; return g - B; }); } function I(a) { const l = w(a), u = e.displayFormatter ? e.displayFormatter(l) : l.map((r) => r[e.textField]).join(e.separator); d.value = T.value ? u || a : u; } function p(a) { const l = a.split(e.separator).map((c) => [c, !0]), u = new Map(l); let r = []; return y.value[0].data ? x(y.value, r) : r = y.value, r = r.map((c) => c.data ? c.data : c), r.filter((c) => u.has(c[e.textField]) || u.has(c[e.valueField])); } function b(a) { const l = {}; return l[e.idField] = a, l[e.textField] = a, [l]; } function C(a) { let l = p(a); const u = l && l.length > 0; return T.value && !u && (l = b(a)), l; } return R(() => e.data, () => { y.value = e.data; }), R([y], ([a]) => { if (e.modelValue) { const l = a.find((u) => u[e.valueField] === e.modelValue); l && (d.value = l[e.textField]); } }), R(() => e.modelValue, (a, l) => { a !== l && (v.value = a, I(a)); }), I(e.modelValue), { dataSource: y, displayText: d, editable: T, modelValue: v, getItemsByDisplayText: p, getItemsByValue: w, getSelectedItemsByDisplayText: C, flatTreeNodes: x }; } function ye(e, d) { const { comboEditorRef: v, dataSource: y, searchFields: T, originalValue: x, showPopover: w, flatTreeNodes: I, comboTreeRef: p } = e; let b = !1, C = null; function a(n, s) { n.forEach((o) => { const S = s.find((V) => V.id === o.id); o.selectable = S.selectable != null ? !!S.selectable : !0, o.children && a(o.children, s); }); } function l(n, s) { const o = (n.children || []).map((V) => l(V, s)).filter((V) => V !== null); return T.value.some((V) => { var k; return (k = n.data[V]) == null ? void 0 : k.toString().toLowerCase().includes(s.toLowerCase()); }) ? { data: { ...n.data }, children: n.children, // 注意这里保留原始子节点 id: n.data[d] } : o.length > 0 ? { data: { ...n.data }, children: o, id: n.data[d] } : null; } function u() { x.value = M(y.value); } function r(n) { var o; if (w.value || (o = v.value) == null || o.showPopup(), !n) { u(); return; } const s = y.value.map((S) => l(S, n)).filter((S) => S !== null); if (s.length) { const S = []; I(y.value, S), a(s, S); } x.value = M(s); } const c = G((n) => { var o; const s = (o = n.target) == null ? void 0 : o.value; r(s); }, 200); function h(n) { var o; if (b) return; let s = (o = n.target) == null ? void 0 : o.value; s !== "" && (s = s.trim()), n.target._value !== s && c(n); } function t() { b = !0; } function g(n) { var o; b = !1; const s = (o = n.target) == null ? void 0 : o.value; s !== "" && r(s.trim()); } function B() { C && (C.removeEventListener("compositionstart", t), C.removeEventListener("compositionend", g), C = null); } function j() { var s, o, S; B(); const n = (S = (o = (s = p.value) == null ? void 0 : s.$el) == null ? void 0 : o.querySelector) == null ? void 0 : S.call(o, "input"); n && (C = n, n.addEventListener("compositionstart", t), n.addEventListener("compositionend", g)); } return R(() => p.value, (n) => { n ? j() : B(); }, { flush: "post" }), z(() => { B(); }), { onValueChange: h, resetDataSource: u, setupCompositionEvents: j }; } const D = /* @__PURE__ */ H({ name: "FComboTree", props: L, emits: ["clear", "update:modelValue", "change", "search", "expandNode"], setup(e, d) { const v = m(), y = m(e.disabled), T = m(e.enableClear), x = m(e.enableSearch), w = m(e.readonly), I = m(e.searchFields || [e.textField]), p = m(), b = m(), C = m(!0); let a = {}; const { dataSource: l, displayText: u, editable: r, modelValue: c, flatTreeNodes: h } = ve(e), t = P(() => e.multiSelect); P(() => v.value ? v.value.elementRef.getBoundingClientRect().width : 0); const g = P(() => { var f; const i = (f = v.value) == null ? void 0 : f.popoverRef; return i ? i.shown : !1; }), { onValueChange: B, resetDataSource: j } = ye({ comboEditorRef: v, dataSource: l, searchFields: I, originalValue: p, showPopover: g, flatTreeNodes: h, comboTreeRef: b }, e.idField); function n() { !t.value && v.value && C.value && v.value.hidePopup(); } const s = (i) => { const f = i == null ? void 0 : i.map((F) => F.data || F); return e.displayFormatter ? e.displayFormatter(f) : f.map((F) => F[e.textField]).join(e.separator); }; function o(i = []) { if (!t.value) u.value = s(i), c.value = i.map((f) => f.data ? f.data[e.valueField] : f[e.valueField]).join(e.separator), d.emit("update:modelValue", c.value), d.emit("change", i, c.value); else { const f = Object.keys(a), F = Object.values(a); u.value = s(F), c.value = f.join(e.separator), d.emit("update:modelValue", c.value), d.emit("change", F, c.value); } n(); } function S(i) { var f; c.value = "", a = {}, g.value && ((f = v.value) == null || f.hidePopup()), d.emit("update:modelValue", ""), d.emit("change", null, c.value), d.emit("clear"); } function V(i) { t.value && (delete a[i.id], o()); } function k(i) { t.value && (a[i.id] = i, o()); } R([() => e.disabled, () => e.editable, () => e.enableClear, () => e.enableSearch, () => e.readonly], ([i, f, F, N, E]) => { y.value = i, r.value = f, T.value = F, x.value = N, w.value = E; }); const A = () => { if (p.value = M(l.value), t.value && c.value) { const i = []; h(l.value, i), c.value.split(e.separator).reduce((f, F) => (f[F] = i.find((N) => N.id === F), f), a); } }; function $() { C.value = !1, j(), setTimeout(() => { var i; (i = b.value) == null || i.checkItems(c.value.split(e.separator)), C.value = !0; }, 10); } function U(i) { const { node: f, treeRef: F } = i, { data: N } = f.raw, E = f.raw; d.emit("expandNode", { data: N, treeRef: F, treeNode: E }); } return () => O(_, { ref: v, id: e.id, disable: y.value, readonly: w.value, forcePlaceholder: e.forcePlaceholder, editable: r.value && !e.multiSelect, buttonContent: e.dropDownIcon, placeholder: e.placeholder, enableClear: T.value, maxLength: e.maxLength, tabIndex: e.tabIndex, enableTitle: e.enableTitle, inputType: e.viewType, popupOnClick: !0, modelValue: u.value, "onUpdate:modelValue": (i) => u.value = i, onClear: S, onInput: B, focusOnCreated: e.focusOnCreated, selectOnCreated: e.selectOnCreated, beforeOpen: A, placement: e.placement, popupMinWidth: e.minPanelWidth }, { default: () => [g.value && O(me, { ref: b, maxHeight: e.maxHeight, multiSelect: e.multiSelect, enableSearch: e.enableSearch, idField: e.idField, valueField: e.valueField, textField: e.textField, titleField: e.titleField, data: p.value, selectedValues: c.value, onSelectionChange: o, formatter: e.formatter, editorParams: e.editorParams, repositoryToken: e.repositoryToken, customRowStatus: e.customRowStatus, searchHandler: B, onUnSelectItem: V, onSelectItem: k, onClearSearch: $, onExpandNode: U }, null)] }); } }); D.register = (e, d, v, y) => { e["combo-tree"] = D, d["combo-tree"] = se; }; const xe = Y(D); export { D as FComboTree, ce as Placement, re as ViewType, L as comboTreeProps, xe as default, se as propsResolver };