lecodes-cli 0.1.6 → 0.2.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 (73) hide show
  1. package/README.md +7 -1
  2. package/dist/index.js +202 -84
  3. package/package.json +4 -4
  4. package/runtime/sdk/animate/animate.ts +238 -0
  5. package/runtime/sdk/animate/bezier.ts +138 -0
  6. package/runtime/sdk/animate/easings.ts +126 -0
  7. package/runtime/sdk/core/Aspect.ts +151 -0
  8. package/runtime/sdk/core/color.ts +66 -0
  9. package/runtime/sdk/core/events.ts +38 -0
  10. package/runtime/sdk/core/registry.ts +23 -0
  11. package/runtime/sdk/g2/Camera2D.ts +33 -0
  12. package/runtime/sdk/g2/CharacterController2D.ts +75 -0
  13. package/runtime/sdk/g2/Node2D.ts +194 -0
  14. package/runtime/sdk/g2/Physics2D.ts +126 -0
  15. package/runtime/sdk/g2/Scene2D.ts +101 -0
  16. package/runtime/sdk/g2/Shape.ts +63 -0
  17. package/runtime/sdk/g2/Sprite.ts +79 -0
  18. package/runtime/sdk/g2/SpriteAnimation.ts +90 -0
  19. package/runtime/sdk/g2/Texture2D.ts +37 -0
  20. package/runtime/sdk/g2/Tilemap.ts +41 -0
  21. package/runtime/sdk/g2/Trigger.ts +47 -0
  22. package/runtime/sdk/g2/loop.ts +39 -0
  23. package/runtime/sdk/g2/touch.ts +83 -0
  24. package/runtime/sdk/gl/Camera.ts +40 -0
  25. package/runtime/sdk/gl/Collider.ts +29 -0
  26. package/runtime/sdk/gl/Geometry.ts +218 -0
  27. package/runtime/sdk/gl/Light.ts +37 -0
  28. package/runtime/sdk/gl/Material.ts +124 -0
  29. package/runtime/sdk/gl/Mesh.ts +100 -0
  30. package/runtime/sdk/gl/Model.ts +40 -0
  31. package/runtime/sdk/gl/ModelAnimation.ts +64 -0
  32. package/runtime/sdk/gl/Node.ts +234 -0
  33. package/runtime/sdk/gl/Noise.ts +30 -0
  34. package/runtime/sdk/gl/Particles.ts +185 -0
  35. package/runtime/sdk/gl/Physics.ts +95 -0
  36. package/runtime/sdk/gl/Plane.ts +53 -0
  37. package/runtime/sdk/gl/Ray.ts +16 -0
  38. package/runtime/sdk/gl/Scene.ts +179 -0
  39. package/runtime/sdk/gl/Texture.ts +35 -0
  40. package/runtime/sdk/gl/controls.ts +95 -0
  41. package/runtime/sdk/gl/state.ts +6 -0
  42. package/runtime/sdk/gl/touch.ts +56 -0
  43. package/runtime/sdk/inject.ts +85 -0
  44. package/runtime/sdk/math/Mathf.ts +118 -0
  45. package/runtime/sdk/math/mat4.ts +278 -0
  46. package/runtime/sdk/math/quat.ts +232 -0
  47. package/runtime/sdk/math/vec.ts +255 -0
  48. package/runtime/sdk/plugins/qr.ts +36 -0
  49. package/runtime/sdk/runtime/device.ts +33 -0
  50. package/runtime/sdk/runtime/fetch.ts +71 -0
  51. package/runtime/sdk/runtime/files.ts +23 -0
  52. package/runtime/sdk/runtime/input.ts +12 -0
  53. package/runtime/sdk/runtime/media.ts +111 -0
  54. package/runtime/sdk/runtime/misc.ts +12 -0
  55. package/runtime/sdk/runtime/net.ts +36 -0
  56. package/runtime/sdk/runtime/storage.ts +13 -0
  57. package/runtime/sdk/runtime/touch.ts +50 -0
  58. package/runtime/sdk/ui/UI.ts +19 -0
  59. package/runtime/sdk/ui/UIButton.ts +84 -0
  60. package/runtime/sdk/ui/UIContainer.ts +100 -0
  61. package/runtime/sdk/ui/UIImage.ts +68 -0
  62. package/runtime/sdk/ui/UIInput.ts +78 -0
  63. package/runtime/sdk/ui/UINode.ts +342 -0
  64. package/runtime/sdk/ui/UIScreen.ts +122 -0
  65. package/runtime/sdk/ui/UIScrollable.ts +70 -0
  66. package/runtime/sdk/ui/UISpacer.ts +14 -0
  67. package/runtime/sdk/ui/UIText.ts +40 -0
  68. package/runtime/sdk/ui/UIVideo.ts +38 -0
  69. package/runtime/sdk/ui/UIVirtualizedList.ts +222 -0
  70. package/runtime/sdk/ui/UIWidget.ts +97 -0
  71. package/runtime/sdk/ui/fonts.ts +10 -0
  72. package/runtime/sdk/ui/router.ts +73 -0
  73. package/runtime/inject.js +0 -4629
