@farris/ui-vue
Version:
Farris Vue, a Farris Design based Vue3 component library.
675 lines (674 loc) • 18.4 kB
JavaScript
import { withInstall as U } from "../common/index.esm.js";
import { defineComponent as j, ref as c, watch as w, inject as W, computed as I, onMounted as q, createVNode as T } from "vue";
import { debounce as z, cloneDeep as O } from "lodash-es";
import G from "../button-edit/index.esm.js";
import { resolveAppearance as _, createPropsResolver as J } from "../dynamic-resolver/index.esm.js";
import K from "../tree-view/index.esm.js";
import { FInputGroup as Q } from "../input-group/index.esm.js";
const X = /* @__PURE__ */ new Map([
["appearance", _]
]), Y = "https://json-schema.org/draft/2020-12/schema", Z = "https://farris-design.gitee.io/combo-list.schema.json", ee = "combo-tree", te = "A Farris Input Component", ae = "object", le = {
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
}
}, ne = [
"id",
"type"
], ie = {
$schema: Y,
$id: Z,
title: ee,
description: te,
type: ae,
properties: le,
required: ne
};
function oe(e, r, s) {
return r;
}
var ue = /* @__PURE__ */ ((e) => (e.Text = "text", e.Tag = "tag", e))(ue || {}), de = /* @__PURE__ */ ((e) => (e.top = "top", e.bottom = "bottom", e.auto = "auto", e))(de || {});
const k = {
/**
* 组件标识
*/
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"] }
}, re = J(k, ie, X, oe), ce = {
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: () => {
} }
}, se = /* @__PURE__ */ j({
name: "FComboTreeContainer",
props: ce,
emits: ["selectionChange", "selectItem", "unSelectItem"],
setup(e, r) {
const s = c(e.data), f = c([]), g = c(e.separator), p = c(e.width), S = c(e.height), F = c(e.maxHeight), h = c(String(e.selectedValues).split(g.value)), v = c(), C = {
customRowStatus: e.customRowStatus
};
w(() => e.selectedValues, (t) => {
h.value = String(t).split(g.value);
}), w(() => e.data, (t) => {
var m;
s.value = t, (m = v.value) == null || m.updateDataSource(t);
});
const n = {
enableSelectRow: !0,
multiSelect: e.multiSelect,
showCheckbox: e.multiSelect,
multiSelectMode: "OnCheckAndClick"
};
let o = null;
e.repositoryToken && (o = W(e.repositoryToken));
const d = I(() => [{
field: e.textField,
title: "",
dataType: "string",
formatter: e.formatter
}]), a = I(() => {
const t = {};
return p.value !== void 0 && (t.width = `${p.value}px`), S.value !== void 0 && (t.height = `${S.value}px`), F.value !== void 0 && F.value > 0 && (t.maxHeight = `${F.value}px`, t.overflow = "auto"), s.value.length === 0 && (t.height = "200px"), t.position = "relative", t;
});
function l(t = []) {
t && t.length > 0 ? (f.value = [...t], h.value = f.value.map((m) => m[e.idField])) : (f.value = [], h.value = []), r.emit("selectionChange", f.value);
}
q(() => {
o && o.getData(e.editorParams).then((t) => {
s.value = t;
}), h.value && v.value.activeRowById(h.value[0]);
});
const i = (t) => {
v.value.selectItemByIds(t);
};
return r.expose({
treeInstance: v,
checkItems: i
}), () => T("div", {
class: "f-combo-tree-container d-flex flex-column",
style: a.value
}, [e.enableSearch && T("div", {
class: "p-2",
style: "position: sticky;top:0;z-index: 2; background:white",
onMousedown: (t) => t.stopPropagation()
}, [T(Q, {
buttonContent: '<i class="f-icon f-icon-search"></i>',
enableClear: !0,
placeholder: "请输入搜索内容",
onClear: () => r.emit("clearSearch"),
onInput: (t, m) => e.searchHandler(m)
}, null)]), T(K, {
ref: v,
fit: !0,
data: s.value,
idField: e.idField,
columns: d.value,
"selection-values": h.value,
onSelectionUpdate: l,
columnOption: {
fitColumns: !0,
fitMode: "expand"
},
rowOption: C,
selection: n,
rowNumber: {
enable: !1
},
onSelectItem: (t) => r.emit("selectItem", t.raw),
onUnSelectItem: (t) => r.emit("unSelectItem", t.raw)
}, null)]);
}
});
function fe(e) {
const r = c(""), s = c(e.modelValue), f = c(e.data || []), g = c(e.editable);
function p(n, o = []) {
return n = n || [], n.reduce((d, a) => (a.id = a.id || a.data[e.idField], d.push(a), a.children && a.children.length && p(a.children, d), d), o);
}
function S(n) {
const o = String(n).split(e.separator).map((i, t) => [i, t]), d = new Map(o), a = [];
return p(f.value, a), a.filter((i) => {
const t = i.data ? String(i.data[e.valueField]) : String(i[e.valueField]);
return d.has(t);
}).map((i) => i.data ? i.data : i).sort((i, t) => {
const m = d.get(String(i[e.valueField])) || 0, x = d.get(String(t[e.valueField])) || 0;
return m - x;
});
}
function F(n) {
const o = S(n), d = e.displayFormatter ? e.displayFormatter(o) : o.map((a) => a[e.textField]).join(e.separator);
r.value = g.value ? d || n : d;
}
function h(n) {
const o = n.split(e.separator).map((l) => [l, !0]), d = new Map(o);
let a = [];
return f.value[0].data ? p(f.value, a) : a = f.value, a = a.map((l) => l.data ? l.data : l), a.filter((l) => d.has(l[e.textField]) || d.has(l[e.valueField]));
}
function v(n) {
const o = {};
return o[e.idField] = n, o[e.textField] = n, [o];
}
function C(n) {
let o = h(n);
const d = o && o.length > 0;
return g.value && !d && (o = v(n)), o;
}
return w(() => e.data, () => {
f.value = e.data;
}), w([f], ([n]) => {
if (e.modelValue) {
const o = n.find((d) => d[e.valueField] === e.modelValue);
o && (r.value = o[e.textField]);
}
}), w(() => e.modelValue, (n, o) => {
n !== o && (s.value = n, F(n));
}), F(e.modelValue), { dataSource: f, displayText: r, editable: g, modelValue: s, getItemsByDisplayText: h, getItemsByValue: S, getSelectedItemsByDisplayText: C, flatTreeNodes: p };
}
function me(e, r) {
const { comboEditorRef: s, dataSource: f, searchFields: g, originalValue: p, showPopover: S, flatTreeNodes: F } = e;
function h(a, l) {
a.forEach((i) => {
const t = l.find((m) => m.id === i.id);
i.selectable = t.selectable != null ? !!t.selectable : !0, i.children && h(i.children, l);
});
}
function v(a, l) {
const i = (a.children || []).map((m) => v(m, l)).filter((m) => m !== null);
return g.value.some((m) => {
var x;
return (x = a.data[m]) == null ? void 0 : x.toString().toLowerCase().includes(l.toLowerCase());
}) ? {
data: { ...a.data },
children: a.children,
// 注意这里保留原始子节点
id: a.data[r]
} : i.length > 0 ? {
data: { ...a.data },
children: i,
id: a.data[r]
} : null;
}
function C() {
p.value = O(f.value);
}
function n(a) {
var i;
if (S.value || (i = s.value) == null || i.showPopup(), !a) {
C();
return;
}
const l = f.value.map((t) => v(t, a)).filter((t) => t !== null);
if (l.length) {
const t = [];
F(f.value, t), h(l, t);
}
p.value = O(l);
}
const o = z((a) => {
var i;
const l = (i = a.target) == null ? void 0 : i.value;
n(l);
}, 200);
function d(a) {
var i;
let l = (i = a.target) == null ? void 0 : i.value;
l !== "" && (l = l.trim()), a.target._value !== l && o(a);
}
return {
onValueChange: d,
resetDataSource: C
};
}
const P = /* @__PURE__ */ j({
name: "FComboTree",
props: k,
emits: ["clear", "update:modelValue", "change", "search"],
setup(e, r) {
const s = c(), f = c(e.disabled), g = c(e.enableClear), p = c(e.enableSearch), S = c(e.readonly), F = c(e.searchFields || [e.textField]), h = c(), v = c(), C = c(!0);
let n = {};
const {
dataSource: o,
displayText: d,
editable: a,
modelValue: l,
flatTreeNodes: i
} = fe(e), t = I(() => e.multiSelect);
I(() => s.value ? s.value.elementRef.getBoundingClientRect().width : 0);
const m = I(() => {
var y;
const u = (y = s.value) == null ? void 0 : y.popoverRef;
return u ? u.shown : !1;
}), {
onValueChange: x,
resetDataSource: M
} = me({
comboEditorRef: s,
dataSource: o,
searchFields: F,
originalValue: h,
showPopover: m,
flatTreeNodes: i
}, e.idField);
function D() {
!t.value && s.value && C.value && s.value.hidePopup();
}
const R = (u) => {
const y = u == null ? void 0 : u.map((b) => b.data || b);
return e.displayFormatter ? e.displayFormatter(y) : y.map((b) => b[e.textField]).join(e.separator);
};
function V(u = []) {
if (!t.value)
d.value = R(u), l.value = u.map((y) => y.data ? y.data[e.valueField] : y[e.valueField]).join(e.separator), r.emit("update:modelValue", l.value), r.emit("change", u, l.value);
else {
const y = Object.keys(n), b = Object.values(n);
d.value = R(b), l.value = y.join(e.separator), r.emit("update:modelValue", l.value), r.emit("change", b, l.value);
}
D();
}
function N(u) {
var y;
l.value = "", n = {}, m.value && ((y = s.value) == null || y.hidePopup()), r.emit("update:modelValue", ""), r.emit("change", null, l.value), r.emit("clear");
}
function H(u) {
t.value && (delete n[u.id], V());
}
function A(u) {
t.value && (n[u.id] = u, V());
}
w([() => e.disabled, () => e.editable, () => e.enableClear, () => e.enableSearch, () => e.readonly], ([u, y, b, B, E]) => {
f.value = u, a.value = y, g.value = b, p.value = B, S.value = E;
});
const L = () => {
if (h.value = O(o.value), t.value && l.value) {
const u = [];
i(o.value, u), l.value.split(e.separator).reduce((y, b) => (y[b] = u.find((B) => B.id === b), y), n);
}
};
function $() {
C.value = !1, M(), setTimeout(() => {
var u;
(u = v.value) == null || u.checkItems(l.value.split(e.separator)), C.value = !0;
}, 10);
}
return () => T(G, {
ref: s,
id: e.id,
disable: f.value,
readonly: S.value,
forcePlaceholder: e.forcePlaceholder,
editable: a.value && !e.multiSelect,
buttonContent: e.dropDownIcon,
placeholder: e.placeholder,
enableClear: g.value,
maxLength: e.maxLength,
tabIndex: e.tabIndex,
enableTitle: e.enableTitle,
inputType: e.viewType,
popupOnClick: !0,
modelValue: d.value,
"onUpdate:modelValue": (u) => d.value = u,
onClear: N,
onInput: x,
focusOnCreated: e.focusOnCreated,
selectOnCreated: e.selectOnCreated,
beforeOpen: L,
placement: e.placement,
popupMinWidth: e.minPanelWidth
}, {
default: () => [m.value && T(se, {
ref: v,
maxHeight: e.maxHeight,
multiSelect: e.multiSelect,
enableSearch: e.enableSearch,
idField: e.idField,
valueField: e.valueField,
textField: e.textField,
titleField: e.titleField,
data: h.value,
selectedValues: l.value,
onSelectionChange: V,
formatter: e.formatter,
editorParams: e.editorParams,
repositoryToken: e.repositoryToken,
customRowStatus: e.customRowStatus,
searchHandler: x,
onUnSelectItem: H,
onSelectItem: A,
onClearSearch: $
}, null)]
});
}
});
P.register = (e, r, s, f) => {
e["combo-tree"] = P, r["combo-tree"] = re;
};
const Fe = U(P);
export {
P as FComboTree,
de as Placement,
ue as ViewType,
k as comboTreeProps,
Fe as default,
re as propsResolver
};