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.
Files changed (63) hide show
  1. package/.gitattributes +2 -0
  2. package/.github/workflows/jsr.yml +19 -0
  3. package/.prettierrc +5 -0
  4. package/3rdparty/preact/LICENSE +21 -0
  5. package/3rdparty/preact/clone-element.ts +45 -0
  6. package/3rdparty/preact/compat/Children.ts +21 -0
  7. package/3rdparty/preact/compat/forwardRef.ts +49 -0
  8. package/3rdparty/preact/compat/index.ts +3 -0
  9. package/3rdparty/preact/compat/memo.ts +34 -0
  10. package/3rdparty/preact/compat/util.ts +38 -0
  11. package/3rdparty/preact/component.ts +235 -0
  12. package/3rdparty/preact/constants.ts +3 -0
  13. package/3rdparty/preact/create-context.ts +71 -0
  14. package/3rdparty/preact/create-element.ts +98 -0
  15. package/3rdparty/preact/diff/catch-error.ts +40 -0
  16. package/3rdparty/preact/diff/children.ts +355 -0
  17. package/3rdparty/preact/diff/index.ts +563 -0
  18. package/3rdparty/preact/diff/props.ts +174 -0
  19. package/3rdparty/preact/hooks/index.ts +536 -0
  20. package/3rdparty/preact/hooks/internal.d.ts +85 -0
  21. package/3rdparty/preact/hooks.d.ts +145 -0
  22. package/3rdparty/preact/index.ts +13 -0
  23. package/3rdparty/preact/internal.d.ts +155 -0
  24. package/3rdparty/preact/jsx-runtime/index.ts +80 -0
  25. package/3rdparty/preact/jsx.d.ts +1008 -0
  26. package/3rdparty/preact/options.ts +16 -0
  27. package/3rdparty/preact/preact.d.ts +317 -0
  28. package/3rdparty/preact/render.ts +76 -0
  29. package/3rdparty/preact/signals/index.ts +443 -0
  30. package/3rdparty/preact/signals/internal.d.ts +36 -0
  31. package/3rdparty/preact/signals-core/index.ts +663 -0
  32. package/3rdparty/preact/style.d.ts +205 -0
  33. package/3rdparty/preact/util.ts +29 -0
  34. package/@DO_NOT_CHANGE.txt +3 -0
  35. package/README.md +33 -0
  36. package/definitions/app.d.ts +52048 -0
  37. package/definitions/augments.d.ts +16 -0
  38. package/definitions/globals.d.ts +34 -0
  39. package/definitions/index.d.ts +9 -0
  40. package/definitions/jsx.d.ts +517 -0
  41. package/definitions/modules.d.ts +29 -0
  42. package/definitions/onejs.d.ts +164 -0
  43. package/definitions/preact.jsx.d.ts +7 -0
  44. package/definitions/proto-overrides.d.ts +13 -0
  45. package/definitions/puerts.d.ts +31 -0
  46. package/definitions/unity-engine.d.ts +23 -0
  47. package/hooks/eventful.ts +56 -0
  48. package/import-transform.mjs +42 -0
  49. package/index.ts +44 -0
  50. package/jsr.json +10 -0
  51. package/onejs-tw-config.cjs +188 -0
  52. package/package.json +9 -0
  53. package/preloads/inject.ts +44 -0
  54. package/styling/index.tsx +80 -0
  55. package/styling/utils/generateAlphabeticName.ts +21 -0
  56. package/styling/utils/generateComponentId.ts +6 -0
  57. package/styling/utils/hash.ts +46 -0
  58. package/switch.cjs +185 -0
  59. package/uss-transform-plugin.cjs +83 -0
  60. package/utils/color-palettes.ts +3 -0
  61. package/utils/color-parser.ts +249 -0
  62. package/utils/float-parser.ts +31 -0
  63. 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
+