lecodes-cli 0.10.4 → 0.12.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.
Files changed (54) hide show
  1. package/README.md +1 -1
  2. package/dist/index.js +48887 -6261
  3. package/package.json +4 -3
  4. package/runtime/scene-harness.json +1 -1
  5. package/runtime/sdk/compile/aspectMacro.ts +42 -0
  6. package/runtime/sdk/compile/assetIconMacro.ts +382 -0
  7. package/runtime/sdk/compile/assetMacro.ts +45 -0
  8. package/runtime/sdk/compile/assetName.ts +50 -0
  9. package/runtime/sdk/compile/bundler.ts +244 -0
  10. package/runtime/sdk/compile/compileProject.ts +106 -0
  11. package/runtime/sdk/compile/detectEntry.ts +125 -0
  12. package/runtime/sdk/compile/fontMacro.ts +459 -0
  13. package/runtime/sdk/compile/fontRegistry.ts +78 -0
  14. package/runtime/sdk/compile/header.ts +55 -0
  15. package/runtime/sdk/compile/index.ts +53 -0
  16. package/runtime/sdk/compile/libraryImports.ts +52 -0
  17. package/runtime/sdk/compile/sceneEditor.ts +78 -0
  18. package/runtime/sdk/compile/sfnt.ts +98 -0
  19. package/runtime/sdk/compile/sourcemap.ts +25 -0
  20. package/runtime/sdk/g2/Node2D.ts +3 -0
  21. package/runtime/sdk/g2/SpriteAnimation.ts +101 -20
  22. package/runtime/sdk/g2/SpriteSheet.ts +166 -0
  23. package/runtime/sdk/g2/Tileset.ts +71 -0
  24. package/runtime/sdk/g2/autotile.ts +394 -0
  25. package/runtime/sdk/g2/cells.ts +91 -0
  26. package/runtime/sdk/g2/defineScene2d.ts +381 -0
  27. package/runtime/sdk/g2/scenarios2d.ts +69 -0
  28. package/runtime/sdk/inject.ts +18 -0
  29. package/runtime/sdk/runtime/app.ts +21 -3
  30. package/runtime/sdk/scene/defineScene.ts +10 -70
  31. package/runtime/sdk/scene/grammar.ts +85 -0
  32. package/runtime/sdk/ui/NativeView.ts +9 -12
  33. package/runtime/sdk/ui/UI.ts +9 -1
  34. package/runtime/sdk/ui/UIBottomSheet.ts +10 -20
  35. package/runtime/sdk/ui/UIButton.ts +19 -36
  36. package/runtime/sdk/ui/UIContainer.ts +41 -103
  37. package/runtime/sdk/ui/UIImage.ts +10 -18
  38. package/runtime/sdk/ui/UIInput.ts +14 -26
  39. package/runtime/sdk/ui/UIModal.ts +10 -20
  40. package/runtime/sdk/ui/UINode.ts +142 -36
  41. package/runtime/sdk/ui/UIPager.ts +29 -28
  42. package/runtime/sdk/ui/UIPopover.ts +10 -16
  43. package/runtime/sdk/ui/UIScreen.ts +23 -40
  44. package/runtime/sdk/ui/UIScrollable.ts +37 -47
  45. package/runtime/sdk/ui/UISpacer.ts +4 -8
  46. package/runtime/sdk/ui/UITabs.ts +175 -0
  47. package/runtime/sdk/ui/UIText.ts +7 -13
  48. package/runtime/sdk/ui/UIVideo.ts +11 -13
  49. package/runtime/sdk/ui/UIVirtualizedList.ts +43 -49
  50. package/runtime/sdk/ui/UIWidget.ts +24 -36
  51. package/runtime/sdk/ui/fonts.ts +3 -0
  52. package/runtime/sdk/ui/router.ts +13 -0
  53. package/runtime/sdk/ui/theme.ts +21 -30
  54. package/runtime/sdk-types.json +1 -1
@@ -1,20 +1,20 @@
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 Classes, type Style, type UINodeChild, type ChildrenFn } from "./UINode"
3
+ import { ContainerElement, buildUI, type BaseStyle, type Color, type ContainerStyle, type DrawableStyle, type PaddingStyle, type PositionStyle, type UIChildArg, type UIContainerBase, type UINodeChild, type ChildrenFn } from "./UINode"
4
4
 
