uicore-ts 1.1.105 → 1.1.110
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/compiledScripts/UIActionIndicator.js.map +2 -2
- package/compiledScripts/UILoadingView.d.ts +21 -0
- package/compiledScripts/UILoadingView.js +144 -0
- package/compiledScripts/UILoadingView.js.map +7 -0
- package/compiledScripts/UIRectangle.d.ts +16 -1
- package/compiledScripts/UIRectangle.js +103 -0
- package/compiledScripts/UIRectangle.js.map +3 -3
- package/compiledScripts/UITextView.d.ts +3 -3
- package/compiledScripts/UITextView.js +16 -6
- package/compiledScripts/UITextView.js.map +2 -2
- package/compiledScripts/UIView.d.ts +7 -0
- package/compiledScripts/UIView.js +26 -0
- package/compiledScripts/UIView.js.map +2 -2
- package/compiledScripts/index.d.ts +1 -0
- package/compiledScripts/index.js +1 -0
- package/compiledScripts/index.js.map +2 -2
- package/package.json +1 -1
- package/scripts/UIActionIndicator.ts +8 -18
- package/scripts/UILoadingView.ts +201 -0
- package/scripts/UIRectangle.ts +153 -1
- package/scripts/UITextView.ts +23 -7
- package/scripts/UIView.ts +65 -14
- package/scripts/index.ts +2 -0
package/compiledScripts/index.js
CHANGED
|
@@ -49,4 +49,5 @@ __reExport(scripts_exports, require("./UIInterfaces"), module.exports);
|
|
|
49
49
|
__reExport(scripts_exports, require("./ClientCheckers"), module.exports);
|
|
50
50
|
__reExport(scripts_exports, require("./UICore"), module.exports);
|
|
51
51
|
__reExport(scripts_exports, require("./UIRootViewController"), module.exports);
|
|
52
|
+
__reExport(scripts_exports, require("./UILoadingView"), module.exports);
|
|
52
53
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../scripts/index.ts"],
|
|
4
|
-
"sourcesContent": ["export * from \"./UIObject\"\nexport * from \"./UIView\"\nexport * from \"./UIViewController\"\nexport * from \"./UITimer\"\nexport * from \"./UITextArea\"\nexport * from \"./UITextView\"\nexport * from \"./UITextField\"\nexport * from \"./UITableView\"\nexport * from \"./UIStringFilter\"\nexport * from \"./UISlideScrollerView\"\nexport * from \"./UIScrollView\"\nexport * from \"./UIRoute\"\nexport * from \"./UIRectangle\"\nexport * from \"./UIPoint\"\nexport * from \"./UINativeScrollView\"\nexport * from \"./UILink\"\nexport * from \"./UILinkButton\"\nexport * from \"./UILayoutGrid\"\nexport * from \"./UIKeyValueStringFilter\"\nexport * from \"./UIKeyValueSorter\"\nexport * from \"./UIImageView\"\nexport * from \"./UIDialogView\"\nexport * from \"./UIDateTimeInput\"\nexport * from \"./UICoreExtensions\"\nexport * from \"./UICore\"\nexport * from \"./UIColor\"\nexport * from \"./UIBaseButton\"\nexport * from \"./UIButton\"\nexport * from \"./UIActionIndicator\"\nexport * from \"./UICoreExtensionValueObject\"\nexport * from \"./UIInterfaces\"\nexport * from \"./ClientCheckers\"\nexport * from \"./UICore\"\nexport * from \"./UIRootViewController\"\n\n\n\n\n\n\n\n\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;AAAA;AAAA;AAAA,4BAAc,uBAAd;AACA,4BAAc,qBADd;AAEA,4BAAc,+BAFd;AAGA,4BAAc,sBAHd;AAIA,4BAAc,yBAJd;AAKA,4BAAc,yBALd;AAMA,4BAAc,0BANd;AAOA,4BAAc,0BAPd;AAQA,4BAAc,6BARd;AASA,4BAAc,kCATd;AAUA,4BAAc,2BAVd;AAWA,4BAAc,sBAXd;AAYA,4BAAc,0BAZd;AAaA,4BAAc,sBAbd;AAcA,4BAAc,iCAdd;AAeA,4BAAc,qBAfd;AAgBA,4BAAc,2BAhBd;AAiBA,4BAAc,2BAjBd;AAkBA,4BAAc,qCAlBd;AAmBA,4BAAc,+BAnBd;AAoBA,4BAAc,0BApBd;AAqBA,4BAAc,2BArBd;AAsBA,4BAAc,8BAtBd;AAuBA,4BAAc,+BAvBd;AAwBA,4BAAc,qBAxBd;AAyBA,4BAAc,sBAzBd;AA0BA,4BAAc,2BA1Bd;AA2BA,4BAAc,uBA3Bd;AA4BA,4BAAc,gCA5Bd;AA6BA,4BAAc,yCA7Bd;AA8BA,4BAAc,2BA9Bd;AA+BA,4BAAc,6BA/Bd;AAgCA,4BAAc,qBAhCd;AAiCA,4BAAc,mCAjCd;",
|
|
4
|
+
"sourcesContent": ["export * from \"./UIObject\"\nexport * from \"./UIView\"\nexport * from \"./UIViewController\"\nexport * from \"./UITimer\"\nexport * from \"./UITextArea\"\nexport * from \"./UITextView\"\nexport * from \"./UITextField\"\nexport * from \"./UITableView\"\nexport * from \"./UIStringFilter\"\nexport * from \"./UISlideScrollerView\"\nexport * from \"./UIScrollView\"\nexport * from \"./UIRoute\"\nexport * from \"./UIRectangle\"\nexport * from \"./UIPoint\"\nexport * from \"./UINativeScrollView\"\nexport * from \"./UILink\"\nexport * from \"./UILinkButton\"\nexport * from \"./UILayoutGrid\"\nexport * from \"./UIKeyValueStringFilter\"\nexport * from \"./UIKeyValueSorter\"\nexport * from \"./UIImageView\"\nexport * from \"./UIDialogView\"\nexport * from \"./UIDateTimeInput\"\nexport * from \"./UICoreExtensions\"\nexport * from \"./UICore\"\nexport * from \"./UIColor\"\nexport * from \"./UIBaseButton\"\nexport * from \"./UIButton\"\nexport * from \"./UIActionIndicator\"\nexport * from \"./UICoreExtensionValueObject\"\nexport * from \"./UIInterfaces\"\nexport * from \"./ClientCheckers\"\nexport * from \"./UICore\"\nexport * from \"./UIRootViewController\"\nexport * from \"./UILoadingView\"\n\n\n\n\n\n\n\n\n\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;AAAA;AAAA;AAAA,4BAAc,uBAAd;AACA,4BAAc,qBADd;AAEA,4BAAc,+BAFd;AAGA,4BAAc,sBAHd;AAIA,4BAAc,yBAJd;AAKA,4BAAc,yBALd;AAMA,4BAAc,0BANd;AAOA,4BAAc,0BAPd;AAQA,4BAAc,6BARd;AASA,4BAAc,kCATd;AAUA,4BAAc,2BAVd;AAWA,4BAAc,sBAXd;AAYA,4BAAc,0BAZd;AAaA,4BAAc,sBAbd;AAcA,4BAAc,iCAdd;AAeA,4BAAc,qBAfd;AAgBA,4BAAc,2BAhBd;AAiBA,4BAAc,2BAjBd;AAkBA,4BAAc,qCAlBd;AAmBA,4BAAc,+BAnBd;AAoBA,4BAAc,0BApBd;AAqBA,4BAAc,2BArBd;AAsBA,4BAAc,8BAtBd;AAuBA,4BAAc,+BAvBd;AAwBA,4BAAc,qBAxBd;AAyBA,4BAAc,sBAzBd;AA0BA,4BAAc,2BA1Bd;AA2BA,4BAAc,uBA3Bd;AA4BA,4BAAc,gCA5Bd;AA6BA,4BAAc,yCA7Bd;AA8BA,4BAAc,2BA9Bd;AA+BA,4BAAc,6BA/Bd;AAgCA,4BAAc,qBAhCd;AAiCA,4BAAc,mCAjCd;AAkCA,4BAAc,4BAlCd;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "uicore-ts",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.110",
|
|
4
4
|
"description": "UICore is a library to build native-like user interfaces using pure Typescript. No HTML is needed at all. Components are described as TS classes and all user interactions are handled explicitly. This library is strongly inspired by the UIKit framework that is used in IOS. In addition, UICore has tools to handle URL based routing, array sorting and filtering and adds a number of other utilities for convenience.",
|
|
5
5
|
"main": "compiledScripts/index.js",
|
|
6
6
|
"types": "compiledScripts/index.d.ts",
|
|
@@ -22,9 +22,6 @@ export class UIActionIndicator extends UIView {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
25
|
set size(size: number) {
|
|
29
26
|
|
|
30
27
|
this._size = size
|
|
@@ -40,15 +37,14 @@ export class UIActionIndicator extends UIView {
|
|
|
40
37
|
}
|
|
41
38
|
|
|
42
39
|
|
|
43
|
-
|
|
44
40
|
override set hidden(hidden: boolean) {
|
|
45
|
-
|
|
41
|
+
|
|
46
42
|
super.hidden = hidden
|
|
47
|
-
|
|
48
|
-
if (hidden) {
|
|
49
43
|
|
|
44
|
+
if (hidden) {
|
|
45
|
+
|
|
50
46
|
this.indicatorView.removeFromSuperview()
|
|
51
|
-
|
|
47
|
+
|
|
52
48
|
}
|
|
53
49
|
else {
|
|
54
50
|
|
|
@@ -81,26 +77,20 @@ export class UIActionIndicator extends UIView {
|
|
|
81
77
|
|
|
82
78
|
this.indicatorView.style.height = "" + this._size.integerValue + "px"
|
|
83
79
|
this.indicatorView.style.width = "" + this._size.integerValue + "px"
|
|
84
|
-
|
|
80
|
+
|
|
85
81
|
const minSize = Math.min(this.bounds.height, this.bounds.width)
|
|
86
|
-
|
|
82
|
+
|
|
87
83
|
this.indicatorView.style.maxHeight = "" + minSize.integerValue + "px"
|
|
88
84
|
this.indicatorView.style.maxWidth = "" + minSize.integerValue + "px"
|
|
89
|
-
|
|
85
|
+
|
|
90
86
|
const size = Math.min(this._size, minSize)
|
|
91
|
-
|
|
87
|
+
|
|
92
88
|
this.indicatorView.style.left = "" + ((bounds.width - size) * 0.5 - 11).integerValue + "px"
|
|
93
89
|
this.indicatorView.style.top = "" + ((bounds.height - size) * 0.5 - 11).integerValue + "px"
|
|
94
90
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
91
|
}
|
|
99
92
|
|
|
100
93
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
94
|
}
|
|
105
95
|
|
|
106
96
|
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { UIColor } from "./UIColor"
|
|
2
|
+
import { IS_DEFINED, NO, YES } from "./UIObject"
|
|
3
|
+
import { UIRectangle } from "./UIRectangle"
|
|
4
|
+
import { IUILoadingView, UIView } from "./UIView"
|
|
5
|
+
|
|
6
|
+
export class UILoadingView extends UIView implements IUILoadingView {
|
|
7
|
+
|
|
8
|
+
private spinnerView: UIView
|
|
9
|
+
private isPulsing: boolean = NO
|
|
10
|
+
private _theme: "light" | "dark" = "light"
|
|
11
|
+
|
|
12
|
+
override set loading(loading: boolean) {
|
|
13
|
+
// cannot set loading on loading view
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
override get loading() {
|
|
17
|
+
return NO
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Sets the visual theme of the loader.
|
|
22
|
+
* 'light' (default): Suitable for light backgrounds. Dark spinner, white-ish overlay.
|
|
23
|
+
* 'dark': Suitable for dark backgrounds. Light spinner, black-ish overlay.
|
|
24
|
+
*/
|
|
25
|
+
set theme(theme: "light" | "dark") {
|
|
26
|
+
this._theme = theme
|
|
27
|
+
this.updateColors()
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
get theme() {
|
|
31
|
+
return this._theme
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
constructor(elementID?: string) {
|
|
35
|
+
super(elementID)
|
|
36
|
+
|
|
37
|
+
// 1. Initialize Spinner (Custom Bootstrap-like implementation)
|
|
38
|
+
this.spinnerView = new UIView(this.elementID + "_Spinner")
|
|
39
|
+
this.spinnerView.addStyleClass("UILoadingViewSpinnerContainer")
|
|
40
|
+
this.addSubview(this.spinnerView);
|
|
41
|
+
|
|
42
|
+
// 2. Configure defaults
|
|
43
|
+
(this as UILoadingView).configureWithObject({
|
|
44
|
+
backgroundColor: UIColor.transparentColor,
|
|
45
|
+
userInteractionEnabled: YES, // Blocks touches to underlying view
|
|
46
|
+
pausesPointerEvents: YES, // Prevents events from passing through
|
|
47
|
+
style: { height: "100%", width: "100%" }
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
// 3. Initialize CSS
|
|
51
|
+
this.initViewStyleSelectors()
|
|
52
|
+
this.updateColors()
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
override initViewStyleSelectors() {
|
|
57
|
+
super.initViewStyleSelectors()
|
|
58
|
+
|
|
59
|
+
// 1. Pulsing Animation
|
|
60
|
+
const pulseKeyframe = "UILoadingViewPulse"
|
|
61
|
+
UIView.injectCSS(`
|
|
62
|
+
@keyframes ${pulseKeyframe} {
|
|
63
|
+
0% { background-color: rgba(0, 0, 0, 0.15); }
|
|
64
|
+
50% { background-color: rgba(0, 0, 0, 0.35); }
|
|
65
|
+
100% { background-color: rgba(0, 0, 0, 0.15); }
|
|
66
|
+
}
|
|
67
|
+
`, "UILoadingViewPulseCSS")
|
|
68
|
+
UIView.createStyleSelector(".UILoadingViewPulsing", `animation: ${pulseKeyframe} 1.2s infinite ease-in-out;`)
|
|
69
|
+
|
|
70
|
+
// 2. Spinner Rotation (Bootstrap style)
|
|
71
|
+
const spinKeyframe = "UILoadingViewSpin"
|
|
72
|
+
UIView.injectCSS(`
|
|
73
|
+
@keyframes ${spinKeyframe} {
|
|
74
|
+
from { transform: rotate(0deg); }
|
|
75
|
+
to { transform: rotate(-360deg); }
|
|
76
|
+
}
|
|
77
|
+
`, "UILoadingViewSpinCSS")
|
|
78
|
+
|
|
79
|
+
// We apply the animation to the ::after pseudo-element
|
|
80
|
+
// to avoid conflicts with the framework's positioning on the element itself.
|
|
81
|
+
UIView.createStyleSelector(".UILoadingViewSpinnerContainer::after", `
|
|
82
|
+
content: "";
|
|
83
|
+
display: block;
|
|
84
|
+
width: 100%;
|
|
85
|
+
height: 100%;
|
|
86
|
+
border-radius: 50%;
|
|
87
|
+
border-style: solid;
|
|
88
|
+
border-width: 5px;
|
|
89
|
+
border-color: inherit;
|
|
90
|
+
border-right-color: transparent !important;
|
|
91
|
+
animation: ${spinKeyframe} 1.5s linear infinite;
|
|
92
|
+
box-sizing: border-box;
|
|
93
|
+
`)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
private updateColors() {
|
|
97
|
+
// --- Indicator Mode Styling ---
|
|
98
|
+
const isLightTheme = this._theme === "light"
|
|
99
|
+
|
|
100
|
+
// Background Overlay
|
|
101
|
+
// Light Theme -> UI is light -> Use White overlay with high alpha
|
|
102
|
+
// Dark Theme -> UI is dark -> Use Black overlay with medium alpha
|
|
103
|
+
const overlayColor = isLightTheme
|
|
104
|
+
? new UIColor("rgba(255, 255, 255, 0.7)")
|
|
105
|
+
: new UIColor("rgba(0, 0, 0, 0.5)")
|
|
106
|
+
|
|
107
|
+
// Spinner Color
|
|
108
|
+
// Light Theme -> UI is light -> Spinner should be Dark (e.g. Bootstrap text-body-emphasis #212529 or primary)
|
|
109
|
+
// Dark Theme -> UI is dark -> Spinner should be Light (e.g. #f8f9fa)
|
|
110
|
+
const spinnerColor = isLightTheme
|
|
111
|
+
? new UIColor("#343a40") // Dark Grey
|
|
112
|
+
: new UIColor("#f8f9fa") // Light/White
|
|
113
|
+
|
|
114
|
+
if (!this.isPulsing) {
|
|
115
|
+
this.backgroundColor = overlayColor
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Apply colors to spinner borders
|
|
119
|
+
// We set Top, Bottom, Left. Right is forced transparent by CSS class.
|
|
120
|
+
this.spinnerView.style.borderTopColor = spinnerColor.stringValue
|
|
121
|
+
this.spinnerView.style.borderBottomColor = spinnerColor.stringValue
|
|
122
|
+
this.spinnerView.style.borderLeftColor = spinnerColor.stringValue
|
|
123
|
+
|
|
124
|
+
// --- Pulsing Mode Styling ---
|
|
125
|
+
// We could switch animations here, but simply clearing the background
|
|
126
|
+
// allows the CSS animation to take over if the class is active.
|
|
127
|
+
if (this.isPulsing) {
|
|
128
|
+
this.style.backgroundColor = ""
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
override layoutSubviews() {
|
|
134
|
+
|
|
135
|
+
super.layoutSubviews();
|
|
136
|
+
|
|
137
|
+
// 1. Always fill the parent view
|
|
138
|
+
(this as UILoadingView).configureWithObject({
|
|
139
|
+
style: { height: "100%", width: "100%" }
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
const bounds = this.bounds
|
|
143
|
+
const minDimension = Math.min(bounds.width, bounds.height)
|
|
144
|
+
|
|
145
|
+
// 2. Adaptive Logic
|
|
146
|
+
// If smaller than 40px, use pulsing. Otherwise spinner.
|
|
147
|
+
if (minDimension < 40) {
|
|
148
|
+
this.enablePulsingMode()
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
this.enableIndicatorMode()
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
private enablePulsingMode() {
|
|
156
|
+
if (this.isPulsing) {
|
|
157
|
+
return
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
this.spinnerView.hidden = YES
|
|
161
|
+
this.addStyleClass("UILoadingViewPulsing")
|
|
162
|
+
|
|
163
|
+
// Clear manual background so CSS animation visible
|
|
164
|
+
this.style.backgroundColor = ""
|
|
165
|
+
|
|
166
|
+
this.isPulsing = YES
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
private enableIndicatorMode() {
|
|
170
|
+
// Remove pulsing class
|
|
171
|
+
this.removeStyleClass("UILoadingViewPulsing")
|
|
172
|
+
this.isPulsing = NO
|
|
173
|
+
|
|
174
|
+
this.spinnerView.hidden = NO
|
|
175
|
+
|
|
176
|
+
// Apply Overlay Color immediately
|
|
177
|
+
this.updateColors()
|
|
178
|
+
|
|
179
|
+
// Layout Spinner
|
|
180
|
+
// Bootstrap standard is ~2rem (32px). We can scale it slightly based on available space if we wanted,
|
|
181
|
+
// but a fixed "neutral" size usually looks best unless very restricted.
|
|
182
|
+
const spinnerSize = 32
|
|
183
|
+
const borderWidth = 4 // 0.25em approx
|
|
184
|
+
|
|
185
|
+
const bounds = this.bounds
|
|
186
|
+
|
|
187
|
+
// Center the spinner
|
|
188
|
+
const x = (bounds.width - spinnerSize) / 2
|
|
189
|
+
const y = (bounds.height - spinnerSize) / 2
|
|
190
|
+
|
|
191
|
+
this.spinnerView.frame = new UIRectangle(x, y, spinnerSize, spinnerSize)
|
|
192
|
+
this.spinnerView.style.borderWidth = borderWidth + "px"
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
UIView.LoadingViewClass = UILoadingView
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
|
package/scripts/UIRectangle.ts
CHANGED
|
@@ -941,8 +941,32 @@ export class UIRectangle extends UIObject {
|
|
|
941
941
|
}
|
|
942
942
|
|
|
943
943
|
|
|
944
|
+
IF(condition: boolean): UIRectangleConditionalChain<UIRectangle> {
|
|
945
|
+
const conditionalBlock = new UIRectangleConditionalBlock<UIRectangle>(this, condition)
|
|
946
|
+
return conditionalBlock.getProxy()
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
// These will be intercepted by the proxy, but we define them for TypeScript
|
|
950
|
+
ELSE_IF(condition: boolean): UIRectangle {
|
|
951
|
+
return this
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
ELSE(): UIRectangle {
|
|
955
|
+
return this
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
ENDIF(): this
|
|
959
|
+
ENDIF<T, R>(performFunction: (result: T) => R): R
|
|
960
|
+
ENDIF<T, R>(performFunction?: (result: T) => R): R | this {
|
|
961
|
+
if (performFunction) {
|
|
962
|
+
return performFunction(this as any)
|
|
963
|
+
}
|
|
964
|
+
return this
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
|
|
944
968
|
// Bounding box
|
|
945
|
-
static boundingBoxForPoints(points:
|
|
969
|
+
static boundingBoxForPoints(points: UIPoint[]) {
|
|
946
970
|
const result = new UIRectangle()
|
|
947
971
|
for (let i = 0; i < points.length; i++) {
|
|
948
972
|
result.updateByAddingPoint(points[i])
|
|
@@ -950,6 +974,21 @@ export class UIRectangle extends UIObject {
|
|
|
950
974
|
return result
|
|
951
975
|
}
|
|
952
976
|
|
|
977
|
+
static boundingBoxForRectanglesAndPoints(rectanglesAndPoints: (UIPoint | UIRectangle)[]) {
|
|
978
|
+
const result = new UIRectangle()
|
|
979
|
+
for (let i = 0; i < rectanglesAndPoints.length; i++) {
|
|
980
|
+
const rectangleOrPoint = rectanglesAndPoints[i]
|
|
981
|
+
if (rectangleOrPoint instanceof UIRectangle) {
|
|
982
|
+
result.updateByAddingPoint(rectangleOrPoint.min)
|
|
983
|
+
result.updateByAddingPoint(rectangleOrPoint.max)
|
|
984
|
+
}
|
|
985
|
+
else {
|
|
986
|
+
result.updateByAddingPoint(rectangleOrPoint)
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
return result
|
|
990
|
+
}
|
|
991
|
+
|
|
953
992
|
|
|
954
993
|
beginUpdates() {
|
|
955
994
|
this._isBeingUpdated = YES
|
|
@@ -977,6 +1016,119 @@ export class UIRectangle extends UIObject {
|
|
|
977
1016
|
}
|
|
978
1017
|
|
|
979
1018
|
|
|
1019
|
+
type UIRectangleConditionalChain<T> = {
|
|
1020
|
+
[K in keyof UIRectangle]: UIRectangle[K] extends (...args: infer Args) => infer R
|
|
1021
|
+
? (...args: Args) => UIRectangleConditionalChain<T | R>
|
|
1022
|
+
: UIRectangle[K]
|
|
1023
|
+
} & {
|
|
1024
|
+
ELSE_IF<U>(condition: boolean): UIRectangleConditionalChain<T | U>
|
|
1025
|
+
ELSE<U>(): UIRectangleConditionalChain<T | U>
|
|
1026
|
+
ENDIF(): T
|
|
1027
|
+
ENDIF<R>(performFunction: (result: T) => R): R
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
|
|
1031
|
+
class UIRectangleConditionalBlock<T> {
|
|
1032
|
+
private parentRectangle: UIRectangle
|
|
1033
|
+
private conditionMet: boolean
|
|
1034
|
+
private branchHasExecuted: boolean = false // Renamed for clarity
|
|
1035
|
+
private currentResult: any
|
|
1036
|
+
|
|
1037
|
+
constructor(rectangle: UIRectangle, condition: boolean, initialResult?: any) {
|
|
1038
|
+
this.parentRectangle = rectangle
|
|
1039
|
+
this.conditionMet = condition
|
|
1040
|
+
this.currentResult = initialResult ?? rectangle
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
private createProxy(): UIRectangleConditionalChain<T> {
|
|
1044
|
+
const self = this
|
|
1045
|
+
return new Proxy(this.parentRectangle, {
|
|
1046
|
+
get(target, prop) {
|
|
1047
|
+
// Intercept ELSE_IF
|
|
1048
|
+
if (prop === 'ELSE_IF') {
|
|
1049
|
+
return <U>(condition: boolean): UIRectangleConditionalChain<T | U> => {
|
|
1050
|
+
if (!self.branchHasExecuted && !self.conditionMet) {
|
|
1051
|
+
self.conditionMet = condition
|
|
1052
|
+
}
|
|
1053
|
+
// Return new block that tracks the union type
|
|
1054
|
+
const newBlock = new UIRectangleConditionalBlock<T | U>(
|
|
1055
|
+
self.parentRectangle,
|
|
1056
|
+
self.conditionMet,
|
|
1057
|
+
self.currentResult
|
|
1058
|
+
)
|
|
1059
|
+
newBlock.branchHasExecuted = self.branchHasExecuted
|
|
1060
|
+
return newBlock.createProxy() as any
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
// Intercept ELSE
|
|
1065
|
+
if (prop === 'ELSE') {
|
|
1066
|
+
return <U>(): UIRectangleConditionalChain<T | U> => {
|
|
1067
|
+
if (!self.branchHasExecuted && !self.conditionMet) {
|
|
1068
|
+
self.conditionMet = true
|
|
1069
|
+
}
|
|
1070
|
+
const newBlock = new UIRectangleConditionalBlock<T | U>(
|
|
1071
|
+
self.parentRectangle,
|
|
1072
|
+
self.conditionMet,
|
|
1073
|
+
self.currentResult
|
|
1074
|
+
)
|
|
1075
|
+
newBlock.branchHasExecuted = self.branchHasExecuted
|
|
1076
|
+
return newBlock.createProxy() as any
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
// Intercept ENDIF with overloads
|
|
1081
|
+
if (prop === 'ENDIF') {
|
|
1082
|
+
// Return an overloaded function
|
|
1083
|
+
function endif(): T
|
|
1084
|
+
function endif<R>(performFunction: (result: T) => R): R
|
|
1085
|
+
function endif<R>(performFunction?: (result: T) => R): R | T {
|
|
1086
|
+
if (performFunction) {
|
|
1087
|
+
return performFunction(self.currentResult)
|
|
1088
|
+
}
|
|
1089
|
+
return self.currentResult
|
|
1090
|
+
}
|
|
1091
|
+
return endif
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
// For all other methods
|
|
1095
|
+
const value = target[prop as keyof UIRectangle]
|
|
1096
|
+
if (value instanceof Function) {
|
|
1097
|
+
return (...args: any[]) => {
|
|
1098
|
+
if (self.conditionMet) {
|
|
1099
|
+
// Mark that this branch is executing (only on first method call)
|
|
1100
|
+
if (!self.branchHasExecuted) {
|
|
1101
|
+
self.branchHasExecuted = true
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
const result = (value as Function).apply(target, args)
|
|
1105
|
+
|
|
1106
|
+
// Store the result
|
|
1107
|
+
self.currentResult = result
|
|
1108
|
+
|
|
1109
|
+
// If the method returns a UIRectangle, update parent reference
|
|
1110
|
+
if (result instanceof UIRectangle) {
|
|
1111
|
+
self.parentRectangle = result
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
return self.createProxy()
|
|
1115
|
+
}
|
|
1116
|
+
// If condition not met, return proxy to continue chain
|
|
1117
|
+
return self.createProxy()
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
return value
|
|
1121
|
+
}
|
|
1122
|
+
}) as any
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
getProxy(): UIRectangleConditionalChain<T> {
|
|
1126
|
+
return this.createProxy()
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
|
|
1131
|
+
|
|
980
1132
|
|
|
981
1133
|
|
|
982
1134
|
|
package/scripts/UITextView.ts
CHANGED
|
@@ -35,10 +35,10 @@ export class UITextView extends UIView {
|
|
|
35
35
|
} as const
|
|
36
36
|
|
|
37
37
|
static textAlignment = {
|
|
38
|
-
"left": "
|
|
38
|
+
"left": "flex-start",
|
|
39
39
|
"center": "center",
|
|
40
|
-
"right": "
|
|
41
|
-
"justify": "
|
|
40
|
+
"right": "flex-end",
|
|
41
|
+
"justify": "stretch"
|
|
42
42
|
} as const
|
|
43
43
|
|
|
44
44
|
//#endregion
|
|
@@ -61,7 +61,24 @@ export class UITextView extends UIView {
|
|
|
61
61
|
|
|
62
62
|
this.textColor = this.textColor
|
|
63
63
|
|
|
64
|
-
this.userInteractionEnabled = YES
|
|
64
|
+
this.userInteractionEnabled = YES;
|
|
65
|
+
|
|
66
|
+
(this as UITextView).configureWithObject({
|
|
67
|
+
style: {
|
|
68
|
+
display: "flex",
|
|
69
|
+
flexDirection: "column", // Ensures vertical stacking logic
|
|
70
|
+
|
|
71
|
+
// 'safe' ensures that if content overflows, it aligns to the start (top)
|
|
72
|
+
// instead of overflowing upwards or downwards equally.
|
|
73
|
+
justifyContent: "safe center",
|
|
74
|
+
alignItems: "flex-start", // Keeps text left-aligned (change to "center" for horizontal center)
|
|
75
|
+
|
|
76
|
+
// Optional: ensure text wraps if it gets too long
|
|
77
|
+
whiteSpace: "normal",
|
|
78
|
+
wordWrap: "break-word",
|
|
79
|
+
overflowWrap: "break-word"
|
|
80
|
+
}
|
|
81
|
+
})
|
|
65
82
|
|
|
66
83
|
if (textViewType == UITextView.type.textArea) {
|
|
67
84
|
this.pausesPointerEvents = YES
|
|
@@ -188,12 +205,11 @@ export class UITextView extends UIView {
|
|
|
188
205
|
|
|
189
206
|
get textAlignment() {
|
|
190
207
|
// @ts-ignore
|
|
191
|
-
return this.style.
|
|
208
|
+
return this.style.alignItems
|
|
192
209
|
}
|
|
193
210
|
|
|
194
211
|
set textAlignment(textAlignment: ValueOf<typeof UITextView.textAlignment>) {
|
|
195
|
-
this.
|
|
196
|
-
this.style.textAlign = textAlignment
|
|
212
|
+
this.style.alignItems = textAlignment
|
|
197
213
|
}
|
|
198
214
|
|
|
199
215
|
//#endregion
|