airx 0.2.2 → 0.3.0-alpha.1
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/README.md +73 -25
- package/output/esm/element.d.ts +2 -1
- package/output/esm/index.d.ts +2 -3
- package/output/esm/index.js +100 -91
- package/output/esm/index.js.map +1 -1
- package/output/esm/render/common/index.d.ts +5 -3
- package/output/esm/signal/index.d.ts +6 -0
- package/output/esm/types.d.ts +2 -3
- package/output/umd/element.d.ts +2 -1
- package/output/umd/index.d.ts +2 -3
- package/output/umd/index.js +99 -92
- package/output/umd/index.js.map +1 -1
- package/output/umd/render/common/index.d.ts +5 -3
- package/output/umd/signal/index.d.ts +6 -0
- package/output/umd/types.d.ts +2 -3
- package/package.json +2 -1
- package/output/esm/reactive.d.ts +0 -10
- package/output/umd/reactive.d.ts +0 -10
package/output/umd/index.js
CHANGED
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.airx = {}));
|
|
5
5
|
})(this, (function (exports) { 'use strict';
|
|
6
6
|
|
|
7
|
-
const globalContext
|
|
7
|
+
const globalContext = {
|
|
8
8
|
current: null
|
|
9
9
|
};
|
|
10
10
|
function useContext() {
|
|
11
|
-
if (globalContext
|
|
11
|
+
if (globalContext.current == null) {
|
|
12
12
|
throw new Error('Unable to find a valid component context');
|
|
13
13
|
}
|
|
14
|
-
return globalContext
|
|
14
|
+
return globalContext.current;
|
|
15
15
|
}
|
|
16
16
|
const onMounted = (listener) => {
|
|
17
17
|
return useContext().onMounted(listener);
|
|
@@ -26,85 +26,65 @@
|
|
|
26
26
|
return useContext().provide(key, value);
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
-
const
|
|
29
|
+
const isPrintLogs = typeof process != 'undefined'
|
|
30
|
+
&& process?.env?.NODE_ENV === 'development'
|
|
31
|
+
&& process?.env?.AIRX_DEBUG === 'true';
|
|
30
32
|
function createLogger(name) {
|
|
31
33
|
function getPrintPrefix() {
|
|
32
34
|
const date = new Date().toLocaleString();
|
|
33
35
|
return `[${date}][${name}]`;
|
|
34
36
|
}
|
|
35
37
|
function debug(...args) {
|
|
36
|
-
if (
|
|
38
|
+
if (isPrintLogs)
|
|
37
39
|
console.log(getPrintPrefix(), ...args);
|
|
38
40
|
}
|
|
39
41
|
return { debug };
|
|
40
42
|
}
|
|
41
43
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
44
|
+
let firstSignal = undefined;
|
|
45
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
46
|
+
const globalNS = (function () {
|
|
47
|
+
// the only reliable means to get the global object is
|
|
48
|
+
// `Function('return this')()`
|
|
49
|
+
// However, this causes CSP violations in Chrome apps.
|
|
50
|
+
if (typeof self !== 'undefined') {
|
|
51
|
+
return self;
|
|
52
|
+
}
|
|
53
|
+
if (typeof window !== 'undefined') {
|
|
54
|
+
return window;
|
|
55
|
+
}
|
|
56
|
+
if (typeof global !== 'undefined') {
|
|
57
|
+
return global;
|
|
58
|
+
}
|
|
59
|
+
throw new Error('unable to locate global object');
|
|
60
|
+
})();
|
|
61
|
+
// 通过函数包装来延迟加载 Signal
|
|
62
|
+
// 这对使用 Polyfill 的应用来说更友好
|
|
63
|
+
function getSignal() {
|
|
64
|
+
const globalSignal = globalNS['Signal'];
|
|
65
|
+
if (globalSignal == null)
|
|
66
|
+
throw new Error('Signal is undefined');
|
|
67
|
+
if (firstSignal == null)
|
|
68
|
+
firstSignal = globalSignal;
|
|
69
|
+
if (firstSignal !== globalSignal)
|
|
70
|
+
throw new Error('Signal have multiple instances');
|
|
71
|
+
return globalSignal;
|
|
70
72
|
}
|
|
71
|
-
function
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
configurable: false,
|
|
75
|
-
enumerable: false,
|
|
76
|
-
writable: true,
|
|
77
|
-
value: new Set()
|
|
78
|
-
});
|
|
79
|
-
return object;
|
|
73
|
+
function createWatch(notify) {
|
|
74
|
+
const signal = getSignal();
|
|
75
|
+
return new signal.subtle.Watcher(notify);
|
|
80
76
|
}
|
|
81
|
-
function
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
return () => { deps.delete(listener); };
|
|
77
|
+
function createComputed(computation, options) {
|
|
78
|
+
const signal = getSignal();
|
|
79
|
+
return new signal.Computed(computation, options);
|
|
85
80
|
}
|
|
86
|
-
function
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
globalContext.dependencies.add(ref);
|
|
90
|
-
}
|
|
91
|
-
let value = ref.value;
|
|
92
|
-
Reflect.defineProperty(ref, 'value', {
|
|
93
|
-
get() {
|
|
94
|
-
if (!globalContext.dependencies.has(ref)) {
|
|
95
|
-
globalContext.dependencies.add(ref);
|
|
96
|
-
}
|
|
97
|
-
return value;
|
|
98
|
-
},
|
|
99
|
-
set(newValue) {
|
|
100
|
-
value = newValue;
|
|
101
|
-
triggerRef(ref);
|
|
102
|
-
return value;
|
|
103
|
-
}
|
|
104
|
-
});
|
|
105
|
-
return ref;
|
|
81
|
+
function isState(target) {
|
|
82
|
+
const signal = getSignal();
|
|
83
|
+
return target instanceof signal.State;
|
|
106
84
|
}
|
|
107
85
|
|
|
86
|
+
const airxElementSymbol = Symbol('airx-element');
|
|
87
|
+
|
|
108
88
|
/**
|
|
109
89
|
* createElement 是用于创建 AirxElement 的工具函数
|
|
110
90
|
*/
|
|
@@ -183,7 +163,15 @@
|
|
|
183
163
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
184
164
|
provide(key, value) {
|
|
185
165
|
this.providedMap.set(key, value);
|
|
186
|
-
return v =>
|
|
166
|
+
return v => {
|
|
167
|
+
if (typeof v === 'function') {
|
|
168
|
+
const old = this.providedMap.get(key);
|
|
169
|
+
const func = v;
|
|
170
|
+
this.providedMap.set(key, func(old));
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
this.providedMap.set(key, v);
|
|
174
|
+
};
|
|
187
175
|
}
|
|
188
176
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
189
177
|
inject(key) {
|
|
@@ -378,9 +366,11 @@
|
|
|
378
366
|
// 添加 ref 处理
|
|
379
367
|
if ('ref' in instance.memoProps) {
|
|
380
368
|
context.onMounted(() => {
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
369
|
+
const ref = instance.memoProps.ref;
|
|
370
|
+
// 如果组件有自己的 dom 并且 ref 为 state
|
|
371
|
+
if (instance.domRef && isState(ref)) {
|
|
372
|
+
ref.set(instance.domRef);
|
|
373
|
+
return () => ref.set(undefined);
|
|
384
374
|
}
|
|
385
375
|
});
|
|
386
376
|
}
|
|
@@ -445,32 +435,44 @@
|
|
|
445
435
|
}
|
|
446
436
|
// airx 组件
|
|
447
437
|
if (typeof element?.type === 'function') {
|
|
448
|
-
|
|
449
|
-
|
|
438
|
+
if (instance.signalWatcher == null) {
|
|
439
|
+
// Watch 是惰性的,只有当 Signal 被读取时才会触发 --!
|
|
440
|
+
const signalWatcher = createWatch(async () => {
|
|
441
|
+
instance.needReRender = true;
|
|
442
|
+
onUpdateRequire?.(instance);
|
|
443
|
+
queueMicrotask(() => {
|
|
444
|
+
signalWatcher.watch();
|
|
445
|
+
const paddings = signalWatcher.getPending();
|
|
446
|
+
for (const padding of paddings)
|
|
447
|
+
padding.get();
|
|
448
|
+
});
|
|
449
|
+
});
|
|
450
|
+
instance.signalWatcher = signalWatcher;
|
|
451
|
+
instance.context.addDisposer(() => signalWatcher.unwatch());
|
|
452
|
+
}
|
|
453
|
+
if (instance.childrenRender == null) {
|
|
450
454
|
const component = element.type;
|
|
451
|
-
const beforeContext = globalContext
|
|
452
|
-
globalContext
|
|
453
|
-
const componentReturnValue =
|
|
455
|
+
const beforeContext = globalContext.current;
|
|
456
|
+
globalContext.current = instance.context.getSafeContext();
|
|
457
|
+
const componentReturnValue = component(instance.memoProps);
|
|
454
458
|
if (typeof componentReturnValue !== 'function') {
|
|
455
459
|
throw new Error('Component must return a render function');
|
|
456
460
|
}
|
|
457
|
-
globalContext
|
|
458
|
-
instance.
|
|
459
|
-
const
|
|
461
|
+
globalContext.current = beforeContext;
|
|
462
|
+
instance.childrenRender = componentReturnValue;
|
|
463
|
+
const childrenComputed = createComputed(() => componentReturnValue());
|
|
464
|
+
instance.signalWatcher.watch(childrenComputed);
|
|
465
|
+
const children = childrenComputed.get();
|
|
460
466
|
reconcileChildren(pluginContext, instance, childrenAsElements(children));
|
|
461
467
|
}
|
|
462
468
|
if (instance.needReRender) {
|
|
463
|
-
|
|
469
|
+
// 这里有个问题,如果是由于父组件导致的子组件渲染
|
|
470
|
+
// 直接使用 childrenComputed.get() 将读取到缓存值
|
|
471
|
+
// const children = instance.childrenRender?.()
|
|
472
|
+
const children = instance.childrenRender();
|
|
464
473
|
reconcileChildren(pluginContext, instance, childrenAsElements(children));
|
|
465
474
|
delete instance.needReRender;
|
|
466
475
|
}
|
|
467
|
-
// 处理依赖触发的更新
|
|
468
|
-
collector.complete().forEach(ref => {
|
|
469
|
-
instance.context.addDisposer(watchSignal(ref, () => {
|
|
470
|
-
instance.needReRender = true;
|
|
471
|
-
onUpdateRequire?.(instance);
|
|
472
|
-
}));
|
|
473
|
-
});
|
|
474
476
|
}
|
|
475
477
|
// 浏览器组件/标签
|
|
476
478
|
if (typeof element?.type === 'string') {
|
|
@@ -675,7 +677,7 @@
|
|
|
675
677
|
Object.keys(prevProps)
|
|
676
678
|
.filter(isProperty)
|
|
677
679
|
.filter(isGone(prevProps, nextProps))
|
|
678
|
-
.forEach(name => dom.
|
|
680
|
+
.forEach(name => dom.removeAttribute(name));
|
|
679
681
|
// Set new or changed properties
|
|
680
682
|
Object.keys(nextProps)
|
|
681
683
|
.filter(isProperty)
|
|
@@ -1143,7 +1145,7 @@
|
|
|
1143
1145
|
Object.keys(prevProps)
|
|
1144
1146
|
.filter(isProperty)
|
|
1145
1147
|
.filter(isGone(prevProps, nextProps))
|
|
1146
|
-
.forEach(name => dom.
|
|
1148
|
+
.forEach(name => dom.removeAttribute(name));
|
|
1147
1149
|
// Set new or changed properties
|
|
1148
1150
|
Object.keys(nextProps)
|
|
1149
1151
|
.filter(isProperty)
|
|
@@ -1196,18 +1198,25 @@
|
|
|
1196
1198
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1197
1199
|
function createApp(element) {
|
|
1198
1200
|
const appContext = new PluginContext();
|
|
1201
|
+
const ensureAsElement = (element) => {
|
|
1202
|
+
if (typeof element === 'function') {
|
|
1203
|
+
return createElement(element, {});
|
|
1204
|
+
}
|
|
1205
|
+
return element;
|
|
1206
|
+
};
|
|
1199
1207
|
const app = {
|
|
1200
1208
|
plugin: (...plugins) => {
|
|
1201
1209
|
appContext.registerPlugin(...plugins);
|
|
1202
1210
|
return app;
|
|
1203
1211
|
},
|
|
1204
1212
|
mount: (container) => {
|
|
1205
|
-
|
|
1213
|
+
container.innerHTML = ''; // 先清空再说
|
|
1214
|
+
render(appContext, ensureAsElement(element), container);
|
|
1206
1215
|
return app;
|
|
1207
1216
|
},
|
|
1208
1217
|
renderToHTML: () => {
|
|
1209
1218
|
return new Promise(resolve => {
|
|
1210
|
-
render$1(appContext, element, resolve);
|
|
1219
|
+
render$1(appContext, ensureAsElement(element), resolve);
|
|
1211
1220
|
});
|
|
1212
1221
|
}
|
|
1213
1222
|
};
|
|
@@ -1218,12 +1227,10 @@
|
|
|
1218
1227
|
exports.component = component;
|
|
1219
1228
|
exports.createApp = createApp;
|
|
1220
1229
|
exports.createElement = createElement;
|
|
1221
|
-
exports.createSignal = createSignal;
|
|
1222
1230
|
exports.inject = inject;
|
|
1223
1231
|
exports.onMounted = onMounted;
|
|
1224
1232
|
exports.onUnmounted = onUnmounted;
|
|
1225
1233
|
exports.provide = provide;
|
|
1226
|
-
exports.watchSignal = watchSignal;
|
|
1227
1234
|
|
|
1228
1235
|
}));
|
|
1229
1236
|
//# sourceMappingURL=index.js.map
|