@effindomv2/fui-as 0.1.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 (137) hide show
  1. package/LICENSE.md +7 -0
  2. package/browser/src/common-harness/host-imports.ts +430 -0
  3. package/browser/src/common-harness/interop.ts +39 -0
  4. package/browser/src/common-harness/managed-harness-bitmap-host.ts +92 -0
  5. package/browser/src/common-harness/managed-harness-fetch-host.ts +201 -0
  6. package/browser/src/common-harness/managed-harness-file-host.ts +1101 -0
  7. package/browser/src/common-harness/managed-harness-file-payloads.ts +143 -0
  8. package/browser/src/common-harness/managed-harness-file-types.ts +106 -0
  9. package/browser/src/common-harness/managed-harness-session.ts +15 -0
  10. package/browser/src/common-harness/managed-harness.ts +1323 -0
  11. package/browser/src/common-harness/managed-history.ts +168 -0
  12. package/browser/src/common-harness/persisted-restore-policy.ts +50 -0
  13. package/browser/src/common-harness/persisted-ui-state-controller.ts +309 -0
  14. package/browser/src/common-harness/text-session-bridge.ts +452 -0
  15. package/browser/src/common-harness/types.ts +205 -0
  16. package/browser/src/common-harness/ui-chrome.ts +191 -0
  17. package/browser/src/common-harness/ui-imports.ts +529 -0
  18. package/browser/src/common-harness/wasm-module-cache.ts +47 -0
  19. package/browser/src/common-harness.ts +27 -0
  20. package/browser/src/file-processing-worker.ts +89 -0
  21. package/browser/src/host-events.ts +97 -0
  22. package/browser/src/host-services.ts +203 -0
  23. package/browser/src/index.ts +62 -0
  24. package/browser/src/persisted-ui-state.ts +206 -0
  25. package/browser/src/routed-harness.ts +198 -0
  26. package/browser/src/worker-bootstrap.ts +483 -0
  27. package/browser/src/worker-manager.ts +230 -0
  28. package/browser/src/worker-types.ts +50 -0
  29. package/package.json +89 -0
  30. package/scripts/build-demo-as.sh +91 -0
  31. package/scripts/build.sh +325 -0
  32. package/scripts/generate-host-events.ts +175 -0
  33. package/scripts/generate-host-services.ts +157 -0
  34. package/src/Fui.ts +205 -0
  35. package/src/FuiExports.ts +55 -0
  36. package/src/FuiPrimitives.ts +15 -0
  37. package/src/FuiWorker.ts +3 -0
  38. package/src/FuiWorkerExports.ts +6 -0
  39. package/src/bindings/ui.ts +531 -0
  40. package/src/color.ts +86 -0
  41. package/src/controls/AntiSelectionArea.ts +23 -0
  42. package/src/controls/Button.ts +750 -0
  43. package/src/controls/Checkbox.ts +181 -0
  44. package/src/controls/ContextMenu.ts +885 -0
  45. package/src/controls/ControlTemplateSet.ts +37 -0
  46. package/src/controls/Dialog.ts +355 -0
  47. package/src/controls/Dropdown.ts +856 -0
  48. package/src/controls/Form.ts +110 -0
  49. package/src/controls/NavLink.ts +211 -0
  50. package/src/controls/Popup.ts +129 -0
  51. package/src/controls/ProgressBar.ts +180 -0
  52. package/src/controls/RadioButton.ts +135 -0
  53. package/src/controls/RadioGroup.ts +244 -0
  54. package/src/controls/SelectionArea.ts +75 -0
  55. package/src/controls/Slider.ts +471 -0
  56. package/src/controls/Switch.ts +132 -0
  57. package/src/controls/TextArea.ts +20 -0
  58. package/src/controls/TextInput.ts +7 -0
  59. package/src/controls/index.ts +18 -0
  60. package/src/controls/internal/ButtonPresenter.ts +95 -0
  61. package/src/controls/internal/CheckboxIndicatorPresenter.ts +93 -0
  62. package/src/controls/internal/DropdownChevronPresenter.ts +67 -0
  63. package/src/controls/internal/DropdownFieldPresenter.ts +110 -0
  64. package/src/controls/internal/DropdownOptionRowPresenter.ts +82 -0
  65. package/src/controls/internal/PopupPresenter.ts +198 -0
  66. package/src/controls/internal/PressableIndicatorPresenter.ts +32 -0
  67. package/src/controls/internal/PressableLabeledControl.ts +221 -0
  68. package/src/controls/internal/RadioIndicatorPresenter.ts +73 -0
  69. package/src/controls/internal/SliderPresenter.ts +157 -0
  70. package/src/controls/internal/SwitchIndicatorPresenter.ts +72 -0
  71. package/src/controls/internal/TextInputCore.ts +695 -0
  72. package/src/controls/internal/TextInputPresenter.ts +72 -0
  73. package/src/controls/templating.ts +54 -0
  74. package/src/core/Action.ts +94 -0
  75. package/src/core/Actions.ts +37 -0
  76. package/src/core/Animation.ts +412 -0
  77. package/src/core/Application.ts +328 -0
  78. package/src/core/Assets.ts +264 -0
  79. package/src/core/AttachedProperties.ts +32 -0
  80. package/src/core/Bitmap.ts +70 -0
  81. package/src/core/BoundCallback.ts +104 -0
  82. package/src/core/Callbacks.ts +17 -0
  83. package/src/core/ContextMenuManager.ts +466 -0
  84. package/src/core/DebugApi.ts +30 -0
  85. package/src/core/Disposable.ts +10 -0
  86. package/src/core/DragDropManager.ts +179 -0
  87. package/src/core/DragGesture.ts +184 -0
  88. package/src/core/DynamicAssetIds.ts +24 -0
  89. package/src/core/Errors.ts +48 -0
  90. package/src/core/EventRouter.ts +408 -0
  91. package/src/core/ExternalDropManager.ts +122 -0
  92. package/src/core/Fetch.ts +264 -0
  93. package/src/core/FetchFfi.ts +15 -0
  94. package/src/core/File.ts +1002 -0
  95. package/src/core/FocusAdornerManager.ts +263 -0
  96. package/src/core/FocusVisibility.ts +36 -0
  97. package/src/core/FrameScheduler.ts +28 -0
  98. package/src/core/KeyboardScroll.ts +161 -0
  99. package/src/core/KeyboardScrollTracker.ts +386 -0
  100. package/src/core/Logger.ts +80 -0
  101. package/src/core/Navigation.ts +13 -0
  102. package/src/core/Node.ts +1708 -0
  103. package/src/core/PersistedState.ts +102 -0
  104. package/src/core/PersistedUiState.ts +142 -0
  105. package/src/core/Platform.ts +219 -0
  106. package/src/core/Signal.ts +89 -0
  107. package/src/core/Theme.ts +365 -0
  108. package/src/core/Timers.ts +129 -0
  109. package/src/core/ToolTip.ts +122 -0
  110. package/src/core/ToolTipManager.ts +459 -0
  111. package/src/core/Transitions.ts +34 -0
  112. package/src/core/Typography.ts +204 -0
  113. package/src/core/Worker.ts +196 -0
  114. package/src/core/bind.ts +37 -0
  115. package/src/core/event_exports.ts +596 -0
  116. package/src/core/ffi.ts +728 -0
  117. package/src/host-services/runtime.ts +25 -0
  118. package/src/nodes/FlexBox.ts +789 -0
  119. package/src/nodes/GradientStop.ts +9 -0
  120. package/src/nodes/Grid.ts +183 -0
  121. package/src/nodes/Image.ts +189 -0
  122. package/src/nodes/Portal.ts +14 -0
  123. package/src/nodes/RichText.ts +312 -0
  124. package/src/nodes/ScrollBar.ts +570 -0
  125. package/src/nodes/ScrollBox.ts +415 -0
  126. package/src/nodes/ScrollState.ts +10 -0
  127. package/src/nodes/ScrollView.ts +511 -0
  128. package/src/nodes/Svg.ts +142 -0
  129. package/src/nodes/Text.ts +145 -0
  130. package/src/nodes/TextCore.ts +558 -0
  131. package/src/nodes/VirtualList.ts +431 -0
  132. package/src/nodes/helpers.ts +25 -0
  133. package/src/nodes/index.ts +14 -0
  134. package/src/tsconfig.json +7 -0
  135. package/src/worker/Worker.ts +169 -0
  136. package/src/worker/WorkerJob.ts +65 -0
  137. package/src/worker/ffi.ts +23 -0
