lecodes-cli 0.9.2 → 0.10.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 +4 -0
- package/dist/index.js +677 -230
- package/package.json +2 -2
- package/runtime/scene-harness.json +1 -1
- package/runtime/sdk/compile/aspectMacro.ts +42 -0
- package/runtime/sdk/compile/assetMacro.ts +45 -0
- package/runtime/sdk/compile/bundler.ts +239 -0
- package/runtime/sdk/compile/compileProject.ts +104 -0
- package/runtime/sdk/compile/detectEntry.ts +125 -0
- package/runtime/sdk/compile/fontMacro.ts +459 -0
- package/runtime/sdk/compile/fontRegistry.ts +78 -0
- package/runtime/sdk/compile/header.ts +51 -0
- package/runtime/sdk/compile/index.ts +38 -0
- package/runtime/sdk/compile/libraryImports.ts +52 -0
- package/runtime/sdk/compile/sceneEditor.ts +78 -0
- package/runtime/sdk/compile/sfnt.ts +98 -0
- package/runtime/sdk/compile/sourcemap.ts +25 -0
- package/runtime/sdk/gl/Material.ts +52 -0
- package/runtime/sdk/gl/Particles.ts +477 -116
- package/runtime/sdk/inject.ts +1 -1
- package/runtime/sdk/ui/NativeView.ts +5 -5
- package/runtime/sdk/ui/UIButton.ts +5 -5
- package/runtime/sdk/ui/UIContainer.ts +13 -13
- package/runtime/sdk/ui/UIImage.ts +5 -5
- package/runtime/sdk/ui/UIInput.ts +9 -9
- package/runtime/sdk/ui/UINode.ts +114 -34
- package/runtime/sdk/ui/UIPager.ts +5 -9
- package/runtime/sdk/ui/UIScreen.ts +5 -5
- package/runtime/sdk/ui/UIScrollable.ts +5 -5
- package/runtime/sdk/ui/UISpacer.ts +5 -5
- package/runtime/sdk/ui/UIText.ts +5 -5
- package/runtime/sdk/ui/UIVideo.ts +5 -5
- package/runtime/sdk/ui/UIVirtualizedList.ts +5 -5
- package/runtime/sdk/ui/UIWidget.ts +5 -5
- package/runtime/sdk-types.json +1 -1
package/runtime/sdk/inject.ts
CHANGED
|
@@ -126,4 +126,4 @@ export { Camera } from "./gl/Camera"
|
|
|
126
126
|
export { Ray } from "./gl/Ray"
|
|
127
127
|
export { Plane } from "./gl/Plane"
|
|
128
128
|
export { Noise } from "./gl/Noise"
|
|
129
|
-
export { Particles,
|
|
129
|
+
export { Particles, Trail, curve, colorCurve } from "./gl/Particles"
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
import { _channelCall, _channelEmit, _channelOff, _channelOn, type ChannelListeners } from "../runtime/channel"
|
|
13
13
|
import { _bumpNavEpoch, _navSupported, _setCurrent, Presentable, type PresentOptions } from "./presentable"
|
|
14
|
-
import { Element, type AnimateStyle, type BaseStyle, type DrawableStyle, type ElementStyle, type OnLayoutCallback, type BoundingClientRect, type Style } from "./UINode"
|
|
14
|
+
import { Element, type AnimateStyle, type BaseStyle, type DrawableStyle, type ElementStyle, type OnLayoutCallback, type BoundingClientRect, type Classes, type Style } from "./UINode"
|
|
15
15
|
|
|
16
16
|
export type UINativeViewStyle = ElementStyle & DrawableStyle
|
|
17
17
|
|
|
@@ -42,10 +42,10 @@ export interface NativeView {
|
|
|
42
42
|
|
|
43
43
|
onLayout(onLayout: OnLayoutCallback): this
|
|
44
44
|
getBoundingClientRect(): BoundingClientRect | null
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
/** Style-class proxy — read `el.class.checked`, set `el.class.checked = true`, toggle with
|
|
46
|
+
* `!el.class.checked`, bind `el.class.done = () => sig.value`, batch/chain `el.class({ … })`.
|
|
47
|
+
* Classes cascade to descendants. See {@link Classes}. */
|
|
48
|
+
readonly class: Classes<this>
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
let nextViewId = 1
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ClickEvent, TouchStartEvent, LongPressEvent } from "../runtime/touch"
|
|
2
2
|
import type { ClickEvent as ClickEventType, TouchStartEvent as TouchStartEventType, LongPressEvent as LongPressEventType } from "../runtime/touch"
|
|
3
|
-
import { type ElementStyle, type ContainerStyle, type Style, ContainerElement, type DrawableStyle, type UINodeChild, type ChildrenFn, type OnLayoutCallback, type BoundingClientRect, type BaseStyle, type AnimateStyle, type Color } from "./UINode"
|
|
3
|
+
import { type ElementStyle, type ContainerStyle, type Classes, type Style, ContainerElement, type DrawableStyle, type UINodeChild, type ChildrenFn, type OnLayoutCallback, type BoundingClientRect, type BaseStyle, type AnimateStyle, type Color } from "./UINode"
|
|
4
4
|
|
|
5
5
|
export type UIButtonStyle = ElementStyle & DrawableStyle & ContainerStyle & { rippleColor?: Color | "default" }
|
|
6
6
|
|
|
@@ -27,10 +27,10 @@ export interface UIButton {
|
|
|
27
27
|
onLayout(onLayout: OnLayoutCallback): this
|
|
28
28
|
getBoundingClientRect(): BoundingClientRect | null
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
/** Style-class proxy — read `el.class.checked`, set `el.class.checked = true`, toggle with
|
|
31
|
+
* `!el.class.checked`, bind `el.class.done = () => sig.value`, batch/chain `el.class({ … })`.
|
|
32
|
+
* Classes cascade to descendants. See {@link Classes}. */
|
|
33
|
+
readonly class: Classes<this>
|
|
34
34
|
|
|
35
35
|
readonly children: UINodeChild[],
|
|
36
36
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ContainerElement, type AnimateStyle, type AppearStyle, type ChildrenFn, type ContainerStyle, type DisappearStyle, type DrawableStyle, type ElementStyle, type OnLayoutCallback, type BoundingClientRect, type Style, type StyleFn, type UINode, type UINodeChild } from "./UINode"
|
|
1
|
+
import { ContainerElement, type AnimateStyle, type AppearStyle, type ChildrenFn, type ContainerStyle, type DisappearStyle, type DrawableStyle, type ElementStyle, type OnLayoutCallback, type BoundingClientRect, type Classes, type Style, type StyleFn, type UINode, type UINodeChild } from "./UINode"
|
|
2
2
|
|
|
3
3
|
export type UIContainerStyle = ElementStyle & DrawableStyle & ContainerStyle
|
|
4
4
|
|
|
@@ -16,10 +16,10 @@ export interface UIColumn {
|
|
|
16
16
|
onLayout(onLayout: OnLayoutCallback): this
|
|
17
17
|
getBoundingClientRect(): BoundingClientRect | null
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
/** Style-class proxy — read `el.class.checked`, set `el.class.checked = true`, toggle with
|
|
20
|
+
* `!el.class.checked`, bind `el.class.done = () => sig.value`, batch/chain `el.class({ … })`.
|
|
21
|
+
* Classes cascade to descendants. See {@link Classes}. */
|
|
22
|
+
readonly class: Classes<this>
|
|
23
23
|
|
|
24
24
|
readonly children: UINodeChild[]
|
|
25
25
|
}
|
|
@@ -55,10 +55,10 @@ export interface UIRow {
|
|
|
55
55
|
onLayout(onLayout: OnLayoutCallback): this
|
|
56
56
|
getBoundingClientRect(): BoundingClientRect | null
|
|
57
57
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
/** Style-class proxy — read `el.class.checked`, set `el.class.checked = true`, toggle with
|
|
59
|
+
* `!el.class.checked`, bind `el.class.done = () => sig.value`, batch/chain `el.class({ … })`.
|
|
60
|
+
* Classes cascade to descendants. See {@link Classes}. */
|
|
61
|
+
readonly class: Classes<this>
|
|
62
62
|
|
|
63
63
|
readonly children: UINodeChild[],
|
|
64
64
|
}
|
|
@@ -94,10 +94,10 @@ export interface UIBox {
|
|
|
94
94
|
onLayout(onLayout: OnLayoutCallback): this
|
|
95
95
|
getBoundingClientRect(): BoundingClientRect | null
|
|
96
96
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
97
|
+
/** Style-class proxy — read `el.class.checked`, set `el.class.checked = true`, toggle with
|
|
98
|
+
* `!el.class.checked`, bind `el.class.done = () => sig.value`, batch/chain `el.class({ … })`.
|
|
99
|
+
* Classes cascade to descendants. See {@link Classes}. */
|
|
100
|
+
readonly class: Classes<this>
|
|
101
101
|
|
|
102
102
|
readonly children: UINodeChild[],
|
|
103
103
|
}
|
|
@@ -2,7 +2,7 @@ import type { FetchResponse } from "../runtime/fetch"
|
|
|
2
2
|
import type { SvgSourceValue as SvgSource } from "../runtime/misc"
|
|
3
3
|
import type { File } from "../runtime/fetch"
|
|
4
4
|
import { Canvas, isCanvas } from "../canvas/Canvas"
|
|
5
|
-
import { Element, type AnimateStyle, type Color, type ElementStyle, type OnLayoutCallback, type BoundingClientRect, type Style } from "./UINode"
|
|
5
|
+
import { Element, type AnimateStyle, type Color, type ElementStyle, type OnLayoutCallback, type BoundingClientRect, type Classes, type Style } from "./UINode"
|
|
6
6
|
|
|
7
7
|
export type UIImageStyle = ElementStyle & { borderRadius?: number, objectFit?: "cover" | "contain" | "fill", tintColor?: Color }
|
|
8
8
|
|
|
@@ -39,10 +39,10 @@ export interface UIImage {
|
|
|
39
39
|
onLayout(onLayout: OnLayoutCallback): this
|
|
40
40
|
getBoundingClientRect(): BoundingClientRect | null
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
/** Style-class proxy — read `el.class.checked`, set `el.class.checked = true`, toggle with
|
|
43
|
+
* `!el.class.checked`, bind `el.class.done = () => sig.value`, batch/chain `el.class({ … })`.
|
|
44
|
+
* Classes cascade to descendants. See {@link Classes}. */
|
|
45
|
+
readonly class: Classes<this>
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
class ImageElement extends Element<"image"> {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ElementStyle, type DrawableStyle, type Style, type StyleFn, type AppearStyle, type DisappearStyle, Element, type TextStyle, type Color, type OnLayoutCallback, type BoundingClientRect, type BaseStyle, type AnimateStyle } from "./UINode";
|
|
1
|
+
import { type ElementStyle, type DrawableStyle, type Classes, type Style, type StyleFn, type AppearStyle, type DisappearStyle, Element, type TextStyle, type Color, type OnLayoutCallback, type BoundingClientRect, type BaseStyle, type AnimateStyle } from "./UINode";
|
|
2
2
|
|
|
3
3
|
type InputStyle = {
|
|
4
4
|
placeholder?: string,
|
|
@@ -71,10 +71,10 @@ export interface UIInput {
|
|
|
71
71
|
/** Release focus (dismisses the keyboard when this input held it). */
|
|
72
72
|
blur(): void
|
|
73
73
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
74
|
+
/** Style-class proxy — read `el.class.checked`, set `el.class.checked = true`, toggle with
|
|
75
|
+
* `!el.class.checked`, bind `el.class.done = () => sig.value`, batch/chain `el.class({ … })`.
|
|
76
|
+
* Classes cascade to descendants. See {@link Classes}. */
|
|
77
|
+
readonly class: Classes<this>
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
export interface UITextArea {
|
|
@@ -98,10 +98,10 @@ export interface UITextArea {
|
|
|
98
98
|
/** Release focus (dismisses the keyboard when this text area held it). */
|
|
99
99
|
blur(): void
|
|
100
100
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
101
|
+
/** Style-class proxy — read `el.class.checked`, set `el.class.checked = true`, toggle with
|
|
102
|
+
* `!el.class.checked`, bind `el.class.done = () => sig.value`, batch/chain `el.class({ … })`.
|
|
103
|
+
* Classes cascade to descendants. See {@link Classes}. */
|
|
104
|
+
readonly class: Classes<this>
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
class InputElement<T extends "input" | "textarea"> extends Element<T> {
|
package/runtime/sdk/ui/UINode.ts
CHANGED
|
@@ -6,6 +6,8 @@ export interface UINode {
|
|
|
6
6
|
/** Author-given semantic name (a stable selector for tests + AI review feedback). */
|
|
7
7
|
readonly name?: string
|
|
8
8
|
style: Style<this, any>
|
|
9
|
+
/** Style-class proxy — read/set/toggle/bind the `$`-classes declared in `.style()`. See {@link Classes}. */
|
|
10
|
+
readonly class: Classes<this>
|
|
9
11
|
}
|
|
10
12
|
|
|
11
13
|
export type UINodeChild = UINode | null | undefined | false
|
|
@@ -238,13 +240,73 @@ const handler: ProxyHandler<any> = {
|
|
|
238
240
|
getOwnPropertyDescriptor(target, p) {
|
|
239
241
|
return Object.getOwnPropertyDescriptor(target._el._style, p)
|
|
240
242
|
},
|
|
241
|
-
ownKeys(target) {
|
|
243
|
+
ownKeys(target) {
|
|
242
244
|
return Object.keys(target._el._style)
|
|
243
245
|
}
|
|
244
246
|
}
|
|
245
247
|
|
|
248
|
+
// ---- the el.class proxy --------------------------------------------------------------------------
|
|
249
|
+
|
|
250
|
+
// `$checked` and `checked` name the same class — `$` is only the declaration-site prefix in .style().
|
|
251
|
+
const classKey = (name: string) => name[0] === "$" ? name.slice(1) : name
|
|
252
|
+
|
|
253
|
+
// Single-class state write, shared by the set trap, the batch form and binding re-runs. No-op when
|
|
254
|
+
// the state already matches, so an unchanged binding re-run doesn't resend over the bridge.
|
|
255
|
+
function writeClass(el: any, name: string, enabled: boolean) {
|
|
256
|
+
if ((el._classes?.has(name) ?? false) === enabled) return
|
|
257
|
+
if (enabled) {
|
|
258
|
+
(el._classes ??= new Set()).add(name)
|
|
259
|
+
} else {
|
|
260
|
+
el._classes.delete(name)
|
|
261
|
+
}
|
|
262
|
+
if (el._id !== 0) {
|
|
263
|
+
_creatorUI.setClass(el._id, name, enabled)
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// One class write: a function value installs/replaces a reactive binding, a plain value replaces
|
|
268
|
+
// the binding (last write wins — unlike the style proxy's hot-path caveat, a stale class binding
|
|
269
|
+
// silently reverting a later plain write would be a footgun, and class flips are never per-frame).
|
|
270
|
+
function writeClassValue(el: any, name: string, value: ClassValue) {
|
|
271
|
+
name = classKey(name)
|
|
272
|
+
if (typeof value === "function") {
|
|
273
|
+
createBinding(el, "#class:" + name, () => { writeClass(el, name, !!value()) })
|
|
274
|
+
} else {
|
|
275
|
+
if (el._fx !== undefined) disposeBinding(el, "#class:" + name)
|
|
276
|
+
writeClass(el, name, !!value)
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// The callable target of the el.class proxy (batch form), bound to the element like styleFunction.
|
|
281
|
+
function classFunction(this: any, classes: Record<string, ClassValue>) {
|
|
282
|
+
for (const key of Object.keys(classes)) {
|
|
283
|
+
writeClassValue(this, key, classes[key])
|
|
284
|
+
}
|
|
285
|
+
return this
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
const classHandler: ProxyHandler<any> = {
|
|
289
|
+
get(target, key) {
|
|
290
|
+
if (typeof key !== "string") return undefined
|
|
291
|
+
return target._el._classes?.has(classKey(key)) ?? false
|
|
292
|
+
},
|
|
293
|
+
set(target, key, value) {
|
|
294
|
+
if (typeof key === "string") writeClassValue(target._el, key, value)
|
|
295
|
+
return true
|
|
296
|
+
},
|
|
297
|
+
// Object.keys(el.class) / spread list the ACTIVE class names (inspection + tests).
|
|
298
|
+
getOwnPropertyDescriptor(target, p) {
|
|
299
|
+
if (typeof p !== "string" || !(target._el._classes?.has(classKey(p)) ?? false)) return undefined
|
|
300
|
+
return { value: true, enumerable: true, configurable: true, writable: true }
|
|
301
|
+
},
|
|
302
|
+
ownKeys(target) {
|
|
303
|
+
const classes = target._el._classes
|
|
304
|
+
return classes !== undefined ? [ ...classes ] : []
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
246
308
|
function Style() {
|
|
247
|
-
|
|
309
|
+
|
|
248
310
|
}
|
|
249
311
|
|
|
250
312
|
// Reactive style input: every primitive-valued prop also accepts a `() => value` binding that
|
|
@@ -253,7 +315,7 @@ function Style() {
|
|
|
253
315
|
export type Reactive<T> = { [K in keyof T]: NonNullable<T[K]> extends object ? T[K] : T[K] | (() => T[K]) }
|
|
254
316
|
|
|
255
317
|
// User-defined style classes: any `$`-prefixed key in .style() declares a state block (like
|
|
256
|
-
// onPressed, but with any name), toggled from code via
|
|
318
|
+
// onPressed, but with any name), toggled from code via the `el.class` proxy. `duration`/`delay`
|
|
257
319
|
// make the swap transition. Class state INHERITS down the tree (CSS-`.dark`-on-body style): a
|
|
258
320
|
// class set on a node also activates same-name `$` blocks on all descendants within the same
|
|
259
321
|
// root — see docs/style-class-cascade-plan.md. `$pressed`/`$focused` are reserved: hosts toggle
|
|
@@ -265,6 +327,30 @@ export type Reactive<T> = { [K in keyof T]: NonNullable<T[K]> extends object ? T
|
|
|
265
327
|
// tests/ui-types.test.ts.
|
|
266
328
|
export type ClassStyles<T> = { [key: `$${string}`]: T & { duration?: number, delay?: number } }
|
|
267
329
|
|
|
330
|
+
/** Value accepted by a `el.class` write: a boolean sets the class, a `() => boolean` binds it —
|
|
331
|
+
* the class then tracks the signals the function reads (re-evaluated on change). Reads through
|
|
332
|
+
* the proxy always return a plain boolean, never the bound function. */
|
|
333
|
+
export type ClassValue = boolean | (() => boolean)
|
|
334
|
+
|
|
335
|
+
/** The `el.class` proxy — the runtime switch for `$`-class blocks declared in `.style()`
|
|
336
|
+
* (see {@link ClassStyles}). One surface, mirroring `el.style`:
|
|
337
|
+
*
|
|
338
|
+
* ```ts
|
|
339
|
+
* el.class.checked // read: is it active on THIS element? → boolean
|
|
340
|
+
* el.class.checked = true // activate (false deactivates)
|
|
341
|
+
* el.class.open = !el.class.open // toggle
|
|
342
|
+
* el.class.done = () => todo.done.value // reactive binding (signals)
|
|
343
|
+
* el.class({ checked: true, done: () => … }) // batch form — returns the element, chainable
|
|
344
|
+
* ```
|
|
345
|
+
*
|
|
346
|
+
* Class names are accepted with or without the declaration-site `$` prefix. `R` is the concrete
|
|
347
|
+
* node type, so the batch form chains like `.style()`.
|
|
348
|
+
*
|
|
349
|
+
* Typing note: property access is `any` because an index signature can't give reads (`boolean`)
|
|
350
|
+
* and writes ({@link ClassValue}) different types — the batch form is the fully typed path;
|
|
351
|
+
* single-key writes are runtime-coerced with `!!`. */
|
|
352
|
+
export type Classes<R> = ((classes: Record<string, ClassValue>) => R) & { [key: string]: any }
|
|
353
|
+
|
|
268
354
|
// NB: do NOT annotate `this: R` here. `this` is a parameter position, so it makes R contravariant,
|
|
269
355
|
// which makes every node type INVARIANT in its own type params (and in `this`). That is what made
|
|
270
356
|
// `UIScreen<false>` unassignable to `UIScreen<boolean>` (a navigator page), and would block any
|
|
@@ -273,7 +359,7 @@ export type ClassStyles<T> = { [key: `$${string}`]: T & { duration?: number, del
|
|
|
273
359
|
// R stays only in the (covariant) return, so `.style()` still returns the concrete node type for
|
|
274
360
|
// chaining. Guarded by the type tests in tests/ui-types.test-d.ts.
|
|
275
361
|
// Orientation state blocks — override props applied only in landscape / portrait (like a `$`-class,
|
|
276
|
-
// keyed by device orientation instead of
|
|
362
|
+
// keyed by device orientation instead of `el.class`). Same full-`T` rule as class blocks.
|
|
277
363
|
export type OrientationStyles<T> = {
|
|
278
364
|
onLandscape?: T,
|
|
279
365
|
onPortrait?: T,
|
|
@@ -397,37 +483,31 @@ export class Element<T extends string> {
|
|
|
397
483
|
* re-assign _id on every open). */
|
|
398
484
|
protected _classes?: Set<string>
|
|
399
485
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
*
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
hasClass(name: string): boolean {
|
|
422
|
-
return this._classes?.has(name[0] === "$" ? name.slice(1) : name) ?? false
|
|
423
|
-
}
|
|
486
|
+
protected _classProxy?: any
|
|
487
|
+
|
|
488
|
+
/** Style-class control — flips the `$`-class blocks declared in `.style()`. One proxy, same
|
|
489
|
+
* contract as `el.style`:
|
|
490
|
+
*
|
|
491
|
+
* - `el.class.checked` — read: is the class active on THIS element? → `boolean`
|
|
492
|
+
* - `el.class.checked = true` / `= false` — activate / deactivate
|
|
493
|
+
* - `el.class.open = !el.class.open` — toggle
|
|
494
|
+
* - `el.class.done = () => todo.done.value` — reactive: the class tracks the signals the
|
|
495
|
+
* function reads; a later write to the same class (plain or function) replaces the binding
|
|
496
|
+
* - `el.class({ checked: true, done: () => … })` — batch form, returns the element (chainable)
|
|
497
|
+
*
|
|
498
|
+
* Names are accepted with or without the leading `$`. A class set on an element CASCADES: it is
|
|
499
|
+
* also active on every descendant (their same-name `$` blocks light up), until the subtree's
|
|
500
|
+
* root — hosted screens/widgets don't inherit. Reads reflect only this element's own classes;
|
|
501
|
+
* there is no opt-out below an active ancestor. `Object.keys(el.class)` lists the active names. */
|
|
502
|
+
get class(): any {
|
|
503
|
+
if (this._classProxy) return this._classProxy
|
|
504
|
+
const obj = classFunction.bind(this)
|
|
505
|
+
// @ts-ignore
|
|
506
|
+
obj._el = this
|
|
424
507
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
if (name[0] === "$") name = name.slice(1)
|
|
429
|
-
createBinding(this, "#class:" + name, () => { this.setClass(name, !!fn()) })
|
|
430
|
-
return this
|
|
508
|
+
const proxy = new Proxy(obj, classHandler)
|
|
509
|
+
this._classProxy = proxy
|
|
510
|
+
return proxy
|
|
431
511
|
}
|
|
432
512
|
|
|
433
513
|
protected ll?: OnLayoutCallback[]
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ContainerElement, type AnimateStyle, type BaseStyle, type ChildrenFn, type DrawableStyle, type ElementStyle, type OnLayoutCallback, type BoundingClientRect, type Style, type UINodeChild } from "./UINode"
|
|
1
|
+
import { ContainerElement, type AnimateStyle, type BaseStyle, type ChildrenFn, type DrawableStyle, type ElementStyle, type OnLayoutCallback, type BoundingClientRect, type Classes, type Style, type UINodeChild } from "./UINode"
|
|
2
2
|
import { disposeBinding } from "../core/signals"
|
|
3
3
|
import type { UIScreen } from "./UIScreen"
|
|
4
4
|
|
|
@@ -84,10 +84,10 @@ export interface UIPager {
|
|
|
84
84
|
onLayout(onLayout: OnLayoutCallback): this,
|
|
85
85
|
getBoundingClientRect(): BoundingClientRect | null,
|
|
86
86
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
87
|
+
/** Style-class proxy — read `el.class.checked`, set `el.class.checked = true`, toggle with
|
|
88
|
+
* `!el.class.checked`, bind `el.class.done = () => sig.value`, batch/chain `el.class({ … })`.
|
|
89
|
+
* Classes cascade to descendants. See {@link Classes}. */
|
|
90
|
+
readonly class: Classes<this>,
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
export class PagerElement extends ContainerElement<"pager"> {
|
|
@@ -268,7 +268,6 @@ export class PagerElement extends ContainerElement<"pager"> {
|
|
|
268
268
|
// top, this pager is active. The hook reads screen._pagerOwner LIVE (not a captured `this`), so
|
|
269
269
|
// re-homing a screen into another pager activates the right one.
|
|
270
270
|
private _track(screen: any): void {
|
|
271
|
-
console.log("_track()")
|
|
272
271
|
screen._pagerOwner = this
|
|
273
272
|
if (!screen._pagerHooked) {
|
|
274
273
|
screen._pagerHooked = true
|
|
@@ -277,9 +276,7 @@ export class PagerElement extends ContainerElement<"pager"> {
|
|
|
277
276
|
}
|
|
278
277
|
}
|
|
279
278
|
_activate(): void {
|
|
280
|
-
console.log("openCount: " + this._openCount)
|
|
281
279
|
if (++this._openCount === 1 && _activeStack.indexOf(this) < 0) {
|
|
282
|
-
console.log("activate")
|
|
283
280
|
_activeStack.push(this)
|
|
284
281
|
}
|
|
285
282
|
}
|
|
@@ -288,7 +285,6 @@ export class PagerElement extends ContainerElement<"pager"> {
|
|
|
288
285
|
this._openCount = 0
|
|
289
286
|
const i = _activeStack.indexOf(this)
|
|
290
287
|
if (i >= 0) _activeStack.splice(i, 1)
|
|
291
|
-
console.log(`Deactivate. Curent stack is ${_activeStack.length}`)
|
|
292
288
|
}
|
|
293
289
|
}
|
|
294
290
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { TouchStartEvent } from "../runtime/touch"
|
|
2
2
|
import { _bumpNavEpoch, _navSupported, _setCurrent, Presentable, type PresentOptions } from "./presentable"
|
|
3
|
-
import { ContainerElement, type AnimateStyle, type BaseStyle, type ContainerStyle, type DrawableStyle, type OnLayoutCallback, type BoundingClientRect, type PaddingStyle, type Style, type UINodeChild, type ChildrenFn, } from "./UINode"
|
|
3
|
+
import { ContainerElement, type AnimateStyle, type BaseStyle, type ContainerStyle, type DrawableStyle, type OnLayoutCallback, type BoundingClientRect, type PaddingStyle, type Classes, type Style, type UINodeChild, type ChildrenFn, } from "./UINode"
|
|
4
4
|
|
|
5
5
|
export type UIScreenStyle = ContainerStyle & DrawableStyle & PaddingStyle & BaseStyle
|
|
6
6
|
|
|
@@ -46,10 +46,10 @@ export interface UIScreen {
|
|
|
46
46
|
onLayout(onLayout: OnLayoutCallback): this
|
|
47
47
|
getBoundingClientRect(): BoundingClientRect | null
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
49
|
+
/** Style-class proxy — read `el.class.checked`, set `el.class.checked = true`, toggle with
|
|
50
|
+
* `!el.class.checked`, bind `el.class.done = () => sig.value`, batch/chain `el.class({ … })`.
|
|
51
|
+
* Classes cascade to descendants. See {@link Classes}. */
|
|
52
|
+
readonly class: Classes<this>
|
|
53
53
|
|
|
54
54
|
onTouchStart(callback: (ev: TouchStartEvent<UIScreen>) => void): this,
|
|
55
55
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { UIContainerStyle } from "./UIContainer"
|
|
2
|
-
import { type Style, type AnimateStyle, type UINodeChild, type ChildrenFn, type OnLayoutCallback, type BoundingClientRect, type Color, ContainerElement } from "./UINode"
|
|
2
|
+
import { type Classes, type Style, type AnimateStyle, type UINodeChild, type ChildrenFn, type OnLayoutCallback, type BoundingClientRect, type Color, ContainerElement } from "./UINode"
|
|
3
3
|
|
|
4
4
|
// refreshControlColor tints the native pull-to-refresh spinner (pairs with onRefresh).
|
|
5
5
|
// keyboardDismissMode: how a scroll gesture in THIS scrollable dismisses the keyboard.
|
|
@@ -28,10 +28,10 @@ export interface UIScrollable {
|
|
|
28
28
|
onLayout(onLayout: OnLayoutCallback): this
|
|
29
29
|
getBoundingClientRect(): BoundingClientRect | null
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
/** Style-class proxy — read `el.class.checked`, set `el.class.checked = true`, toggle with
|
|
32
|
+
* `!el.class.checked`, bind `el.class.done = () => sig.value`, batch/chain `el.class({ … })`.
|
|
33
|
+
* Classes cascade to descendants. See {@link Classes}. */
|
|
34
|
+
readonly class: Classes<this>
|
|
35
35
|
|
|
36
36
|
onScroll(callback: (scrollPosition: number) => void): UIScrollable,
|
|
37
37
|
onScrollRelease(callback: () => void): UIScrollable,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Element, type ElementStyle, type Style, type StyleFn } from "./UINode"
|
|
1
|
+
import { Element, type ElementStyle, type Classes, type Style, type StyleFn } from "./UINode"
|
|
2
2
|
|
|
3
3
|
export type UISpacerStyle = ElementStyle
|
|
4
4
|
|
|
@@ -6,10 +6,10 @@ export interface UISpacer {
|
|
|
6
6
|
readonly type: "spacer",
|
|
7
7
|
style: Style<this, UISpacerStyle>,
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
/** Style-class proxy — read `el.class.checked`, set `el.class.checked = true`, toggle with
|
|
10
|
+
* `!el.class.checked`, bind `el.class.done = () => sig.value`, batch/chain `el.class({ … })`.
|
|
11
|
+
* Classes cascade to descendants. See {@link Classes}. */
|
|
12
|
+
readonly class: Classes<this>
|
|
13
13
|
}
|
|
14
14
|
export function UISpacer(): UISpacer
|
|
15
15
|
export function UISpacer(style: UISpacerStyle): UISpacer
|
package/runtime/sdk/ui/UIText.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createBinding } from "../core/signals"
|
|
2
|
-
import { Element, type AnimateStyle, type BaseStyle, type DrawableStyle, type ElementStyle, type OnLayoutCallback, type BoundingClientRect, type Style, type TextStyle } from "./UINode"
|
|
2
|
+
import { Element, type AnimateStyle, type BaseStyle, type DrawableStyle, type ElementStyle, type OnLayoutCallback, type BoundingClientRect, type Classes, type Style, type TextStyle } from "./UINode"
|
|
3
3
|
|
|
4
4
|
export type UITextStyle = ElementStyle & TextStyle & DrawableStyle
|
|
5
5
|
|
|
@@ -13,10 +13,10 @@ export interface UIText {
|
|
|
13
13
|
onLayout(onLayout: OnLayoutCallback): this
|
|
14
14
|
getBoundingClientRect(): BoundingClientRect | null
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
/** Style-class proxy — read `el.class.checked`, set `el.class.checked = true`, toggle with
|
|
17
|
+
* `!el.class.checked`, bind `el.class.done = () => sig.value`, batch/chain `el.class({ … })`.
|
|
18
|
+
* Classes cascade to descendants. See {@link Classes}. */
|
|
19
|
+
readonly class: Classes<this>
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
export class TextElement extends Element<"text"> {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { VideoPlayer } from "../runtime/media"
|
|
2
2
|
import { _bumpNavEpoch, _navSupported, _setCurrent, Presentable, type PresentOptions } from "./presentable"
|
|
3
|
-
import { Element, type AnimateStyle, type AppearStyle, type BaseStyle, type DisappearStyle, type DrawableStyle, type ElementStyle, type OnLayoutCallback, type BoundingClientRect, type Style, type StyleFn } from "./UINode"
|
|
3
|
+
import { Element, type AnimateStyle, type AppearStyle, type BaseStyle, type DisappearStyle, type DrawableStyle, type ElementStyle, type OnLayoutCallback, type BoundingClientRect, type Classes, type Style, type StyleFn } from "./UINode"
|
|
4
4
|
|
|
5
5
|
export type UIVideoStyle = ElementStyle & DrawableStyle & { objectFit?: "cover" | "contain" | "fill" }
|
|
6
6
|
|
|
@@ -22,10 +22,10 @@ export interface UIVideo {
|
|
|
22
22
|
onLayout(onLayout: OnLayoutCallback): this
|
|
23
23
|
getBoundingClientRect(): BoundingClientRect | null
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
/** Style-class proxy — read `el.class.checked`, set `el.class.checked = true`, toggle with
|
|
26
|
+
* `!el.class.checked`, bind `el.class.done = () => sig.value`, batch/chain `el.class({ … })`.
|
|
27
|
+
* Classes cascade to descendants. See {@link Classes}. */
|
|
28
|
+
readonly class: Classes<this>
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
class VideoElement extends Element<"video"> implements Presentable {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Element, type Color, type DrawableStyle, type ElementStyle, type OnLayoutCallback, type BoundingClientRect, type PaddingStyle, type Style, type UINodeChild } from "./UINode"
|
|
1
|
+
import { Element, type Color, type DrawableStyle, type ElementStyle, type OnLayoutCallback, type BoundingClientRect, type PaddingStyle, type Classes, type Style, type UINodeChild } from "./UINode"
|
|
2
2
|
|
|
3
3
|
// refreshControlColor tints the native pull-to-refresh spinner (pairs with onRefresh).
|
|
4
4
|
export type UIVirtualizedListStyle = DrawableStyle & ElementStyle & { refreshControlColor?: Color }
|
|
@@ -51,10 +51,10 @@ export interface UIVirtualizedList<T = unknown> {
|
|
|
51
51
|
onLayout(onLayout: OnLayoutCallback): this
|
|
52
52
|
getBoundingClientRect(): BoundingClientRect | null
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
54
|
+
/** Style-class proxy — read `el.class.checked`, set `el.class.checked = true`, toggle with
|
|
55
|
+
* `!el.class.checked`, bind `el.class.done = () => sig.value`, batch/chain `el.class({ … })`.
|
|
56
|
+
* Classes cascade to descendants. See {@link Classes}. */
|
|
57
|
+
readonly class: Classes<this>
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
export class VListElement<T> extends Element<"vlist"> implements UIVirtualizedList<T> {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { TouchStartEvent } from "../runtime/touch"
|
|
2
2
|
import { _descOf, _navSupported, Presentable } from "./presentable"
|
|
3
|
-
import { ContainerElement, type AnimateStyle, type BaseStyle, type Color, type ContainerStyle, type DrawableStyle, type OnLayoutCallback, type BoundingClientRect, type PaddingStyle, type PositionStyle, type Style, type UINodeChild, type ChildrenFn } from "./UINode"
|
|
3
|
+
import { ContainerElement, type AnimateStyle, type BaseStyle, type Color, type ContainerStyle, type DrawableStyle, type OnLayoutCallback, type BoundingClientRect, type PaddingStyle, type PositionStyle, type Classes, type Style, type UINodeChild, type ChildrenFn } from "./UINode"
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
export type UIWidgetStyle = ContainerStyle & DrawableStyle & PaddingStyle & BaseStyle & PositionStyle & {
|
|
@@ -49,10 +49,10 @@ export interface UIWidget {
|
|
|
49
49
|
onOverlayTap(callback: () => void): this,
|
|
50
50
|
onBackPressed(callback: () => void): this
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
52
|
+
/** Style-class proxy — read `el.class.checked`, set `el.class.checked = true`, toggle with
|
|
53
|
+
* `!el.class.checked`, bind `el.class.done = () => sig.value`, batch/chain `el.class({ … })`.
|
|
54
|
+
* Classes cascade to descendants. See {@link Classes}. */
|
|
55
|
+
readonly class: Classes<this>
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
|