@@ -0,0 +1,19 @@
1
+ // Renderer-side contract + per-renderer status (DOM / canvas-ui / desktop) for every component
2
+ // below is tracked in packages/canvas-ui/COMPONENTS.md.
3
+ export { UIButton, type UIButtonStyle } from './UIButton'
4
+ export { UIScreen, type UIScreenStyle } from './UIScreen'
5
+ export { UISpacer, type UISpacerStyle } from './UISpacer'
6
+ export { UIText, type UITextStyle } from './UIText'
7
+ export { registerFont } from './fonts'
8
+ export { UIImage, type UIImageStyle } from './UIImage'
9
+ export { UIVideo, type UIVideoStyle } from './UIVideo'
10
+ export { UIInput, UITextArea, type UIInputStyle } from './UIInput'
11
+
12
+ export { UIWidget, type UIWidgetStyle } from './UIWidget'
13
+
14
+ export { UIRow, UIColumn, UIBox, type UIContainerStyle } from './UIContainer'
15
+ export { UIScrollable, type UIScrollableStyle } from './UIScrollable'
16
+
17
+ export { UIVirtualizedList } from './UIVirtualizedList'
18
+
19
+ export { Router } from './router'
@@ -0,0 +1,84 @@
1
+ import { ClickEvent, TouchStartEvent } from "../runtime/touch"
2
+ import type { ClickEvent as ClickEventType, TouchStartEvent as TouchStartEventType } from "../runtime/touch"
3
+ import { type ElementStyle, type ContainerStyle, type Style, ContainerElement, type DrawableStyle, type UINodeChild, type OnLayoutCallback, type BaseStyle, type AnimateStyle, type Color } from "./UINode"
4
+
5
+ export type UIButtonStyle = ElementStyle & DrawableStyle & ContainerStyle & { rippleColor?: Color | "default" }
6
+
7
+ export interface UIButton {
8
+ readonly type: "button",
9
+
10
+ style: Style<this, UIButtonStyle & { onPressed?: DrawableStyle & BaseStyle & { duration?: number } }>,
11
+ animateTo: AnimateStyle<this, DrawableStyle & BaseStyle>,
12
+ animateFrom: AnimateStyle<this, DrawableStyle & BaseStyle>
13
+
14
+ onClick(callback: (ev: ClickEventType<UIButton>) => void): this,
15
+ onTouchStart(callback: (ev: TouchStartEventType<UIButton>) => void): this,
16
+ isPressed(): boolean,
17
+
18
+ append(...nodes: UINodeChild[]): this
19
+ insert(index: number, ...nodes: UINodeChild[]): this
20
+ remove(...nodes: UINodeChild[]): this
21
+ setContent(nodes: UINodeChild[]): this
22
+
23
+ onLayout(onLayout: OnLayoutCallback): this
24
+ readonly children: UINodeChild[],
25
+ }
26
+
27
+
28
+ class ButtonElement extends ContainerElement<"button"> {
29
+
30
+ readonly clickListeners: any[] = []
31
+ readonly touchStartListeners: any[] = []
32
+
33
+ onClick (callback: any): this {
34
+ this.clickListeners.push(callback)
35
+ return this
36
+ }
37
+ _emitClick(pointerId: number, clientX: number, clientY: number) {
38
+ const touchEvent = new ClickEvent(clientX, clientY, pointerId)
39
+ touchEvent.target = this
40
+ for (let callback of this.clickListeners) {
41
+ callback(touchEvent)
42
+ }
43
+ return null
44
+ }
45
+
46
+ onTouchStart (callback: any): this {
47
+ this.touchStartListeners.push(callback)
48
+ return this
49
+ }
50
+ _emitTouchStart(pointerId: number, clientX: number, clientY: number): any {
51
+ const touchEvent = new TouchStartEvent(clientX, clientY, pointerId)
52
+ touchEvent.target = this
53
+ for (let callback of this.touchStartListeners) {
54
+ callback(touchEvent)
55
+ if ((touchEvent as any)._trackHandler) {
56
+ return (touchEvent as any)._trackHandler
57
+ }
58
+ }
59
+ return null
60
+ }
61
+
62
+ isPressed(): boolean {
63
+ if (!this._id) return false
64
+ return _creatorUI.isButtonPressed(this._id)
65
+ }
66
+ }
67
+
68
+ export function UIButton(): UIButton;
69
+ export function UIButton(children: UINodeChild[]): UIButton;
70
+ export function UIButton(style: UIButtonStyle): UIButton;
71
+ export function UIButton(style: UIButtonStyle, children: UINodeChild[]): UIButton;
72
+ export function UIButton(...args: [] | [UINodeChild[] | UIButtonStyle] | [UIButtonStyle, children: UINodeChild[]]): UIButton {
73
+ if (args.length === 0) {
74
+ return new ButtonElement("button", {}, [])
75
+ } else if (args.length === 1) {
76
+ if (Array.isArray(args[0])) {
77
+ return new ButtonElement("button", {}, args[0])
78
+ } else {
79
+ return new ButtonElement("button", args[0], [])
80
+ }
81
+ } else {
82
+ return new ButtonElement("button", args[0], args[1])
83
+ }
84
+ }
@@ -0,0 +1,100 @@
1
+ import { ContainerElement, type AnimateStyle, type AppearStyle, type ContainerStyle, type DisappearStyle, type DrawableStyle, type ElementStyle, type OnLayoutCallback, type Style, type StyleFn, type UINode, type UINodeChild } from "./UINode"
2
+
3
+ export type UIContainerStyle = ElementStyle & DrawableStyle & ContainerStyle
4
+
5
+ export interface UIColumn {
6
+ readonly type: "column",
7
+ style: Style<this, UIContainerStyle>,
8
+ animateTo: AnimateStyle<this, UIContainerStyle>
9
+ animateFrom: AnimateStyle<this, UIContainerStyle>
10
+
11
+ append(...nodes: UINodeChild[]): UIColumn
12
+ insert(index: number, ...nodes: UINodeChild[]): UIColumn
13
+ remove(...nodes: UINodeChild[]): UIColumn
14
+ setContent(nodes: UINodeChild[]): this
15
+
16
+ onLayout(onLayout: OnLayoutCallback): this
17
+
18
+ readonly children: UINodeChild[]
19
+ }
20
+ export function UIColumn(): UIColumn
21
+ export function UIColumn(children: UINodeChild[]): UIColumn
22
+ export function UIColumn(style: UIContainerStyle): UIColumn
23
+ export function UIColumn(style: UIContainerStyle, children: UINodeChild[]): UIColumn
24
+ export function UIColumn(...args: [] | [UINodeChild[] | UIContainerStyle] | [UIContainerStyle, children: UINodeChild[]]): UIColumn {
25
+ if (args.length === 0) {
26
+ return new ContainerElement("column", {}, [])
27
+ } else if (args.length === 1) {
28
+ if (Array.isArray(args[0])) {
29
+ return new ContainerElement("column", {}, args[0])
30
+ } else {
31
+ return new ContainerElement("column", args[0], [])
32
+ }
33
+ } else {
34
+ return new ContainerElement("column", args[0], args[1])
35
+ }
36
+ }
37
+
38
+ export interface UIRow {
39
+ readonly type: "row",
40
+ style: Style<this, UIContainerStyle>,
41
+ animateTo: AnimateStyle<this, UIContainerStyle>,
42
+ animateFrom: AnimateStyle<this, UIContainerStyle>,
43
+
44
+ append(...nodes: UINodeChild[]): UIRow
45
+ insert(index: number, ...nodes: UINodeChild[]): UIRow
46
+ remove(...nodes: UINodeChild[]): UIRow
47
+ setContent(nodes: UINodeChild[]): this
48
+
49
+ onLayout(onLayout: OnLayoutCallback): this
50
+
51
+ readonly children: UINodeChild[],
52
+ }
53
+ export function UIRow(children: UINodeChild[]): UIRow
54
+ export function UIRow(style: UIContainerStyle): UIRow
55
+ export function UIRow(style: UIContainerStyle, children: UINodeChild[]): UIRow
56
+ export function UIRow(...args: [] | [UINodeChild[] | UIContainerStyle] | [UIContainerStyle, children: UINodeChild[]]): UIRow {
57
+ if (args.length === 0) {
58
+ return new ContainerElement("row", {}, [])
59
+ } else if (args.length === 1) {
60
+ if (Array.isArray(args[0])) {
61
+ return new ContainerElement("row", {}, args[0])
62
+ } else {
63
+ return new ContainerElement("row", args[0], [])
64
+ }
65
+ } else {
66
+ return new ContainerElement("row", args[0], args[1])
67
+ }
68
+ }
69
+
70
+ export interface UIBox {
71
+ readonly type: "box",
72
+ style: Style<this, UIContainerStyle>,
73
+ animateTo: AnimateStyle<this, UIContainerStyle>,
74
+ animateFrom: AnimateStyle<this, UIContainerStyle>,
75
+
76
+ append(...nodes: UINodeChild[]): this
77
+ insert(index: number, ...nodes: UINodeChild[]): this
78
+ remove(...nodes: UINodeChild[]): this
79
+ setContent(nodes: UINodeChild[]): this
80
+
81
+ onLayout(onLayout: OnLayoutCallback): this
82
+
83
+ readonly children: UINodeChild[],
84
+ }
85
+ export function UIBox(children: UINodeChild[]): UIBox
86
+ export function UIBox(style: UIContainerStyle): UIBox
87
+ export function UIBox(style: UIContainerStyle, children: UINodeChild[]): UIBox
88
+ export function UIBox(...args: [] | [UINodeChild[] | UIContainerStyle] | [UIContainerStyle, children: UINodeChild[]]): UIBox {
89
+ if (args.length === 0) {
90
+ return new ContainerElement("box", {}, [])
91
+ } else if (args.length === 1) {
92
+ if (Array.isArray(args[0])) {
93
+ return new ContainerElement("box", {}, args[0])
94
+ } else {
95
+ return new ContainerElement("box", args[0], [])
96
+ }
97
+ } else {
98
+ return new ContainerElement("box", args[0], args[1])
99
+ }
100
+ }
@@ -0,0 +1,68 @@
1
+ import type { FetchResponse } from "../runtime/fetch"
2
+ import type { SvgSourceValue as SvgSource } from "../runtime/misc"
3
+ import type { File } from "../runtime/fetch"
4
+ import { Element, type AnimateStyle, type Color, type ElementStyle, type OnLayoutCallback, type Style } from "./UINode"
5
+
6
+ export type UIImageStyle = ElementStyle & { borderRadius?: number, objectFit?: "cover" | "contain" | "fill", tintColor?: Color }
7
+
8
+ export interface UIImage {
9
+ readonly type: "image",
10
+ src: string | FetchResponse | File | SvgSource,
11
+ style: Style<this, UIImageStyle>
12
+ animateTo: AnimateStyle<this, UIImageStyle>
13
+ animateFrom: AnimateStyle<this, UIImageStyle>
14
+
15
+ // Render only a sub-rectangle of the source texture (coords/size in texture pixels).
16
+ // This is the atlas / spritesheet primitive: the initial crop is the first call, sprite
17
+ // animation is swapping the rect per frame. The rect's w/h become the node's intrinsic
18
+ // size (one frame, not the whole atlas) and it overrides objectFit — the cropped frame
19
+ // always fills the box.
20
+ setSourceRect(x: number, y: number, w: number, h: number): this
21
+
22
+ onLayout(onLayout: OnLayoutCallback): this
23
+ }
24
+
25
+ class ImageElement extends Element<"image"> {
26
+ private _src: string | FetchResponse | File | SvgSource
27
+ // Current source sub-rect; undefined until the first setSourceRect. Kept on the node (not
28
+ // just sent as a command) so a crop set while detached (_id == 0) is reapplied at mount —
29
+ // the viewer reads it when it creates the element.
30
+ private _sourceRect?: [number, number, number, number]
31
+ constructor(style: any, src: string | FetchResponse | File | SvgSource) {
32
+ super("image", style)
33
+ this._src = src
34
+ }
35
+
36
+ get src() {
37
+ return this._src
38
+ }
39
+ set src(value) {
40
+ this._src = value
41
+ if (this._id !== 0) {
42
+ _creatorUI.updateNode(this._id, "src", value)
43
+ }
44
+ }
45
+
46
+ setSourceRect(x: number, y: number, w: number, h: number): this {
47
+ // Stash on the node so a crop set before mount is reapplied when the element is created.
48
+ this._sourceRect = [x, y, w, h]
49
+ // Live mutation: fast channel (not _style → no PX_VALUE density scaling: these are texture
50
+ // pixels, a different coordinate space). On a detached node there is nothing to mutate yet —
51
+ // the stash above carries it to mount. The viewer decides relayout vs draw-only by comparing
52
+ // w/h against the rect it has stashed on the element.
53
+ if (this._id !== 0) {
54
+ _creatorUI.setSourceRect(this._id, x, y, w, h)
55
+ }
56
+ return this
57
+ }
58
+ }
59
+
60
+ export function UIImage(src: string | FetchResponse | File | SvgSource): UIImage
61
+ export function UIImage(style: UIImageStyle, src: string | FetchResponse | File | SvgSource): UIImage
62
+ export function UIImage(...args: [string | FetchResponse | File | SvgSource] | [UIImageStyle, string | FetchResponse | File | SvgSource]): UIImage {
63
+ if (args.length === 1) {
64
+ return new ImageElement({}, args[0])
65
+ } else {
66
+ return new ImageElement(args[0], args[1])
67
+ }
68
+ }
@@ -0,0 +1,78 @@
1
+ import { type ElementStyle, type DrawableStyle, type Style, type StyleFn, type AppearStyle, type DisappearStyle, Element, type TextStyle, type Color, type OnLayoutCallback, type BaseStyle, type AnimateStyle } from "./UINode";
2
+
3
+ type InputStyle = { placeholder?: string, placeholderColor?: Color, type?: "text" | "password" | "search" }
4
+ export type UIInputStyle = ElementStyle & DrawableStyle & TextStyle & InputStyle
5
+
6
+ export interface UIInput {
7
+ readonly type: "input",
8
+
9
+ value: string
10
+
11
+ style: Style<this, UIInputStyle & { onFocused?: DrawableStyle & BaseStyle & { duration?: number } }>,
12
+ animateTo: AnimateStyle<this, DrawableStyle & BaseStyle>
13
+ animateFrom: AnimateStyle<this, DrawableStyle & BaseStyle>
14
+
15
+ onChange(callback: (value: string) => void): UIInput
16
+ onFocus(callback: () => void): UIInput
17
+ onBlur(callback: () => void): UIInput
18
+ onLayout(onLayout: OnLayoutCallback): this
19
+ }
20
+
21
+ export interface UITextArea {
22
+ readonly type: "textarea",
23
+
24
+ value: string
25
+
26
+ style: Style<this, UIInputStyle & { onFocused?: DrawableStyle & BaseStyle & { duration?: number } }>,
27
+ // styleV: StyleFn<this, UIInputStyle>,
28
+ // styleH: StyleFn<this, UIInputStyle>,
29
+
30
+ // appear: AppearStyle<this, UIInputStyle>
31
+ // disappear: DisappearStyle<this, UIInputStyle>
32
+
33
+ onChange(callback: (value: string) => void): UITextArea
34
+ onFocus(callback: () => void): UITextArea
35
+ onBlur(callback: () => void): UITextArea
36
+ }
37
+
38
+ class InputElement<T extends "input" | "textarea"> extends Element<T> {
39
+
40
+ readonly cl: Function[] = []
41
+ readonly fl: Function[] = []
42
+ readonly bl: Function[] = []
43
+
44
+ get value() {
45
+ return _creatorUI.getTextValue(this._id)
46
+ }
47
+ set value(value: string) {
48
+ if (this._id !== 0) {
49
+ _creatorUI.updateNode(this._id, "value", value)
50
+ }
51
+ }
52
+
53
+ onChange (callback: (value: string) => void): this {
54
+ this.cl.push(callback)
55
+ return this
56
+ }
57
+ onFocus(callback: () => void): this {
58
+ this.fl.push(callback)
59
+ return this
60
+ }
61
+ onBlur(callback: () => void): this {
62
+ this.bl.push(callback)
63
+ return this
64
+ }
65
+ }
66
+
67
+ export function UIInput(): UIInput;
68
+ export function UIInput(style: UIInputStyle): UIInput;
69
+ export function UIInput(style?: UIInputStyle): UIInput {
70
+ return new InputElement("input", style ?? {})
71
+ }
72
+
73
+ export function UITextArea(): UITextArea;
74
+ export function UITextArea(style: UIInputStyle): UITextArea;
75
+ export function UITextArea(style?: UIInputStyle): UITextArea {
76
+ return new InputElement("textarea", style ?? {})
77
+ }
78
+
@@ -0,0 +1,342 @@
1
+ import type { FetchResponse } from "../runtime/fetch"
2
+
3
+ export interface UINode {
4
+ readonly type: string
5
+ /** Author-given semantic name (a stable selector for tests + AI review feedback). */
6
+ readonly name?: string
7
+ style: Style<this, any>
8
+ }
9
+
10
+ export type UINodeChild = UINode | null | undefined | false
11
+
12
+ export type Color = number | string | null
13
+
14
+ export type BaseStyle = {
15
+ opacity?: number | `${number}`,
16
+ transform?: string | null,
17
+ backgroundColor?: Color | null,
18
+ bgColor?: Color | null,
19
+ overflow?: "visible" | "hidden",
20
+ boxSizing?: "border-box" | "content-box",
21
+ /**
22
+ * Author-given semantic name — a stable selector for tests and for marking elements in the AI
23
+ * code-review feedback loop. NOT a style: it's extracted at construction (never sent to the layout
24
+ * engine) and surfaced on the node + in the renderer's serialized output. Available on every element.
25
+ */
26
+ name?: string,
27
+ }
28
+
29
+ export type DrawableStyle = {
30
+ backgroundImage?: FetchResponse | File | string | null,
31
+ bgGradient?: string,
32
+ backgroundGradient?: string,
33
+ bgImage?: FetchResponse | File | string | null,
34
+ backgroundSize?: "cover" | "contain" | "tile",
35
+ bgSize?: "cover" | "contain" | "tile",
36
+ border?: string | number | null,
37
+ borderWidth?: number,
38
+ borderColor?: Color,
39
+
40
+ borderLeft?: string | number | null,
41
+ borderLeftWidth?: number,
42
+ borderLeftColor?: Color,
43
+ borderTop?: string | number | null,
44
+ borderTopWidth?: number,
45
+ borderTopColor?: Color,
46
+ borderRight?: string | number | null,
47
+ borderRightWidth?: number,
48
+ borderRightColor?: Color,
49
+ borderBottom?: string | number | null,
50
+ borderBottomWidth?: number,
51
+ borderBottomColor?: Color,
52
+
53
+ borderRadius?: UIValue | string,
54
+ borderTopLeftRadius?: UIValue,
55
+ borderTopRightRadius?: UIValue,
56
+ borderBottomLeftRadius?: UIValue,
57
+ borderBottomRightRadius?: UIValue,
58
+
59
+ pointerEvents?: "all" | "none",
60
+ }
61
+
62
+ export type ContainerStyle = {
63
+ flexDirection?: "row" | "column",
64
+ justifyContent?: "flex-start" | "center" | "flex-end" | "space-between" | "space-evenly",
65
+ alignItems?: "flex-start" | "center" | "flex-end" | "stretch",
66
+ gap?: UIValue,
67
+ flexWrap?: "nowrap" | "wrap" | "wrap-reverse"
68
+ }
69
+
70
+ export type ScrollStyle = {
71
+ scrollX?: "auto" | "all" | "none",
72
+ scrollY?: "auto" | "all" | "none"
73
+ }
74
+
75
+ type UIValue = number |
76
+ `${number}px` |
77
+ `${number}vw` |
78
+ `${number}vh` |
79
+ `${number}vmin` |
80
+ `${number}vmax` |
81
+ `${number}em` |
82
+ `calc(${string})` |
83
+ `min(${string})` |
84
+ `max(${string})` |
85
+ `${string}%` |
86
+ `clamp(${string})`
87
+
88
+ export type PaddingStyle = {
89
+ paddingLeft?: UIValue | "safe-left" | "safe-left-comfort",
90
+ paddingTop?: UIValue | "safe-top" | "safe-top-comfort",
91
+ paddingRight?: UIValue | "safe-right" | "safe-right-comfort",
92
+ paddingBottom?: UIValue | "safe-bottom" | "safe-bottom-comfort",
93
+ padding?: UIValue | "safe-all" | "safe-all-comfort",
94
+ paddingHorizontal?: UIValue,
95
+ paddingVertical?: UIValue,
96
+
97
+ pl?: UIValue | "safe-left" | "safe-left-comfort",
98
+ pt?: UIValue | "safe-top" | "safe-top-comfort",
99
+ pr?: UIValue | "safe-right" | "safe-right-comfort",
100
+ pb?: UIValue | "safe-bottom" | "safe-bottom-comfort",
101
+ p?: UIValue | "safe-all" | "safe-all-comfort",
102
+ px?: UIValue,
103
+ py?: UIValue,
104
+ }
105
+
106
+
107
+
108
+ export type MarginStyle = {
109
+ marginLeft?: UIValue | "auto" | "safe-left" | "safe-left-comfort",
110
+ marginTop?: UIValue | "auto" | "safe-top" | "safe-top-comfort",
111
+ marginRight?: UIValue | "auto" | "safe-right" | "safe-right-comfort",
112
+ marginBottom?: UIValue | "auto" | "safe-bottom" | "safe-bottom-comfort",
113
+ margin?: UIValue | "auto" | "safe-all" | "safe-all-comfort",
114
+ marginHorizontal?: UIValue | "auto",
115
+ marginVertical?: UIValue | "auto",
116
+
117
+ ml?: UIValue | "auto" | "safe-left" | "safe-left-comfort",
118
+ mt?: UIValue | "auto" | "safe-top" | "safe-top-comfort",
119
+ mr?: UIValue | "auto" | "safe-right" | "safe-right-comfort",
120
+ mb?: UIValue | "auto" | "safe-bottom" | "safe-bottom-comfort",
121
+ m?: UIValue | "auto" | "safe-all" | "safe-all-comfort",
122
+ mx?: UIValue | "auto",
123
+ my?: UIValue | "auto",
124
+ }
125
+
126
+ export type PositionStyle = {
127
+ top?: UIValue | `${number}%` | 'safe-top' | 'safe-top-comfort',
128
+ left?: UIValue | `${number}%` | 'safe-left' | 'safe-left-comfort',
129
+ bottom?: UIValue | `${number}%` | 'safe-bottom' | 'safe-bottom-comfort',
130
+ right?: UIValue | `${number}%` | 'safe-right' | 'safe-right-comfort',
131
+ width?: UIValue | `${number}%` | "auto",
132
+ height?: UIValue | `${number}%` | "auto",
133
+ maxWidth?: UIValue | `${number}%` | "auto",
134
+ maxHeight?: UIValue | `${number}%` | "auto",
135
+ minWidth?: UIValue | `${number}%` | "auto",
136
+ minHeight?: UIValue | `${number}%` | "auto",
137
+ }
138
+
139
+ export type ElementStyle = PaddingStyle & MarginStyle & BaseStyle & PositionStyle & {
140
+ position?: "absolute" | "static" | "relative",
141
+ aspectRatio?: number,
142
+ flex?: number | string,
143
+ flexGrow?: number,
144
+ flexShrink?: number,
145
+ flexBase?: UIValue | `${number}%` | "auto",
146
+ alignSelf?: "flex-start" | "center" | "flex-end" | "stretch",
147
+ display?: "none" | "flex"
148
+ }
149
+
150
+ export type TextStyle = {
151
+ textAlign?: "start" | "center" | "end" | "left" | "right"
152
+ fontFamily?: string,
153
+ fontSize?: UIValue,
154
+ lineHeight?: UIValue | "normal",
155
+ fontWeight?: number | `${number}` | "normal" | "bold",
156
+ fontStyle?: "normal" | "italic",
157
+ color?: Color,
158
+ textDecoration?: "underline" | "line-through" | "none",
159
+ letterSpacing?: UIValue
160
+ }
161
+
162
+ // Не надо переписывать эту функцию 10 раз, обрати внимание, что у тебя тут возвращается this
163
+ function styleFunction(this: any, newStyle: any) {
164
+ Object.assign(this._style, newStyle)
165
+ if (this._id !== 0) {
166
+ _creatorUI.mergeStyle(this._id, newStyle)
167
+ }
168
+ return this
169
+ }
170
+
171
+ const handler: ProxyHandler<any> = {
172
+ get(target, key, receiver) {
173
+ if (key === "_raw") {
174
+ return target._el._style
175
+ }
176
+ return target._el._style[key]
177
+ },
178
+ set(target, key: string, value: string | number) {
179
+ if (target._el._id !== 0) {
180
+ _creatorUI.updateStyle(target._el._id, key, value)
181
+ }
182
+ target._el._style[key] = value
183
+ return true
184
+ },
185
+ getOwnPropertyDescriptor(target, p) {
186
+ return Object.getOwnPropertyDescriptor(target._el._style, p)
187
+ },
188
+ ownKeys(target) {
189
+ return Object.keys(target._el._style)
190
+ }
191
+ }
192
+
193
+ function Style() {
194
+
195
+ }
196
+
197
+ export type StyleFn <R, T extends object> = ((this: R, style: T & { onLandscape?: T, onPortait?: T }) => R)
198
+ export type Style <R, T extends object> = StyleFn<R,T> & T & { onLandscape?: T, onPortait?: T }
199
+
200
+ export type AnimateStyle<R, T extends object> = ((this: R, style: T & { duration?: number, delay?: number, layer?: number, commit?: boolean }) => R)
201
+
202
+ export type AppearStyle <R, T> = (arg: { from: T, duration?: number, delay?: number }) => R
203
+ export type DisappearStyle <R, T> = (arg: { to: T, duration?: number, delay?: number }) => R
204
+
205
+ export type OnLayoutCallback = (layout: { left: number, top: number, width: number, height: number }) => void
206
+
207
+ export class Element<T extends string> {
208
+ readonly type: T
209
+ /** Author-given semantic name (LeCodes `name`) — see BaseStyle.name. Extracted from the options
210
+ * object so it never reaches the layout engine; the renderer reads it off the node. */
211
+ readonly name?: string
212
+ protected _style: any
213
+
214
+ protected _id: number = 0
215
+
216
+ protected _styleProxy: any
217
+ protected _appear: any
218
+ protected _disappear: any
219
+
220
+ constructor(type: T, style: any) {
221
+ this.type = type
222
+ if (style && typeof style.name === "string" && style.name.length > 0) {
223
+ this.name = style.name
224
+ delete style.name
225
+ }
226
+ this._style = style
227
+ }
228
+
229
+ get style(): any {
230
+ if (this._styleProxy) return this._styleProxy
231
+ const obj = styleFunction.bind(this)
232
+ // @ts-ignore
233
+ obj._el = this
234
+
235
+ const proxy = new Proxy(obj, handler)
236
+ this._styleProxy = proxy
237
+ return proxy
238
+ }
239
+
240
+ animateTo(style: any): this{
241
+ _creatorUI.animateTo(this._id, style)
242
+ if (style.commit !== false) {
243
+ Object.assign(this._style, style)
244
+ }
245
+ return this
246
+ }
247
+ animateFrom(style: any): this{
248
+ _creatorUI.animateFrom(this._id, style)
249
+ return this
250
+ }
251
+
252
+ protected ll?: OnLayoutCallback[]
253
+ onLayout(onLayout: OnLayoutCallback): this {
254
+ if (this.ll) {
255
+ this.ll.push(onLayout)
256
+ } else {
257
+ this.ll = [ onLayout ]
258
+ }
259
+ return this
260
+ }
261
+ }
262
+
263
+ export class ContainerElement<T extends string> extends Element<T> {
264
+ children: any[] = []
265
+
266
+ constructor(type: T, style: any, children: any[]) {
267
+ super(type, style)
268
+ this.children = children
269
+ }
270
+
271
+ append(...nodes: UINodeChild[]): this {
272
+ if (this._id === 0) {
273
+ this.children.push(...nodes)
274
+ return this
275
+ }
276
+ let index = 0
277
+ for (let child of this.children) {
278
+ if (child) {
279
+ index++
280
+ }
281
+ }
282
+ for (let node of nodes) {
283
+ if (!node) continue
284
+ _creatorUI.insertNode(index, this._id, node)
285
+ index++
286
+ }
287
+ this.children.push(...nodes)
288
+ return this
289
+ }
290
+ insert(index: number, ...nodes: UINodeChild[]): this {
291
+ if (this._id === 0) {
292
+ this.children.splice(index, 0, ...nodes)
293
+ return this
294
+ }
295
+
296
+ let _index = 0
297
+ for (let i = 0; i < index; i++) {
298
+ if (this.children[i]) {
299
+ _index++
300
+ }
301
+ }
302
+ for (let node of nodes) {
303
+ if (!node) continue
304
+ _creatorUI.insertNode(_index, this._id, node)
305
+ _index++
306
+ }
307
+ this.children.splice(index, 0, ...nodes)
308
+ return this
309
+ }
310
+ remove(...nodesToDelete: UINode[]): this {
311
+ const set = new Set(nodesToDelete)
312
+
313
+ for (let i = 0; i < this.children.length; i++) {
314
+ if (set.has(this.children[i])) {
315
+ set.delete(this.children[i])
316
+ this.children.splice(i, 1)
317
+ i--
318
+
319
+ if (set.size === 0) {
320
+ break
321
+ }
322
+ }
323
+ }
324
+
325
+ if (this._id === 0) {
326
+ return this
327
+ }
328
+ for (let node of nodesToDelete) {
329
+ _creatorUI.removeNode(this._id, node)
330
+ }
331
+ return this
332
+ }
333
+
334
+ setContent(children: UINodeChild[]): this {
335
+ if (this._id !== 0) {
336
+ _creatorUI.setContent(this._id, this.children, children)
337
+ }
338
+ this.children.length = 0
339
+ this.children.push(...children)
340
+ return this
341
+ }
342
+ }