@@ -0,0 +1,145 @@
1
+ import { SemanticRole } from "../core/ffi";
2
+ import { FontFamily } from "../core/Typography";
3
+ import { TextCore, TextProps } from "./TextCore";
4
+
5
+ export { TextProps } from "./TextCore";
6
+
7
+ export class Text extends TextCore {
8
+ constructor(content: string = "") {
9
+ super(content);
10
+ this.selectable();
11
+ }
12
+
13
+ static from(props: TextProps): Text {
14
+ const text = new Text(props.content);
15
+ if (props.hasWidth) {
16
+ text.width(props.widthValue, props.widthUnit);
17
+ }
18
+ if (props.hasHeight) {
19
+ text.height(props.heightValue, props.heightUnit);
20
+ }
21
+ if (props.hasFontFamily) {
22
+ const family = props.fontFamilyValue;
23
+ if (family !== null) {
24
+ text.fontFamily(changetype<FontFamily>(family));
25
+ }
26
+ }
27
+ if (props.hasFont && props.hasFontFamily) {
28
+ text.fontSize(props.fontSize);
29
+ } else if (props.hasFont) {
30
+ text.font(props.fontId, props.fontSize);
31
+ }
32
+ if (props.hasFontWeight) {
33
+ text.fontWeight(props.fontWeightValue);
34
+ }
35
+ if (props.hasFontStyle) {
36
+ text.fontStyle(props.fontStyleValue);
37
+ }
38
+ if (props.hasLineHeight) {
39
+ text.lineHeight(props.lineHeightValue);
40
+ }
41
+ if (props.hasColor) {
42
+ text.textColor(props.color);
43
+ }
44
+ if (props.hasTextAlign) {
45
+ text.textAlign(props.textAlignValue);
46
+ }
47
+ if (props.hasVerticalAlign) {
48
+ text.verticalAlign(props.verticalAlignValue);
49
+ }
50
+ if (props.hasLimits) {
51
+ text.textLimits(props.maxChars, props.maxLines);
52
+ }
53
+ if (props.hasOverflow) {
54
+ text.overflow(props.overflowValue);
55
+ }
56
+ if (props.hasOverflowFade) {
57
+ text.overflowFade(props.overflowFadeHorizontalValue, props.overflowFadeVerticalValue);
58
+ }
59
+ if (props.hasObscured) {
60
+ text.obscured(props.obscuredValue);
61
+ }
62
+ if (props.hasEditable) {
63
+ text.editable(props.editableValue);
64
+ }
65
+ if (props.hasCaretColor) {
66
+ text.caretColor(props.caretColorValue);
67
+ }
68
+ if (props.hasSelectable) {
69
+ text.selectable(props.selectableValue, props.selectionColor);
70
+ }
71
+ return text;
72
+ }
73
+
74
+ text(content: string): this {
75
+ super.text(content);
76
+ this.syncDefaultSemantics();
77
+ return this;
78
+ }
79
+
80
+ overflowFade(horizontal: bool = true, vertical: bool = false): this {
81
+ this.setOverflowFade(horizontal, vertical);
82
+ return this;
83
+ }
84
+
85
+ semanticLabel(label: string): this {
86
+ if (!this.hasExplicitSemanticRole()) {
87
+ this.setDefaultSemanticRole(SemanticRole.StaticText);
88
+ }
89
+ super.semanticLabel(label);
90
+ return this;
91
+ }
92
+
93
+ build(): u64 {
94
+ this.syncDefaultSemantics();
95
+ return super.build();
96
+ }
97
+
98
+ _handleTextChanged(text: string): void {
99
+ super._handleTextChanged(text);
100
+ this.syncDefaultSemantics();
101
+ }
102
+
103
+ _handleTextReplaced(start: u32, end: u32, text: string): void {
104
+ super._handleTextReplaced(start, end, text);
105
+ this.syncDefaultSemantics();
106
+ }
107
+
108
+ protected onRetainedParentChanged(): void {
109
+ this.syncDefaultSemantics();
110
+ }
111
+
112
+ private syncDefaultSemantics(): void {
113
+ if (this.hasExplicitSemanticRole()) {
114
+ this.clearDefaultSemanticLabel();
115
+ this.clearDefaultSemanticRole();
116
+ return;
117
+ }
118
+ if (this.hasExplicitSemanticLabel()) {
119
+ this.clearDefaultSemanticLabel();
120
+ this.setDefaultSemanticRole(SemanticRole.StaticText);
121
+ return;
122
+ }
123
+ if (!this.shouldApplyDefaultSemantics()) {
124
+ this.clearDefaultSemanticLabel();
125
+ this.clearDefaultSemanticRole();
126
+ return;
127
+ }
128
+ this.setDefaultSemanticRole(SemanticRole.StaticText);
129
+ this.setDefaultSemanticLabel(this.content);
130
+ }
131
+
132
+ private shouldApplyDefaultSemantics(): bool {
133
+ if (this.content.length == 0) {
134
+ return false;
135
+ }
136
+ let ancestor = this.parentNode;
137
+ while (ancestor !== null) {
138
+ if (ancestor._resolvedSemanticRole() != SemanticRole.None) {
139
+ return false;
140
+ }
141
+ ancestor = ancestor.parentNode;
142
+ }
143
+ return true;
144
+ }
145
+ }
@@ -0,0 +1,558 @@
1
+ import * as ui from "../bindings/ui";
2
+ import { HandlerAction } from "../core/Action";
3
+ import { Disposable, disposeAll } from "../core/Disposable";
4
+ import { Node } from "../core/Node";
5
+ import { warn } from "../core/Logger";
6
+ import { Theme, activeTheme } from "../core/Theme";
7
+ import { FontFamily, FontStack, FontStyle, FontWeight } from "../core/Typography";
8
+ import {
9
+ CursorStyle,
10
+ HandleValue,
11
+ NodeType,
12
+ TextAlign,
13
+ TextOverflow,
14
+ TextVerticalAlign,
15
+ Unit,
16
+ } from "../core/ffi";
17
+
18
+ export class TextProps {
19
+ content: string = "";
20
+ widthValue: f32 = 0.0;
21
+ widthUnit: Unit = Unit.Pixel;
22
+ hasWidth: bool = false;
23
+ heightValue: f32 = 0.0;
24
+ heightUnit: Unit = Unit.Pixel;
25
+ hasHeight: bool = false;
26
+ fontId: u32 = 0;
27
+ fontSize: f32 = 0.0;
28
+ hasFont: bool = false;
29
+ fontFamilyValue: FontFamily | null = null;
30
+ hasFontFamily: bool = false;
31
+ fontWeightValue: FontWeight = FontWeight.Regular;
32
+ hasFontWeight: bool = false;
33
+ fontStyleValue: FontStyle = FontStyle.Normal;
34
+ hasFontStyle: bool = false;
35
+ lineHeightValue: f32 = 0.0;
36
+ hasLineHeight: bool = false;
37
+ color: u32 = 0;
38
+ hasColor: bool = false;
39
+ textAlignValue: TextAlign = TextAlign.Left;
40
+ hasTextAlign: bool = false;
41
+ verticalAlignValue: TextVerticalAlign = TextVerticalAlign.Top;
42
+ hasVerticalAlign: bool = false;
43
+ maxChars: i32 = 2147483647;
44
+ maxLines: i32 = 0;
45
+ hasLimits: bool = false;
46
+ wrappingValue: bool = true;
47
+ hasWrapping: bool = false;
48
+ overflowValue: TextOverflow = TextOverflow.Clip;
49
+ hasOverflow: bool = false;
50
+ overflowFadeHorizontalValue: bool = false;
51
+ overflowFadeVerticalValue: bool = false;
52
+ hasOverflowFade: bool = false;
53
+ obscuredValue: bool = false;
54
+ hasObscured: bool = false;
55
+ editableValue: bool = false;
56
+ hasEditable: bool = false;
57
+ caretColorValue: u32 = 0;
58
+ hasCaretColor: bool = false;
59
+ selectableValue: bool = false;
60
+ selectionColor: u32 = 0;
61
+ hasSelectable: bool = false;
62
+ }
63
+
64
+ export class TextCore extends Node {
65
+ private contentValue: string;
66
+ private widthValue: f32 = 0.0;
67
+ private widthUnit: Unit = Unit.Pixel;
68
+ private hasWidth: bool = false;
69
+ private heightValue: f32 = 0.0;
70
+ private heightUnit: Unit = Unit.Pixel;
71
+ private hasHeight: bool = false;
72
+ private fontId: u32 = 0;
73
+ private fontSizeValue: f32 = 0.0;
74
+ private hasFont: bool = false;
75
+ private fontFamilyValue: FontFamily | null = null;
76
+ private fontWeightValue: FontWeight = FontWeight.Regular;
77
+ private fontStyleValue: FontStyle = FontStyle.Normal;
78
+ private usesDirectFontId: bool = false;
79
+ private lineHeightValue: f32 = 0.0;
80
+ private hasLineHeight: bool = false;
81
+ private color: u32 = 0;
82
+ private hasColor: bool = false;
83
+ private textAlignValue: TextAlign = TextAlign.Left;
84
+ private hasTextAlign: bool = false;
85
+ private verticalAlignValue: TextVerticalAlign = TextVerticalAlign.Top;
86
+ private hasVerticalAlign: bool = false;
87
+ private maxChars: i32 = 2147483647;
88
+ private maxLinesValue: i32 = 0;
89
+ private hasLimits: bool = false;
90
+ private wrappingValue: bool = true;
91
+ private hasWrapping: bool = false;
92
+ private overflowValue: TextOverflow = TextOverflow.Clip;
93
+ private hasOverflow: bool = false;
94
+ private overflowFadeHorizontalValue: bool = false;
95
+ private overflowFadeVerticalValue: bool = false;
96
+ private hasOverflowFade: bool = false;
97
+ private obscuredValue: bool = false;
98
+ private hasObscured: bool = false;
99
+ private editableValue: bool = false;
100
+ private hasEditable: bool = false;
101
+ private caretColorValue: u32 = 0;
102
+ private hasCaretColor: bool = false;
103
+ private selectableValue: bool = false;
104
+ private selectionColor: u32 = 0;
105
+ private hasSelectable: bool = false;
106
+ private textChangedCb: ((text: string) => void) | null = null;
107
+ private selectionChangedCb: ((start: u32, end: u32) => void) | null = null;
108
+ private selectionStartValue: u32 = 0;
109
+ private selectionEndValue: u32 = 0;
110
+ private readonly disposables: Array<Disposable> = new Array<Disposable>();
111
+ private usesThemeSelectionColor: bool = false;
112
+ private textStyleRunsWords: Uint32Array | null = null;
113
+
114
+ constructor(content: string = "") {
115
+ super();
116
+ this.contentValue = content;
117
+ this.track(activeTheme.addAction(new HandlerAction<TextCore, Theme>(this, (text: TextCore, theme: Theme): void => {
118
+ text.handleThemeChanged(theme);
119
+ })));
120
+ }
121
+
122
+ get usesDefaultSelectionBehavior(): bool {
123
+ return !this.hasSelectable;
124
+ }
125
+
126
+ get content(): string {
127
+ return this.contentValue;
128
+ }
129
+
130
+ get isEditableText(): bool {
131
+ return this.editableValue;
132
+ }
133
+
134
+ get isSelectableText(): bool {
135
+ return this.selectableValue;
136
+ }
137
+
138
+ get selectionStart(): u32 {
139
+ return this.selectionStartValue;
140
+ }
141
+
142
+ get selectionEnd(): u32 {
143
+ return this.selectionEndValue;
144
+ }
145
+
146
+ width(value: f32, unit: Unit = Unit.Pixel): this {
147
+ this.widthValue = value;
148
+ this.widthUnit = unit;
149
+ this.hasWidth = true;
150
+ if (this.hasBuiltHandle()) {
151
+ ui.setWidth(this.handle, value, <u32>unit);
152
+ this.notifyRetainedLayoutMutation();
153
+ }
154
+ return this;
155
+ }
156
+
157
+ height(value: f32, unit: Unit = Unit.Pixel): this {
158
+ this.heightValue = value;
159
+ this.heightUnit = unit;
160
+ this.hasHeight = true;
161
+ if (this.hasBuiltHandle()) {
162
+ ui.setHeight(this.handle, value, <u32>unit);
163
+ this.notifyRetainedLayoutMutation();
164
+ }
165
+ return this;
166
+ }
167
+
168
+ text(content: string): this {
169
+ this.contentValue = content;
170
+ if (this.hasBuiltHandle()) {
171
+ ui.setText(this.handle, content);
172
+ this.notifyRetainedMutation();
173
+ }
174
+ return this;
175
+ }
176
+
177
+ protected setTextStyleRunsWords(runsWords: Uint32Array | null): void {
178
+ this.textStyleRunsWords = runsWords;
179
+ if (this.hasBuiltHandle()) {
180
+ if (runsWords === null) {
181
+ ui.setTextStyleRuns(this.handle, new Uint32Array(0));
182
+ } else {
183
+ ui.setTextStyleRuns(this.handle, changetype<Uint32Array>(runsWords));
184
+ }
185
+ this.notifyRetainedMutation();
186
+ }
187
+ }
188
+
189
+ _defaultSemanticLabel(label: string): this {
190
+ this.setDefaultSemanticLabel(label);
191
+ return this;
192
+ }
193
+
194
+ font(fontId: u32, size: f32): this {
195
+ this.usesDirectFontId = true;
196
+ this.fontFamilyValue = null;
197
+ this.fontId = fontId;
198
+ this.fontSizeValue = size;
199
+ this.hasFont = true;
200
+ if (fontId == 0) {
201
+ warn("Typography", "Text.font() received font id 0; the text will render with the default font fallback.");
202
+ }
203
+ if (this.hasBuiltHandle()) {
204
+ this.applyResolvedFont();
205
+ }
206
+ return this;
207
+ }
208
+
209
+ fontStack(stack: FontStack, size: f32): this {
210
+ this.font(stack.id, size);
211
+ return this;
212
+ }
213
+
214
+ fontFamily(family: FontFamily): this {
215
+ this.usesDirectFontId = false;
216
+ this.fontFamilyValue = family;
217
+ if (this.hasBuiltHandle() && this.hasFont) {
218
+ this.applyResolvedFont();
219
+ }
220
+ return this;
221
+ }
222
+
223
+ fontWeight(weight: FontWeight): this {
224
+ this.fontWeightValue = weight;
225
+ if (this.hasBuiltHandle() && this.hasFont) {
226
+ this.applyResolvedFont();
227
+ }
228
+ return this;
229
+ }
230
+
231
+ fontStyle(style: FontStyle): this {
232
+ this.fontStyleValue = style;
233
+ if (this.hasBuiltHandle() && this.hasFont) {
234
+ this.applyResolvedFont();
235
+ }
236
+ return this;
237
+ }
238
+
239
+ fontSize(size: f32): this {
240
+ this.fontSizeValue = size;
241
+ this.hasFont = true;
242
+ if (this.hasBuiltHandle()) {
243
+ this.applyResolvedFont();
244
+ }
245
+ return this;
246
+ }
247
+
248
+ lineHeight(px: f32): this {
249
+ this.lineHeightValue = px;
250
+ this.hasLineHeight = true;
251
+ if (this.hasBuiltHandle()) {
252
+ ui.setLineHeight(this.handle, px);
253
+ this.notifyRetainedMutation();
254
+ }
255
+ return this;
256
+ }
257
+
258
+ textColor(color: u32): this {
259
+ this.color = color;
260
+ this.hasColor = true;
261
+ if (this.hasBuiltHandle()) {
262
+ ui.setTextColor(this.handle, color);
263
+ this.notifyRetainedMutation();
264
+ }
265
+ return this;
266
+ }
267
+
268
+ textAlign(align: TextAlign): this {
269
+ this.textAlignValue = align;
270
+ this.hasTextAlign = true;
271
+ if (this.hasBuiltHandle()) {
272
+ ui.setTextAlign(this.handle, <u32>align);
273
+ this.notifyRetainedMutation();
274
+ }
275
+ return this;
276
+ }
277
+
278
+ verticalAlign(align: TextVerticalAlign): this {
279
+ this.verticalAlignValue = align;
280
+ this.hasVerticalAlign = true;
281
+ if (this.hasBuiltHandle()) {
282
+ ui.setTextVerticalAlign(this.handle, <u32>align);
283
+ this.notifyRetainedMutation();
284
+ }
285
+ return this;
286
+ }
287
+
288
+ maxLines(lines: i32): this {
289
+ this.maxChars = 2147483647;
290
+ this.maxLinesValue = lines;
291
+ this.hasLimits = true;
292
+ if (this.hasBuiltHandle()) {
293
+ ui.setTextLimits(this.handle, this.maxChars, this.maxLinesValue);
294
+ this.notifyRetainedMutation();
295
+ }
296
+ return this;
297
+ }
298
+
299
+ textLimits(maxChars: i32, maxLines: i32): this {
300
+ this.maxChars = maxChars;
301
+ this.maxLinesValue = maxLines;
302
+ this.hasLimits = true;
303
+ if (this.hasBuiltHandle()) {
304
+ ui.setTextLimits(this.handle, maxChars, maxLines);
305
+ this.notifyRetainedMutation();
306
+ }
307
+ return this;
308
+ }
309
+
310
+ wrapping(flag: bool = true): this {
311
+ this.wrappingValue = flag;
312
+ this.hasWrapping = true;
313
+ if (this.hasBuiltHandle()) {
314
+ ui.setTextWrapping(this.handle, flag);
315
+ this.notifyRetainedMutation();
316
+ }
317
+ return this;
318
+ }
319
+
320
+ overflow(mode: TextOverflow): this {
321
+ this.overflowValue = mode;
322
+ this.hasOverflow = true;
323
+ if (this.hasBuiltHandle()) {
324
+ ui.setTextOverflow(this.handle, <u32>mode);
325
+ this.notifyRetainedMutation();
326
+ }
327
+ return this;
328
+ }
329
+
330
+ protected setOverflowFade(horizontal: bool, vertical: bool): void {
331
+ this.overflowFadeHorizontalValue = horizontal;
332
+ this.overflowFadeVerticalValue = vertical;
333
+ this.hasOverflowFade = true;
334
+ if (this.hasBuiltHandle()) {
335
+ ui.setTextOverflowFade(this.handle, horizontal, vertical);
336
+ this.notifyRetainedMutation();
337
+ }
338
+ }
339
+
340
+ obscured(flag: bool): this {
341
+ this.obscuredValue = flag;
342
+ this.hasObscured = true;
343
+ if (this.hasBuiltHandle()) {
344
+ ui.setTextObscured(this.handle, flag);
345
+ this.notifyRetainedMutation();
346
+ }
347
+ return this;
348
+ }
349
+
350
+ editable(flag: bool = true): this {
351
+ this.editableValue = flag;
352
+ this.hasEditable = true;
353
+ if (flag && !this.hasSelectable) {
354
+ this.selectable(true);
355
+ }
356
+ if (this.hasBuiltHandle()) {
357
+ ui.setEditable(this.handle, flag);
358
+ this.notifyRetainedMutation();
359
+ }
360
+ return this;
361
+ }
362
+
363
+ caretColor(color: u32): this {
364
+ this.caretColorValue = color;
365
+ this.hasCaretColor = true;
366
+ if (this.hasBuiltHandle()) {
367
+ ui.setCaretColor(this.handle, color);
368
+ this.notifyRetainedMutation();
369
+ }
370
+ return this;
371
+ }
372
+
373
+ selectable(flag: bool = true, selectionColor: u32 = 0): this {
374
+ this.selectableValue = flag;
375
+ this.usesThemeSelectionColor = selectionColor == 0;
376
+ this.selectionColor = this.usesThemeSelectionColor ? activeTheme.value.colors.selection : selectionColor;
377
+ this.hasSelectable = true;
378
+ if (flag) {
379
+ this.cursor(CursorStyle.Text);
380
+ } else if (this.cursorStyle == CursorStyle.Text) {
381
+ this.cursor(CursorStyle.Default);
382
+ }
383
+ if (this.hasBuiltHandle()) {
384
+ ui.setSelectable(this.handle, flag, this.selectionColor);
385
+ this.notifyRetainedMutation();
386
+ }
387
+ return this;
388
+ }
389
+
390
+ onTextChanged(cb: (text: string) => void): this {
391
+ this.textChangedCb = cb;
392
+ return this;
393
+ }
394
+
395
+ onSelectionChanged(cb: (start: u32, end: u32) => void): this {
396
+ this.selectionChangedCb = cb;
397
+ return this;
398
+ }
399
+
400
+ onClick(cb: () => void): this {
401
+ super.onClick(cb);
402
+ return this;
403
+ }
404
+
405
+ onPointerEnter(cb: () => void): this {
406
+ super.onPointerEnter(cb);
407
+ return this;
408
+ }
409
+
410
+ onPointerLeave(cb: () => void): this {
411
+ super.onPointerLeave(cb);
412
+ return this;
413
+ }
414
+
415
+ build(): u64 {
416
+ if (this.hasBuiltHandle()) {
417
+ return this.handle;
418
+ }
419
+
420
+ this.handle = ui.createNode(<u32>NodeType.Text);
421
+ this.applyNodeMetadata();
422
+ this.finishBuild();
423
+ if (this.hasWidth) {
424
+ ui.setWidth(this.handle, this.widthValue, <u32>this.widthUnit);
425
+ }
426
+ if (this.hasHeight) {
427
+ ui.setHeight(this.handle, this.heightValue, <u32>this.heightUnit);
428
+ }
429
+ ui.setText(this.handle, this.contentValue);
430
+ if (this.textStyleRunsWords !== null) {
431
+ ui.setTextStyleRuns(this.handle, changetype<Uint32Array>(this.textStyleRunsWords));
432
+ }
433
+ if (this.hasFont) {
434
+ ui.setFont(this.handle, this.resolveFontId(), this.fontSizeValue);
435
+ }
436
+ if (this.hasLineHeight) {
437
+ ui.setLineHeight(this.handle, this.lineHeightValue);
438
+ }
439
+ ui.setTextColor(this.handle, this.hasColor ? this.color : activeTheme.value.colors.textPrimary);
440
+ if (this.hasTextAlign) {
441
+ ui.setTextAlign(this.handle, <u32>this.textAlignValue);
442
+ }
443
+ if (this.hasVerticalAlign) {
444
+ ui.setTextVerticalAlign(this.handle, <u32>this.verticalAlignValue);
445
+ }
446
+ if (this.hasLimits) {
447
+ ui.setTextLimits(this.handle, this.maxChars, this.maxLinesValue);
448
+ }
449
+ if (this.hasWrapping) {
450
+ ui.setTextWrapping(this.handle, this.wrappingValue);
451
+ }
452
+ if (this.hasOverflow) {
453
+ ui.setTextOverflow(this.handle, <u32>this.overflowValue);
454
+ }
455
+ if (this.hasOverflowFade) {
456
+ ui.setTextOverflowFade(this.handle, this.overflowFadeHorizontalValue, this.overflowFadeVerticalValue);
457
+ }
458
+ if (this.hasObscured) {
459
+ ui.setTextObscured(this.handle, this.obscuredValue);
460
+ }
461
+ if (this.hasEditable) {
462
+ ui.setEditable(this.handle, this.editableValue);
463
+ }
464
+ if (this.hasSelectable) {
465
+ ui.setSelectable(this.handle, this.selectableValue, this.selectionColor);
466
+ }
467
+ if (this.hasCaretColor) {
468
+ ui.setCaretColor(this.handle, this.caretColorValue);
469
+ }
470
+ return this.handle;
471
+ }
472
+
473
+ dispose(): void {
474
+ disposeAll(this.disposables);
475
+ this.disposeTree();
476
+ }
477
+
478
+ _debugMainAxisPercentValue(isHorizontal: bool): f32 {
479
+ if (isHorizontal) {
480
+ return this.hasWidth && this.widthUnit == Unit.Percent ? this.widthValue : -1.0;
481
+ }
482
+ return this.hasHeight && this.heightUnit == Unit.Percent ? this.heightValue : -1.0;
483
+ }
484
+
485
+ private handleThemeChanged(theme: Theme): void {
486
+ if (this.hasBuiltHandle() && !this.hasColor) {
487
+ ui.setTextColor(this.handle, theme.colors.textPrimary);
488
+ this.notifyRetainedMutation();
489
+ }
490
+ if (this.hasBuiltHandle() && this.hasFont && !this.usesDirectFontId && this.fontFamilyValue === null) {
491
+ this.applyResolvedFont();
492
+ }
493
+ if (this.hasSelectable && this.usesThemeSelectionColor) {
494
+ this.selectionColor = theme.colors.selection;
495
+ if (this.hasBuiltHandle()) {
496
+ ui.setSelectable(this.handle, this.selectableValue, this.selectionColor);
497
+ this.notifyRetainedMutation();
498
+ }
499
+ }
500
+ }
501
+
502
+ private resolveFontId(): u32 {
503
+ if (this.usesDirectFontId) {
504
+ return this.fontId;
505
+ }
506
+ const family = this.fontFamilyValue === null
507
+ ? activeTheme.value.fonts.bodyFamily
508
+ : changetype<FontFamily>(this.fontFamilyValue);
509
+ this.fontId = family.resolve(this.fontWeightValue, this.fontStyleValue);
510
+ return this.fontId;
511
+ }
512
+
513
+ private applyResolvedFont(): void {
514
+ const resolvedFontId = this.resolveFontId();
515
+ if (resolvedFontId == 0) {
516
+ warn(
517
+ "Typography",
518
+ "Text node resolved font id 0 while applying font settings; check the configured FontFamily or font id.",
519
+ );
520
+ }
521
+ ui.setFont(this.handle, resolvedFontId, this.fontSizeValue);
522
+ this.notifyRetainedMutation();
523
+ }
524
+
525
+ _handleTextChanged(text: string): void {
526
+ this.contentValue = text;
527
+ const callback = this.textChangedCb;
528
+ if (callback !== null) {
529
+ callback(text);
530
+ }
531
+ }
532
+
533
+ _handleTextReplaced(start: u32, end: u32, text: string): void {
534
+ const length = this.contentValue.length;
535
+ const clampedStart = min<u32>(start, <u32>length);
536
+ const clampedEnd = min<u32>(max<u32>(start, end), <u32>length);
537
+ const prefix = this.contentValue.substring(0, <i32>clampedStart);
538
+ const suffix = this.contentValue.substring(<i32>clampedEnd);
539
+ this.contentValue = prefix + text + suffix;
540
+ const callback = this.textChangedCb;
541
+ if (callback !== null) {
542
+ callback(this.contentValue);
543
+ }
544
+ }
545
+
546
+ _handleSelectionChanged(start: u32, end: u32): void {
547
+ this.selectionStartValue = start;
548
+ this.selectionEndValue = end;
549
+ const callback = this.selectionChangedCb;
550
+ if (callback !== null) {
551
+ callback(start, end);
552
+ }
553
+ }
554
+
555
+ private track(disposable: Disposable): void {
556
+ this.disposables.push(disposable);
557
+ }
558
+ }