onejs-core 0.3.5
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/.gitattributes +2 -0
- package/.github/workflows/jsr.yml +19 -0
- package/.prettierrc +5 -0
- package/3rdparty/preact/LICENSE +21 -0
- package/3rdparty/preact/clone-element.ts +45 -0
- package/3rdparty/preact/compat/Children.ts +21 -0
- package/3rdparty/preact/compat/forwardRef.ts +49 -0
- package/3rdparty/preact/compat/index.ts +3 -0
- package/3rdparty/preact/compat/memo.ts +34 -0
- package/3rdparty/preact/compat/util.ts +38 -0
- package/3rdparty/preact/component.ts +235 -0
- package/3rdparty/preact/constants.ts +3 -0
- package/3rdparty/preact/create-context.ts +71 -0
- package/3rdparty/preact/create-element.ts +98 -0
- package/3rdparty/preact/diff/catch-error.ts +40 -0
- package/3rdparty/preact/diff/children.ts +355 -0
- package/3rdparty/preact/diff/index.ts +563 -0
- package/3rdparty/preact/diff/props.ts +174 -0
- package/3rdparty/preact/hooks/index.ts +536 -0
- package/3rdparty/preact/hooks/internal.d.ts +85 -0
- package/3rdparty/preact/hooks.d.ts +145 -0
- package/3rdparty/preact/index.ts +13 -0
- package/3rdparty/preact/internal.d.ts +155 -0
- package/3rdparty/preact/jsx-runtime/index.ts +80 -0
- package/3rdparty/preact/jsx.d.ts +1008 -0
- package/3rdparty/preact/options.ts +16 -0
- package/3rdparty/preact/preact.d.ts +317 -0
- package/3rdparty/preact/render.ts +76 -0
- package/3rdparty/preact/signals/index.ts +443 -0
- package/3rdparty/preact/signals/internal.d.ts +36 -0
- package/3rdparty/preact/signals-core/index.ts +663 -0
- package/3rdparty/preact/style.d.ts +205 -0
- package/3rdparty/preact/util.ts +29 -0
- package/@DO_NOT_CHANGE.txt +3 -0
- package/README.md +33 -0
- package/definitions/app.d.ts +52048 -0
- package/definitions/augments.d.ts +16 -0
- package/definitions/globals.d.ts +34 -0
- package/definitions/index.d.ts +9 -0
- package/definitions/jsx.d.ts +517 -0
- package/definitions/modules.d.ts +29 -0
- package/definitions/onejs.d.ts +164 -0
- package/definitions/preact.jsx.d.ts +7 -0
- package/definitions/proto-overrides.d.ts +13 -0
- package/definitions/puerts.d.ts +31 -0
- package/definitions/unity-engine.d.ts +23 -0
- package/hooks/eventful.ts +56 -0
- package/import-transform.mjs +42 -0
- package/index.ts +44 -0
- package/jsr.json +10 -0
- package/onejs-tw-config.cjs +188 -0
- package/package.json +9 -0
- package/preloads/inject.ts +44 -0
- package/styling/index.tsx +80 -0
- package/styling/utils/generateAlphabeticName.ts +21 -0
- package/styling/utils/generateComponentId.ts +6 -0
- package/styling/utils/hash.ts +46 -0
- package/switch.cjs +185 -0
- package/uss-transform-plugin.cjs +83 -0
- package/utils/color-palettes.ts +3 -0
- package/utils/color-parser.ts +249 -0
- package/utils/float-parser.ts +31 -0
- package/utils/index.ts +12 -0
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
import { options, Component } from "preact";
|
|
2
|
+
import { useRef, useMemo, useEffect } from "preact/hooks";
|
|
3
|
+
import {
|
|
4
|
+
signal,
|
|
5
|
+
computed,
|
|
6
|
+
batch,
|
|
7
|
+
effect,
|
|
8
|
+
Signal,
|
|
9
|
+
type ReadonlySignal,
|
|
10
|
+
} from "preact/signals-core";
|
|
11
|
+
import {
|
|
12
|
+
VNode,
|
|
13
|
+
Effect,
|
|
14
|
+
PropertyUpdater,
|
|
15
|
+
AugmentedComponent,
|
|
16
|
+
AugmentedElement as Element,
|
|
17
|
+
} from "./internal";
|
|
18
|
+
|
|
19
|
+
export { signal, computed, batch, effect, Signal, type ReadonlySignal };
|
|
20
|
+
|
|
21
|
+
const HAS_PENDING_UPDATE = 1 << 0;
|
|
22
|
+
const HAS_HOOK_STATE = 1 << 1;
|
|
23
|
+
const HAS_COMPUTEDS = 1 << 2;
|
|
24
|
+
|
|
25
|
+
const enum OptionsTypes {
|
|
26
|
+
HOOK = "_hook",
|
|
27
|
+
DIFF = "_diff",
|
|
28
|
+
DIFFED = "diffed",
|
|
29
|
+
RENDER = "_render",
|
|
30
|
+
CATCH_ERROR = "_catchError",
|
|
31
|
+
UNMOUNT = "unmount",
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
interface OptionsType {
|
|
35
|
+
[OptionsTypes.HOOK](component: Component, index: number, type: number): void;
|
|
36
|
+
[OptionsTypes.DIFF](vnode: VNode): void;
|
|
37
|
+
[OptionsTypes.DIFFED](vnode: VNode): void;
|
|
38
|
+
[OptionsTypes.RENDER](vnode: VNode): void;
|
|
39
|
+
[OptionsTypes.CATCH_ERROR](error: any, vnode: VNode, oldVNode: VNode): void;
|
|
40
|
+
[OptionsTypes.UNMOUNT](vnode: VNode): void;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
type HookFn<T extends keyof OptionsType> = (
|
|
44
|
+
old: OptionsType[T],
|
|
45
|
+
...a: Parameters<OptionsType[T]>
|
|
46
|
+
) => ReturnType<OptionsType[T]>;
|
|
47
|
+
|
|
48
|
+
// Install a Preact options hook
|
|
49
|
+
function hook<T extends OptionsTypes>(hookName: T, hookFn: HookFn<T>) {
|
|
50
|
+
// @ts-ignore-next-line private options hooks usage
|
|
51
|
+
options[hookName] = hookFn.bind(null, options[hookName] || (() => {}));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
let currentComponent: AugmentedComponent | undefined;
|
|
55
|
+
let finishUpdate: (() => void) | undefined;
|
|
56
|
+
|
|
57
|
+
function setCurrentUpdater(updater?: Effect) {
|
|
58
|
+
// end tracking for the current update:
|
|
59
|
+
if (finishUpdate) finishUpdate();
|
|
60
|
+
// start tracking the new update:
|
|
61
|
+
finishUpdate = updater && updater._start();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function createUpdater(update: () => void) {
|
|
65
|
+
let updater!: Effect;
|
|
66
|
+
effect(function (this: Effect) {
|
|
67
|
+
updater = this;
|
|
68
|
+
});
|
|
69
|
+
updater._callback = update;
|
|
70
|
+
return updater;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** @todo This may be needed for complex prop value detection. */
|
|
74
|
+
// function isSignalValue(value: any): value is Signal {
|
|
75
|
+
// if (typeof value !== "object" || value == null) return false;
|
|
76
|
+
// if (value instanceof Signal) return true;
|
|
77
|
+
// // @TODO: uncomment this when we land Reactive (ideally behind a brand check)
|
|
78
|
+
// // for (let i in value) if (value[i] instanceof Signal) return true;
|
|
79
|
+
// return false;
|
|
80
|
+
// }
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* A wrapper component that renders a Signal directly as a Text node.
|
|
84
|
+
* @todo: in Preact 11, just decorate Signal with `type:null`
|
|
85
|
+
*/
|
|
86
|
+
function Text(this: AugmentedComponent, { data }: { data: Signal }) {
|
|
87
|
+
// hasComputeds.add(this);
|
|
88
|
+
|
|
89
|
+
// Store the props.data signal in another signal so that
|
|
90
|
+
// passing a new signal reference re-runs the text computed:
|
|
91
|
+
const currentSignal = useSignal(data);
|
|
92
|
+
currentSignal.value = data;
|
|
93
|
+
|
|
94
|
+
const s = useMemo(() => {
|
|
95
|
+
// mark the parent component as having computeds so it gets optimized
|
|
96
|
+
let v = this._vnode;
|
|
97
|
+
while ((v = v._parent!)) {
|
|
98
|
+
if (v._component) {
|
|
99
|
+
v._component._updateFlags |= HAS_COMPUTEDS;
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Replace this component's vdom updater with a direct text one:
|
|
105
|
+
this._updater!._callback = () => {
|
|
106
|
+
(this.base as Text).data = s.peek();
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
return computed(() => {
|
|
110
|
+
let data = currentSignal.value;
|
|
111
|
+
let s = data.value;
|
|
112
|
+
return s === 0 ? 0 : s === true ? "" : s || "";
|
|
113
|
+
});
|
|
114
|
+
}, []);
|
|
115
|
+
|
|
116
|
+
return s.value;
|
|
117
|
+
}
|
|
118
|
+
Text.displayName = "_st";
|
|
119
|
+
|
|
120
|
+
Object.defineProperties(Signal.prototype, {
|
|
121
|
+
constructor: { configurable: true },
|
|
122
|
+
type: { configurable: true, value: Text },
|
|
123
|
+
props: {
|
|
124
|
+
configurable: true,
|
|
125
|
+
get() {
|
|
126
|
+
return { data: this };
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
// Setting a VNode's _depth to 1 forces Preact to clone it before modifying:
|
|
130
|
+
// https://github.com/preactjs/preact/blob/d7a433ee8463a7dc23a05111bb47de9ec729ad4d/src/diff/children.js#L77
|
|
131
|
+
// @todo remove this for Preact 11
|
|
132
|
+
__b: { configurable: true, value: 1 },
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
/** Inject low-level property/attribute bindings for Signals into Preact's diff */
|
|
136
|
+
hook(OptionsTypes.DIFF, (old, vnode) => {
|
|
137
|
+
if (typeof vnode.type === "string") {
|
|
138
|
+
let signalProps: Record<string, any> | undefined;
|
|
139
|
+
|
|
140
|
+
let props = vnode.props;
|
|
141
|
+
for (let i in props) {
|
|
142
|
+
if (i === "children") continue;
|
|
143
|
+
|
|
144
|
+
let value = props[i];
|
|
145
|
+
if (value instanceof Signal) {
|
|
146
|
+
if (!signalProps) vnode.__np = signalProps = {};
|
|
147
|
+
signalProps[i] = value;
|
|
148
|
+
props[i] = value.peek();
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
old(vnode);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
/** Set up Updater before rendering a component */
|
|
157
|
+
hook(OptionsTypes.RENDER, (old, vnode) => {
|
|
158
|
+
setCurrentUpdater();
|
|
159
|
+
|
|
160
|
+
let updater;
|
|
161
|
+
|
|
162
|
+
let component = vnode._component;
|
|
163
|
+
if (component) {
|
|
164
|
+
component._updateFlags &= ~HAS_PENDING_UPDATE;
|
|
165
|
+
|
|
166
|
+
updater = component._updater;
|
|
167
|
+
if (updater === undefined) {
|
|
168
|
+
component._updater = updater = createUpdater(() => {
|
|
169
|
+
component._updateFlags |= HAS_PENDING_UPDATE;
|
|
170
|
+
component.setState({});
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
currentComponent = component;
|
|
176
|
+
setCurrentUpdater(updater);
|
|
177
|
+
old(vnode);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
/** Finish current updater if a component errors */
|
|
181
|
+
hook(OptionsTypes.CATCH_ERROR, (old, error, vnode, oldVNode) => {
|
|
182
|
+
setCurrentUpdater();
|
|
183
|
+
currentComponent = undefined;
|
|
184
|
+
old(error, vnode, oldVNode);
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
/** Finish current updater after rendering any VNode */
|
|
188
|
+
hook(OptionsTypes.DIFFED, (old, vnode) => {
|
|
189
|
+
setCurrentUpdater();
|
|
190
|
+
currentComponent = undefined;
|
|
191
|
+
|
|
192
|
+
let dom: Element;
|
|
193
|
+
|
|
194
|
+
// vnode._dom is undefined during string rendering,
|
|
195
|
+
// so we use this to skip prop subscriptions during SSR.
|
|
196
|
+
if (typeof vnode.type === "string" && (dom = vnode._dom as Element)) {
|
|
197
|
+
let props = vnode.__np;
|
|
198
|
+
let renderedProps = vnode.props;
|
|
199
|
+
if (props) {
|
|
200
|
+
let updaters = dom._updaters;
|
|
201
|
+
if (updaters) {
|
|
202
|
+
for (let prop in updaters) {
|
|
203
|
+
let updater = updaters[prop];
|
|
204
|
+
if (updater !== undefined && !(prop in props)) {
|
|
205
|
+
updater._dispose();
|
|
206
|
+
// @todo we could just always invoke _dispose() here
|
|
207
|
+
updaters[prop] = undefined;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
} else {
|
|
211
|
+
updaters = {};
|
|
212
|
+
dom._updaters = updaters;
|
|
213
|
+
}
|
|
214
|
+
for (let prop in props) {
|
|
215
|
+
let updater = updaters[prop];
|
|
216
|
+
let signal = props[prop];
|
|
217
|
+
if (updater === undefined) {
|
|
218
|
+
updater = createPropUpdater(dom, prop, signal, renderedProps);
|
|
219
|
+
updaters[prop] = updater;
|
|
220
|
+
} else {
|
|
221
|
+
updater._update(signal, renderedProps);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
old(vnode);
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
function createPropUpdater(
|
|
230
|
+
dom: Element,
|
|
231
|
+
prop: string,
|
|
232
|
+
propSignal: Signal,
|
|
233
|
+
props: Record<string, any>
|
|
234
|
+
): PropertyUpdater {
|
|
235
|
+
const setAsProperty =
|
|
236
|
+
prop in dom &&
|
|
237
|
+
// SVG elements need to go through `setAttribute` because they
|
|
238
|
+
// expect things like SVGAnimatedTransformList instead of strings.
|
|
239
|
+
// @ts-ignore
|
|
240
|
+
dom.ownerSVGElement === undefined;
|
|
241
|
+
|
|
242
|
+
const changeSignal = signal(propSignal);
|
|
243
|
+
return {
|
|
244
|
+
_update: (newSignal: Signal, newProps: typeof props) => {
|
|
245
|
+
changeSignal.value = newSignal;
|
|
246
|
+
props = newProps;
|
|
247
|
+
},
|
|
248
|
+
_dispose: effect(() => {
|
|
249
|
+
const value = changeSignal.value.value;
|
|
250
|
+
// If Preact just rendered this value, don't render it again:
|
|
251
|
+
if (props[prop] === value) return;
|
|
252
|
+
props[prop] = value;
|
|
253
|
+
if (setAsProperty) {
|
|
254
|
+
// @ts-ignore-next-line silly
|
|
255
|
+
dom[prop] = value;
|
|
256
|
+
} else if (value) {
|
|
257
|
+
dom.setAttribute(prop, value);
|
|
258
|
+
} else {
|
|
259
|
+
dom.removeAttribute(prop);
|
|
260
|
+
}
|
|
261
|
+
}),
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/** Unsubscribe from Signals when unmounting components/vnodes */
|
|
266
|
+
hook(OptionsTypes.UNMOUNT, (old, vnode: VNode) => {
|
|
267
|
+
if (typeof vnode.type === "string") {
|
|
268
|
+
let dom = vnode._dom as Element | undefined;
|
|
269
|
+
// vnode._dom is undefined during string rendering
|
|
270
|
+
if (dom) {
|
|
271
|
+
const updaters = dom._updaters;
|
|
272
|
+
if (updaters) {
|
|
273
|
+
dom._updaters = undefined;
|
|
274
|
+
for (let prop in updaters) {
|
|
275
|
+
let updater = updaters[prop];
|
|
276
|
+
if (updater) updater._dispose();
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
} else {
|
|
281
|
+
let component = vnode._component;
|
|
282
|
+
if (component) {
|
|
283
|
+
const updater = component._updater;
|
|
284
|
+
if (updater) {
|
|
285
|
+
component._updater = undefined;
|
|
286
|
+
updater._dispose();
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
old(vnode);
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
/** Mark components that use hook state so we can skip sCU optimization. */
|
|
294
|
+
hook(OptionsTypes.HOOK, (old, component, index, type) => {
|
|
295
|
+
if (type < 3)
|
|
296
|
+
(component as AugmentedComponent)._updateFlags |= HAS_HOOK_STATE;
|
|
297
|
+
old(component, index, type);
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Auto-memoize components that use Signals/Computeds.
|
|
302
|
+
* Note: Does _not_ optimize components that use hook/class state.
|
|
303
|
+
*/
|
|
304
|
+
Component.prototype.shouldComponentUpdate = function (
|
|
305
|
+
this: AugmentedComponent,
|
|
306
|
+
props,
|
|
307
|
+
state
|
|
308
|
+
) {
|
|
309
|
+
// @todo: Once preactjs/preact#3671 lands, this could just use `currentUpdater`:
|
|
310
|
+
const updater = this._updater;
|
|
311
|
+
const hasSignals = updater && updater._sources !== undefined;
|
|
312
|
+
|
|
313
|
+
// let reason;
|
|
314
|
+
// if (!hasSignals && !hasComputeds.has(this)) {
|
|
315
|
+
// reason = "no signals or computeds";
|
|
316
|
+
// } else if (hasPendingUpdate.has(this)) {
|
|
317
|
+
// reason = "has pending update";
|
|
318
|
+
// } else if (hasHookState.has(this)) {
|
|
319
|
+
// reason = "has hook state";
|
|
320
|
+
// }
|
|
321
|
+
// if (reason) {
|
|
322
|
+
// if (!this) reason += " (`this` bug)";
|
|
323
|
+
// console.log("not optimizing", this?.constructor?.name, ": ", reason, {
|
|
324
|
+
// details: {
|
|
325
|
+
// hasSignals,
|
|
326
|
+
// hasComputeds: hasComputeds.has(this),
|
|
327
|
+
// hasPendingUpdate: hasPendingUpdate.has(this),
|
|
328
|
+
// hasHookState: hasHookState.has(this),
|
|
329
|
+
// deps: Array.from(updater._deps),
|
|
330
|
+
// updater,
|
|
331
|
+
// },
|
|
332
|
+
// });
|
|
333
|
+
// }
|
|
334
|
+
|
|
335
|
+
// if this component used no signals or computeds, update:
|
|
336
|
+
if (!hasSignals && !(this._updateFlags & HAS_COMPUTEDS)) return true;
|
|
337
|
+
|
|
338
|
+
// if there is a pending re-render triggered from Signals,
|
|
339
|
+
// or if there is hook or class state, update:
|
|
340
|
+
if (this._updateFlags & (HAS_PENDING_UPDATE | HAS_HOOK_STATE)) return true;
|
|
341
|
+
|
|
342
|
+
// @ts-ignore
|
|
343
|
+
for (let i in state) return true;
|
|
344
|
+
|
|
345
|
+
// if any non-Signal props changed, update:
|
|
346
|
+
for (let i in props) {
|
|
347
|
+
if (i !== "__source" && props[i] !== this.props[i]) return true;
|
|
348
|
+
}
|
|
349
|
+
for (let i in this.props) if (!(i in props)) return true;
|
|
350
|
+
|
|
351
|
+
// this is a purely Signal-driven component, don't update:
|
|
352
|
+
return false;
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
export function useSignal<T>(value: T) {
|
|
356
|
+
return useMemo(() => signal<T>(value), []);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
export function useComputed<T>(compute: () => T) {
|
|
360
|
+
const $compute = useRef(compute);
|
|
361
|
+
$compute.current = compute;
|
|
362
|
+
(currentComponent as AugmentedComponent)._updateFlags |= HAS_COMPUTEDS;
|
|
363
|
+
return useMemo(() => computed<T>(() => $compute.current()), []);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
export function useSignalEffect(cb: () => void | (() => void)) {
|
|
367
|
+
const callback = useRef(cb);
|
|
368
|
+
callback.current = cb;
|
|
369
|
+
|
|
370
|
+
useEffect(() => {
|
|
371
|
+
return effect(() => {
|
|
372
|
+
callback.current();
|
|
373
|
+
});
|
|
374
|
+
}, []);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* @todo Determine which Reactive implementation we'll be using.
|
|
379
|
+
* @internal
|
|
380
|
+
*/
|
|
381
|
+
// export function useReactive<T extends object>(value: T): Reactive<T> {
|
|
382
|
+
// return useMemo(() => reactive<T>(value), []);
|
|
383
|
+
// }
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* @internal
|
|
387
|
+
* Update a Reactive's using the properties of an object or other Reactive.
|
|
388
|
+
* Also works for Signals.
|
|
389
|
+
* @example
|
|
390
|
+
* // Update a Reactive with Object.assign()-like syntax:
|
|
391
|
+
* const r = reactive({ name: "Alice" });
|
|
392
|
+
* update(r, { name: "Bob" });
|
|
393
|
+
* update(r, { age: 42 }); // property 'age' does not exist in type '{ name?: string }'
|
|
394
|
+
* update(r, 2); // '2' has no properties in common with '{ name?: string }'
|
|
395
|
+
* console.log(r.name.value); // "Bob"
|
|
396
|
+
*
|
|
397
|
+
* @example
|
|
398
|
+
* // Update a Reactive with the properties of another Reactive:
|
|
399
|
+
* const A = reactive({ name: "Alice" });
|
|
400
|
+
* const B = reactive({ name: "Bob", age: 42 });
|
|
401
|
+
* update(A, B);
|
|
402
|
+
* console.log(`${A.name} is ${A.age}`); // "Bob is 42"
|
|
403
|
+
*
|
|
404
|
+
* @example
|
|
405
|
+
* // Update a signal with assign()-like syntax:
|
|
406
|
+
* const s = signal(42);
|
|
407
|
+
* update(s, "hi"); // Argument type 'string' not assignable to type 'number'
|
|
408
|
+
* update(s, {}); // Argument type '{}' not assignable to type 'number'
|
|
409
|
+
* update(s, 43);
|
|
410
|
+
* console.log(s.value); // 43
|
|
411
|
+
*
|
|
412
|
+
* @param obj The Reactive or Signal to be updated
|
|
413
|
+
* @param update The value, Signal, object or Reactive to update `obj` to match
|
|
414
|
+
* @param overwrite If `true`, any properties `obj` missing from `update` are set to `undefined`
|
|
415
|
+
*/
|
|
416
|
+
/*
|
|
417
|
+
export function update<T extends SignalOrReactive>(
|
|
418
|
+
obj: T,
|
|
419
|
+
update: Partial<Unwrap<T>>,
|
|
420
|
+
overwrite = false
|
|
421
|
+
) {
|
|
422
|
+
if (obj instanceof Signal) {
|
|
423
|
+
obj.value = peekValue(update);
|
|
424
|
+
} else {
|
|
425
|
+
for (let i in update) {
|
|
426
|
+
if (i in obj) {
|
|
427
|
+
obj[i].value = peekValue(update[i]);
|
|
428
|
+
} else {
|
|
429
|
+
let sig = signal(peekValue(update[i]));
|
|
430
|
+
sig[KEY] = i;
|
|
431
|
+
obj[i] = sig;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
if (overwrite) {
|
|
435
|
+
for (let i in obj) {
|
|
436
|
+
if (!(i in update)) {
|
|
437
|
+
obj[i].value = undefined;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
*/
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Component, VNode as PVNode } from "preact";
|
|
2
|
+
import { Signal } from "preact/signals-core";
|
|
3
|
+
|
|
4
|
+
export interface Effect {
|
|
5
|
+
_sources: object | undefined;
|
|
6
|
+
_start(): () => void;
|
|
7
|
+
_callback(): void;
|
|
8
|
+
_dispose(): void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface PropertyUpdater {
|
|
12
|
+
_update: (newSignal: Signal, newProps: Record<string, any>) => void;
|
|
13
|
+
_dispose: () => void;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface AugmentedElement extends HTMLElement {
|
|
17
|
+
_updaters?: Record<string, PropertyUpdater | undefined> | null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface AugmentedComponent extends Component<any, any> {
|
|
21
|
+
_vnode: VNode;
|
|
22
|
+
_updater?: Effect;
|
|
23
|
+
_updateFlags: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface VNode<P = any> extends PVNode<P> {
|
|
27
|
+
/** The component instance for this VNode */
|
|
28
|
+
_component: AugmentedComponent;
|
|
29
|
+
/** The parent VNode */
|
|
30
|
+
_parent?: VNode;
|
|
31
|
+
/** The DOM node for this VNode */
|
|
32
|
+
_dom?: Element | Text;
|
|
33
|
+
/** Props that had Signal values before diffing (used after diffing to subscribe) */
|
|
34
|
+
__np?: Record<string, any> | null;
|
|
35
|
+
}
|
|
36
|
+
|