@cmtlyt/lingshu-toolkit 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/607.js +737 -0
- package/dist/707.js +13 -3
- package/dist/react/index.d.ts +7 -0
- package/dist/react/index.js +120 -3
- package/dist/react/use-force-update/index.d.ts +1 -0
- package/dist/react/use-force-update/index.js +6 -0
- package/dist/react/use-force-update/index.test.d.ts +1 -0
- package/dist/react/use-ref-state/index.d.ts +8 -0
- package/dist/react/use-ref-state/index.js +33 -0
- package/dist/react/use-ref-state/index.test.d.ts +1 -0
- package/dist/react/use-storage/index.d.ts +2 -0
- package/dist/react/use-storage/index.js +15 -0
- package/dist/react/use-storage/index.test.d.ts +1 -0
- package/dist/react/use-valid-data/index.d.ts +3 -3
- package/dist/shared/allx/__test__/allsettled.test.d.ts +1 -0
- package/dist/shared/allx/__test__/basic.test.d.ts +1 -0
- package/dist/shared/allx/__test__/circular-dependency.test.d.ts +1 -0
- package/dist/shared/allx/__test__/dependency.test.d.ts +1 -0
- package/dist/shared/allx/__test__/edge-cases.test.d.ts +1 -0
- package/dist/shared/allx/__test__/error-handling.test.d.ts +1 -0
- package/dist/shared/allx/__test__/execution-order.test.d.ts +1 -0
- package/dist/shared/allx/__test__/falsy-values.test.d.ts +1 -0
- package/dist/shared/allx/__test__/performance.test.d.ts +1 -0
- package/dist/shared/allx/__test__/type-checking.test.d.ts +1 -0
- package/dist/shared/allx/__test__/use-cases.test.d.ts +1 -0
- package/dist/shared/allx/index.d.ts +13 -0
- package/dist/shared/allx/index.js +44 -0
- package/dist/shared/allx/types.d.ts +13 -0
- package/dist/shared/allx/types.js +0 -0
- package/dist/shared/allx/utils.d.ts +9 -0
- package/dist/shared/allx/utils.js +94 -0
- package/dist/shared/animation/__test__/animation-pause-resume.test.d.ts +1 -0
- package/dist/shared/animation/__test__/animation.test.d.ts +1 -0
- package/dist/shared/animation/__test__/step-animation.test.d.ts +1 -0
- package/dist/shared/animation/__test__/utils.test.d.ts +1 -0
- package/dist/shared/animation/index.d.ts +3 -0
- package/dist/shared/animation/index.js +77 -0
- package/dist/shared/animation/types.d.ts +24 -0
- package/dist/shared/animation/types.js +0 -0
- package/dist/shared/animation/utils.d.ts +14 -0
- package/dist/shared/animation/utils.js +134 -0
- package/dist/shared/condition-merge/index.d.ts +1 -5
- package/dist/shared/create-storage-handler/index.browser.test.d.ts +1 -0
- package/dist/shared/create-storage-handler/index.d.ts +10 -0
- package/dist/shared/create-storage-handler/index.js +68 -0
- package/dist/shared/create-storage-handler/index.test.d.ts +1 -0
- package/dist/shared/data-handler/index.d.ts +7 -2
- package/dist/shared/data-handler/tools.d.ts +36 -12
- package/dist/shared/data-handler/tools.js +8 -4
- package/dist/shared/data-handler/types.d.ts +2 -2
- package/dist/shared/data-mixed-manager/__test__/basic.test.d.ts +1 -0
- package/dist/shared/data-mixed-manager/__test__/build-options.test.d.ts +1 -0
- package/dist/shared/data-mixed-manager/__test__/constructor-options.test.d.ts +1 -0
- package/dist/shared/data-mixed-manager/__test__/data-management.test.d.ts +1 -0
- package/dist/shared/data-mixed-manager/__test__/edge-cases.test.d.ts +1 -0
- package/dist/shared/data-mixed-manager/__test__/events.browser.test.d.ts +1 -0
- package/dist/shared/data-mixed-manager/__test__/events.test.d.ts +1 -0
- package/dist/shared/data-mixed-manager/__test__/fixed-slots.test.d.ts +1 -0
- package/dist/shared/data-mixed-manager/__test__/insert-mode.test.d.ts +1 -0
- package/dist/shared/data-mixed-manager/constants.d.ts +8 -0
- package/dist/shared/data-mixed-manager/constants.js +9 -0
- package/dist/shared/data-mixed-manager/index.d.ts +128 -0
- package/dist/shared/data-mixed-manager/index.js +226 -0
- package/dist/shared/data-mixed-manager/types.d.ts +90 -0
- package/dist/shared/data-mixed-manager/types.js +0 -0
- package/dist/shared/index.d.ts +8 -0
- package/dist/shared/index.js +2 -1
- package/dist/shared/throw-error/index.d.ts +1 -0
- package/dist/shared/throw-error/index.js +5 -2
- package/dist/shared/types/base.d.ts +6 -0
- package/dist/shared/utils/__test__/base.test.d.ts +1 -0
- package/dist/shared/utils/__test__/verify.test.d.ts +1 -0
- package/dist/shared/utils/base.d.ts +3 -0
- package/dist/shared/utils/base.js +6 -0
- package/dist/shared/utils/index.d.ts +2 -0
- package/dist/shared/utils/index.js +2 -0
- package/dist/shared/utils/verify.d.ts +53 -0
- package/dist/shared/utils/verify.js +67 -0
- package/dist/shared/with-resolvers/index.d.ts +6 -0
- package/dist/shared/with-resolvers/index.js +15 -0
- package/dist/shared/with-resolvers/index.test.d.ts +1 -0
- package/dist/test/utils.d.ts +13 -0
- package/package.json +9 -7
package/dist/607.js
ADDED
|
@@ -0,0 +1,737 @@
|
|
|
1
|
+
import { throwType, createError, logger, $dt, throwError, getType, identity, dataHandler, $t, noop } from "./707.js";
|
|
2
|
+
function isSymbol(_v) {
|
|
3
|
+
return 'symbol' == typeof _v;
|
|
4
|
+
}
|
|
5
|
+
function isUndef(_v) {
|
|
6
|
+
return void 0 === _v;
|
|
7
|
+
}
|
|
8
|
+
function isNull(_v) {
|
|
9
|
+
return null === _v;
|
|
10
|
+
}
|
|
11
|
+
function isNullOrUndef(_v) {
|
|
12
|
+
return isNull(_v) || isUndef(_v);
|
|
13
|
+
}
|
|
14
|
+
function verify_isNaN(_v) {
|
|
15
|
+
return Number.isNaN(_v);
|
|
16
|
+
}
|
|
17
|
+
function isPlainSymbol(_v) {
|
|
18
|
+
return isSymbol(_v) && isUndef(Symbol.keyFor(_v));
|
|
19
|
+
}
|
|
20
|
+
function isObject(_v) {
|
|
21
|
+
return 'object' == typeof _v && !isNull(_v);
|
|
22
|
+
}
|
|
23
|
+
function isPlainObject(_v) {
|
|
24
|
+
return isObject(_v) && !isArray(_v);
|
|
25
|
+
}
|
|
26
|
+
function isArray(_v) {
|
|
27
|
+
return Array.isArray(_v);
|
|
28
|
+
}
|
|
29
|
+
function isEmptyArray(_v) {
|
|
30
|
+
return isArray(_v) && 0 === _v.length;
|
|
31
|
+
}
|
|
32
|
+
function isString(_v) {
|
|
33
|
+
return 'string' == typeof _v;
|
|
34
|
+
}
|
|
35
|
+
function isEmptyString(_v) {
|
|
36
|
+
return isString(_v) && 0 === _v.length;
|
|
37
|
+
}
|
|
38
|
+
function isNumber(_v) {
|
|
39
|
+
return 'number' == typeof _v;
|
|
40
|
+
}
|
|
41
|
+
function isPlainNumber(_v) {
|
|
42
|
+
return isNumber(_v) && !verify_isNaN(_v);
|
|
43
|
+
}
|
|
44
|
+
function isPropertyKey(_v) {
|
|
45
|
+
return isString(_v) || isNumber(_v) || isSymbol(_v);
|
|
46
|
+
}
|
|
47
|
+
function isBoolean(_v) {
|
|
48
|
+
return 'boolean' == typeof _v;
|
|
49
|
+
}
|
|
50
|
+
function isTrue(_v) {
|
|
51
|
+
return true === _v || isString(_v) && 'true' === _v.toLowerCase();
|
|
52
|
+
}
|
|
53
|
+
function isFalse(_v) {
|
|
54
|
+
return false === _v || isString(_v) && 'false' === _v.toLowerCase();
|
|
55
|
+
}
|
|
56
|
+
function isTruthy(_v) {
|
|
57
|
+
return !!_v;
|
|
58
|
+
}
|
|
59
|
+
function isFalsy(_v) {
|
|
60
|
+
return !(verify_isNaN(_v) || _v);
|
|
61
|
+
}
|
|
62
|
+
function isFunction(_v) {
|
|
63
|
+
return 'function' == typeof _v;
|
|
64
|
+
}
|
|
65
|
+
function isPromiseLike(_v) {
|
|
66
|
+
return isObject(_v) && isFunction(_v.then);
|
|
67
|
+
}
|
|
68
|
+
function withResolvers() {
|
|
69
|
+
return 'function' == typeof Promise.withResolvers ? Promise.withResolvers() : (()=>{
|
|
70
|
+
const resolver = {
|
|
71
|
+
promise: null,
|
|
72
|
+
resolve: null,
|
|
73
|
+
reject: null
|
|
74
|
+
};
|
|
75
|
+
resolver.promise = new Promise((resolve, reject)=>{
|
|
76
|
+
resolver.resolve = resolve;
|
|
77
|
+
resolver.reject = reject;
|
|
78
|
+
});
|
|
79
|
+
return resolver;
|
|
80
|
+
})();
|
|
81
|
+
}
|
|
82
|
+
function detectCycle(from, to, waitingForGraph) {
|
|
83
|
+
const visited = new Set();
|
|
84
|
+
const queue = [
|
|
85
|
+
to
|
|
86
|
+
];
|
|
87
|
+
let head = 0;
|
|
88
|
+
while(head < queue.length){
|
|
89
|
+
const node = queue[head++];
|
|
90
|
+
if (node === from) return true;
|
|
91
|
+
if (visited.has(node)) continue;
|
|
92
|
+
visited.add(node);
|
|
93
|
+
const deps = waitingForGraph.get(node);
|
|
94
|
+
if (deps) {
|
|
95
|
+
const depsIter = deps.values();
|
|
96
|
+
for(let dep = depsIter.next(); !dep.done; dep = depsIter.next())queue.push(dep.value);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
function getCached(results, depName, allSettled) {
|
|
102
|
+
if (Reflect.getOwnPropertyDescriptor(results, depName)) {
|
|
103
|
+
const cached = results[depName];
|
|
104
|
+
if (allSettled) return 'rejected' === cached.status ? Promise.reject(cached.reason) : Promise.resolve(cached.value);
|
|
105
|
+
return Promise.resolve(cached);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function createDepResolver(waitingFor, resolverMap, currentTask, depName) {
|
|
109
|
+
waitingFor.set(currentTask, (waitingFor.get(currentTask) || new Set()).add(depName));
|
|
110
|
+
const depResolvers = resolverMap.get(depName) || withResolvers();
|
|
111
|
+
resolverMap.set(depName, depResolvers);
|
|
112
|
+
return depResolvers.promise.then((value)=>{
|
|
113
|
+
waitingFor.get(currentTask)?.delete(depName);
|
|
114
|
+
return value;
|
|
115
|
+
}, (error)=>{
|
|
116
|
+
waitingFor.get(currentTask)?.delete(depName);
|
|
117
|
+
throw error;
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
function cleanWaitingForGraph(waitingForGraph, depName) {
|
|
121
|
+
waitingForGraph.forEach((deps, task)=>{
|
|
122
|
+
deps.delete(depName);
|
|
123
|
+
if (0 === deps.size) waitingForGraph.delete(task);
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
function createDepProxy(tasks, results, options) {
|
|
127
|
+
const resolverMap = new Map();
|
|
128
|
+
const taskNameSet = new Set(Reflect.ownKeys(tasks));
|
|
129
|
+
const waitingForGraph = new Map();
|
|
130
|
+
const resolveDepFor = (depName, value)=>{
|
|
131
|
+
const resolver = resolverMap.get(depName);
|
|
132
|
+
if (resolver) {
|
|
133
|
+
resolver.resolve(value);
|
|
134
|
+
resolverMap.delete(depName);
|
|
135
|
+
}
|
|
136
|
+
cleanWaitingForGraph(waitingForGraph, depName);
|
|
137
|
+
};
|
|
138
|
+
const rejectDepFor = (depName, error)=>{
|
|
139
|
+
const resolver = resolverMap.get(depName);
|
|
140
|
+
if (resolver) {
|
|
141
|
+
resolver.reject(error);
|
|
142
|
+
resolverMap.delete(depName);
|
|
143
|
+
}
|
|
144
|
+
cleanWaitingForGraph(waitingForGraph, depName);
|
|
145
|
+
};
|
|
146
|
+
const createContextFor = (currentTask)=>new Proxy({}, {
|
|
147
|
+
get (_, depName) {
|
|
148
|
+
if (!taskNameSet.has(depName)) return Promise.reject(createError('allx', `Unknown task "${String(depName)}"`));
|
|
149
|
+
const cached = getCached(results, depName, options.allSettled);
|
|
150
|
+
if (cached) return cached;
|
|
151
|
+
if (detectCycle(currentTask, depName, waitingForGraph)) return Promise.reject(createError('allx', `Circular dependency detected: "${String(currentTask)}" -> "${String(depName)}"`));
|
|
152
|
+
return createDepResolver(waitingForGraph, resolverMap, currentTask, depName);
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
return {
|
|
156
|
+
taskNameSet,
|
|
157
|
+
createContextFor,
|
|
158
|
+
resolveDepFor,
|
|
159
|
+
rejectDepFor
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
function getValueFormatFunc(options) {
|
|
163
|
+
if (!options) return (value, _type = 'fulfilled')=>value;
|
|
164
|
+
if (options.allSettled) return (value, status = 'fulfilled')=>'fulfilled' === status ? {
|
|
165
|
+
status,
|
|
166
|
+
value
|
|
167
|
+
} : {
|
|
168
|
+
status,
|
|
169
|
+
reason: value
|
|
170
|
+
};
|
|
171
|
+
return (value, _type = 'fulfilled')=>value;
|
|
172
|
+
}
|
|
173
|
+
const validInfo = $dt({
|
|
174
|
+
allSettled: $t.boolean(false)
|
|
175
|
+
});
|
|
176
|
+
async function allx(tasks, options) {
|
|
177
|
+
const validOptions = dataHandler(options || {}, validInfo, {
|
|
178
|
+
unwrap: true
|
|
179
|
+
});
|
|
180
|
+
const { allSettled } = validOptions;
|
|
181
|
+
const results = {};
|
|
182
|
+
const depCtrl = createDepProxy(tasks, results, validOptions);
|
|
183
|
+
const valueFormat = getValueFormatFunc(options);
|
|
184
|
+
const promises = [];
|
|
185
|
+
depCtrl.taskNameSet.forEach(async (taskName)=>{
|
|
186
|
+
const taskFn = tasks[taskName];
|
|
187
|
+
const context = {
|
|
188
|
+
$: depCtrl.createContextFor(taskName)
|
|
189
|
+
};
|
|
190
|
+
const taskResolvers = withResolvers();
|
|
191
|
+
taskResolvers.promise.then((value)=>{
|
|
192
|
+
results[taskName] = valueFormat(value, 'fulfilled');
|
|
193
|
+
depCtrl.resolveDepFor(taskName, value);
|
|
194
|
+
return value;
|
|
195
|
+
}, (error)=>{
|
|
196
|
+
if (allSettled) results[taskName] = valueFormat(error, 'rejected');
|
|
197
|
+
depCtrl.rejectDepFor(taskName, error);
|
|
198
|
+
});
|
|
199
|
+
promises.push(taskResolvers.promise);
|
|
200
|
+
if (isPromiseLike(taskFn)) return void await taskFn.then(taskResolvers.resolve, taskResolvers.reject);
|
|
201
|
+
if (!isFunction(taskFn)) return void taskResolvers.resolve(taskFn);
|
|
202
|
+
try {
|
|
203
|
+
const result = await taskFn.call(context);
|
|
204
|
+
taskResolvers.resolve(result);
|
|
205
|
+
} catch (error) {
|
|
206
|
+
taskResolvers.reject(error);
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
if (allSettled) return Promise.allSettled(promises).then(()=>results);
|
|
210
|
+
return Promise.all(promises).then(()=>results);
|
|
211
|
+
}
|
|
212
|
+
function getNextValueHandler(from, to, valueFormatter) {
|
|
213
|
+
const type = getType(from);
|
|
214
|
+
const context = {
|
|
215
|
+
progress: 0,
|
|
216
|
+
valueFormatter
|
|
217
|
+
};
|
|
218
|
+
const baseNextValue = (_from, _to)=>{
|
|
219
|
+
const { valueFormatter: formatter, progress } = context;
|
|
220
|
+
if ('number' !== getType(_from)) return _from;
|
|
221
|
+
return formatter(_from + (_to - _from) * progress);
|
|
222
|
+
};
|
|
223
|
+
const arrayHandler = (_from, _to)=>{
|
|
224
|
+
const result = Array.from(_from, (item, idx)=>{
|
|
225
|
+
if (Array.isArray(item)) return arrayHandler(item, _to[idx]);
|
|
226
|
+
if ('object' === getType(item)) return objectHandler(item, _to[idx]);
|
|
227
|
+
return baseNextValue(item, _to[idx]);
|
|
228
|
+
});
|
|
229
|
+
return result;
|
|
230
|
+
};
|
|
231
|
+
const objectHandler = (_from, _to)=>{
|
|
232
|
+
const result = {};
|
|
233
|
+
const keys = Reflect.ownKeys(_from);
|
|
234
|
+
for(let i = 0; i < keys.length; i++){
|
|
235
|
+
const key = keys[i];
|
|
236
|
+
const fromValue = _from[key];
|
|
237
|
+
const toValue = _to[key];
|
|
238
|
+
if (Array.isArray(_from[key])) result[key] = arrayHandler(fromValue, toValue);
|
|
239
|
+
else if ('object' === getType(fromValue)) result[key] = objectHandler(fromValue, toValue);
|
|
240
|
+
else result[key] = baseNextValue(fromValue, toValue);
|
|
241
|
+
}
|
|
242
|
+
return result;
|
|
243
|
+
};
|
|
244
|
+
let nextValueHandler = baseNextValue;
|
|
245
|
+
if ('array' === type) nextValueHandler = arrayHandler;
|
|
246
|
+
else if ('object' === type) nextValueHandler = objectHandler;
|
|
247
|
+
return (progress)=>{
|
|
248
|
+
context.progress = progress;
|
|
249
|
+
return nextValueHandler(from, to);
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
function matchValid(from, to, valueParser) {
|
|
253
|
+
const fromType = getType(from);
|
|
254
|
+
const toType = getType(to);
|
|
255
|
+
if (fromType !== toType) throwType('animation/stepAnimation', 'from and to must be the same type');
|
|
256
|
+
if ('array' === fromType) {
|
|
257
|
+
if (from.length !== to.length) throwType('animation/stepAnimation', 'from and to must be the same length');
|
|
258
|
+
const result = [
|
|
259
|
+
Array.from({
|
|
260
|
+
length: from.length
|
|
261
|
+
}),
|
|
262
|
+
Array.from({
|
|
263
|
+
length: to.length
|
|
264
|
+
})
|
|
265
|
+
];
|
|
266
|
+
for(let i = 0; i < from.length; i++){
|
|
267
|
+
const [fromItem, toItem] = matchValid(from[i], to[i], valueParser);
|
|
268
|
+
result[0][i] = fromItem;
|
|
269
|
+
result[1][i] = toItem;
|
|
270
|
+
}
|
|
271
|
+
return result;
|
|
272
|
+
}
|
|
273
|
+
if ('object' === fromType) {
|
|
274
|
+
const toKeys = Reflect.ownKeys(to);
|
|
275
|
+
const fromKeys = new Set(Reflect.ownKeys(from));
|
|
276
|
+
const result = [
|
|
277
|
+
{},
|
|
278
|
+
{}
|
|
279
|
+
];
|
|
280
|
+
for(let i = 0; i < toKeys.length; i++){
|
|
281
|
+
const key = toKeys[i];
|
|
282
|
+
if (!fromKeys.has(key)) throwType('animation/stepAnimation', `from does not have this key: ${String(key)}`);
|
|
283
|
+
const [fromItem, toItem] = matchValid(from[key], to[key], valueParser);
|
|
284
|
+
result[0][key] = fromItem;
|
|
285
|
+
result[1][key] = toItem;
|
|
286
|
+
}
|
|
287
|
+
return result;
|
|
288
|
+
}
|
|
289
|
+
if ('number' !== fromType) return [
|
|
290
|
+
valueParser(from),
|
|
291
|
+
valueParser(to)
|
|
292
|
+
];
|
|
293
|
+
return [
|
|
294
|
+
from,
|
|
295
|
+
to
|
|
296
|
+
];
|
|
297
|
+
}
|
|
298
|
+
function createNextTick(resolvers, rcSignal) {
|
|
299
|
+
const nextTick = (()=>{
|
|
300
|
+
if ('function' == typeof globalThis.requestAnimationFrame) return globalThis.requestAnimationFrame;
|
|
301
|
+
return (callback)=>setTimeout(callback, 16);
|
|
302
|
+
})();
|
|
303
|
+
return (callback)=>{
|
|
304
|
+
if (rcSignal.stopSignal) return true;
|
|
305
|
+
nextTick(()=>tryRun(callback, resolvers, (error)=>{
|
|
306
|
+
rcSignal.stop();
|
|
307
|
+
resolvers.reject(error);
|
|
308
|
+
}));
|
|
309
|
+
return false;
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
async function tryRun(callback, resolvers, customErrorHandler) {
|
|
313
|
+
return new Promise((resolve, reject)=>{
|
|
314
|
+
const result = callback();
|
|
315
|
+
if (result && 'function' == typeof result.then) return result.then(resolve, reject);
|
|
316
|
+
resolve();
|
|
317
|
+
}).catch(customErrorHandler || resolvers.reject);
|
|
318
|
+
}
|
|
319
|
+
function createRunningControllerSignal(startFn, options) {
|
|
320
|
+
const { onStart, onStop, onClear } = options;
|
|
321
|
+
const resolvers = withResolvers();
|
|
322
|
+
const ctrl = {
|
|
323
|
+
stopSignal: true,
|
|
324
|
+
resolvers,
|
|
325
|
+
stop: ()=>{
|
|
326
|
+
ctrl.stopSignal = true;
|
|
327
|
+
onStop();
|
|
328
|
+
},
|
|
329
|
+
start: ()=>{
|
|
330
|
+
ctrl.stopSignal = false;
|
|
331
|
+
onStart();
|
|
332
|
+
startFn();
|
|
333
|
+
},
|
|
334
|
+
clear: ()=>{
|
|
335
|
+
ctrl.stopSignal = true;
|
|
336
|
+
onClear();
|
|
337
|
+
resolvers.resolve(true);
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
return ctrl;
|
|
341
|
+
}
|
|
342
|
+
const animation_validInfo = $dt({
|
|
343
|
+
autoStart: $t.boolean(true),
|
|
344
|
+
easing: $t["function"](()=>identity),
|
|
345
|
+
onStart: $t["function"](()=>noop),
|
|
346
|
+
onStop: $t["function"](()=>noop),
|
|
347
|
+
onClear: $t["function"](()=>noop),
|
|
348
|
+
onUpdate: $t["function"](()=>noop),
|
|
349
|
+
onComplete: $t["function"](()=>noop),
|
|
350
|
+
formatterValue: $t["function"](()=>identity),
|
|
351
|
+
formatter: $t["function"](()=>identity),
|
|
352
|
+
parser: $t["function"](()=>identity)
|
|
353
|
+
});
|
|
354
|
+
function* stepAnimation(from, to, step, options = {}) {
|
|
355
|
+
if (!Number.isInteger(step) || step <= 0) throwError('stepAnimation', 'step must be a positive integer', RangeError);
|
|
356
|
+
const validOptions = dataHandler(options, animation_validInfo, {
|
|
357
|
+
unwrap: true
|
|
358
|
+
});
|
|
359
|
+
const { parser: valueParser = identity, formatterValue = identity, formatter } = validOptions;
|
|
360
|
+
const [validFrom, validTo] = matchValid(from, to, valueParser);
|
|
361
|
+
const getNextValue = getNextValueHandler(validFrom, validTo, formatterValue);
|
|
362
|
+
for(let i = 0; i <= step; i++){
|
|
363
|
+
const value = formatter(getNextValue(i / step));
|
|
364
|
+
yield value;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
function animation(from, to, duration, options = {}) {
|
|
368
|
+
if (duration <= 0 || !Number.isInteger(duration)) throwError('animation', 'duration must be a positive integer', RangeError);
|
|
369
|
+
const validOptions = dataHandler(options, animation_validInfo, {
|
|
370
|
+
unwrap: true
|
|
371
|
+
});
|
|
372
|
+
const [validFrom, validTo] = matchValid(from, to, validOptions.parser);
|
|
373
|
+
const { autoStart, easing, onComplete, onUpdate, formatterValue, formatter } = validOptions;
|
|
374
|
+
const _getNextValue = getNextValueHandler(validFrom, validTo, formatterValue);
|
|
375
|
+
const getNextValue = (...args)=>formatter(_getNextValue(...args));
|
|
376
|
+
let startTime = 0;
|
|
377
|
+
let hasStarted = false;
|
|
378
|
+
const rcSignal = createRunningControllerSignal(()=>{
|
|
379
|
+
const now = performance.now();
|
|
380
|
+
startTime += now;
|
|
381
|
+
const stopFlag = nextTick(tick);
|
|
382
|
+
if (stopFlag) {
|
|
383
|
+
startTime -= performance.now();
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
if (!hasStarted) {
|
|
387
|
+
onUpdate(getNextValue(0));
|
|
388
|
+
hasStarted = true;
|
|
389
|
+
}
|
|
390
|
+
}, validOptions);
|
|
391
|
+
const { resolvers } = rcSignal;
|
|
392
|
+
const nextTick = createNextTick(resolvers, rcSignal);
|
|
393
|
+
const tick = ()=>{
|
|
394
|
+
const elapsed = performance.now() - startTime;
|
|
395
|
+
const progress = easing(Math.min(elapsed / duration, 1));
|
|
396
|
+
const value = getNextValue(progress);
|
|
397
|
+
onUpdate(value);
|
|
398
|
+
if (elapsed < duration) {
|
|
399
|
+
const stopFlag = nextTick(tick);
|
|
400
|
+
if (stopFlag) startTime = -elapsed;
|
|
401
|
+
} else {
|
|
402
|
+
onComplete();
|
|
403
|
+
resolvers.resolve(false);
|
|
404
|
+
}
|
|
405
|
+
};
|
|
406
|
+
if (false !== autoStart) rcSignal.start();
|
|
407
|
+
return {
|
|
408
|
+
promise: resolvers.promise,
|
|
409
|
+
stop: rcSignal.stop,
|
|
410
|
+
start: rcSignal.start,
|
|
411
|
+
clear: rcSignal.clear
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
function getEmpty(_v) {
|
|
415
|
+
return Array.isArray(_v) ? [] : {};
|
|
416
|
+
}
|
|
417
|
+
function valueCheck(_v) {
|
|
418
|
+
return Array.isArray(_v) || 'object' == typeof _v;
|
|
419
|
+
}
|
|
420
|
+
function conditionMerge(...input) {
|
|
421
|
+
const conditionItems = (input.length > 1 ? input : input[0]).map((item)=>{
|
|
422
|
+
let result = null;
|
|
423
|
+
if (Array.isArray(item)) {
|
|
424
|
+
const [condition, value, fullback] = item;
|
|
425
|
+
result = {
|
|
426
|
+
condition,
|
|
427
|
+
value,
|
|
428
|
+
fullback
|
|
429
|
+
};
|
|
430
|
+
} else if (Object.getOwnPropertyDescriptor(item, 'condition')) result = item;
|
|
431
|
+
else throwType('conditionMerge', 'input must be an ConditionItem');
|
|
432
|
+
const validValue = valueCheck(result.value);
|
|
433
|
+
const validFullback = void 0 === result.fullback || valueCheck(result.fullback);
|
|
434
|
+
if (!(validValue && validFullback)) throwType('conditionMerge', 'value and fullback must be an array or object');
|
|
435
|
+
return result;
|
|
436
|
+
});
|
|
437
|
+
const result = getEmpty(conditionItems[0].value);
|
|
438
|
+
const mergeFn = Array.isArray(result) ? (a1, a2)=>Reflect.apply(Array.prototype.splice.bind(a1, a1.length, 0), null, a2) : Object.assign;
|
|
439
|
+
for(let i = 0, item = conditionItems[i]; i < conditionItems.length; item = conditionItems[++i])mergeFn(result, item.condition ? item.value : item.fullback || getEmpty(item.value));
|
|
440
|
+
return result;
|
|
441
|
+
}
|
|
442
|
+
const create_storage_handler_validInfo = $dt({
|
|
443
|
+
storageKey: 'validString',
|
|
444
|
+
storageType: $t["enum"]([
|
|
445
|
+
'local',
|
|
446
|
+
'session',
|
|
447
|
+
'memory'
|
|
448
|
+
], 'local'),
|
|
449
|
+
autoSaveInterval: $t.number(0)
|
|
450
|
+
});
|
|
451
|
+
const memoryStorage = {
|
|
452
|
+
data: {},
|
|
453
|
+
getItem (key) {
|
|
454
|
+
return this.data[key];
|
|
455
|
+
},
|
|
456
|
+
setItem (key, value) {
|
|
457
|
+
this.data[key] = value;
|
|
458
|
+
},
|
|
459
|
+
removeItem (key) {
|
|
460
|
+
delete this.data[key];
|
|
461
|
+
}
|
|
462
|
+
};
|
|
463
|
+
function getStorage(storageType) {
|
|
464
|
+
try {
|
|
465
|
+
if ('memory' === storageType) return memoryStorage;
|
|
466
|
+
return 'local' === storageType ? localStorage : sessionStorage;
|
|
467
|
+
} catch {
|
|
468
|
+
logger.warn('createStorage', 'Failed to access localStorage or sessionStorage, using memoryStorage instead.');
|
|
469
|
+
return memoryStorage;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
const CLEAR_FLAG = Symbol('cleared');
|
|
473
|
+
function createStorageHandler(storageKey, initialData, options = {}) {
|
|
474
|
+
const { storageKey: validStorageKey, storageType, autoSaveInterval } = dataHandler({
|
|
475
|
+
storageKey,
|
|
476
|
+
...options
|
|
477
|
+
}, create_storage_handler_validInfo, {
|
|
478
|
+
unwrap: true
|
|
479
|
+
});
|
|
480
|
+
const storage = getStorage(storageType);
|
|
481
|
+
const storageData = storage.getItem(validStorageKey);
|
|
482
|
+
const context = {
|
|
483
|
+
data: storageData ? JSON.parse(storageData) : initialData || {}
|
|
484
|
+
};
|
|
485
|
+
return {
|
|
486
|
+
get (key) {
|
|
487
|
+
if (context.data === CLEAR_FLAG) throwError('createStorageHandler', 'Storage has been cleared.');
|
|
488
|
+
if (null == key) return context.data;
|
|
489
|
+
return context.data[key];
|
|
490
|
+
},
|
|
491
|
+
set (value, key) {
|
|
492
|
+
if (context.data === CLEAR_FLAG) throwError('createStorageHandler', 'Storage has been cleared.');
|
|
493
|
+
if (null == key) context.data = value;
|
|
494
|
+
else context.data[key] = value;
|
|
495
|
+
if (autoSaveInterval > 0) setTimeout(()=>{
|
|
496
|
+
storage.setItem(validStorageKey, JSON.stringify(context.data));
|
|
497
|
+
}, autoSaveInterval);
|
|
498
|
+
else storage.setItem(validStorageKey, JSON.stringify(context.data));
|
|
499
|
+
},
|
|
500
|
+
clear () {
|
|
501
|
+
context.data = CLEAR_FLAG;
|
|
502
|
+
storage.removeItem(validStorageKey);
|
|
503
|
+
}
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
const SLOT_TYPE = {
|
|
507
|
+
fixed: {
|
|
508
|
+
fixedFlag: Symbol('fixed')
|
|
509
|
+
},
|
|
510
|
+
insert: {
|
|
511
|
+
insertFlag: Symbol('insert')
|
|
512
|
+
}
|
|
513
|
+
};
|
|
514
|
+
const data_mixed_manager_validInfo = $dt({
|
|
515
|
+
name: $t.string('default'),
|
|
516
|
+
fixedSlots: $t.array([]),
|
|
517
|
+
dataList: $t.array([]),
|
|
518
|
+
listener: $t.object({})
|
|
519
|
+
});
|
|
520
|
+
class DataMixedManager extends EventTarget {
|
|
521
|
+
addEventListener(...args) {
|
|
522
|
+
return super.addEventListener.apply(this, args);
|
|
523
|
+
}
|
|
524
|
+
removeEventListener(...args) {
|
|
525
|
+
return super.removeEventListener.apply(this, args);
|
|
526
|
+
}
|
|
527
|
+
options;
|
|
528
|
+
fixedSlots = new Map();
|
|
529
|
+
dataList = [];
|
|
530
|
+
mixedData = [];
|
|
531
|
+
lastMixedSlotIdx = -1;
|
|
532
|
+
prevDataLength = 0;
|
|
533
|
+
isBatching = false;
|
|
534
|
+
constructor(options){
|
|
535
|
+
super();
|
|
536
|
+
const validOptions = dataHandler(options || {}, data_mixed_manager_validInfo, {
|
|
537
|
+
unwrap: true
|
|
538
|
+
});
|
|
539
|
+
const { fixedSlots, dataList, listener } = validOptions;
|
|
540
|
+
this.options = validOptions;
|
|
541
|
+
this.addFixedSlots(fixedSlots, {
|
|
542
|
+
lazy: true
|
|
543
|
+
});
|
|
544
|
+
this.appendList(dataList);
|
|
545
|
+
try {
|
|
546
|
+
this.initListener(listener);
|
|
547
|
+
} catch (error) {
|
|
548
|
+
throwError('dataMixedManager', error.message, error.constructor);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
initListener(listener) {
|
|
552
|
+
const listenerNames = Object.keys(listener);
|
|
553
|
+
for(let i = 0, name = listenerNames[i], handler = listener[name]; i < listenerNames.length; name = listenerNames[++i], handler = listener[name])this.addEventListener(name, handler);
|
|
554
|
+
}
|
|
555
|
+
getTypeText(_type) {
|
|
556
|
+
switch(_type){
|
|
557
|
+
case SLOT_TYPE.fixed:
|
|
558
|
+
return 'fixed';
|
|
559
|
+
case SLOT_TYPE.insert:
|
|
560
|
+
return 'insert';
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
buildSlotConfig(config, type) {
|
|
564
|
+
const typeText = this.getTypeText(config.type || type);
|
|
565
|
+
return {
|
|
566
|
+
...config,
|
|
567
|
+
type: typeText,
|
|
568
|
+
inputPosition: config.position,
|
|
569
|
+
insertMode: config.insertMode || 'cover'
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
addFixedSlot(config, buildOptions) {
|
|
573
|
+
const realConfig = this.reorderFixedSlots(this.buildSlotConfig(config, SLOT_TYPE.fixed));
|
|
574
|
+
this.fixedSlots.set(realConfig.position, realConfig);
|
|
575
|
+
this.buildMixedData(buildOptions);
|
|
576
|
+
return realConfig.position;
|
|
577
|
+
}
|
|
578
|
+
reorderFixedSlots(config) {
|
|
579
|
+
const { position: oldPosition, insertMode } = config;
|
|
580
|
+
if (null == insertMode || 'cover' === insertMode || !this.fixedSlots.has(oldPosition)) return {
|
|
581
|
+
...config,
|
|
582
|
+
inputPosition: oldPosition
|
|
583
|
+
};
|
|
584
|
+
const position = 'after' === insertMode ? oldPosition + 1 : oldPosition;
|
|
585
|
+
for(let i = position + 1, preItem = this.fixedSlots.get(i - 1), currItem = this.fixedSlots.get(i); preItem; ++i, preItem = currItem, currItem = this.fixedSlots.get(i)){
|
|
586
|
+
preItem.position = i;
|
|
587
|
+
this.fixedSlots.set(i, preItem);
|
|
588
|
+
}
|
|
589
|
+
return {
|
|
590
|
+
...config,
|
|
591
|
+
position,
|
|
592
|
+
inputPosition: oldPosition
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
addFixedSlots(configs, buildOptions) {
|
|
596
|
+
if (!configs.length) return [];
|
|
597
|
+
const positions = this.batchUpdate(()=>configs.map((config)=>this.addFixedSlot(config)));
|
|
598
|
+
this.buildMixedData(buildOptions);
|
|
599
|
+
return positions;
|
|
600
|
+
}
|
|
601
|
+
deleteFixedSlot(position, buildOptions) {
|
|
602
|
+
this.fixedSlots.delete(position);
|
|
603
|
+
this.buildMixedData(buildOptions);
|
|
604
|
+
}
|
|
605
|
+
deleteFixedSlots(positions, buildOptions) {
|
|
606
|
+
if (!positions.length) return;
|
|
607
|
+
this.batchUpdate(()=>positions.forEach((position)=>void this.deleteFixedSlot(position)));
|
|
608
|
+
this.buildMixedData(buildOptions);
|
|
609
|
+
}
|
|
610
|
+
batchUpdate(callback) {
|
|
611
|
+
try {
|
|
612
|
+
this.isBatching = true;
|
|
613
|
+
const result = callback();
|
|
614
|
+
return result;
|
|
615
|
+
} finally{
|
|
616
|
+
this.isBatching = false;
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
clearFixedSlots(buildOptions) {
|
|
620
|
+
this.fixedSlots.clear();
|
|
621
|
+
this.buildMixedData(buildOptions);
|
|
622
|
+
}
|
|
623
|
+
appendList(list, buildOptions) {
|
|
624
|
+
if (!list.length) return;
|
|
625
|
+
this.dataList.push(...list);
|
|
626
|
+
this.buildMixedData({
|
|
627
|
+
...buildOptions,
|
|
628
|
+
lazy: true === (buildOptions || {}).lazy
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
clearList() {
|
|
632
|
+
this.dataList.length = 0;
|
|
633
|
+
this.mixedData.length = 0;
|
|
634
|
+
this.dispatch('change', {
|
|
635
|
+
mode: 'clear',
|
|
636
|
+
mixedData: this.getMixedData({
|
|
637
|
+
mode: 'rebuild'
|
|
638
|
+
})
|
|
639
|
+
});
|
|
640
|
+
this.dispatch('clear');
|
|
641
|
+
}
|
|
642
|
+
getMixedData(buildOptions) {
|
|
643
|
+
this.buildMixedData({
|
|
644
|
+
...buildOptions,
|
|
645
|
+
lazy: false
|
|
646
|
+
});
|
|
647
|
+
return this.mixedData.slice();
|
|
648
|
+
}
|
|
649
|
+
dispatch(name, data) {
|
|
650
|
+
const detail = {
|
|
651
|
+
name: this.options.name,
|
|
652
|
+
...data
|
|
653
|
+
};
|
|
654
|
+
this.dispatchEvent(new CustomEvent(name, {
|
|
655
|
+
detail
|
|
656
|
+
}));
|
|
657
|
+
if ("u" > typeof window) window.dispatchEvent(new CustomEvent(`[DMM]:${name}`, {
|
|
658
|
+
detail
|
|
659
|
+
}));
|
|
660
|
+
}
|
|
661
|
+
buildMixedData(buildOptions) {
|
|
662
|
+
if (this.isBatching) return;
|
|
663
|
+
const { lazy, mode } = buildOptions || {};
|
|
664
|
+
if ('rebuild' === mode) {
|
|
665
|
+
this.prevDataLength = 0;
|
|
666
|
+
this.lastMixedSlotIdx = -1;
|
|
667
|
+
}
|
|
668
|
+
if (false !== lazy || this.dataList.length <= this.prevDataLength) return;
|
|
669
|
+
let dataStartIdx = this.prevDataLength;
|
|
670
|
+
const dataEndIdx = this.dataList.length;
|
|
671
|
+
const newItemCount = dataEndIdx - dataStartIdx;
|
|
672
|
+
this.prevDataLength = dataEndIdx;
|
|
673
|
+
const isPatchMode = dataStartIdx > 0;
|
|
674
|
+
const filteredSlots = this.sliceSlots(isPatchMode ? this.mixedData.length : this.lastMixedSlotIdx, this.mixedData.length + newItemCount);
|
|
675
|
+
this.lastMixedSlotIdx = filteredSlots.at(-1) ?? this.lastMixedSlotIdx;
|
|
676
|
+
let mixedStartIdx = isPatchMode ? this.mixedData.length : 0;
|
|
677
|
+
this.mixedData.length = (isPatchMode ? newItemCount + mixedStartIdx : dataEndIdx) + filteredSlots.length;
|
|
678
|
+
for(let fpIdx = 0, fpItem = filteredSlots[fpIdx]; dataStartIdx < dataEndIdx; ++mixedStartIdx)if (mixedStartIdx === fpItem) {
|
|
679
|
+
const fixedSlot = this.fixedSlots.get(fpItem);
|
|
680
|
+
this.mixedData[mixedStartIdx] = {
|
|
681
|
+
isFixed: true,
|
|
682
|
+
type: fixedSlot.type,
|
|
683
|
+
data: fixedSlot.data
|
|
684
|
+
};
|
|
685
|
+
fpItem = filteredSlots[++fpIdx];
|
|
686
|
+
} else {
|
|
687
|
+
this.mixedData[mixedStartIdx] = {
|
|
688
|
+
isFixed: false,
|
|
689
|
+
type: 'plain',
|
|
690
|
+
data: this.dataList[dataStartIdx]
|
|
691
|
+
};
|
|
692
|
+
++dataStartIdx;
|
|
693
|
+
}
|
|
694
|
+
this.dispatch('change', {
|
|
695
|
+
mode: isPatchMode ? 'patch' : 'rebuild',
|
|
696
|
+
mixedData: this.mixedData.slice()
|
|
697
|
+
});
|
|
698
|
+
}
|
|
699
|
+
sliceSlots(startIdx, endIdx = 1 / 0) {
|
|
700
|
+
let prevItem = -2;
|
|
701
|
+
let count = 0;
|
|
702
|
+
return Array.from(this.fixedSlots.keys()).sort((ai, bi)=>ai - bi).filter((item)=>{
|
|
703
|
+
if (item >= startIdx && item < endIdx + count || item - 1 === prevItem) {
|
|
704
|
+
++count;
|
|
705
|
+
prevItem = item;
|
|
706
|
+
return true;
|
|
707
|
+
}
|
|
708
|
+
return false;
|
|
709
|
+
});
|
|
710
|
+
}
|
|
711
|
+
insertSlot(config) {
|
|
712
|
+
const realPosition = this.addFixedSlot({
|
|
713
|
+
...config,
|
|
714
|
+
type: SLOT_TYPE.insert
|
|
715
|
+
});
|
|
716
|
+
if (realPosition > this.mixedData.length) return realPosition;
|
|
717
|
+
this.buildMixedData({
|
|
718
|
+
lazy: false,
|
|
719
|
+
mode: 'rebuild'
|
|
720
|
+
});
|
|
721
|
+
return realPosition;
|
|
722
|
+
}
|
|
723
|
+
insertSlots(configs) {
|
|
724
|
+
if (!configs.length) return [];
|
|
725
|
+
const positions = this.batchUpdate(()=>configs.map((config)=>this.insertSlot(config)));
|
|
726
|
+
this.buildMixedData({
|
|
727
|
+
lazy: false,
|
|
728
|
+
mode: 'rebuild'
|
|
729
|
+
});
|
|
730
|
+
return positions;
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
function dataMixedManager(options) {
|
|
734
|
+
return new DataMixedManager(options);
|
|
735
|
+
}
|
|
736
|
+
Symbol('__PACK__');
|
|
737
|
+
export { allx, animation, conditionMerge, createStorageHandler, dataMixedManager, isArray, isBoolean, isEmptyArray, isEmptyString, isFalse, isFalsy, isFunction, isNull, isNullOrUndef, isNumber, isObject, isPlainNumber, isPlainObject, isPlainSymbol, isPromiseLike, isPropertyKey, isString, isSymbol, isTrue, isTruthy, isUndef, stepAnimation, verify_isNaN as isNaN, withResolvers };
|