UNPKG

@opentiny/vue-renderless

Version:

An enterprise-class UI component library, support both Vue.js 2 and Vue.js 3, as well as PC and mobile.

253 lines (252 loc) 8.83 kB
import { __spreadProps, __spreadValues } from "../chunk-G2ADBYYC.js"; const DEFAULT_FILED_NAMES = { text: "label", value: "id", children: "children" }; const createSourceData = ({ props, state, api }) => () => { if (!api.validProps()) return; const { options, valueField, textField, type } = props; if (type === "cascade") return options; const values = api.parseType(state.defaultValues.slice()); const types = Array.from({ length: values.length }); const ranges = Array.from({ length: values.length }); const indices = Array.from({ length: values.length }); const visibleOptions = options.map((opt, i) => { let slicedValues, existOption; if (Array.isArray(opt)) { if (opt.length === 0) return []; let index = opt.findIndex((item) => item[valueField] === values[i]); index = index === -1 ? 0 : index; types[i] = "a"; ranges[i] = [0, opt.length - 1]; indices[i] = index; slicedValues = api.sliceValue(0, opt.length - 1); existOption = (i2) => opt[i2]; } else if (opt && typeof opt === "object") { let range; if (Array.isArray(opt.range)) { range = opt.range.slice(0, 2); } else if (typeof opt.rangeMethod === "function") { range = opt.rangeMethod(...values); state.isOldCascadeType = true; } types[i] = "o"; ranges[i] = api.parseType(range); slicedValues = api.sliceValue(ranges[i][0], ranges[i][1]); existOption = (i2) => opt.optionMethod(i2, ...values); } if (!slicedValues || !existOption) return []; return slicedValues.map((slicedValue) => { const option = slicedValue === null ? { [valueField]: null, [textField]: "" } : existOption(slicedValue); return option; }); }); return visibleOptions; }; const changeHandler = ({ state, columnFieldNames, columnsType, api }) => (columnIndex, option) => { const fields = columnFieldNames.value; if (option && Object.keys(option).length) { state.defaultValues = state.defaultValues ? state.defaultValues : []; if (columnsType.value === "cascade") { state.defaultValues[columnIndex] = option[fields.value] || ""; let index = columnIndex; let cursor = option; while (cursor && cursor[fields.children] && cursor[fields.children][0]) { state.defaultValues[index + 1] = cursor[fields.children][0][fields.value]; index++; cursor = cursor[fields.children][0]; } if (cursor && cursor[fields.children] && cursor[fields.children].length === 0) { state.defaultValues = state.defaultValues.slice(0, index + 1); } } else { state.defaultValues[columnIndex] = Object.prototype.hasOwnProperty.call(option, fields.value) ? option[fields.value] : ""; } api.change(columnIndex); } }; const formatCascade = ({ columnFieldNames }) => (columns, defaultValues) => { const formatted = []; const fields = columnFieldNames.value; let cursor = { text: "", value: "", [fields.children]: columns }; let columnIndex = 0; while (cursor && cursor[fields.children]) { const options = cursor[fields.children]; const value = defaultValues[columnIndex]; let index = options.findIndex((columnItem) => columnItem[fields.value] === value); if (index === -1) index = 0; cursor = cursor[fields.children][index]; columnIndex++; formatted.push(options); } return formatted.slice(); }; const columnFieldNamesComputed = ({ props, computed }) => computed(() => { return __spreadProps(__spreadValues({}, DEFAULT_FILED_NAMES), { text: props.textField, value: props.valueField, children: props.childrenField }); }); const defaultIndexes = ({ state, computed, columnFieldNames, columnsList }) => computed(() => { const fields = columnFieldNames.value; return columnsList.value.map((column, index) => { const targetIndex = column.findIndex((item) => item[fields.value] === state.defaultValues[index]); return targetIndex === -1 ? 0 : targetIndex; }); }); const confirmDisabled = ({ props, state, columnsList }) => () => { if (typeof props.disabled !== "function") { return false; } state.isDisabled = columnsList.value.some((column, columnIndex) => { return props.disabled(state.defaultValues[columnIndex], ...state.defaultValues); }); }; const change = ({ api, state, columnFieldNames, columnsList }) => () => { if (api.isSameValue(state.oldValues, state.defaultValues)) return; state.oldValues = state.defaultValues.slice(); if (state.isOldCascadeType) { state.formattedColumns = api.createSourceData(); } api.getColumnsList(); api.confirmDisabled(); const fields = columnFieldNames.value; state.selectedOptions = columnsList.value.map((column, index) => { return column.find((item) => item[fields.value] === state.defaultValues[index]) || column[0]; }); }; const columnsTypeComputed = ({ state, computed, columnFieldNames }) => computed(() => { const firstColumn = state.formattedColumns && state.formattedColumns[0]; const fields = columnFieldNames.value; if (firstColumn) { if (Array.isArray(firstColumn)) { return "multiple"; } if (fields.children in firstColumn) { return "cascade"; } } return "single"; }); const getColumnsList = ({ state, api, columnsType, columnsList }) => () => { let result = []; switch (columnsType.value) { case "multiple": result = state.formattedColumns; break; case "cascade": result = api.formatCascade(state.formattedColumns, state.defaultValues ? state.defaultValues : []); break; default: result = [state.formattedColumns]; break; } columnsList.value = result; }; const setValue = ({ api, state }) => (value) => { if (!api.isSameValue(value, state.defaultValues)) { state.defaultValues = (value || []).slice(); api.change(); } }; const isSameValue = (valA, valB) => JSON.stringify(valA) === JSON.stringify(valB); const sliceValue = (min, max) => { const values = [min]; Array.from({ length: max - min }).map((v, i) => values.push(min + i + 1)); return values; }; const validArr = (arr) => Array.isArray(arr) && arr.length; const validProps = ({ props }) => () => { const { modelValue, options } = props; const isSameLen = modelValue && modelValue.length ? modelValue.length === options.length : true; return Array.isArray(modelValue) && Array.isArray(options) && isSameLen; }; const parseType = ({ props }) => (values) => { const { valueType } = props; return values.map(valueType === "number" ? Number : valueType === "string" ? String : (i) => i); }; const init = ({ api, state }) => () => { state.isInit = true; state.formattedColumns = api.createSourceData(); api.getColumnsList(); }; const usePicker = (args) => { const { ref, reactive, watch, computed, toRefs, props } = args; const state = reactive({ formattedColumns: [], defaultValues: [], selectedOptions: [], oldValues: [], isOldCascadeType: false, isDisabled: false, isInit: false }); const api = {}; const columnsList = ref([]); const pickerColumn = ref([]); const columnFieldNames = columnFieldNamesComputed({ props, computed }); const columnsType = columnsTypeComputed({ state, computed, columnFieldNames }); Object.assign(api, { change: change({ api, state, columnFieldNames, columnsList }), changeHandler: changeHandler({ state, columnFieldNames, columnsType, api }), formatCascade: formatCascade({ columnFieldNames }), setValue: setValue({ api, state }), validProps: validProps({ props }), parseType: parseType({ props }), init: init({ api, state }), isSameValue, sliceValue, getColumnsList: getColumnsList({ state, api, columnsType, columnsList }), confirmDisabled: confirmDisabled({ props, state, columnsList }), defaultIndexes: defaultIndexes({ state, computed, columnFieldNames, columnsList }), createSourceData: createSourceData({ props, state, api }) }); initWatch({ props, api, state, watch }); return __spreadProps(__spreadValues({}, toRefs(state)), { columnsType, columnsList, columnFieldNames, changeHandler: api.changeHandler, defaultIndexes: api.defaultIndexes, pickerColumn, isSameValue: api.isSameValue, setValue: api.setValue }); }; const initWatch = ({ props, api, state, watch }) => { watch( () => props.modelValue, (newValues) => { api.setValue(newValues); }, { deep: true, immediate: true } ); watch( () => props.options, () => props.visible && api.init(), { deep: true, immediate: true } ); watch( () => props.visible, () => props.visible && !state.isInit && api.init(), { deep: true, immediate: true } ); }; export { usePicker };