UNPKG

@farris/ui-vue

Version:

Farris Vue, a Farris Design based Vue3 component library.

1,737 lines (1,736 loc) 51.2 kB
import { defineComponent as k, ref as I, computed as M, watch as L, onMounted as z, createVNode as V, reactive as N, inject as _ } from "vue"; import ae from "../button-edit/index.esm.js"; import { LocaleService as J } from "../locale/index.esm.js"; import { resolveAppearance as oe, createPropsResolver as de, getPropsResolverGenerator as ue } from "../dynamic-resolver/index.esm.js"; import ce from "../list-view/index.esm.js"; import { isUndefined as re } from "lodash-es"; import { useTouchMomentum as se, useTouch as me, useCommonUtils as q, useBem as X, useFarrisConfig as fe, FormSchemaEntityFieldType$Type as R, EVENT_PROPERTY_TAB_IDS as he, withInstall as ve } from "../common/index.esm.js"; import "bignumber.js"; import ge from "../../designer/button-edit/index.esm.js"; import { InputBaseProperty as ye } from "../property-panel/index.esm.js"; import { useDesignerComponent as be } from "../designer-canvas/index.esm.js"; const K = /* @__PURE__ */ new Map([ ["appearance", oe] ]), Se = "https://json-schema.org/draft/2020-12/schema", Ce = "https://farris-design.gitee.io/combo-list.schema.json", Fe = "combo-list", xe = "A Farris Input Component", Te = "object", we = { 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-list" }, appearance: { description: "", type: "object", properties: { class: { type: "string" }, style: { type: "string" } }, default: {} }, binding: { description: "", type: "object", default: {} }, disabled: { description: "", type: "boolean", default: !1 }, enableClear: { description: "", type: "boolean", default: !1 }, editable: { description: "", type: "boolean", default: !1 }, enableLinkLabel: { description: "", type: "boolean", default: !1 }, label: { description: "", type: "string", default: "" }, lableWidth: { description: "", type: "number" }, placeholder: { description: "", type: "string", default: "请选择" }, idField: { description: "", type: "string", default: "id" }, valueField: { description: "", type: "string", default: "id" }, titleField: { description: "", type: "string", default: "name" }, textField: { description: "", type: "string", default: "name" }, dataSourceType: { description: "", type: "string", default: "static" }, data: { description: "", type: "array" }, dataSource: { description: "", type: "string" }, remote: { description: "", type: "string" }, 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" }, multiSelect: { description: "", type: "boolean", default: !1 }, maxLength: { description: "", type: "number", default: null }, visible: { description: "", type: "boolean", default: !0 }, onBlur: { description: "", type: "string", default: "" }, onClickLinkLabel: { description: "", type: "string", default: "" }, maxHeight: { description: "", type: "number", default: 350 }, minPanelWidth: { description: "", type: "number", default: 160 }, popupOnClick: { description: "", type: "boolean", default: !0 }, separator: { description: "", type: "string", default: "," }, viewType: { description: "", type: "string", default: "tag" }, enableSearch: { description: "启用搜索", type: "boolean", default: !0 }, enableHighlightSearch: { description: "启用高亮搜索", type: "boolean", default: !1 }, beforeOpen: { description: "打开下拉面板前回调", type: "string" }, beforeHide: { description: "关闭下拉面板前回调", type: "string" }, onShown: { description: "面板打开事件", type: "string" }, onHidden: { description: "面板关闭事件", type: "string" }, onChange: { description: "值变化事件", type: "string", default: "" }, onInput: { description: "输入事件", type: "string", default: "" }, onClear: { description: "清空事件", type: "string", default: "" }, onDataChanged: { description: "清空事件", type: "string", default: "" }, hideDisabledItems: { description: "隐藏禁用项", type: "boolean", default: !1 }, expandable: { description: "", type: "boolean", default: !1 }, expandMode: { description: "", type: "string", default: "text" }, expandContent: { description: "", type: "string", default: "" }, expandDisabled: { description: "", type: "boolean", default: !1 }, onExpandClick: { description: "", type: "string", default: "" }, showSelectAll: { description: "", type: "boolean", default: !1 } }, Ve = [ "type" ], Ie = [ "id", "appearance", "binding", "visible" ], Pe = { onClear: "清空事件", onShown: "面板打开事件", onHidden: "面板关闭事件", onChange: "值变化事件", beforeOpen: "打开面板前事件", beforeHide: "关闭面板前事件" }, Q = { $schema: Se, $id: Ce, title: Fe, description: xe, type: Te, properties: we, required: Ve, ignore: Ie, events: Pe }; function Z(e, t, a) { return t; } function Be() { function e(t, a, l) { const r = {}; return r.beforeOpen = (m) => a.call("beforeOpen", t, [m, t], l), r; } return { resolve: e }; } var pe = /* @__PURE__ */ ((e) => (e.top = "top", e.bottom = "bottom", e.auto = "auto", e))(pe || {}); const U = { /** * 组件唯一标识。 */ id: { type: String }, /** * 下拉列表数据源。 * * @default [] */ data: { type: Array, default: [] }, /** * 是否禁用组件。 * * @default false */ disabled: { default: !1, type: Boolean }, /** * 下拉按钮图标 HTML 字符串。 * * @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: { default: !1, type: Boolean }, /** * 是否启用清空按钮。 * * @default true */ enableClear: { default: !0, type: Boolean }, /** * 是否启用下拉面板搜索。 * * @default false */ enableSearch: { type: Boolean, default: !1 }, /** * 鼠标悬停时是否显示控件值提示。 * * @default true */ enableTitle: { default: !0, type: Boolean }, /** * 是否自适应编辑器宽度。 * * @default false */ fitEditor: { default: !1, type: Boolean }, /** * 是否在禁用或只读状态下强制显示占位符。 * * @default false */ forcePlaceholder: { default: !1, type: Boolean }, /** * 清空值时是否隐藏下拉面板。 * * @default true */ hidePanelOnClear: { default: !0, type: Boolean }, /** * 数据源中作为唯一标识的字段名。 * * @default 'id' */ idField: { default: "id", type: String }, /** * 字段映射配置。 */ mapFields: { type: Object }, /** * 下拉面板最大高度,单位 px。 * * @default 350 */ maxHeight: { default: 350, type: Number }, /** * 可编辑状态下的最大输入长度。 */ maxLength: { type: Number }, /** * 是否支持多选。 * * @default false */ multiSelect: { type: Boolean, default: !1 }, /** * 可选,多选模式下是否显示全选复选框 * 默认`false` */ showSelectAll: { type: Boolean, default: !1 }, /** * 绑定值 * 组件绑定值。 * * @default '' */ modelValue: { type: String, default: "" }, /** * 值为空时的占位符文本。 * * @default '请选择' */ placeholder: { type: String, default: "请选择" }, /** * 下拉面板展示位置。 * * @default Placement.auto */ placement: { type: String, default: "auto" /* auto */ }, /** * 是否只读。 * * @default false */ readonly: { default: !1, type: Boolean }, /** * 远端数据源配置,设置后将优先从远端加载数据。 * * @default null */ remote: { default: null, type: Object }, /** * 是否支持远端过滤搜索。 * * @default false */ remoteSearch: { default: !1, type: Boolean }, /** * 多选时多个值之间的分隔符。 * * @default ',' */ separator: { default: ",", type: String }, /** * 组件的 tab 索引。 * * @default -1 */ tabIndex: { type: Number, default: -1 }, /** * 数据源中作为显示文本的字段名。 * * @default 'name' */ textField: { default: "name", type: String }, /** * 数据源中作为 title 提示的字段名。 * * @default 'name' */ titleField: { default: "name", type: String }, /** * 数据源中作为绑定值的字段名。 * * @default 'id' */ valueField: { default: "id", type: String }, /** * 多选时选中值在输入框中的展示方式。 * * @remarks * 支持 `text`(文本)和 `tag`(标签)两种模式。 * * @default 'tag' */ viewType: { default: "tag", type: String }, /** * 值变化回调函数。 * * @default () => {} */ change: { type: Function, default: () => { } }, /** * 作为内嵌编辑器创建后是否自动获得焦点。 * * @default false */ focusOnCreated: { type: Boolean, default: !1 }, /** * 作为内嵌编辑器创建后是否默认选中文本。 * * @default false */ selectOnCreated: { type: Boolean, default: !1 }, /** * 是否根据内容自动计算高度。 * * @deprecated 该属性已废弃。 * @default true */ autoHeight: { type: Boolean, default: !0 }, /** * 下拉面板打开前的回调函数,返回 false 可阻止打开。 * * @default null */ beforeOpen: { type: Function, default: null }, /** * 自定义远端数据加载函数,返回 Promise。 */ load: { type: Function }, /** * 搜索过滤配置,可传入布尔值或自定义过滤函数。 * * @default false */ searchOption: { type: [Boolean, Function], default: !1 }, /** * 搜索时是否高亮匹配文本。 * * @default true */ enableHighlightSearch: { type: Boolean, default: !0 }, /** * 下拉面板最小宽度,单位 px。 * * @default 160 */ minPanelWidth: { type: Number, default: 160 }, /** * 是否在点击输入框时弹出下拉面板。 * * @default true */ popupOnClick: { type: Boolean, default: !0 }, /** * 是否可扩展(显示扩展按钮/文本)。 * * @default false */ expandable: { type: Boolean, default: !1 }, /** * 扩展模式,可选 `text` `button`。 * * @default 'text' */ expandMode: { type: String, default: "text" }, /** * 扩展区域显示的文本内容。 * * @default '' */ expandContent: { type: String, default: "" }, /** * 扩展按钮是否禁用。 * * @default false */ expandDisabled: { type: Boolean, default: !1 }, /** * 下拉面板的自定义 CSS 类名。 * * @default '' */ popupClass: { type: String, default: "" }, /** * 是否隐藏禁用的数据项。 * * @remarks * 默认 `false`,禁用项显示为置灰状态;设置为 `true` 时禁用项不显示。 * * @default false */ hideDisabledItems: { type: Boolean, default: !1 } }, Me = Object.assign({}, U, { readonly: {} }), ot = de(U, Q, K, Z), D = ue( U, Q, K, Z ), Ae = Be(), He = { dataSource: { type: Array, default: [] }, enableSearch: { type: Boolean, default: !1 }, idField: { type: String, default: "id" }, multiSelect: { type: Boolean, default: !1 }, /** 多选模式下是否显示全选复选框 */ showSelectAll: { type: Boolean, default: !1 }, selectedValues: { type: String, default: "" }, separator: { type: String, default: "," }, textField: { type: String, default: "name" }, titleField: { type: String, default: "name" }, width: { type: Number }, maxHeight: { type: Number }, valueField: { type: String, default: "id" }, /** 值变化事件 */ onSelectionChange: { type: Function, default: () => { } }, searchOption: { type: [Boolean, Function], default: !1 }, // 搜索启用高亮 enableHighlightSearch: { type: Boolean, default: !0 } }, Le = /* @__PURE__ */ k({ name: "FComboListContainer", props: He, emits: ["selectionChange"], setup(e, t) { const a = I(), l = I(e.dataSource), r = I(e.dataSource), m = I([]), o = I(e.separator), T = I(e.width), g = I(e.maxHeight), y = M(() => e.multiSelect), v = I(e.multiSelect ? String(e.selectedValues).split(o.value) : [e.selectedValues]), h = M(() => ({ enableSelectRow: !0, multiSelect: e.multiSelect, multiSelectMode: "OnCheckAndClick", showCheckbox: y.value, showSelectAll: e.showSelectAll, showSelection: !0 })); L(e.dataSource, () => { l.value = e.dataSource, r.value = e.dataSource; }), M(() => e.enableSearch ? "SearchBar" : "ContentHeader"); const F = M(() => { const n = {}; return T.value !== void 0 && (n.width = `${T.value}px`), g.value !== void 0 && g.value > 0 && (n.maxHeight = `${g.value}px`), n; }); function b(n) { a.value.search(n); } function x(n) { m.value = n.map((u) => Object.assign({}, u)), v.value = n.map((u) => u[e.idField]), t.emit("selectionChange", m.value); } function B(n) { if (e.enableHighlightSearch) return; let u = []; const { searchOption: s } = e; typeof s == "function" ? u = l.value.filter((c) => s(n, c)) : u = l.value.filter((c) => c[e.valueField].indexOf(n) > -1 || c[e.textField].indexOf(n) > -1), a.value.updateDataSource(u); } L([() => e.selectedValues], ([n]) => { e.multiSelect ? n === null ? v.value = [] : v.value = n.split(o.value) : n === null ? v.value = [] : v.value = [n]; }); function w(n) { a.value.activeRowById(n); } return z(() => { var n, u; if (!e.multiSelect) { const s = (n = v.value) == null ? void 0 : n[0]; let c = s; const i = l.value.map((d) => d[e.valueField || e.idField]); if (!re(s) && i.includes(s)) { const d = typeof s, f = typeof ((u = l.value[0]) == null ? void 0 : u[e.valueField || e.idField]); f === "number" && d !== f && (c = Number(s)), f === "boolean" && d !== f && (c = s === "true" ? !0 : s === "false" ? !1 : s), w(c); } } }), t.expose({ search: b, activeRowById: w }), () => V("div", { class: "f-combo-list-container", style: F.value }, [V(ce, { ref: a, size: "small", itemClass: "f-combo-list-item", itemContentClass: "text-truncate", header: "ContentHeader", headerClass: "f-combo-list-search-box", data: l.value, idField: e.idField, textField: e.textField, titleField: e.titleField, multiSelect: e.multiSelect, selection: h.value, enableHighlightSearch: e.enableHighlightSearch, selectionValues: v.value, onSelectionUpdate: x, onAfterSearch: B }, null)]); } }), W = { property: "all", duration: 0.3, timingFunction: "cubic-bezier(0.17, 0.89, 0.45, 1)", delay: 0 }, Ee = (e, t) => { const a = e.lineHeight / 2, l = se({ maxOverflowY: 44 }), r = N({ ...W }), m = (c) => { t.emit("change", c); }, o = N({ value: 0, max: 0, min: 0, start: 0, index: 0, currentItem: void 0, active: !1 }), T = () => { o.max = e.visiableOptionCount / 2 * e.lineHeight; const c = e.column.length * e.lineHeight; o.min = o.max - c + e.lineHeight; }, g = (c = 0) => { T(), o.index = c, o.value = o.max - c * e.lineHeight, o.currentItem = e.column[c]; }, y = (c) => { const i = e.column.length - 1, d = Math.min(o.index, i), f = e.column.findIndex((S) => S[e.valueField] === c); return f >= 0 ? f : d; }, v = (c) => { const i = e.column.length - 1; return o.index > i ? e.column[i] : e.column[c]; }, h = (c) => { c && (o.currentItem = c, r.duration = 0); const i = o.currentItem[e.valueField], d = y(i), f = v(o.index)[e.valueField]; g(d), i !== f && setTimeout(() => { m(o.currentItem); }, r.duration * 1e3); }, F = () => { const c = Array.isArray(e.value) ? e.value[0] : e.value; g(y(c)); }; F(), L(() => e.value, () => { e.multiSelect || F(); }), L(() => e.column, () => h()); const b = (c, i = o.max, d = o.min) => { const f = o.start + c; o.value = f > a ? Math.min(f, i) : Math.max(f, d), o.index = Math.round((o.max - o.value) / e.lineHeight), o.currentItem = v(o.index); }, x = me(), B = (c) => { x.start(c), o.active = !0, o.start = o.value, l.start(o.start), r.duration = 0; }, w = (c) => { c.preventDefault(), x.move(c), b( x.deltaY.value, o.max + e.lineHeight, o.min - e.lineHeight ), l.move(x.deltaY.value), r.duration = W.duration; }, n = (c) => { const i = c < 0, d = c % e.lineHeight > a ? 1 : 0, f = Math.floor(c / e.lineHeight); return (i ? f - d : f + d) * e.lineHeight + a; }; return { translateY: o, transition: r, onTouchStart: B, onTouchMove: w, onTouchEnd: () => { o.start = 0; const c = l.end(); let i = 0; if (c) { const { destination: d, duration: f } = l.get(o.value, o.min, o.max); i = d, r.duration = f / 1e3; } else i = o.value; b(n(i)), m(o.currentItem); }, onTransitionend: () => { o.active = !1; }, updateTranslate: h }; }, ke = { column: { type: Array, default: () => [] }, valueField: { type: String, default: "value" }, textField: { type: String, default: "text" }, value: { type: [Array, String, Number], default: () => [] }, multiSelect: { type: Boolean, default: !1 }, showIcon: { type: Boolean, default: !1 }, lineHeight: { type: Number, default: 0 }, visiableOptionCount: { type: Number, default: 5 } }, Oe = /* @__PURE__ */ k({ props: ke, emits: ["change", "click"], setup(e, t) { const { addUnit: a } = q(), { bem: l } = X("FComboTouchList"), { translateY: r, transition: m, onTouchStart: o, onTouchMove: T, onTouchEnd: g, onTransitionend: y } = Ee(e, t), v = (b) => { t.emit("click", b); }, h = M(() => ({ transform: `translateY(${a(r.value)})`, transition: `all ${r.active ? m.duration : 0}s ${m.timingFunction} 0s` })), F = (b) => e.showIcon ? Array.isArray(e.value) && e.value.includes(b[e.valueField]) : !1; return () => V("div", { class: l("column"), style: h.value, onTouchstart: o, onTouchmove: T, onTouchend: g, onTransitionend: y }, [e.column.map((b) => V("div", { class: l("column-item"), onClick: () => v(b) }, [V("span", null, [b[e.textField]]), F(b) && V("span", { class: `f-icon f-icon-check ${l("column-item-icon")}` }, null)]))]); } }), Re = { modelValue: { type: [String, Array], default: "" }, columns: { type: Array, default: () => [] }, title: { type: String, default: "" }, valueField: { type: String, default: "value" }, textField: { type: String, default: "text" }, childrenField: { type: String, default: "children" }, multiSelect: { type: Boolean, default: !1 }, lineHeight: { type: Number, default: 44 }, cancelText: { type: String, default: "取消" }, confirmText: { type: String, default: "确定" }, optionFormatter: { type: Function, default: void 0 }, visiableOptionCount: { type: Number, default: 5 }, showToolbar: { type: Boolean, default: !0 }, separator: { type: String, default: "," } }, Ne = (e, t) => { const { finalValue: a, initValue: l, setSelectedByIndex: r, getSelectedValueByIndex: m } = t, { isArray: o, isFunction: T, isObject: g } = q(), y = (i) => i && i[0], v = M(() => { var i; return ((i = e.columns) == null ? void 0 : i.length) > 0 && o(e.columns[0]); }), h = (i) => { if ((i == null ? void 0 : i.length) === 0) return !1; const d = y(i); return d && o(d[e.childrenField]); }, F = (i, d) => { const f = y(i), S = m(d); let p = i.find((E) => E[e.valueField] === S); p = p || f; const A = p[e.childrenField] || []; if (h(A)) { const E = F(A, d + 1); return [A, ...E]; } return [A]; }, b = () => { const i = e.columns, d = F(i, 0); return [i, ...d]; }, x = (i, d) => { const f = i[e.textField]; return T(e.optionFormatter) ? e.optionFormatter(d, i) : f; }, B = (i, d) => i.map((f) => { const S = g(f) ? f : { [e.valueField]: f, [e.textField]: f }; return S[e.textField] = x(S, d), S; }), w = M(() => { let i = []; return v.value ? i = e.columns : h(e.columns) ? i = b() : i = [e.columns], i.map(B); }), n = () => w.value.map((i, d) => { const f = a.value[d]; return i.find((p) => p[e.valueField] === f); }).filter((i) => i), u = () => n().map((i) => i[e.valueField]), s = () => n().map((i) => i[e.textField]).join("-"), c = () => { w.value.forEach((i, d) => { if (e.multiSelect) a.value[d].forEach((S) => { const p = i.find((A) => A[e.valueField] === S); p && r(d, p); }); else { const f = a.value[d], S = i.find((p) => p[e.valueField] === f); S ? r(d, S) : r(d, y(i)); } }); }; return L( () => e.modelValue, () => { l(e.modelValue), c(); }, { immediate: !0 } ), { columns: w, getPickeds: n, getValue: u, getTextValue: s }; }, $e = (e) => { const { isArray: t, isMultiArray: a, isString: l, isDef: r } = q(), m = (n) => { let u = []; return t(n) ? u = n : l(n) ? u = n.split(e.separator) : r(n) && (u = [n]), e.multiSelect ? a(u) ? u : [u] : u; }, o = I([]), T = (n) => { o.value = m(n); }, g = N([]), y = M(() => g.map((n) => n[e.valueField])), v = N([]), h = M(() => v.map((n) => n.map((u) => u[e.valueField]))); return { finalValue: o, initValue: T, getSelected: () => e.multiSelect ? v : g, getSelectedValue: () => e.multiSelect ? h.value : y.value, setSelectedByIndex: (n, u) => { if (e.multiSelect) { const s = v[n] || []; s.includes(u) ? v[n] = s.filter((c) => c !== u) : v[n] = [...s, u]; } else g[n] = u; }, getSelectedByIndex: (n) => e.multiSelect ? v[n] : g[n], getSelectedValueByIndex: (n) => e.multiSelect ? h.value[n] : y.value[n] }; }, qe = /* @__PURE__ */ k({ props: Re, emits: ["change", "confirm", "cancel", "update:modelValue"], setup(e, t) { const { emit: a } = t, { addUnit: l } = q(), r = $e(e), { finalValue: m, getSelectedValue: o, getSelectedValueByIndex: T, getSelected: g, setSelectedByIndex: y } = r, { columns: v } = Ne(e, r), h = (s, c = !0) => { const { value: i, index: d } = s; (c && !e.multiSelect || !c && e.multiSelect) && (a("change", s), y(d, i)); }, F = () => { m.value = o(), a("confirm", g()), a("update:modelValue", m.value); }, b = () => { a("cancel"); }, { bem: x } = X("FComboTouchList"), B = () => V("div", { class: x("toolbar") }, [V("div", { class: x("toolbar-left"), onClick: b }, [V("span", null, [e.cancelText])]), V("div", { class: x("toolbar-title") }, [V("span", null, [e.title])]), V("div", { class: x("toolbar-right"), onClick: F }, [V("span", null, [e.confirmText])])]), w = M(() => { const s = (e.visiableOptionCount + 1) * e.lineHeight; return { height: l(s) }; }), n = M(() => { const s = e.visiableOptionCount * e.lineHeight / 2; return { backgroundSize: `100% ${l(s)}` }; }), u = () => V("div", { class: x("content") }, [V("div", { class: x("columns"), style: w.value }, [v.value.map((s, c) => V(Oe, { column: s, value: T(c), showIcon: e.multiSelect, textField: e.textField, multiSelect: e.multiSelect, valueField: e.valueField, lineHeight: e.lineHeight, visiableOptionCount: e.visiableOptionCount, onChange: (i) => h({ value: i, index: c }), onClick: (i) => h({ value: i, index: c }, !1) }, null)), !e.multiSelect && V("div", { class: x("mask"), style: n.value }, null), V("div", { class: x("frame") }, null)])]); return () => V("div", { class: x("") }, [e.showToolbar && B(), u()]); } }); function Ue(e, t) { const a = I(""), l = I(e.modelValue), r = I(e.data || []), m = I(e.editable), o = M(() => e.hideDisabledItems ? r.value.filter((n) => !n.disabled) : r.value); function T(n) { const u = e.multiSelect ? String(n).split(e.separator) : [String(n)], s = u.map((d) => [d, !0]), c = new Map(s); return r.value.filter((d) => c.has(String(d[e.valueField]))).sort((d, f) => { const S = u.indexOf(d[e.valueField]), p = u.indexOf(f[e.valueField]); return S - p; }); } function g(n) { const u = T(n).map((s) => s[e.textField]).join(e.separator); a.value = m.value ? u || n : u; } function y(n) { if (e.multiSelect) { const u = n.split(e.separator).map((c) => [c, !0]), s = new Map(u); return r.value.filter((c) => s.has(c[e.textField])); } return r.value.filter((u) => "" + u[e.textField] === n); } function v(n) { const u = {}; return u[e.idField] = n, u[e.textField] = n, [u]; } function h(n) { let u = y(n); const s = u && u.length > 0; return m.value && !s && (u = v(n)), u; } function F() { const { url: n, method: u = "GET", headers: s = { "Content-Type": "application/json;charset=utf-8;" }, body: c = null } = e.remote; if (!n) return; const { basePath: i } = fe().value, d = u.toLowerCase() === "get" ? { method: u, headers: s } : { method: u, headers: s, body: c }; let f = !1; fetch(new Request(i + n, d)).then((S) => { var A, E; if (S.status === 200) return f = !!((E = (A = S.headers) == null ? void 0 : A.get("content-type")) != null && E.includes("application/json")), f ? S.text() : S.json(); throw S.status === 405 ? new Error(J.getLocaleValue("comboList.remoteError")) : new Error(S.statusText); }).then((S) => { S.length && (r.value = f ? JSON.parse(S) : S, l.value && g(l.value)); }).catch((S) => { console.warn(S); }); } e.remote && (e.load ? e.load().then((n) => { r.value = n; }).catch((n) => { console.log(n); }) : F()), L(() => e.data, () => { r.value = e.data; }), L([r], ([n], [u]) => { if (e.modelValue != null && !e.multiSelect) { const s = n.find((c) => c[e.valueField] === l.value); s ? s[e.valueField] !== l.value ? (l.value = s[e.valueField], a.value = s[e.textField], t.emit("update:modelValue", s[e.valueField]), t.emit("change", [s], s[e.valueField])) : a.value !== s[e.textField] && (a.value = s[e.textField]) : l.value !== "" && (l.value = "", a.value = "", t.emit("update:modelValue", ""), t.emit("change", [], "")); } }), L(() => e.modelValue, (n, u) => { u !== n && (l.value = n, g(n)); }); function b(n) { r.value = n, t.emit("dataChanged", n); } function x() { return r.value; } function B() { return a.value; } async function w() { const n = typeof e.beforeOpen == "function"; return !e.beforeOpen || !n ? Promise.resolve(!0) : Promise.resolve().then(() => e.beforeOpen({ instance: { updateDataSource: b, getData: x, getDisplayText: B } })).then((u) => typeof (u == null ? void 0 : u.canOpen) == "boolean" ? u == null ? void 0 : u.canOpen : !0); } return g(e.modelValue), { dataSource: r, filteredDataSource: o, displayText: a, editable: m, modelValue: l, beforeOpenList: w, getItemsByDisplayText: y, getItemsByValue: T, getSelectedItemsByDisplayText: h }; } const Ye = ["moz", "ms", "webkit"]; function Ge() { let e = 0; return (t) => { const a = (/* @__PURE__ */ new Date()).getTime(), l = Math.max(0, 16 - (a - e)), r = setTimeout(() => { t(a + l); }, l); return e = a + l, r; }; } function _e() { if (typeof window > "u") return () => 0; if (window.requestAnimationFrame) return window.requestAnimationFrame.bind(window); const e = Ye.filter((t) => `${t}RequestAnimationFrame` in window)[0]; return e ? window[`${e}RequestAnimationFrame`] : Ge(); } _e(); I(""); function G() { if (typeof window > "u" || typeof navigator > "u") return !1; const e = navigator.userAgent || navigator.vendor || window.opera, t = [ /iPhone/i, /iPod/i, /Android.*Mobile/i, // Android 手机通常包含 "Mobile" 字样,而平板不包含 /webOS/i, /BlackBerry/i, /IEMobile/i, /Opera Mini/i, /Harmony/i ], a = [ /iPad/i, /Android(?!.*Mobile)/i, // Android 平板通常不含 "Mobile" /Tablet/i, /PlayBook/i, /Kindle/i, /Silk/i ]; for (const g of a) if (g.test(e)) return !1; for (const g of t) if (g.test(e)) return !0; if (typeof screen > "u") return !1; const l = "ontouchstart" in window || navigator.maxTouchPoints > 0, r = screen.width, m = screen.height, o = Math.min(r, m); return !!(l && o <= 768); } function We() { const e = G(); return e && document.body.classList.add("f-mobile"), e; } typeof document < "u" && We(); const $ = /* @__PURE__ */ k({ name: "FComboList", props: U, emits: ["clear", "update:modelValue", "change", "input", "dataChanged", "expandClick", "hidden", "shown"], setup(e, t) { const a = I(), l = I(), r = I(e.disabled || e.readonly), m = I(e.enableClear), o = I(e.enableSearch), T = I(e.readonly), { dataSource: g, displayText: y, editable: v, modelValue: h, filteredDataSource: F, getItemsByDisplayText: b, getItemsByValue: x, beforeOpenList: B } = Ue(e, t), w = I(e.dropDownIcon); w.value === '<span class="f-icon f-icon-arrow-chevron-down"></span>' && (w.value = '<span id="' + e.id + '-icon-dropdown" class="f-icon f-icon-arrow-chevron-down"></span>'); const n = M(() => e.multiSelect), u = M(() => l.value ? l.value.elementRef.getBoundingClientRect().width : 0); function s() { !n.value && l.value && l.value.hidePopup(); } function c(C) { y.value = C.map((H) => H[e.textField]).join(e.separator) || h.value; let P = ""; C.length === 1 ? P = C[0][e.valueField] : P = C.map((H) => H[e.valueField]).join(e.separator), h.value !== P && (h.value = P, t.emit("update:modelValue", h.value), t.emit("change", C, h.value)); } function i() { const C = x(h.value); c(C); } function d() { T.value || y.value; } function f(C) { var P; h.value = "", (P = a.value) == null || P.activeRowById(""), t.emit("clear"); } function S(C) { var P, H; e.enableSearch && e.enableHighlightSearch && ((P = a.value) == null || P.search(C)), (H = a.value) == null || H.activeRowById(C), t.emit("change", [h.value], h.value); } function p(C) { if (e.multiSelect) { const P = b(C); e.viewType; const O = P.map((Y) => Y[e.idField || e.valueField]).join(e.separator); h.value !== O && (h.value = O, t.emit("update:modelValue", h.value), t.emit("change", P, h.value)); } else C !== h.value && (h.value = C, t.emit("update:modelValue", h.value), t.emit("change", [], C)); } function A() { return y.value; } function E(C) { const { value: P } = C.target; S(P), t.emit("input", P); } function ee() { l.value.hidePopup(); } function te(C) { g.value = C; } function ne() { return g.value; } const ie = { getDisplayText: A, hidePopup: ee, updateDataSource: te, getData: ne }; t.expose(ie), L([() => e.disabled, () => e.editable, () => e.enableClear, () => e.enableSearch, () => e.readonly], ([C, P, H, O, Y]) => { r.value = C, v.value = P, m.value = H, o.value = O, T.value = Y; }); const le = () => { t.emit("expandClick"); }; return () => V(ae, { ref: l, id: e.id, disable: r.value, readonly: T.value, forcePlaceholder: e.forcePlaceholder, editable: v.value, buttonContent: w.value, placeholder: e.placeholder === "请选择" ? J.getLocaleValue("comboList.placeholder") : e.placeholder, enableClear: m.value, maxLength: e.maxLength, tabIndex: e.tabIndex, enableTitle: e.enableTitle, multiSelect: e.multiSelect, inputType: e.multiSelect ? e.viewType : "text", modelValue: y.value, "onUpdate:modelValue": (C) => y.value = C, focusOnCreated: e.focusOnCreated, selectOnCreated: e.selectOnCreated, onClear: f, onClick: d, onChange: p, onBlur: i, onInput: E, beforeOpen: B, placement: G() ? "bottom" : e.placement, popupMinWidth: e.minPanelWidth, popupClass: "f-combo-list-wrapper", popupOnClick: e.popupOnClick, limitContentBySpace: !0, expandable: e.expandable, expandMode: e.expandMode, expandContent: e.expandContent, expandDisabled: e.expandDisabled, onExpandClick: le, onHidden: () => t.emit("hidden"), onShown: () => t.emit("shown") }, { default: () => [G() ? V(qe, { modelValue: h.value, valueField: e.valueField, textField: e.textField, columns: g.value, multiSelect: e.multiSelect, separator: e.separator, onConfirm: (C) => { const P = e.multiSelect ? C[0] || [] : C; c(P), l == null || l.value.hidePopup(); }, onCancel: () => { l == null || l.value.hidePopup(); } }, null) : V(Le, { class: e.popupClass, ref: a, idField: e.idField, valueField: e.valueField, textField: e.textField, titleField: e.titleField, dataSource: F.value, selectedValues: h.value, separator: e.separator, multiSelect: e.multiSelect, showSelectAll: e.showSelectAll, enableSearch: o.value, maxHeight: e.maxHeight, enableHighlightSearch: e.enableHighlightSearch, width: e.fitEditor ? u.value : void 0, onSelectionChange: (C) => { c(C), s(); } }, null)] }); } }), j = { convertFrom: (e, t) => (e.editor.remote || {})[t], convertTo: (e, t, a) => { e.editor.remote = e.editor.remote || {}, e.editor.remote[t] = a; } }; class je extends ye { constructor(t, a) { super(t, a); } getCommonEditorProperties(t) { var a, l, r, m; return { showSelectAll: { visible: !!((a = t.editor) != null && a.multiSelect), description: "多选模式下是否显示全选复选框", title: "启用全选", type: "boolean", default: !1, refreshPanelAfterChanged: !0 }, viewType: { visible: !!((l = t.editor) != null && l.multiSelect), description: "数据展示类型,有标签和文本两种方式", title: "数据展示类型", type: "enum", editor: { data: [ { id: "tag", name: "标签" }, { id: "text", name: "文本" } ] }, refreshPanelAfterChanged: !0 }, separator: { visible: !!((r = t.editor) != null && r.multiSelect) && ((m = t.editor) == null ? void 0 : m.viewType) === "text", description: "下拉列表启用多选且数据展示类型为文本时的分隔符", title: "分隔符", type: "enum", editor: { data: [ { id: ",", name: "逗号(,)" }, { id: "#", name: "井号(#)" }, { id: ".", name: "句号(.)" }, { id: "|", name: "竖线(|)" } ] } }, editable: { description: "", title: "允许编辑", type: "boolean", refreshPanelAfterChanged: !0, readonly: !0 // readonly: !!propertyData.editor?.multiSelect && (propertyData.editor?.viewType === 'tag' || !propertyData.editor!.viewType) }, hideDisabledItems: { description: "当数据项禁用时,隐藏数据项", title: "隐藏禁用项", type: "boolean", refreshPanelAfterChanged: !0 } // enableHighlightSearch: { // visible: !!propertyData.editor?.editable, // description: "编辑状态下启用高亮搜索", // title: "启用高亮搜索", // type: "boolean" // }, }; } getEditorProperties(t) { var g, y, v, h, F, b, x, B, w, n, u, s, c; const a = this; let l = ""; if (((g = t == null ? void 0 : t.binding) == null ? void 0 : g.type) === "Form") { const i = this.schemaService.getFieldByIDAndVMID(t.binding.field, this.viewModelId); (y = i == null ? void 0 : i.schemaField) != null && y.type && (l = i.schemaField.type.$type); } const r = this.getPropertyEditorParams(t, ["Variable"]), m = !t.editor.dataSourceType || t.editor.dataSourceType === "static", o = (((h = (v = this.designViewModelField) == null ? void 0 : v.type) == null ? void 0 : h.$type) === R.StringType || !!this.formRule && ((F = this.designerHostService.schemaService.getFieldByID(t.binding.field)) == null ? void 0 : F.type.$type) === R.StringType) && ((b = t.editor) == null ? void 0 : b.type) === "combo-list" && ((x = t.editor) == null ? void 0 : x.dataSourceType) === "dynamic" && !((w = (B = t.editor) == null ? void 0 : B.remote) != null && w.url) && !((n = t.editor) != null && n.multiSelect); return a.getComponentConfig( t, { type: "combo-list" }, { // enableSearch: { // description: "编辑状态下启用搜索", // title: "允许编辑", // type: "boolean", // }, enableClear: { description: "是否显示清除按钮", title: "启用清除按钮", type: "boolean" }, dataSourceType: { description: "", title: "数据源类型", type: "enum", editor: { default: "static", data: [ { id: "static", name: "静态" }, { id: "dynamic", name: "动态" } ] }, refreshPanelAfterChanged: !0 }, dataSource: { description: "动态数据源绑定变量", visible: o, title: "数据", editor: { ...r, controlName: "", enableClear: !0 }, refreshPanelAfterChanged: !0 }, data: { description: "", title: "数据", type: "array", visible: m, ...a.getItemCollectionEditor(t, t.editor.valueField, t.editor.textField), // 这个属性,标记当属性变更得时候触发重新更新属性 refreshPanelAfterChanged: !0 }, url: { visible: t.editor.dataSourceType === "dynamic" && !((u = t.editor) != null && u.dataSource), $converter: j, description: "", title: "服务端API", type: "string", refreshPanelAfterChanged: !0 }, // method: { // visible: propertyData.editor.dataSourceType === "dynamic", // $converter: comboListRemoteConverter, // description: "", // title: "服务端API类型", // type: "enum", // editor: { // default: "GET", // data: [ // { id: "GET", name: "GET" }, // { id: "PUT", name: "PUT" }, // { id: "POST", name: "POST" } // ] // }, // }, body: { visible: !1, $converter: j, description: "", title: "服务端API参数", type: "string" }, textField: { description: "", title: "数据源显示字段", type: "string", readonly: t.editor.dataSourceType !== "dynamic" }, valueField: { description: "", title: "数据源值字段", type: "string", readonly: t.editor.dataSourceType !== "dynamic" }, multiSelect: { description: "", title: "启用多选", visible: !l || l === "StringType", readonly: ((s = t.editor) == null ? void 0 : s.dataSourceType) === "dynamic" && !!((c = t.editor) != null && c.dataSource), type: "boolean", refreshPanelAfterChanged: !0 }, maxLength: { description: "", title: "最大输入长度", type: "number", editor: { nullable: !0, min: 0, useThousands: !1, needValid: !0 } }, ...this.getCommonEditorProperties(t) }, (i, d) => { if (!i || !d.editor) return; const f = this; switch (i.propertyID) { case "dataSourceType": { i.propertyValue === "static" ? (d.editor.valueField = "value", d.editor.textField = "name", d.editor.remote = null) : i.propertyValue === "dynamic" && (d.editor.remote = { method: "GET" }, d.editor.valueField = "value", d.editor.textField = "name"); break; } case "data": { !f.checkEnumDataReadonly(d) && d.formatter && (d.formatter.data = [...i.propertyValue]); break; } case "viewType": { i.propertyValue === "tag" && (d.editor.editable = !1); break; } case "dataSource": f.afterMutilEditorChanged(d, i); break; } } ); } getGridFieldEdtiorProperties(t, a) { var g, y, v, h, F, b, x, B, w, n, u, s, c; const l = this; let r = ""; if (((g = t == null ? void 0 : t.binding) == null ? void 0 : g.type) === "Form") { const i = this.schemaService.getFieldByIDAndVMID(t.binding.field, this.viewModelId); (y = i == null ? void 0 : i.schemaField) != null && y.type && (r = i.schemaField.type.$type); } const m = ((h = (v = this.designViewModelField) == null ? void 0 : v.type) == null ? void 0 : h.$type) === R.StringType && ((F = t.editor) == null ? void 0 : F.type) === "combo-list" && ((b = t.editor) == null ? void 0 : b.dataSourceType) === "dynamic" && !((x = t.editor) != null && x.multiSelect), o = this.getPropertyEditorParams(t, ["Variable"]); return l.getComponentConfig( t, { type: "combo-list" }, { // editable: { // description: "", // title: "允许编辑", // type: "boolean", // readonly: propertyData.editor?.type === 'combo-list' // }, enableClear: { description: "", title: "启用清空", type: "boolean" }, dataSourceType: { description: "", title: "数据源类型", type: "enum", editor: { default: "static", data: [ { id: "static", name: "静态" }, { id: "dynamic", name: "动态" } ] }, refreshPanelAfterChanged: !0 }, dataSource: { description: "动态数据源绑定变量", visible: m, title: "数据", editor: { ...o, controlName: "", enableClear: !0 }, refreshPanelAfterChanged: !0 }, data: { description: "", title: "数据", type: "array", visible: !((B = t.editor) != null && B.dataSourceType) || ((w = t.editor) == null ? void 0 : w.dataSourceType) === "static", ...l.getItemCollectionEditor(t, (n = t.editor) == null ? void 0 : n.valueField, (u = t.editor) == null ? void 0 : u.textField), // 这个属性,标记当属性变更得时候触发重新更新属性 refreshPanelAfterChanged: !0 }, textField: { description: "", title: "数据源显示字段", type: "string", readonly: !0 }, valueField: { description: "", title: "数据源值字段", type: "string", readonly: !0 }, multiSelect: { description: "", title: "启用多选", visible: r === "StringType", readonly: ((s = t.editor) == null ? void 0 : s.dataSourceType) === "dynamic" && !!((c = t.editor) != null && c.dataSource), type: "boolean", refreshPanelAfterChanged: !0 }, maxLength: { description: "", title: "最大输入长度", type: "number", editor: { nullable: !0, min: 0, useThousands: !1, needValid: !0 } }, ...this.getCommonEditorProperties(t) }, (i, d) => { if (!i || !d.editor) return; const f = this; switch (i.propertyID) { case "dataSourceType": { i.propertyValue === "static" ? (d.editor.valueField = "value", d.editor.textField = "name", d.editor.remote = null) : i.propertyValue === "dynamic" && (d.editor.remote = { method: "GET" }, d.editor.valueField = "value", d.editor.textField = "name"); break; } case "data": { !f.checkEnumDataReadonly(d) && d.formatter && (d.formatter.data = [...i.propertyValue]); break; } case "dataSource": f.afterMutilEditorChanged(d, i); } } ); } setEditorPropertyRelates(t, a, l) { if (!t || !a.editor) return; const r = this; switch (t.propertyID) { case "dataSourceType": { t.propertyValue === "static" && (a.editor.valueField = "value", a.editor.textField = "name", a.editor.remote = {}); break; } case "data": { !r.checkEnumDataReadonly(a) && a.formatter && (a.formatter.data = [...t.propertyValue]); break; } } } /** * 切换绑定属性 */ changeBindingField(t, a, l) { var m; super.changeBindingField(t, a); const r = l; t.editor && ((m = r == null ? void 0 : r.type) == null ? void 0 : m.$type) === R.EnumType && (t.editor.data = r.type.enumValues || []); } /** * 组装输入类控件的交互面板:包含标签超链、绑定字段值变化前后事件等。 * @param propertyData 属性值 * @param viewModelId 视图模型id * @param showPosition 面板展示位置 * @param customEvent 输入控件特有的事件配置 */ getEventPropertyConfig(t, a = "card", l, r) { const m = this; let o = [ { label: "onChange", name: "值变化事件" }, // { // label: 'onClear', // name: '清空事件' // }, { label: "beforeOpen", name: "打开面板前事件" }, { label: "beforeHide", name: "关闭面板前事件" }, { label: "onShown", name: "面板打开事件" }, { label: "onHidden", name: "面板关闭事件" } ]; o = [...o, ...this.getInputCommonEvents(t)], l && (o = o.concat(l)), this.formRule && (o = o.filter((v) => v.label !== "onChange")), this.appendFieldValueChangeEvents(t, o); const T = m.eventsEditorUtils.formProperties(t, m.viewModelId, o); return { title: "事件", hideTitle: !0, properties: m.createBaseEventProperty(T), tabId: he, tabName: "交互", setPropertyRelates(v, h) { const F = v.propertyValue; delete t[m.viewModelId], F && (F.setPropertyRelates = this.setPropertyRelates, m.eventsEditorUtils.saveRelatedParameters(t, m.viewModelId, F.events, F), m.updateLinkedLabel(F, h)), r && r(v, h, F); const b = m.designViewModelUtils.getDgViewModel(m.viewModelId); b && m.designViewModelField && b.changeField(m.designViewModelField.id, { valueChanging: t.fieldValueChanging || "", valueChanged: t.fieldValueChanged || "" }), t.editor.onShown = t.onShown, t.editor.onHidden = t.onHidden, t.editor.beforeHide = t.beforeHide, t.editor.beforeOpen = t.beforeOpen, t.editor.onChange = t.onChange, t.editor.onClear = t.onClear; } }; } } function ze(e, t) { const a = e.schema; function l(r, m) { return new je(r, t).getPropertyConfig(a, m); } return { getPropsConfig: l }; } const Je = /* @__PURE__ */ k({ name: "FComboListDesign", props: Me, emits: ["clear", "update:modelValue", "change"], setup(e, t) { const a = I(), l = _("designer-host-service"), r = _("design-item-context"), m = ze(r, l), o = be(a, r, m); return z(() => { a.value.componentInstance = o; }), t.expose(o.value), () => V(ge, { ref: a, buttonContent: e.dropDownIcon, readonly: !0, editable: !1, forcePlaceholder: !0, placeholder: e.placeholder, expandable: e.expandable, expandMode: e.expandMode, expandContent: e.expandContent, expandDisabled: e.expandDisabled }, null); } }); $.register = (e, t, a, l, r) => { e["combo-list"] = $, t["combo-list"] = D(r), l["combo-list"] = { callbackResolver: Ae }; }; $.registerDesigner = (e, t, a, l) => { e["combo-list"] = Je, t["combo-list"] = D(l); }; const dt = ve($); export { $ as FComboList, Le as FComboListContainer, qe as FTouchComboListContainer, pe as Placement, Ae as callbackResolver, Me as comboListDesignProps, U as comboListProps, dt as default, ot as propsResolver, D as propsResolverGenerator, Ue as useDataSource };