duoyun-ui
Version:
A lightweight desktop UI component library, implemented using Gem
240 lines • 7.92 kB
JavaScript
import { render, TemplateResult } from '@mantou/gem/lib/element';
import { connect, createStore } from '@mantou/gem/lib/store';
import { cleanObject } from '@mantou/gem/lib/utils';
import { isNullish } from '../lib/types';
export function convertToMap(list, key, value, fallback) {
const argLength = arguments.length;
const isSelf = argLength === 2;
const hasFallback = argLength === 4;
const result = {};
list.forEach((item) => {
if (item) {
// missing `value` is self
result[item[key]] = value ? item[value] : item;
}
});
return new Proxy(result, {
get: (target, prop) => {
return prop in target || isSelf ? target[prop] : hasFallback ? fallback : prop;
},
});
}
/**Get Cascader/Tree max deep*/
export function getCascaderDeep(list, cascaderKey) {
const getChildren = (t) => {
const children = t[cascaderKey];
if (Array.isArray(children)) {
let l = 0;
children.forEach((e) => {
const ll = getChildren(e);
if (ll > l)
l = ll;
});
return 1 + l;
}
return 0;
};
let l = 0;
list.forEach((e) => {
const ll = getChildren(e);
if (ll > l)
l = ll;
});
return 1 + l;
}
/**
* Get the value from the bottom layer,
* compare the new value of the upper layer to choose a new value, bubbling to the top layer
*/
export function getCascaderBubbleWeakMap(list, cascaderKey, getValue, comparerFn = (a) => a, setValueCallback) {
const map = new WeakMap();
const getItemValue = (e) => {
const v = map.get(e) ?? getValue(e);
if (isNullish(v))
return;
return v;
};
const check = (l) => l?.forEach((e) => {
check(e[cascaderKey]);
let value = getItemValue(e);
e[cascaderKey]?.forEach((i) => {
const v = getItemValue(i);
value = isNullish(value) ? v : comparerFn(v, value);
});
if (!isNullish(value)) {
map.set(e, value);
setValueCallback?.(e, value);
}
});
check(list);
return map;
}
/**Simple proxy object, use prop name as a fallback when reading prop */
export function proxyObject(object) {
return new Proxy(object, {
get: (target, prop) => {
return prop in target ? target[prop] : prop;
},
});
}
/**Deep read prop */
export function readProp(obj, paths, options = {}) {
if (!Array.isArray(paths))
return obj[paths];
const len = paths.length;
return paths.reduce((p, c, i) => {
if (!options.fill)
return p?.[c];
if (options.onlyFillIntermediate && i === len - 1)
return p[c];
return (p[c] ||= {});
}, obj);
}
/**Only let the last add Promise take effect, don’t care about the order of Resolve */
export class OrderlyPromisePool {
pool = [];
add(promise, callback) {
const newIndex = this.pool.length;
const removeCallback = () => this.pool.splice(newIndex, 1, null);
this.pool.push(callback);
promise
.then((r) => {
if (this.pool[this.pool.length - 1] === callback) {
callback(r);
this.pool.length = 0;
}
else {
removeCallback();
}
})
.catch((err) => {
removeCallback();
throw err;
});
}
}
export var ComparerType;
(function (ComparerType) {
ComparerType["Eq"] = "eq";
ComparerType["Gte"] = "gte";
ComparerType["Lte"] = "lte";
ComparerType["Lt"] = "lt";
ComparerType["Gt"] = "gt";
ComparerType["Ne"] = "ne";
ComparerType["Miss"] = "miss";
ComparerType["Have"] = "have";
})(ComparerType || (ComparerType = {}));
/**Serialize comparer */
export function comparer(a, comparerType, b) {
const aNum = Number(a);
const bNum = Number(b);
const isNumber = !Number.isNaN(aNum) && !Number.isNaN(aNum);
switch (comparerType) {
case ComparerType.Eq:
// biome-ignore lint/suspicious/noDoubleEquals: <explanation>
return a == b;
case ComparerType.Ne:
// biome-ignore lint/suspicious/noDoubleEquals: <explanation>
return a != b;
case ComparerType.Gt:
return isNumber ? aNum > bNum : a > b;
case ComparerType.Gte:
return isNumber ? aNum >= bNum : a >= b;
case ComparerType.Lt:
return isNumber ? aNum < bNum : a < b;
case ComparerType.Lte:
return isNumber ? aNum <= bNum : a <= b;
case ComparerType.Have:
return a?.includes?.(b);
case ComparerType.Miss:
return !a?.includes?.(b);
default:
return false;
}
}
/**Serialized `TemplateResult` */
const div = document.createElement('div');
export function getStringFromTemplate(input) {
if (input instanceof TemplateResult) {
render(input, div);
return div.textContent || '';
}
return String(input);
}
/**Segmentation search word */
export function splitString(s) {
return s.split(/(?:\s|\/)+/);
}
/**Search */
export function isIncludesString(origin, search, caseSensitive = false) {
const getStr = (s) => (caseSensitive ? s : s.toLowerCase()).trim();
const oString = getStr(getStringFromTemplate(origin));
const sString = getStr(search);
return splitString(sString).some((s) => oString.includes(s));
}
/**Create auto cache(localStorage) Store */
export function createCacheStore(storageKey, initStore, options) {
const getKey = () => {
const prefix = typeof options?.prefix === 'function' ? options.prefix() : options?.prefix;
return prefix ? `${prefix}@${storageKey}` : storageKey;
};
const getStoreStore = (key) => {
let storeCache = undefined;
try {
storeCache = JSON.parse(localStorage.getItem(key) || '{}');
}
catch {
//
}
return storeCache ? { ...initStore, ...storeCache } : initStore;
};
const cacheExcludeKeys = new Set(options?.cacheExcludeKeys || []);
let key = getKey();
const store = createStore(getStoreStore(key));
if (options?.depStore) {
connect(options.depStore, () => {
const newKey = getKey();
if (newKey !== key) {
key = newKey;
cleanObject(store)(getStoreStore(newKey));
}
});
}
const saveStore = () => {
localStorage.setItem(key, JSON.stringify(Object.fromEntries(Object.entries(store).filter(([k]) => !cacheExcludeKeys.has(k)))));
};
addEventListener('pagehide', saveStore);
return { store, saveStore };
}
// 是链接需要使用 img 渲染
export function isRemoteIcon(icon) {
return typeof icon === 'string' && !!icon.trim().match(/^(http|[./])/);
}
/**
* Pass additional fields
*
* not support async function
*/
export class DyPromise extends Promise {
static new(executor, props) {
const instance = new DyPromise(executor);
return Object.assign(instance, props);
}
// biome-ignore lint/suspicious/noThenProperty: extends
then(onfulfilled, onrejected) {
const result = super.then(onfulfilled, onrejected);
return Object.assign(result, this);
}
catch(onrejected) {
const result = super.catch(onrejected);
return Object.assign(result, this);
}
finally(onfinally) {
const result = super.finally(onfinally);
return Object.assign(result, this);
}
}
// 不应该以发生错误的方式来处理拒绝的 Promise
// 缺点:同时有个相同原因的 Promise 需要用错误处理时会被忽略
export const ignoredPromiseReasonSet = new WeakSet();
//# sourceMappingURL=utils.js.map