@farris/ui-vue
Version:
Farris Vue, a Farris Design based Vue3 component library.
721 lines (720 loc) • 19.6 kB
JavaScript
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 },
/**
* 下拉数据源
*/
data: { type: Array, default: [] },
/**
* 可选,展示文本
* 默认为空字符串
*/
displayText: { type: String, default: "" },
/**
* 可选,是否禁用
* 默认为`false`
*/
disabled: { type: Boolean, default: !1 },
/**
* 可选,下拉图标
* 默认为'<span class="f-icon f-icon-arrow-60-down"></span>'
*/
dropDownIcon: { type: String, default: '<span class="f-icon f-icon-arrow-chevron-down"></span>' },
/**
* 可选,是否可编辑
* 默认`false`
*/
editable: { type: Boolean, default: !1 },
/**
* 可选,是否启用清空
* 默认启用
*/
enableClear: { type: Boolean, default: !0 },
/**
* 可选,启用搜索
* 默认为`false`
*/
enableSearch: { type: Boolean, default: !1 },
/**
* 可选,鼠标悬停时是否显示控件值
* 默认显示
*/
enableTitle: { type: Boolean, default: !0 },
fitEditor: { type: Boolean, default: !1 },
/**
* 可选,强制显示占位符
* 默认`false`
*/
forcePlaceholder: { type: Boolean, default: !1 },
/**
* 可选,清空值时隐藏面板
* 默认`true`
*/
hidePanelOnClear: { type: Boolean, default: !0 },
/**
* 可选,数据源id字段
* 默认为`id`
*/
idField: { type: String, default: "id" },
/**
* 可选,字段映射
*/
mapFields: { type: Object },
/**
* 可选,最大高度
* 默认`350`
*/
maxHeight: { type: Number, default: 350 },
/**
* 最大输入长度
*/
maxLength: { type: Number },
/**
* 可选,是否支持多选
* 默认`false`
*/
multiSelect: { type: Boolean, default: !1 },
/**
* 绑定值
*/
modelValue: { type: String, default: "" },
/**
* 占位符
*/
placeholder: { type: String },
/**
* 可选,下拉面板展示位置
* 默认为`auto`
*/
placement: {
type: String,
default: "auto"
/* auto */
},
/**
* 可选,是否只读
* 默认为`false`
*/
readonly: { type: Boolean, default: !1 },
/**
* 可选,是否支持远端过滤
* 默认`false`
*/
remoteSearch: { type: Boolean, default: !1 },
/**
* 可选,分隔符
* 默认`,`
*/
separator: { type: String, default: "," },
/**
* tabIndex
*/
tabIndex: { type: Number, default: -1 },
/**
* 可选,数据源显示字段
* 默认为`name`
*/
textField: { type: String, default: "name" },
/**
* 可选,数据源的title
* 默认为`name`
*/
titleField: { type: String, default: "name" },
/**
* 可选,数据源值字段
* 默认为`id`
*/
valueField: { type: String, default: "id" },
/**
* 可选,下拉列表值展示方式
* 支持text | tag,即文本或标签,默认为`ViewType.Text`,即文本方式`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
};