5
5
 
6
6
  export type UIWidgetStyle = ContainerStyle & DrawableStyle & PaddingStyle & BaseStyle & PositionStyle & {
7
- // A layer behind the widget that intercepts clicks. "transparent" still intercepts;
8
- // null removes the layer. A tap on it fires onOverlayTap.
7
+ /** A layer behind the widget that intercepts clicks — `"transparent"` still intercepts, `null`
8
+ * removes the layer. A tap on it fires `onOverlayTap`. */
9
9
  overlayColor?: Color | null
10
10
  }
11
11
 
12
12
 
13
- export interface UIWidget {
13
+ /** A floating overlay — absolutely positioned in device coordinates, mounted above the page as
14
+ * its own layout root (never a child of what's underneath). The base of dialogs, toasts,
15
+ * mini-players and scene HUDs; `UIModal`/`UIPopover`/`UIBottomSheet` build on it. */
16
+ export interface UIWidget extends UIContainerBase<UIWidgetStyle, DrawableStyle & BaseStyle & { overlayColor?: Color | null }> {
14
17
  readonly type: "widget",
15
- style: Style<this, UIWidgetStyle>,
16
- animateTo: AnimateStyle<this, DrawableStyle & BaseStyle & { overlayColor?: Color | null }>
17
- animateFrom: AnimateStyle<this, DrawableStyle & BaseStyle & { overlayColor?: Color | null }>
18
18
 
19
19
  /**
20
20
  * Attach this widget to a destination (a `Scene`, a `UIScreen`, …): the widget lives on that
@@ -33,27 +33,18 @@ export interface UIWidget {
33
33
  * widget was attached via `attachTo(owner)`, it mounts on that page's layer instead and is
34
34
  * only visible while the owner is presented. */
35
35
  show(): void,
36
+ /** Unmount the widget. */
36
37
  hide(): void,
37
38
 
39
+ /** Mounted right now (`show()` ran, `hide()` hasn't). */
38
40
  readonly isShow: boolean,
39
41
 
40
- append(...nodes: UINodeChild[]): UIWidget
41
- insert(index: number, ...nodes: UINodeChild[]): UIWidget
42
- remove(...nodes: UINodeChild[]): UIWidget
43
- setContent(nodes: UINodeChild[] | ChildrenFn): this
44
-
45
- readonly children: UINodeChild[],
46
-
47
- onLayout(onLayout: OnLayoutCallback): this
48
- getBoundingClientRect(): BoundingClientRect | null
42
+ /** Touch began on the widget; `ev.track(...)` takes over the rest of the gesture. */
49
43
  onTouchStart(callback: (ev: TouchStartEvent<UIWidget>) => void): this,
44
+ /** Tap on the overlay layer (requires an `overlayColor`). */
50
45
  onOverlayTap(callback: () => void): this,
46
+ /** Hardware/system back while the widget is shown. */
51
47
  onBackPressed(callback: () => void): this
52
-
53
- /** Style-class proxy — read `el.class.checked`, set `el.class.checked = true`, toggle with
54
- * `!el.class.checked`, bind `el.class.done = () => sig.value`, batch/chain `el.class({ … })`.
55
- * Classes cascade to descendants. See {@link Classes}. */
56
- readonly class: Classes<this>
57
48
  }
58
49
 
59
50
 
@@ -120,20 +111,17 @@ export class WidgetElement extends ContainerElement<"widget"> {
120
111
  }
121
112
 
122
113
 
123
- export function UIWidget(): UIWidget;
114
+ const makeWidget = (style: any, children: any) => new WidgetElement("widget", style, children)
115
+
116
+ /** @internal Compiler fast path (chisel `flatten_ui` raw lowering) — see UIContainer. */
117
+ export const __UIWidget = (children: UINodeChild[] | ChildrenFn): UIWidget => makeWidget({}, children)
118
+
119
+ /** Create a widget (same argument forms as `UIColumn`). Position it with absolute-style props
120
+ * (`top`/`left`/`bottom`/`right`), then `show()`/`hide()`. */
121
+ export function UIWidget(...children: UIChildArg[]): UIWidget;
124
122
  export function UIWidget(children: UINodeChild[] | ChildrenFn): UIWidget;
125
- export function UIWidget(style: UIWidgetStyle): UIWidget;
126
- export function UIWidget(style: UIWidgetStyle, children: UINodeChild[]): UIWidget;
127
- export function UIWidget(...args: [] | [UINodeChild[] | ChildrenFn | UIWidgetStyle] | [UIWidgetStyle, children: UINodeChild[] | ChildrenFn]): UIWidget {
128
- if (args.length === 0) {
129
- return new WidgetElement("widget", {}, [])
130
- } else if (args.length === 1) {
131
- if (Array.isArray(args[0]) || typeof args[0] === "function") {
132
- return new WidgetElement("widget", {}, args[0])
133
- } else {
134
- return new WidgetElement("widget", args[0], [])
135
- }
136
- } else {
137
- return new WidgetElement("widget", args[0], args[1])
138
- }
123
+ /** @deprecated Style as the first argument is legacy — use chained `.style({...})`. */
124
+ export function UIWidget(style: UIWidgetStyle, children?: UINodeChild[] | ChildrenFn): UIWidget;
125
+ export function UIWidget(...args: any[]): UIWidget {
126
+ return buildUI(args, null, makeWidget)
139
127
  }
@@ -3,6 +3,9 @@ type FontOptions = {
3
3
  style?: "normal" | "italic"
4
4
  }
5
5
 
6
+ /** Register a font face from a URL at runtime under `fontFamily`; resolves once it's ready to
7
+ * use in styles. For registry/project fonts prefer the compile-time `font()` macro — this is the
8
+ * dynamic escape hatch. */
6
9
  export async function registerFont (fontFamily: string, url: string, options: FontOptions = {}): Promise<void> {
7
10
  return new Promise<void>((res, rej) => {
8
11
  _creatorUI.registerFont(fontFamily, url, options, res, rej)
@@ -11,8 +11,13 @@ type NavigateOptions = {
11
11
  transition?: Transition
12
12
  }
13
13
 
14
+ /** Stack navigation over `Presentable` destinations. `init` once with the home page, then
15
+ * `push`/`replace`/`pop`; the back gesture/button pops natively. A direct `page.open()` suspends
16
+ * the router until `restore()`. */
14
17
  type Router = {
18
+ /** The top of the router stack (not necessarily what's on screen — see `Presentable.current`). */
15
19
  get current(): Presentable
20
+ /** Mount the router with `homePage` as the stack root — the app's navigation entry point. */
16
21
  init(homePage: Presentable, opts?: RouterOptions): void
17
22
  /** Push a destination onto the stack — a `UIScreen`, a `Scene`, a `Scene2D`, a `NativeView`,
18
23
  * or a `UIVideo`. The back gesture/button pops it. Destinations with async preparation
@@ -20,11 +25,19 @@ type Router = {
20
25
  * visible until they're ready, and a rejection (permission denied / superseded) leaves the
21
26
  * stack untouched. */
22
27
  push(page: Presentable, opts?: NavigateOptions): void | Promise<void>
28
+ /** Swap the top of the stack for `page` — no back entry to the replaced one. */
23
29
  replace(page: Presentable, opts?: NavigateOptions): void | Promise<void>
30
+ /** Pop the top destination (the programmatic twin of the back gesture); `to` unwinds to a
31
+ * stack index in one step. */
24
32
  pop(to?: number, opts?: NavigateOptions): void
33
+ /** Blank the router's page, keeping the stack — `restore()` brings it back. A destination
34
+ * opened directly stays visible. */
25
35
  hide(): void
36
+ /** Re-present the stack top after `hide()` or a direct `open()` suspended the router. */
26
37
  restore(): void
27
38
 
39
+ /** `"change"` fires on every stack change — pushes, pops, and native back gestures — with the
40
+ * new top destination. */
28
41
  addEventListener(channel: "change", callback: (page: Presentable) => void): void
29
42
  removeEventListener(channel: "change", callback: (page: Presentable) => void): void
30
43
  }
@@ -1,29 +1,7 @@
1
- // theme() — app theme variables (docs/ui-theme-plan.md).
2
- //
3
- // One global variable table lives in the UI core. Styles reference entries with CSS syntax —
4
- // `color: "var(--primaryColor)"` — resolved at style-apply time in the core, so re-calling
5
- // theme() with new values re-styles the LIVE UI (dark mode is just a second call). Two access
6
- // forms with one rule: bare style tokens (`pt: "comfort-top"`) are keywords that may expand to
7
- // formulas (max(safe-top, knob)); `var(--comfort-top)` always reads the raw table value (the
8
- // knob itself).
9
- //
10
- // theme(values) MERGES into the table and returns typed accessors whose values ARE the var()
11
- // strings — define once in a module, import where custom keys need typing:
12
- //
13
- // export const T = theme({ primaryColor: "#0A84FF", cardBg: "#1C1C1E" })
14
- // card.style({ bgColor: T.cardBg }) // T.cardBg === "var(--cardBg)"
15
- //
16
- // System vars need no import — they're static properties on the callable itself:
17
- // theme.primaryColor, theme.fontFamily, theme["comfort-top"], …
18
- //
19
- // Values: strings pass through (colors, fonts, expressions like "max(safe-top, 24px)");
20
- // numbers are LENGTHS (px). `null` removes a key (comfort knobs reset to their defaults:
21
- // 12 vertical, 16 horizontal — the page gutter). Env names (safe-*, vw/vh/vmin/vmax) are
22
- // host-owned facts, never theme keys — they're skipped with a warning.
23
- //
24
- // One key is not a style var: `replaceTransition` — the app-wide default for
25
- // `Router.replace` (any Transition, name or custom spec; `null` resets to "none"). The
26
- // router resolves it in the SDK, so it's consumed here and never sent to the host table.
1
+ // theme() — app theme variables (docs/ui-theme-plan.md). One global var table lives in the UI
2
+ // core; `var(--key)` references resolve at style-apply time, so re-calling theme() re-styles the
3
+ // LIVE UI. Bare style tokens (`pt: "comfort-top"`) are keywords that may expand to formulas
4
+ // (max(safe-top, knob)); `var(--comfort-top)` always reads the raw table value.
27
5
 
28
6
  import type { Transition } from "./presentable"
29
7
 
@@ -41,10 +19,20 @@ export type ThemeAccessors<T> = {
41
19
 
42
20
  const RESERVED = ["safe-top", "safe-bottom", "safe-left", "safe-right", "vw", "vh", "vmin", "vmax"]
43
21
 
44
- /** Merge app theme variables and get typed `var(--key)` accessors back. Strings/numbers are
45
- * style values (numbers = px); `null` removes a key. One special key: `replaceTransition` —
46
- * the app-wide default transition for `Router.replace` (any transition name or custom spec;
47
- * out of the box `"none"`). */
22
+ /**
23
+ * Merge app theme variables into the live table and get typed `var(--key)` accessors back:
24
+ *
25
+ * ```ts
26
+ * export const T = theme({ primaryColor: "#0A84FF", cardBg: "#1C1C1E" })
27
+ * card.style({ bgColor: T.cardBg }) // T.cardBg === "var(--cardBg)"
28
+ * ```
29
+ *
30
+ * Strings pass through (colors, fonts, expressions like `"max(safe-top, 24px)"`); numbers are
31
+ * lengths (px); `null` removes a key (comfort knobs reset to their defaults). Env names
32
+ * (`safe-*`, `vw`/`vh`/…) are host-owned — skipped with a warning. One special key:
33
+ * `replaceTransition` — the app-wide default transition for `Router.replace` (consumed SDK-side,
34
+ * never sent to the host table).
35
+ */
48
36
  const setTheme = <T extends Record<string, string | number | Transition | null>>(
49
37
  // Only `replaceTransition` may carry a Transition — every other key is a style value.
50
38
  values: T & { [K in Exclude<keyof T, "replaceTransition">]: string | number | null }
@@ -73,6 +61,9 @@ const setTheme = <T extends Record<string, string | number | Transition | null>>
73
61
  return accessors as ThemeAccessors<Omit<T, "replaceTransition">>
74
62
  }
75
63
 
64
+ /** App theme: callable to merge variables (`theme({...})` — re-calling re-styles the live UI, so
65
+ * dark mode is just a second call), with the system vars as static properties
66
+ * (`theme.primaryColor`, `theme["comfort-top"]`, …). */
76
67
  export const theme = Object.assign(setTheme, {
77
68
  /** The app accent color. Kit components will read it via `var(--primaryColor, <fallback>)`. */
78
69
  primaryColor: "var(--primaryColor)",